/* * fopen() for a compressed file */ struct zfile *zfile_fopen (const char *name, const char *mode) { struct zfile *l; FILE *f; char zipname[1000]; if( *name == '\0' ) return NULL; l = zfile_create (); l->name = strdup (name); #ifdef SINGLEFILE if (zfile_opensinglefile (l)) return l; #endif f = openzip (l->name, zipname); if (f) { if (strcasecmp (mode, "rb")) { zfile_fclose (l); fclose (f); return 0; } l->zipname = strdup (zipname); } if (!f) { f = fopen (name, mode); if (!f) { zfile_fclose (l); return 0; } } l->f = f; l = zuncompress (l); return l; }
static void handle_stdin(void) { unsigned char header1[4]; off_t usize, gsize; enum filetype method; ssize_t bytes_read; #ifndef NO_COMPRESS_SUPPORT FILE *in; #endif #ifndef SMALL if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) { maybe_warnx("standard input is a terminal -- ignoring"); return; } #endif if (lflag) { struct stat isb; /* XXX could read the whole file, etc. */ if (fstat(STDIN_FILENO, &isb) < 0) { maybe_warn("fstat"); return; } print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime); return; } bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1); if (bytes_read == -1) { maybe_warn("can't read stdin"); return; } else if (bytes_read != sizeof(header1)) { maybe_warnx("(stdin): unexpected end of file"); return; } method = file_gettype(header1); switch (method) { default: #ifndef SMALL if (fflag == 0) { maybe_warnx("unknown compression format"); return; } usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO); break; #endif case FT_GZIP: usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO, (char *)header1, sizeof header1, &gsize, "(stdin)"); break; #ifndef NO_BZIP2_SUPPORT case FT_BZIP2: usize = unbzip2(STDIN_FILENO, STDOUT_FILENO, (char *)header1, sizeof header1, &gsize); break; #endif #ifndef NO_COMPRESS_SUPPORT case FT_Z: if ((in = zdopen(STDIN_FILENO)) == NULL) { maybe_warnx("zopen of stdin"); return; } usize = zuncompress(in, stdout, (char *)header1, sizeof header1, &gsize); fclose(in); break; #endif #ifndef NO_PACK_SUPPORT case FT_PACK: usize = unpack(STDIN_FILENO, STDOUT_FILENO, (char *)header1, sizeof header1, &gsize); break; #endif #ifndef NO_XZ_SUPPORT case FT_XZ: usize = unxz(STDIN_FILENO, STDOUT_FILENO, (char *)header1, sizeof header1, &gsize); break; #endif } #ifndef SMALL if (vflag && !tflag && usize != -1 && gsize != -1) print_verbage(NULL, NULL, usize, gsize); if (vflag && tflag) print_test("(stdin)", usize != -1); #endif }
/* uncompress the given file and remove the original */ static off_t file_uncompress(char *file, char *outfile, size_t outsize) { struct stat isb, osb; off_t size; ssize_t rbytes; unsigned char header1[4]; enum filetype method; int fd, ofd, zfd = -1; #ifndef SMALL ssize_t rv; time_t timestamp = 0; char name[PATH_MAX + 1]; #endif /* gather the old name info */ fd = open(file, O_RDONLY); if (fd < 0) { maybe_warn("can't open %s", file); goto lose; } strlcpy(outfile, file, outsize); if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) { maybe_warnx("%s: unknown suffix -- ignored", file); goto lose; } rbytes = read(fd, header1, sizeof header1); if (rbytes != sizeof header1) { /* we don't want to fail here. */ #ifndef SMALL if (fflag) goto lose; #endif if (rbytes == -1) maybe_warn("can't read %s", file); else goto unexpected_EOF; goto lose; } method = file_gettype(header1); #ifndef SMALL if (fflag == 0 && method == FT_UNKNOWN) { maybe_warnx("%s: not in gzip format", file); goto lose; } #endif #ifndef SMALL if (method == FT_GZIP && Nflag) { unsigned char ts[4]; /* timestamp */ rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP); if (rv >= 0 && rv < (ssize_t)(sizeof ts)) goto unexpected_EOF; if (rv == -1) { if (!fflag) maybe_warn("can't read %s", file); goto lose; } timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0]; if (header1[3] & ORIG_NAME) { rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME); if (rbytes < 0) { maybe_warn("can't read %s", file); goto lose; } if (name[0] != '\0') { char *dp, *nf; /* Make sure that name is NUL-terminated */ name[rbytes] = '\0'; /* strip saved directory name */ nf = strrchr(name, '/'); if (nf == NULL) nf = name; else nf++; /* preserve original directory name */ dp = strrchr(file, '/'); if (dp == NULL) dp = file; else dp++; snprintf(outfile, outsize, "%.*s%.*s", (int) (dp - file), file, (int) rbytes, nf); } } } #endif lseek(fd, 0, SEEK_SET); if (cflag == 0 || lflag) { if (fstat(fd, &isb) != 0) goto lose; #ifndef SMALL if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) { maybe_warnx("%s has %d other links -- skipping", file, isb.st_nlink - 1); goto lose; } if (nflag == 0 && timestamp) isb.st_mtime = timestamp; if (check_outfile(outfile) == 0) goto lose; #endif } if (cflag == 0 && lflag == 0) { zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600); if (zfd == STDOUT_FILENO) { /* We won't close STDOUT_FILENO later... */ zfd = dup(zfd); close(STDOUT_FILENO); } if (zfd == -1) { maybe_warn("can't open %s", outfile); goto lose; } } else zfd = STDOUT_FILENO; switch (method) { #ifndef NO_BZIP2_SUPPORT case FT_BZIP2: /* XXX */ if (lflag) { maybe_warnx("no -l with bzip2 files"); goto lose; } size = unbzip2(fd, zfd, NULL, 0, NULL); break; #endif #ifndef NO_COMPRESS_SUPPORT case FT_Z: { FILE *in, *out; /* XXX */ if (lflag) { maybe_warnx("no -l with Lempel-Ziv files"); goto lose; } if ((in = zdopen(fd)) == NULL) { maybe_warn("zdopen for read: %s", file); goto lose; } out = fdopen(dup(zfd), "w"); if (out == NULL) { maybe_warn("fdopen for write: %s", outfile); fclose(in); goto lose; } size = zuncompress(in, out, NULL, 0, NULL); /* need to fclose() if ferror() is true... */ if (ferror(in) | fclose(in)) { maybe_warn("failed infile fclose"); unlink(outfile); (void)fclose(out); } if (fclose(out) != 0) { maybe_warn("failed outfile fclose"); unlink(outfile); goto lose; } break; } #endif #ifndef NO_PACK_SUPPORT case FT_PACK: if (lflag) { maybe_warnx("no -l with packed files"); goto lose; } size = unpack(fd, zfd, NULL, 0, NULL); break; #endif #ifndef NO_XZ_SUPPORT case FT_XZ: if (lflag) { maybe_warnx("no -l with xz files"); goto lose; } size = unxz(fd, zfd, NULL, 0, NULL); break; #endif #ifndef SMALL case FT_UNKNOWN: if (lflag) { maybe_warnx("no -l for unknown filetypes"); goto lose; } size = cat_fd(NULL, 0, NULL, fd); break; #endif default: if (lflag) { print_list(fd, isb.st_size, outfile, isb.st_mtime); close(fd); return -1; /* XXX */ } size = gz_uncompress(fd, zfd, NULL, 0, NULL, file); break; } if (close(fd) != 0) maybe_warn("couldn't close input"); if (zfd != STDOUT_FILENO && close(zfd) != 0) maybe_warn("couldn't close output"); if (size == -1) { if (cflag == 0) unlink(outfile); maybe_warnx("%s: uncompress failed", file); return -1; } /* if testing, or we uncompressed to stdout, this is all we need */ #ifndef SMALL if (tflag) return size; #endif /* if we are uncompressing to stdin, don't remove the file. */ if (cflag) return size; /* * if we create a file... */ /* * if we can't stat the file don't remove the file. */ ofd = open(outfile, O_RDWR, 0); if (ofd == -1) { maybe_warn("couldn't open (leaving original): %s", outfile); return -1; } if (fstat(ofd, &osb) != 0) { maybe_warn("couldn't stat (leaving original): %s", outfile); close(ofd); return -1; } if (osb.st_size != size) { maybe_warnx("stat gave different size: %" PRIdOFF " != %" PRIdOFF " (leaving original)", size, osb.st_size); close(ofd); unlink(outfile); return -1; } unlink_input(file, &isb); #ifndef SMALL copymodes(ofd, &isb, outfile); #endif close(ofd); return size; unexpected_EOF: maybe_warnx("%s: unexpected end of file", file); lose: if (fd != -1) close(fd); if (zfd != -1 && zfd != STDOUT_FILENO) close(fd); return -1; }
static struct zfile *unzip (struct zfile *z) { unzFile uz; unz_file_info file_info; char filename_inzip[2048]; struct zfile *zf; unsigned int err, zipcnt, i, we_have_file = 0; int select; char tmphist[MAX_DPATH]; int first = 1; if (!zlib_test ()) return z; zf = 0; uz = unzOpen (z); if (!uz) return z; if (unzGoToFirstFile (uz) != UNZ_OK) return z; zipcnt = 1; tmphist[0] = 0; for (;;) { err = unzGetCurrentFileInfo(uz,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0); if (err != UNZ_OK) return z; if (file_info.uncompressed_size > 0) { i = 0; while (ignoreextensions[i]) { if (strlen(filename_inzip) > strlen (ignoreextensions[i]) && !strcasecmp (ignoreextensions[i], filename_inzip + strlen (filename_inzip) - strlen (ignoreextensions[i]))) break; i++; } if (!ignoreextensions[i]) { if (tmphist[0]) { DISK_history_add (tmphist, -1); tmphist[0] = 0; first = 0; } if (first) { if (isdiskimage (filename_inzip)) sprintf (tmphist,"%s/%s", z->name, filename_inzip); } else { sprintf (tmphist,"%s/%s", z->name, filename_inzip); DISK_history_add (tmphist, -1); tmphist[0] = 0; } select = 0; if (!z->zipname) select = 1; if (z->zipname && !strcasecmp (z->zipname, filename_inzip)) select = -1; if (z->zipname && z->zipname[0] == '#' && atol (z->zipname + 1) == (int)zipcnt) select = -1; if (select && !we_have_file) { unsigned int err = unzOpenCurrentFile (uz); if (err == UNZ_OK) { zf = zfile_fopen_empty (filename_inzip, file_info.uncompressed_size); if (zf) { err = unzReadCurrentFile (uz, zf->data, file_info.uncompressed_size); unzCloseCurrentFile (uz); if (err == 0 || err == file_info.uncompressed_size) { zf = zuncompress (zf); if (select < 0 || zfile_gettype (zf)) { we_have_file = 1; } } } if (!we_have_file) { zfile_fclose (zf); zf = 0; } } } } } zipcnt++; err = unzGoToNextFile (uz); if (err != UNZ_OK) break; } if (zf) { zfile_fclose (z); z = zf; } return z; }