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 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
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 (void) fprintf(stderr,"%s: zlib: %s\n", __progname, z.msg);
00206 return 0;
00207 }
00208
00209
00210 rc = inflate(&z, Z_SYNC_FLUSH);
00211
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
00219 (void) inflateEnd(&z);
00220
00221
00222
00223 (*newch)[n++] = '\0';
00224
00225 return n;
00226 }
00227
00228 #endif
00229
00230
00231 static int
00232 uncompressbuf(int method, const unsigned char *old,
00233 unsigned char **newch, int n)
00234
00235
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
00248 }
00249
00250 switch ((pid = fork())) {
00251 case 0:
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 break;
00268 case -1:
00269 error(EXIT_FAILURE, 0, "could not fork (%s).\n", strerror(errno));
00270 break;
00271
00272 default:
00273 (void) close(fdin[0]);
00274 (void) close(fdout[1]);
00275
00276 n--;
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
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
00299 return 0;
00300 }
00301
00302
00303
00304
00305
00306
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
00319 if (nb < compr[i].maglen)
00320 continue;
00321
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
00330 free(newbuf);
00331
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 }