Index: lib/libpkg/Makefile =========================================================================== --- lib/libpkg/Makefile 2011/02/07 20:45:56 #1 +++ lib/libpkg/Makefile 2011/02/07 20:45:56 @@ -23,8 +23,8 @@ CFLAGS+= -DYES_I_KNOW_THE_API_IS_RUBBISH_AND_IS_DOOMED_TO_CHANGE -DPADD= ${LIBFETCH} ${LIBMD} ${LIBUTIL} -LDADD= -lfetch -lmd -lutil +DPADD= ${LIBFETCH} ${LIBMD} ${LIBUTIL} ${LIBARCHIVE} ${LIBZ} ${LIBBZ2} +LDADD= -lfetch -lmd -lutil -larchive -lz -lbz2 .if ${MK_OPENSSL} != "no" DPADD+= ${LIBSSL} ${LIBCRYPTO} Index: lib/libpkg/file.c =========================================================================== --- lib/libpkg/file.c 2011/02/07 20:45:56 #1 +++ lib/libpkg/file.c 2011/02/07 20:45:56 @@ -22,7 +22,10 @@ __FBSDID("$FreeBSD: src/lib/libpkg/file.c,v 1.1 2010/04/23 11:07:43 flz Exp $"); #include "pkg.h" +#include +#include #include +#include #include #include #include @@ -336,35 +339,55 @@ /* Unpack a tar file */ int -unpack(const char *pkg, const char *flist) +unpack(const char *pkg, const char *glob, Boolean onematch) { - const char *comp, *cp; - char suff[80]; + struct archive *reader; + struct archive_entry *entry; + int r; + int flags = ARCHIVE_EXTRACT_TIME | + ARCHIVE_EXTRACT_PERM | + ARCHIVE_EXTRACT_ACL | + ARCHIVE_EXTRACT_FFLAGS; + + reader = archive_read_new(); + archive_read_support_format_tar(reader); + archive_read_support_compression_gzip(reader); + archive_read_support_compression_bzip2(reader); + + if (archive_read_open_file(reader, pkg, 10240)) + goto unpack_err; - comp = ""; - /* - * Figure out by a crude heuristic whether this or not this is probably - * compressed and whichever compression utility was used (gzip or bzip2). - */ - if (strcmp(pkg, "-")) { - cp = strrchr(pkg, '.'); - if (cp) { - strcpy(suff, cp + 1); - if (strchr(suff, 'z') || strchr(suff, 'Z')) { - if (strchr(suff, 'b')) - comp = "-j"; + for(;;) { + r = archive_read_next_header(reader, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) + goto unpack_err; + if (glob == NULL) { + if (archive_read_extract(reader, entry, flags)) + goto unpack_err; + } else { + if (fnmatch(glob, archive_entry_pathname(entry), + FNM_PATHNAME|FNM_PERIOD) == 0) + { + if (archive_read_extract(reader, entry, flags)) + goto unpack_err; else - comp = "-z"; + if (onematch) + break; } } } - else - comp = "-j"; - if (vsystem("/usr/bin/tar -xp %s -f '%s' %s", comp, pkg, flist ? flist : "")) { - warnx("tar extract of %s failed!", pkg); - return 1; - } + + archive_read_close(reader); + archive_read_finish(reader); return 0; + +unpack_err: + warnx("%s", archive_error_string(reader)); + archive_read_close(reader); + archive_read_finish(reader); + return 1; } /* Index: lib/libpkg/pkg.h =========================================================================== --- lib/libpkg/pkg.h 2011/02/07 20:45:56 #1 +++ lib/libpkg/pkg.h 2011/02/07 20:45:56 @@ -188,7 +188,7 @@ void move_file(const char *, const char *, const char *); void copy_hierarchy(const char *, const char *, Boolean); int delete_hierarchy(const char *, Boolean, Boolean); -int unpack(const char *, const char *); +int unpack(const char *, const char *, Boolean); void format_cmd(char *, int, const char *, const char *, const char *); /* Msg */ Index: lib/libpkg/url.c =========================================================================== --- lib/libpkg/url.c 2011/02/07 20:45:56 #1 +++ lib/libpkg/url.c 2011/02/07 20:45:56 @@ -22,12 +22,25 @@ __FBSDID("$FreeBSD: src/lib/libpkg/url.c,v 1.1 2010/04/23 11:07:43 flz Exp $"); #include "pkg.h" +#include +#include #include +#include #include #include #include #include +struct read_data { + FILE *f; + size_t block_size; + void *buffer; + int dupfd; +}; + +static ssize_t file_read(struct archive *, void *, const void **); +static int file_close(struct archive *, void *); + /* * Try and fetch a file by URL, returning the directory name for where * it's unpacked, if successful. @@ -40,12 +53,16 @@ char fname[FILENAME_MAX]; char pen[FILENAME_MAX]; char pkg[FILENAME_MAX]; - char buf[8192]; FILE *ftp; - pid_t tpid; - int pfd[2], pstat, r, w = 0; char *hint; - int fd, pkgfd = 0; + int r, pkgfd = 0; + struct archive *reader; + struct archive_entry *entry; + struct read_data *mydata; + int flags = ARCHIVE_EXTRACT_TIME | + ARCHIVE_EXTRACT_PERM | + ARCHIVE_EXTRACT_ACL | + ARCHIVE_EXTRACT_FFLAGS; rp = NULL; /* Special tip that sysinstall left for us */ @@ -123,49 +140,90 @@ fclose(ftp); return NULL; } - if (pipe(pfd) == -1) { - warn("pipe()"); - cleanup(0); - exit(2); + + reader = archive_read_new(); + archive_read_support_format_tar(reader); + archive_read_support_compression_gzip(reader); + archive_read_support_compression_bzip2(reader); + + mydata = (struct read_data *)malloc(sizeof(*mydata)); + if (mydata == NULL) { + printf("Unable to allocate memory!\n"); + return NULL; } - if ((tpid = fork()) == -1) { - warn("pipe()"); - cleanup(0); - exit(2); + mydata->block_size = 128 * 1024; + mydata->buffer = malloc(mydata->block_size); + if (mydata->buffer == NULL) { + printf("Unable to allocate memory!\n"); + free(mydata); + return NULL; } - if (!tpid) { - dup2(pfd[0], 0); - for (fd = getdtablesize() - 1; fd >= 3; --fd) - close(fd); - execl("/usr/bin/tar", "tar", - Verbose ? "-xpjvf" : "-xpjf", - "-", (char *)0); - _exit(2); - } - close(pfd[0]); + mydata->f = ftp; + if (keep_package) + mydata->dupfd = pkgfd; + else + mydata->dupfd = -1; + + if (archive_read_open(reader, mydata, NULL, file_read, file_close)) + goto unpack_err; + for (;;) { - if ((r = fread(buf, 1, sizeof buf, ftp)) < 1) - break; - if ((w = write(pfd[1], buf, r)) != r) - break; - if (keep_package) { - if ((w = write(pkgfd, buf, r)) != r) + r = archive_read_next_header(reader, &entry); + if (r == ARCHIVE_EOF) break; - } - } + if (r != ARCHIVE_OK) + goto unpack_err; + if (archive_read_extract(reader, entry, flags)) + goto unpack_err; + } + + archive_read_close(reader); + archive_read_finish(reader); + if (ferror(ftp)) warn("warning: error reading from server"); fclose(ftp); if (keep_package) { close(pkgfd); } - close(pfd[1]); - if (w == -1) - warn("warning: error writing to tar"); - tpid = waitpid(tpid, &pstat, 0); - if (Verbose) - printf("tar command returns %d status\n", WEXITSTATUS(pstat)); if (rp && (isatty(0) || Verbose)) printf(" Done.\n"); return rp; + +unpack_err: + warnx("%s", archive_error_string(reader)); + archive_read_close(reader); + archive_read_finish(reader); + return NULL; +} + +static ssize_t +file_read(struct archive *a, void *client_data, const void **buff) +{ + struct read_data *mine = (struct read_data *)client_data; + ssize_t bytes_read; + + *buff = mine->buffer; + bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f); + if (bytes_read < 0) { + archive_set_error(a, errno, "Error reading file"); + } else if (mine->dupfd >= 0) { + if (write(mine->dupfd, mine->buffer, bytes_read) != bytes_read) + { + archive_set_error(a, errno, "Error duplicating archive"); + return -1; + } + } + + return (bytes_read); +} + +static int +file_close(struct archive *a, void *client_data) +{ + struct read_data *mine = (struct read_data *)client_data; + if (mine->buffer != NULL) + free(mine->buffer); + free(mine); + return (ARCHIVE_OK); } Index: usr.sbin/pkg_install/add/perform.c =========================================================================== --- usr.sbin/pkg_install/add/perform.c 2011/02/07 20:45:56 #28 +++ usr.sbin/pkg_install/add/perform.c 2011/02/07 20:45:56 @@ -63,7 +63,6 @@ Package Plist; char pkg_fullname[FILENAME_MAX]; char playpen[FILENAME_MAX]; - char extract_contents[FILENAME_MAX]; char *extract; const char *where_to; FILE *cfile; @@ -129,8 +128,7 @@ warnx("can't stat package file '%s'", pkg_fullname); goto bomb; } - sprintf(extract_contents, "--fast-read %s", CONTENTS_FNAME); - extract = extract_contents; + extract = CONTENTS_FNAME; } else { extract = NULL; @@ -141,7 +139,7 @@ /* Since we can call ourselves recursively, keep notes on where we came from */ if (!getenv("_TOP")) setenv("_TOP", where_to, 1); - if (unpack(pkg_fullname, extract)) { + if (unpack(pkg_fullname, extract, TRUE)) { warnx( "unable to extract table of contents file from '%s' - not a package?", pkg_fullname); @@ -204,7 +202,7 @@ /* Finally unpack the whole mess. If extract is null we already + did so so don't bother doing it again. */ - if (extract && unpack(pkg_fullname, NULL)) { + if (extract && unpack(pkg_fullname, NULL, FALSE)) { warnx("unable to extract '%s'!", pkg_fullname); goto bomb; } Index: usr.sbin/pkg_install/info/perform.c =========================================================================== --- usr.sbin/pkg_install/info/perform.c 2011/02/07 20:45:56 #17 +++ usr.sbin/pkg_install/info/perform.c 2011/02/07 20:45:56 @@ -137,7 +137,7 @@ goto bail; } make_playpen(PlayPen, sb.st_size / 2); - if (unpack(fname, "'+*'")) { + if (unpack(fname, "'+*'", FALSE)) { warnx("error during unpacking, no info for '%s' available", pkg); code = 1; goto bail;