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 }