Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

compress.c

Go to the documentation of this file.
00001 
00002 #include "system.h"
00003 #include "file.h"
00004 #include "debug.h"
00005 
00006 FILE_RCSID("@(#)Id: compress.c,v 1.25 2002/07/03 18:26:37 christos Exp ")
00007 
00008 /*@access fmagic @*/
00009 
00010 /*@-nullassign@*/
00011 /*@unchecked@*/
00012 static struct {
00013 /*@observer@*/
00014         const char *magic;
00015         int   maglen;
00016 /*@observer@*/
00017         const char *const argv[3];
00018         int      silent;
00019 } compr[] = {
00020         { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 },         /* compressed */
00021         /* Uncompress can get stuck; so use gzip first if we have it
00022          * Idea from Damien Clark, thanks! */
00023         { "\037\235", 2, { "uncompress", "-c", NULL }, 1 },     /* compressed */
00024         { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 },         /* gzipped */
00025         { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 },         /* frozen */
00026         { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 },         /* SCO LZH */
00027         /* the standard pack utilities do not accept standard input */
00028         { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 },         /* packed */
00029         { "BZh",      3, { "bzip2", "-cd", NULL }, 1 },         /* bzip2-ed */
00030 };
00031 /*@=nullassign@*/
00032 
00033 /*@unchecked@*/
00034 static int ncompr = sizeof(compr) / sizeof(compr[0]);
00035 
00036 /*
00037  * `safe' write for sockets and pipes.
00038  */
00039 static int
00040 swrite(int fd, const void *buf, size_t n)
00041         /*@*/
00042 {
00043         int rv;
00044         size_t rn = n;
00045 
00046         do {
00047                 switch (rv = write(fd, buf, n)) {
00048                 case -1:
00049                         if (errno == EINTR)
00050                                 continue;
00051                         return -1;
00052                 default:
00053                         n -= rv;
00054                         buf = ((const char *)buf) + rv;
00055                         /*@switchbreak@*/ break;
00056                 }
00057         } while (n > 0);
00058         return rn;
00059 }
00060 
00061 
00062 /*
00063  * `safe' read for sockets and pipes.
00064  */
00065 static int
00066 sread(int fd, /*@out@*/ void *buf, size_t n)
00067         /*@modifies *buf @*/
00068 {
00069         int rv;
00070         size_t rn = n;
00071 
00072         do {
00073                 switch (rv = read(fd, buf, n)) {
00074                 case -1:
00075                         if (errno == EINTR)
00076                                 continue;
00077                         return -1;
00078                 case 0:
00079                         return rn - n;
00080                 default:
00081                         n -= rv;
00082                         buf = ((char *)buf) + rv;
00083                         /*@switchbreak@*/ break;
00084                 }
00085         } while (n > 0);
00086         return rn;
00087 }
00088 
00089 int
00090 file_pipe2file(int fd, const void *startbuf, size_t nbytes)
00091 {
00092         char buf[4096];
00093         int r, tfd;
00094 
00095         (void)strcpy(buf, "/tmp/file.XXXXXX");
00096 #ifndef HAVE_MKSTEMP
00097         {
00098                 char *ptr = mktemp(buf);
00099                 tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
00100                 r = errno;
00101                 (void)unlink(ptr);
00102                 errno = r;
00103         }
00104 #else
00105         tfd = mkstemp(buf);
00106         r = errno;
00107         (void)unlink(buf);
00108         errno = r;
00109 #endif
00110         if (tfd == -1) {
00111                 error(EXIT_FAILURE, 0, "Can't create temporary file for pipe copy (%s)\n",
00112                     strerror(errno));
00113                 /*@notreached@*/
00114         }
00115 
00116         if (swrite(tfd, startbuf, nbytes) != nbytes)
00117                 r = 1;
00118         else {
00119                 while ((r = sread(fd, buf, sizeof(buf))) > 0)
00120                         if (swrite(tfd, buf, r) != r)
00121                                 break;
00122         }
00123 
00124         switch (r) {
00125         case -1:
00126                 error(EXIT_FAILURE, 0, "Error copying from pipe to temp file (%s)\n",
00127                     strerror(errno));
00128                 /*@notreached@*/break;
00129         case 0:
00130                 break;
00131         default:
00132                 error(EXIT_FAILURE, 0, "Error while writing to temp file (%s)\n",
00133                     strerror(errno));
00134                 /*@notreached@*/
00135         }
00136 
00137         /*
00138          * We duplicate the file descriptor, because fclose on a
00139          * tmpfile will delete the file, but any open descriptors
00140          * can still access the phantom inode.
00141          */
00142         if ((fd = dup2(tfd, fd)) == -1) {
00143                 error(EXIT_FAILURE, 0, "Couldn't dup destcriptor for temp file(%s)\n",
00144                     strerror(errno));
00145                 /*@notreached@*/
00146         }
00147         (void)close(tfd);
00148         if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
00149                 error(EXIT_FAILURE, 0, "Couldn't seek on temp file (%s)\n", strerror(errno));
00150                 /*@notreached@*/
00151         }
00152         return fd;
00153 }
00154 
00155 #ifdef HAVE_LIBZ
00156 
00157 #define FHCRC           (1 << 1)
00158 #define FEXTRA          (1 << 2)
00159 #define FNAME           (1 << 3)
00160 #define FCOMMENT        (1 << 4)
00161 
00162 /*@-bounds@*/
00163 static int
00164 uncompressgzipped(const unsigned char *old,
00165                 /*@out@*/ unsigned char **newch, int n)
00166         /*@globals fileSystem @*/
00167         /*@modifies *newch, fileSystem @*/
00168 {
00169         unsigned char flg = old[3];
00170         int data_start = 10;
00171         z_stream z;
00172         int rc;
00173 
00174         if (flg & FEXTRA)
00175                 data_start += 2 + old[data_start] + old[data_start + 1] * 256;
00176         if (flg & FNAME) {
00177                 while(old[data_start])
00178                         data_start++;
00179                 data_start++;
00180         }
00181         if(flg & FCOMMENT) {
00182                 while(old[data_start])
00183                         data_start++;
00184                 data_start++;
00185         }
00186         if(flg & FHCRC)
00187                 data_start += 2;
00188 
00189         *newch = (unsigned char *) xmalloc(HOWMANY + 1);
00190         
00191         z.next_in = (Bytef *)(old + data_start);
00192         z.avail_in = n - data_start;
00193         z.next_out = *newch;
00194         z.avail_out = HOWMANY;
00195         z.zalloc = NULL;
00196         z.zfree = NULL;
00197         z.opaque = NULL;
00198 
00199 /*@-sizeoftype@*/
00200 /*@-type@*/
00201         rc = inflateInit2(&z, -15);
00202 /*@=type@*/
00203 /*@=sizeoftype@*/
00204         if (rc != Z_OK) {
00205                 fprintf(stderr,"%s: zlib: %s\n", __progname,
00206                         (z.msg != NULL ? z.msg : ""));
00207                 return 0;
00208         }
00209 
00210 /*@-type@*/
00211         rc = inflate(&z, Z_SYNC_FLUSH);
00212 /*@=type@*/
00213         if (rc != Z_OK && rc != Z_STREAM_END) {
00214                 fprintf(stderr,"%s: zlib: %s\n", __progname,
00215                         (z.msg != NULL ? z.msg : ""));
00216                 return 0;
00217         }
00218 
00219         n = z.total_out;
00220 /*@-type@*/
00221         (void) inflateEnd(&z);
00222 /*@=type@*/
00223         
00224         /* let's keep the nul-terminate tradition */
00225         (*newch)[n++] = '\0';
00226 
00227         return n;
00228 }
00229 /*@=bounds@*/
00230 #endif
00231 
00232 /*@-bounds@*/
00233 static int
00234 uncompressbuf(int method, const unsigned char *old,
00235                 /*@out@*/ unsigned char **newch, int n)
00236         /*@globals fileSystem, internalState @*/
00237         /*@modifies *newch, fileSystem, internalState @*/
00238 {
00239         int fdin[2], fdout[2];
00240         pid_t pid;
00241 
00242 #ifdef HAVE_LIBZ
00243         if (method == 2)
00244                 return uncompressgzipped(old,newch,n);
00245 #endif
00246 
00247         if (pipe(fdin) == -1 || pipe(fdout) == -1) {
00248                 error(EXIT_FAILURE, 0, "cannot create pipe (%s).\n", strerror(errno));  
00249                 /*@notreached@*/
00250         }
00251 
00252         switch ((pid = fork())) {
00253         case 0: /* child */
00254                 (void) close(0);
00255                 (void) dup(fdin[0]);
00256                 (void) close(fdin[0]);
00257                 (void) close(fdin[1]);
00258 
00259                 (void) close(1);
00260                 (void) dup(fdout[1]);
00261                 (void) close(fdout[0]);
00262                 (void) close(fdout[1]);
00263                 if (compr[method].silent)
00264                         (void) close(2);
00265 
00266 #if defined(__GLIBC__)
00267 
00271                 {
00272                    char* bypassVar = (char*) malloc(1024*sizeof(char));
00273                    if (bypassVar != NULL)
00274                    {
00275                       snprintf(bypassVar,1024*sizeof(char), "__PASSTHROUGH_LD_ASSUME_KERNEL_%d", getppid());
00276                       bypassVar[1023] = '\0';
00277                       if (getenv(bypassVar) != NULL)
00278                       {
00279                          char* bypassVal = (char*) malloc(1024*sizeof(char));
00280                          if (bypassVal != NULL)
00281                          {
00282                             snprintf(bypassVal, 1024*sizeof(char), "%s", getenv(bypassVar));
00283                             unsetenv(bypassVar);
00284                             snprintf(bypassVar, 1024*sizeof(char), "LD_ASSUME_KERNEL=%s", bypassVal);
00285                             bypassVar[1023] = '\0';
00286                             putenv(bypassVar);
00287                             free(bypassVal);
00288                          }
00289                          else
00290                          {
00291                             free(bypassVar);
00292                          }
00293                       }
00294                    }
00295                 }
00296 #endif
00297                 (void) execvp(compr[method].argv[0],
00298                        (char *const *)compr[method].argv);
00299                 exit(EXIT_FAILURE);
00300                 /*@notreached@*/ break;
00301         case -1:
00302                 error(EXIT_FAILURE, 0, "could not fork (%s).\n", strerror(errno));
00303                 /*@notreached@*/break;
00304 
00305         default: /* parent */
00306                 (void) close(fdin[0]);
00307                 (void) close(fdout[1]);
00308 
00309                 n--; /* The buffer is NUL terminated, and we don't need that. */
00310                 if (swrite(fdin[1], old, n) != n) {
00311                         n = 0;
00312                         goto errxit;
00313                 }
00314                 (void) close(fdin[1]);
00315                 fdin[1] = -1;
00316                 *newch = (unsigned char *) xmalloc(HOWMANY + 1);
00317                 if ((n = sread(fdout[0], *newch, HOWMANY)) <= 0) {
00318                         free(*newch);
00319                         n = 0;
00320                         goto errxit;
00321                 }
00322                 /* NUL terminate, as every buffer is handled here. */
00323                 (*newch)[n++] = '\0';
00324 errxit:
00325                 if (fdin[1] != -1)
00326                         (void) close(fdin[1]);
00327                 (void) close(fdout[0]);
00328                 pid = waitpid(pid, NULL, 0);
00329                 return n;
00330         }
00331         /*@notreached@*/
00332         return 0;
00333 }
00334 /*@=bounds@*/
00335 
00336 /*
00337  * compress routines:
00338  *      fmagicZ() - returns 0 if not recognized, uncompresses and prints
00339  *                 information if recognized
00340  */
00341 int
00342 fmagicZ(fmagic fm)
00343 {
00344         unsigned char * buf = fm->buf;
00345         int nb = fm->nb;
00346         unsigned char * newbuf;
00347         int newsize;
00348         int i;
00349 
00350         for (i = 0; i < ncompr; i++) {
00351 /*@-boundsread@*/
00352                 if (nb < compr[i].maglen)
00353                         continue;
00354 /*@=boundsread@*/
00355                 if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
00356                     (newsize = uncompressbuf(i, buf, &newbuf, nb)) != 0) {
00357                         fm->buf = newbuf;
00358                         fm->nb = newsize;
00359                         (void) fmagicF(fm, 1);
00360                         fm->buf = buf;
00361                         fm->nb = nb;
00362 /*@-kepttrans@*/
00363                         free(newbuf);
00364 /*@=kepttrans@*/
00365                         printf(" (");
00366                         (void) fmagicF(fm, 0);
00367                         printf(")");
00368                         return 1;
00369                 }
00370         }
00371 
00372         if (i == ncompr)
00373                 return 0;
00374 
00375         return 1;
00376 }

Generated on Sun Jul 3 07:31:01 2005 for rpm by  doxygen 1.3.9.1