--- distextract.c.orig 2014-09-09 18:12:17.000000000 -0700 +++ distextract.c.dpv_minimal 2014-09-09 19:13:38.000000000 -0700 @@ -32,15 +32,21 @@ #include #include #include +#include -static int extract_files(int nfiles, const char **files); +static int extract_files(struct dpv_file_node *file, int out); +static int count_files(const char *file); + +static struct archive *archive = NULL; int main(void) { char *diststring; - const char **dists; - int i, retval, ndists = 0; + int retval, ndists = 0; + struct dpv_file_node *file_list = NULL, *curfile = file_list; + struct dpv_config *config; + size_t span, file_node_size = sizeof(struct dpv_file_node); if (getenv("DISTRIBUTIONS") == NULL) { fprintf(stderr, "DISTRIBUTIONS variable is not set\n"); @@ -48,25 +54,47 @@ main(void) } diststring = strdup(getenv("DISTRIBUTIONS")); - for (i = 0; diststring[i] != 0; i++) - if (isspace(diststring[i]) && !isspace(diststring[i+1])) - ndists++; - ndists++; /* Last one */ - - dists = calloc(ndists, sizeof(const char *)); - if (dists == NULL) { - fprintf(stderr, "Out of memory!\n"); - free(diststring); - return (1); - } - - for (i = 0; i < ndists; i++) - dists[i] = strsep(&diststring, " \t"); init_dialog(stdin, stdout); dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer"); dlg_put_backtitle(); + dialog_msgbox("", + "Checking distribution archives.\nPlease wait...", 4, 35, FALSE); + while (*diststring != '\0') { + span = strcspn(diststring, "\t\n\v\f\r "); + if (span < 1) { /* currently on whitespace */ + diststring++; + continue; + } + ndists++; + if (curfile == NULL) { + if ((curfile = calloc(1, file_node_size)) == NULL) + exit(1); + file_list = curfile; + } else { + if ((curfile->next = calloc(1, file_node_size)) + == NULL) exit(1); + curfile = curfile->next; + } + + if ((curfile->path = malloc(span + 1)) == NULL) + exit(1); + snprintf(curfile->path, span + 1, "%s", diststring); + curfile->path[span] = '\0'; + + curfile->name = strrchr(curfile->path, '/'); + if (curfile->name == NULL) + curfile->name = curfile->path; + + curfile->length = count_files(curfile->path); + if (curfile->length < 0) { + end_dialog(); + return (1); + } + diststring += span; + } + if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) { char error[512]; sprintf(error, "Could could change to directory %s: %s\n", @@ -76,12 +104,25 @@ main(void) return (1); } - retval = extract_files(ndists, dists); + if ((config = calloc(1, sizeof(struct dpv_config))) == NULL) + exit(1); + config->backtitle = __DECONST(char *, "FreeBSD Installer"); + config->title = __DECONST(char *, "Archive Extraction"); + config->pprompt = + __DECONST(char *, "Extracting distribution files...\n"); + config->aprompt = __DECONST(char *, "\n Overall Progress:"); + config->options |= DPV_WIDE_MODE; + config->label_size = -1; + config->action = extract_files; + config->status_solo = + "%10lli files read @ %'9.1f files/sec."; + config->status_many = + "%10lli files read @ %'9.1f files/sec. [%i/%i busy/wait]"; end_dialog(); - free(diststring); - free(dists); + retval = dpv(config, file_list); + dpv_free(); return (retval); } @@ -89,7 +130,6 @@ main(void) static int count_files(const char *file) { - struct archive *archive; struct archive_entry *entry; static FILE *manifest = NULL; char path[MAXPATHLEN]; @@ -134,6 +174,7 @@ count_files(const char *file) "Error while extracting %s: %s\n", file, archive_error_string(archive)); dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); + archive = NULL; return (-1); } @@ -141,101 +182,58 @@ count_files(const char *file) while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) file_count++; archive_read_free(archive); + archive = NULL; return (file_count); } static int -extract_files(int nfiles, const char **files) +extract_files(struct dpv_file_node *file, int out __unused) { - const char *items[nfiles*2]; char path[PATH_MAX]; - int archive_files[nfiles]; - int total_files, current_files, archive_file; - struct archive *archive; struct archive_entry *entry; char errormsg[512]; - char status[8]; - int i, err, progress, last_progress; + int err; - err = 0; - progress = 0; - - /* Make the transfer list for dialog */ - for (i = 0; i < nfiles; i++) { - items[i*2] = strrchr(files[i], '/'); - if (items[i*2] != NULL) - items[i*2]++; - else - items[i*2] = files[i]; - items[i*2 + 1] = "Pending"; - } - - dialog_msgbox("", - "Checking distribution archives.\nPlease wait...", 0, 0, FALSE); - - /* Count all the files */ - total_files = 0; - for (i = 0; i < nfiles; i++) { - archive_files[i] = count_files(files[i]); - if (archive_files[i] < 0) + if (archive == NULL) { + if ((archive = archive_read_new()) == NULL) { + snprintf(errormsg, sizeof(errormsg), + "Error: %s\n", archive_error_string(NULL)); + dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); + dpv_abort = 1; return (-1); - total_files += archive_files[i]; - } - - current_files = 0; - - for (i = 0; i < nfiles; i++) { - archive = archive_read_new(); + } archive_read_support_format_all(archive); archive_read_support_filter_all(archive); - sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]); + sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), file->path); err = archive_read_open_filename(archive, path, 4096); + } - items[i*2 + 1] = "In Progress"; - archive_file = 0; - - while ((err = archive_read_next_header(archive, &entry)) == - ARCHIVE_OK) { - last_progress = progress; - progress = (current_files*100)/total_files; - - sprintf(status, "-%d", - (archive_file*100)/archive_files[i]); - items[i*2 + 1] = status; - - if (progress > last_progress) - dialog_mixedgauge("Archive Extraction", - "Extracting distribution files...", 0, 0, - progress, nfiles, - __DECONST(char **, items)); - - err = archive_read_extract(archive, entry, - ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | - ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | - ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); - - if (err != ARCHIVE_OK) - break; - - archive_file++; - current_files++; - } - - items[i*2 + 1] = "Done"; - - if (err != ARCHIVE_EOF) { - snprintf(errormsg, sizeof(errormsg), - "Error while extracting %s: %s\n", items[i*2], - archive_error_string(archive)); - items[i*2 + 1] = "Failed"; - dialog_msgbox("Extract Error", errormsg, 0, 0, - TRUE); - return (err); - } - + err = archive_read_next_header(archive, &entry); + if (err == ARCHIVE_OK) + err = archive_read_extract(archive, entry, + ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER | + ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL | + ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS); + if (err == ARCHIVE_EOF) { archive_read_free(archive); + archive = NULL; + file->status = DPV_STATUS_DONE; + return (100); + } else if (err != ARCHIVE_OK) { + snprintf(errormsg, sizeof(errormsg), + "Error while extracting %s: %s\n", file->name, + archive_error_string(archive)); + dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE); + file->status = DPV_STATUS_FAILED; + dpv_abort = 1; + return (-1); } - return (0); + overall_read++; + file->read++; + if (file->length >= 0) + return (file->read * 100 / file->length); + else + return (-1); }