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
00009
00010
00011
00012 static struct {
00013
00014 const char *magic;
00015 int maglen;
00016
00017 const char *const argv[3];
00018 int silent;
00019 } compr[] = {
00020 { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 },
00021
00022
00023 { "\037\235", 2, { "uncompress", "-c", NULL }, 1 },
00024 { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 },
00025 { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 },
00026 { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 },
00027
00028 { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 },
00029 { "BZh", 3, { "bzip2", "-cd", NULL }, 1 },
00030 };
00031
00032
00033
00034 static int ncompr = sizeof(compr) / sizeof(compr[0]);
00035
00036
00037
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 break;
00056 }
00057 } while (n > 0);
00058 return rn;
00059 }
00060
00061
00062
00063
00064
00065 static int
00066 sread(int fd, void *buf, size_t n)
00067
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 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
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 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
00135 }
00136
00137
00138
00139
00140
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
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
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
00163 static int
00164 uncompressgzipped(const unsigned char *old,
00165 unsigned char **newch, int n)
00166
00167
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
00200
00201 rc = inflateInit2(&z, -15);
00202
00203
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
00211 rc = inflate(&z, Z_SYNC_FLUSH);
00212
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
00221 (void) inflateEnd(&z);
00222
00223
00224
00225 (*newch)[n++] = '\0';
00226
00227 return n;
00228 }
00229
00230 #endif
00231
00232
00233 static int
00234 uncompressbuf(int method, const unsigned char *old,
00235 unsigned char **newch, int n)
00236
00237
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
00250 }
00251
00252 switch ((pid = fork())) {
00253 case 0:
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 break;
00301 case -1:
00302 error(EXIT_FAILURE, 0, "could not fork (%s).\n", strerror(errno));
00303 break;
00304
00305 default:
00306 (void) close(fdin[0]);
00307 (void) close(fdout[1]);
00308
00309 n--;
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
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
00332 return 0;
00333 }
00334
00335
00336
00337
00338
00339
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
00352 if (nb < compr[i].maglen)
00353 continue;
00354
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
00363 free(newbuf);
00364
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 }