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