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

file/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 pipe2file(int fd, 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                 (void) fprintf(stderr,"%s: zlib: %s\n", __progname, z.msg);
00206                 return 0;
00207         }
00208 
00209 /*@-type@*/
00210         rc = inflate(&z, Z_SYNC_FLUSH);
00211 /*@=type@*/
00212         if (rc != Z_OK && rc != Z_STREAM_END) {
00213                 fprintf(stderr,"%s: zlib: %s\n", __progname, z.msg);
00214                 return 0;
00215         }
00216 
00217         n = z.total_out;
00218 /*@-type@*/
00219         (void) inflateEnd(&z);
00220 /*@=type@*/
00221         
00222         /* let's keep the nul-terminate tradition */
00223         (*newch)[n++] = '\0';
00224 
00225         return n;
00226 }
00227 /*@=bounds@*/
00228 #endif
00229 
00230 /*@-bounds@*/
00231 static int
00232 uncompressbuf(int method, const unsigned char *old,
00233                 /*@out@*/ unsigned char **newch, int n)
00234         /*@globals fileSystem, internalState @*/
00235         /*@modifies *newch, fileSystem, internalState @*/
00236 {
00237         int fdin[2], fdout[2];
00238         pid_t pid;
00239 
00240 #ifdef HAVE_LIBZ
00241         if (method == 2)
00242                 return uncompressgzipped(old,newch,n);
00243 #endif
00244 
00245         if (pipe(fdin) == -1 || pipe(fdout) == -1) {
00246                 error(EXIT_FAILURE, 0, "cannot create pipe (%s).\n", strerror(errno));  
00247                 /*@notreached@*/
00248         }
00249 
00250         switch ((pid = fork())) {
00251         case 0: /* child */
00252                 (void) close(0);
00253                 (void) dup(fdin[0]);
00254                 (void) close(fdin[0]);
00255                 (void) close(fdin[1]);
00256 
00257                 (void) close(1);
00258                 (void) dup(fdout[1]);
00259                 (void) close(fdout[0]);
00260                 (void) close(fdout[1]);
00261                 if (compr[method].silent)
00262                         (void) close(2);
00263 
00264                 (void) execvp(compr[method].argv[0],
00265                        (char *const *)compr[method].argv);
00266                 exit(EXIT_FAILURE);
00267                 /*@notreached@*/ break;
00268         case -1:
00269                 error(EXIT_FAILURE, 0, "could not fork (%s).\n", strerror(errno));
00270                 /*@notreached@*/break;
00271 
00272         default: /* parent */
00273                 (void) close(fdin[0]);
00274                 (void) close(fdout[1]);
00275 
00276                 n--; /* The buffer is NUL terminated, and we don't need that. */
00277                 if (swrite(fdin[1], old, n) != n) {
00278                         n = 0;
00279                         goto errxit;
00280                 }
00281                 (void) close(fdin[1]);
00282                 fdin[1] = -1;
00283                 *newch = (unsigned char *) xmalloc(HOWMANY + 1);
00284                 if ((n = sread(fdout[0], *newch, HOWMANY)) <= 0) {
00285                         free(*newch);
00286                         n = 0;
00287                         goto errxit;
00288                 }
00289                 /* NUL terminate, as every buffer is handled here. */
00290                 (*newch)[n++] = '\0';
00291 errxit:
00292                 if (fdin[1] != -1)
00293                         (void) close(fdin[1]);
00294                 (void) close(fdout[0]);
00295                 pid = waitpid(pid, NULL, 0);
00296                 return n;
00297         }
00298         /*@notreached@*/
00299         return 0;
00300 }
00301 /*@=bounds@*/
00302 
00303 /*
00304  * compress routines:
00305  *      fmagicZ() - returns 0 if not recognized, uncompresses and prints
00306  *                 information if recognized
00307  */
00308 int
00309 fmagicZ(fmagic fm)
00310 {
00311         unsigned char * buf = fm->buf;
00312         int nb = fm->nb;
00313         unsigned char * newbuf;
00314         int newsize;
00315         int i;
00316 
00317         for (i = 0; i < ncompr; i++) {
00318 /*@-boundsread@*/
00319                 if (nb < compr[i].maglen)
00320                         continue;
00321 /*@=boundsread@*/
00322                 if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
00323                     (newsize = uncompressbuf(i, buf, &newbuf, nb)) != 0) {
00324                         fm->buf = newbuf;
00325                         fm->nb = newsize;
00326                         (void) fmagicF(fm, 1);
00327                         fm->buf = buf;
00328                         fm->nb = nb;
00329 /*@-kepttrans@*/
00330                         free(newbuf);
00331 /*@=kepttrans@*/
00332                         printf(" (");
00333                         (void) fmagicF(fm, 0);
00334                         printf(")");
00335                         return 1;
00336                 }
00337         }
00338 
00339         if (i == ncompr)
00340                 return 0;
00341 
00342         return 1;
00343 }

Generated on Sun Oct 26 13:01:58 2003 for rpm by doxygen1.2.18