00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "file.h"
00036 #include "magic.h"
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #ifdef HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042 #include <string.h>
00043 #include <errno.h>
00044 #include <sys/types.h>
00045 #include <sys/ioctl.h>
00046 #ifdef HAVE_SYS_WAIT_H
00047 #include <sys/wait.h>
00048 #endif
00049 #if defined(HAVE_SYS_TIME_H)
00050 #include <sys/time.h>
00051 #endif
00052 #ifdef HAVE_LIBZ
00053 #include <zlib.h>
00054 #endif
00055
00056
00057 #ifndef lint
00058 FILE_RCSID("@(#)$File: compress.c,v 1.50 2007/03/01 22:14:54 christos Exp $")
00059 #endif
00060
00061
00062
00063 private struct {
00064
00065 const char *magic;
00066 size_t maglen;
00067
00068 const char *const argv[3];
00069 int silent;
00070 } compr[] = {
00071 { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 },
00072
00073
00074 { "\037\235", 2, { "uncompress", "-c", NULL }, 1 },
00075 { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 },
00076 { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 },
00077 { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 },
00078
00079 { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 },
00080 { "PK\3\4", 4, { "gzip", "-cdq", NULL }, 1 },
00081
00082 { "BZh", 3, { "bzip2", "-cd", NULL }, 1 },
00083 };
00084
00085
00086
00087 private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
00088
00089 #define NODATA ((size_t)~0)
00090
00091
00092 private ssize_t swrite(int fd, const void *buf, size_t n)
00093 ;
00094 private size_t uncompressbuf(struct magic_set *ms, int fd, size_t method,
00095 const unsigned char *old, unsigned char **newch, size_t n)
00096
00097 ;
00098 #ifdef HAVE_LIBZ
00099 private size_t
00100 uncompressgzipped(struct magic_set *ms, const unsigned char *old,
00101 unsigned char **newch, size_t n)
00102 ;
00103 #endif
00104
00105 protected int
00106 file_zmagic(struct magic_set *ms, int fd, const char *name,
00107 const unsigned char *buf, size_t nbytes)
00108 {
00109 unsigned char *newbuf = NULL;
00110 size_t i, nsz;
00111 int rv = 0;
00112
00113 if ((ms->flags & MAGIC_COMPRESS) == 0)
00114 return 0;
00115
00116 for (i = 0; i < ncompr; i++) {
00117 if (nbytes < compr[i].maglen)
00118 continue;
00119 if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
00120 (nsz = uncompressbuf(ms, fd, i, buf, &newbuf,
00121 nbytes)) != NODATA) {
00122 ms->flags &= ~MAGIC_COMPRESS;
00123 rv = -1;
00124 if (file_buffer(ms, -1, name, newbuf, nsz) == -1)
00125 goto error;
00126 if (file_printf(ms, " (") == -1)
00127 goto error;
00128 if (file_buffer(ms, -1, NULL, buf, nbytes) == -1)
00129 goto error;
00130 if (file_printf(ms, ")") == -1)
00131 goto error;
00132 rv = 1;
00133 break;
00134 }
00135 }
00136 error:
00137 if (newbuf)
00138 free(newbuf);
00139 ms->flags |= MAGIC_COMPRESS;
00140 return rv;
00141 }
00142
00143
00144
00145
00146 private ssize_t
00147 swrite(int fd, const void *buf, size_t n)
00148 {
00149 int rv;
00150 size_t rn = n;
00151
00152 do
00153 switch (rv = write(fd, buf, n)) {
00154 case -1:
00155 if (errno == EINTR)
00156 continue;
00157 return -1;
00158 default:
00159 n -= rv;
00160 buf = ((const char *)buf) + rv;
00161 break;
00162 }
00163 while (n > 0);
00164 return rn;
00165 }
00166
00167
00168
00169
00170
00171 protected ssize_t
00172 sread(int fd, void *buf, size_t n, int canbepipe)
00173 {
00174 int rv, cnt;
00175 #ifdef FIONREAD
00176 int t = 0;
00177 #endif
00178 size_t rn = n;
00179
00180 if (fd == STDIN_FILENO)
00181 goto nocheck;
00182
00183 #ifdef FIONREAD
00184 if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1) || (t == 0)) {
00185 #ifdef FD_ZERO
00186 for (cnt = 0;; cnt++) {
00187 fd_set check;
00188 struct timeval tout = {0, 100 * 1000};
00189 int rv;
00190
00191 FD_ZERO(&check);
00192 FD_SET(fd, &check);
00193
00194
00195
00196
00197
00198 rv = select(fd + 1, &check, NULL, NULL, &tout);
00199 if (rv == -1) {
00200 if (errno == EINTR || errno == EAGAIN)
00201 continue;
00202 } else if (rv == 0 && cnt >= 5) {
00203 return 0;
00204 } else
00205 break;
00206 }
00207 #endif
00208 (void)ioctl(fd, FIONREAD, &t);
00209 }
00210
00211 if (t > 0 && (size_t)t < n) {
00212 n = t;
00213 rn = n;
00214 }
00215 #endif
00216
00217 nocheck:
00218 do
00219 switch ((rv = read(fd, buf, n))) {
00220 case -1:
00221 if (errno == EINTR)
00222 continue;
00223 return -1;
00224 case 0:
00225 return rn - n;
00226 default:
00227 n -= rv;
00228 buf = ((char *)buf) + rv;
00229 break;
00230 }
00231 while (n > 0);
00232 return rn;
00233 }
00234
00235 protected int
00236 file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
00237 size_t nbytes)
00238 {
00239 char buf[4096];
00240 int r, tfd;
00241
00242 (void)strcpy(buf, "/tmp/file.XXXXXX");
00243 #ifndef HAVE_MKSTEMP
00244 {
00245 char *ptr = mktemp(buf);
00246 tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
00247 r = errno;
00248 (void)unlink(ptr);
00249 errno = r;
00250 }
00251 #else
00252 tfd = mkstemp(buf);
00253 r = errno;
00254 (void)unlink(buf);
00255 errno = r;
00256 #endif
00257 if (tfd == -1) {
00258 file_error(ms, errno,
00259 "cannot create temporary file for pipe copy");
00260 return -1;
00261 }
00262
00263 if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
00264 r = 1;
00265 else {
00266 while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
00267 if (swrite(tfd, buf, (size_t)r) != r)
00268 break;
00269 }
00270
00271 switch (r) {
00272 case -1:
00273 file_error(ms, errno, "error copying from pipe to temp file");
00274 return -1;
00275 case 0:
00276 break;
00277 default:
00278 file_error(ms, errno, "error while writing to temp file");
00279 return -1;
00280 }
00281
00282
00283
00284
00285
00286
00287 if ((fd = dup2(tfd, fd)) == -1) {
00288 file_error(ms, errno, "could not dup descriptor for temp file");
00289 return -1;
00290 }
00291 (void)close(tfd);
00292 if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
00293 file_badseek(ms);
00294 return -1;
00295 }
00296 return fd;
00297 }
00298
00299 #ifdef HAVE_LIBZ
00300
00301 #define FHCRC (1 << 1)
00302 #define FEXTRA (1 << 2)
00303 #define FNAME (1 << 3)
00304 #define FCOMMENT (1 << 4)
00305
00306 private size_t
00307 uncompressgzipped(struct magic_set *ms, const unsigned char *old,
00308 unsigned char **newch, size_t n)
00309 {
00310 unsigned char flg = old[3];
00311 size_t data_start = 10;
00312 z_stream z;
00313 int rc;
00314
00315 if (flg & FEXTRA) {
00316 if (data_start+1 >= n)
00317 return 0;
00318 data_start += 2 + old[data_start] + old[data_start + 1] * 256;
00319 }
00320 if (flg & FNAME) {
00321 while(data_start < n && old[data_start])
00322 data_start++;
00323 data_start++;
00324 }
00325 if(flg & FCOMMENT) {
00326 while(data_start < n && old[data_start])
00327 data_start++;
00328 data_start++;
00329 }
00330 if(flg & FHCRC)
00331 data_start += 2;
00332
00333 if (data_start >= n)
00334 return 0;
00335 if ((*newch = (unsigned char *)malloc(HOWMANY + 1)) == NULL) {
00336 return 0;
00337 }
00338
00339
00340 z.next_in = (Bytef *)strchr((const char *)old + data_start,
00341 old[data_start]);
00342 z.avail_in = n - data_start;
00343 z.next_out = *newch;
00344 z.avail_out = HOWMANY;
00345 z.zalloc = Z_NULL;
00346 z.zfree = Z_NULL;
00347 z.opaque = Z_NULL;
00348
00349 rc = inflateInit2(&z, -15);
00350 if (rc != Z_OK) {
00351 file_error(ms, 0, "zlib: %s", z.msg);
00352 return 0;
00353 }
00354
00355 rc = inflate(&z, Z_SYNC_FLUSH);
00356 if (rc != Z_OK && rc != Z_STREAM_END) {
00357 file_error(ms, 0, "zlib: %s", z.msg);
00358 return 0;
00359 }
00360
00361 n = (size_t)z.total_out;
00362 (void)inflateEnd(&z);
00363
00364
00365 (*newch)[n] = '\0';
00366
00367 return n;
00368 }
00369 #endif
00370
00371
00372 private size_t
00373 uncompressbuf(struct magic_set *ms, int fd, size_t method,
00374 const unsigned char *old, unsigned char **newch, size_t n)
00375 {
00376 int fdin[2], fdout[2];
00377 int r;
00378
00379 #ifdef HAVE_LIBZ
00380 if (method == 2)
00381 return uncompressgzipped(ms, old, newch, n);
00382 #endif
00383 (void)fflush(stdout);
00384 (void)fflush(stderr);
00385
00386 if ((fd != -1 && pipe(fdin) == -1) || pipe(fdout) == -1) {
00387 file_error(ms, errno, "cannot create pipe");
00388 return NODATA;
00389 }
00390 switch (fork()) {
00391 case 0:
00392 (void) close(0);
00393 if (fd != -1) {
00394 (void) dup(fd);
00395 (void) lseek(0, (off_t)0, SEEK_SET);
00396 } else {
00397 (void) dup(fdin[0]);
00398 (void) close(fdin[0]);
00399 (void) close(fdin[1]);
00400 }
00401
00402 (void) close(1);
00403 (void) dup(fdout[1]);
00404 (void) close(fdout[0]);
00405 (void) close(fdout[1]);
00406 #ifndef DEBUG
00407 if (compr[method].silent)
00408 (void)close(2);
00409 #endif
00410
00411 (void) execvp(compr[method].argv[0],
00412 (char *const *)(intptr_t)compr[method].argv);
00413 #ifdef DEBUG
00414 (void)fprintf(stderr, "exec `%s' failed (%s)\n",
00415 compr[method].argv[0], strerror(errno));
00416 #endif
00417 exit(EXIT_FAILURE);
00418
00419 break;
00420 case -1:
00421 file_error(ms, errno, "could not fork");
00422 return NODATA;
00423
00424 default:
00425 (void) close(fdout[1]);
00426 if (fd == -1) {
00427 (void) close(fdin[0]);
00428
00429
00430
00431
00432 switch (fork()) {
00433 case 0:
00434 (void)close(fdout[0]);
00435 if (swrite(fdin[1], old, n) != (ssize_t)n) {
00436 #ifdef DEBUG
00437 (void)fprintf(stderr,
00438 "Write failed (%s)\n",
00439 strerror(errno));
00440 #endif
00441 exit(EXIT_FAILURE);
00442 }
00443 exit(EXIT_SUCCESS);
00444
00445 break;
00446
00447 case -1:
00448 #ifdef DEBUG
00449 (void)fprintf(stderr, "Fork failed (%s)\n",
00450 strerror(errno));
00451 #endif
00452 exit(EXIT_FAILURE);
00453
00454 break;
00455
00456 default:
00457 break;
00458 }
00459 (void) close(fdin[1]);
00460 fdin[1] = -1;
00461 }
00462
00463 if ((*newch = (unsigned char *) malloc(HOWMANY + 1)) == NULL) {
00464 #ifdef DEBUG
00465 (void)fprintf(stderr, "Malloc failed (%s)\n",
00466 strerror(errno));
00467 #endif
00468 n = 0;
00469 goto err;
00470 }
00471 if ((r = sread(fdout[0], *newch, HOWMANY, 0)) <= 0) {
00472 #ifdef DEBUG
00473 (void)fprintf(stderr, "Read failed (%s)\n",
00474 strerror(errno));
00475 #endif
00476 free(*newch);
00477 n = 0;
00478 newch[0] = '\0';
00479 goto err;
00480 } else {
00481 n = r;
00482 }
00483
00484 (*newch)[n] = '\0';
00485 err:
00486 if (fdin[1] != -1)
00487 (void) close(fdin[1]);
00488 (void) close(fdout[0]);
00489 #ifdef WNOHANG
00490 while (waitpid(-1, NULL, WNOHANG) != -1)
00491 continue;
00492 #else
00493 (void)wait(NULL);
00494 #endif
00495 return n;
00496 }
00497
00498 }