xref: /freebsd/usr.sbin/bsdinstall/distextract/distextract.c (revision 4d65a7c6951cea0333f1a0c1b32c38489cdfa6c5)
12118f387SNathan Whitehorn /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
42118f387SNathan Whitehorn  * Copyright (c) 2011 Nathan Whitehorn
582ac9f2bSDevin Teske  * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org>
62118f387SNathan Whitehorn  * All rights reserved.
72118f387SNathan Whitehorn  *
82118f387SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
92118f387SNathan Whitehorn  * modification, are permitted provided that the following conditions
102118f387SNathan Whitehorn  * are met:
112118f387SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
122118f387SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
132118f387SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
142118f387SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
152118f387SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
162118f387SNathan Whitehorn  *
172118f387SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
182118f387SNathan Whitehorn  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
192118f387SNathan Whitehorn  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
202118f387SNathan Whitehorn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
212118f387SNathan Whitehorn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
222118f387SNathan Whitehorn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
232118f387SNathan Whitehorn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
242118f387SNathan Whitehorn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
252118f387SNathan Whitehorn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
262118f387SNathan Whitehorn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
272118f387SNathan Whitehorn  * SUCH DAMAGE.
282118f387SNathan Whitehorn  */
292118f387SNathan Whitehorn 
3046cc2c02SNathan Whitehorn #include <sys/param.h>
31263660c0SAlfonso Siciliano 
3282ac9f2bSDevin Teske #include <archive.h>
3382ac9f2bSDevin Teske #include <ctype.h>
3418f20d5dSAlfonso Siciliano #include <bsddialog.h>
3518f20d5dSAlfonso Siciliano #include <bsddialog_progressview.h>
3682ac9f2bSDevin Teske #include <err.h>
372118f387SNathan Whitehorn #include <errno.h>
382118f387SNathan Whitehorn #include <limits.h>
3918f20d5dSAlfonso Siciliano #include <signal.h>
4082ac9f2bSDevin Teske #include <stdio.h>
4182ac9f2bSDevin Teske #include <stdlib.h>
4282ac9f2bSDevin Teske #include <string.h>
4382ac9f2bSDevin Teske #include <unistd.h>
442118f387SNathan Whitehorn 
45147585b4SBrad Davis #include "opt_osname.h"
46147585b4SBrad Davis 
47bd1df636SDevin Teske /* Data to process */
48f9549860SBaptiste Daroussin static const char *distdir = NULL;
494ff1fc3bSDevin Teske static struct archive *archive = NULL;
50bd1df636SDevin Teske 
51bd1df636SDevin Teske /* Function prototypes */
524ff1fc3bSDevin Teske static void	sig_int(int sig);
5382ac9f2bSDevin Teske static int	count_files(const char *file);
5418f20d5dSAlfonso Siciliano static int	extract_files(struct bsddialog_fileminibar *file);
55bd1df636SDevin Teske 
5618f20d5dSAlfonso Siciliano #define _errx(...) (bsddialog_end(), errx(__VA_ARGS__))
572118f387SNathan Whitehorn 
582118f387SNathan Whitehorn int
main(void)592118f387SNathan Whitehorn main(void)
602118f387SNathan Whitehorn {
61bd1df636SDevin Teske 	char *chrootdir;
62bd1df636SDevin Teske 	char *distributions;
63dd8ca6b2SBaptiste Daroussin 	char *distribs, *distrib;
6482ac9f2bSDevin Teske 	int retval;
6518f20d5dSAlfonso Siciliano 	size_t minibar_size = sizeof(struct bsddialog_fileminibar);
6618f20d5dSAlfonso Siciliano 	unsigned int nminibars;
6718f20d5dSAlfonso Siciliano 	struct bsddialog_fileminibar *dists;
6818f20d5dSAlfonso Siciliano 	struct bsddialog_progviewconf pvconf;
6918f20d5dSAlfonso Siciliano 	struct bsddialog_conf conf;
704ff1fc3bSDevin Teske 	struct sigaction act;
7182ac9f2bSDevin Teske 	char error[PATH_MAX + 512];
72bfd258f7SNathan Whitehorn 
73bd1df636SDevin Teske 	if ((distributions = getenv("DISTRIBUTIONS")) == NULL)
7482ac9f2bSDevin Teske 		errx(EXIT_FAILURE, "DISTRIBUTIONS variable is not set");
75bd1df636SDevin Teske 	if ((distdir = getenv("BSDINSTALL_DISTDIR")) == NULL)
76f9549860SBaptiste Daroussin 		distdir = "";
77dd8ca6b2SBaptiste Daroussin 	if ((distribs = strdup(distributions)) == NULL)
78dd8ca6b2SBaptiste Daroussin 		errx(EXIT_FAILURE, "memory error");
79bfd258f7SNathan Whitehorn 
8018f20d5dSAlfonso Siciliano 	if (bsddialog_init() == BSDDIALOG_ERROR)
81263660c0SAlfonso Siciliano 		errx(EXIT_FAILURE, "Error libbsdialog: %s",
82263660c0SAlfonso Siciliano 		    bsddialog_geterror());
8318f20d5dSAlfonso Siciliano 	bsddialog_initconf(&conf);
84147585b4SBrad Davis 	bsddialog_backtitle(&conf, OSNAME " Installer");
8518f20d5dSAlfonso Siciliano 	bsddialog_infobox(&conf,
86263660c0SAlfonso Siciliano 	    "Checking distribution archives.\nPlease wait...", 4, 35);
8757bda1b6SNathan Whitehorn 
8818f20d5dSAlfonso Siciliano 	/* Parse $DISTRIBUTIONS */
8918f20d5dSAlfonso Siciliano 	nminibars = 0;
9018f20d5dSAlfonso Siciliano 	dists = NULL;
91dd8ca6b2SBaptiste Daroussin 	while ((distrib = strsep(&distribs, "\t\n\v\f\r ")) != NULL) {
92dd8ca6b2SBaptiste Daroussin 		if (strlen(distrib) == 0)
93bd1df636SDevin Teske 			continue;
94bd1df636SDevin Teske 
95bd1df636SDevin Teske 		/* Allocate a new struct for the distribution */
9618f20d5dSAlfonso Siciliano 		dists = realloc(dists, (nminibars + 1) * minibar_size);
9718f20d5dSAlfonso Siciliano 		if (dists == NULL)
98bd1df636SDevin Teske 			_errx(EXIT_FAILURE, "Out of memory!");
99bd1df636SDevin Teske 
10018f20d5dSAlfonso Siciliano 		/* Set file path */
101dd8ca6b2SBaptiste Daroussin 		dists[nminibars].path = distrib;
102bd1df636SDevin Teske 
10318f20d5dSAlfonso Siciliano 		/* Set mini bar label */
10418f20d5dSAlfonso Siciliano 		dists[nminibars].label = strrchr(dists[nminibars].path, '/');
10518f20d5dSAlfonso Siciliano 		if (dists[nminibars].label == NULL)
10618f20d5dSAlfonso Siciliano 			dists[nminibars].label = dists[nminibars].path;
107bd1df636SDevin Teske 
108bd1df636SDevin Teske 		/* Set initial length in files (-1 == error) */
10918f20d5dSAlfonso Siciliano 		dists[nminibars].size = count_files(dists[nminibars].path);
11018f20d5dSAlfonso Siciliano 		if (dists[nminibars].size < 0) {
11118f20d5dSAlfonso Siciliano 			bsddialog_end();
112bd1df636SDevin Teske 			return (EXIT_FAILURE);
113bd1df636SDevin Teske 		}
114bd1df636SDevin Teske 
115263660c0SAlfonso Siciliano 		/* Set initial status and implicitly miniperc to pending */
116263660c0SAlfonso Siciliano 		dists[nminibars].status = BSDDIALOG_MG_PENDING;
11718f20d5dSAlfonso Siciliano 
11818f20d5dSAlfonso Siciliano 		/* Set initial read */
11918f20d5dSAlfonso Siciliano 		dists[nminibars].read = 0;
12018f20d5dSAlfonso Siciliano 
12118f20d5dSAlfonso Siciliano 		nminibars += 1;
122bd1df636SDevin Teske 	}
123bd1df636SDevin Teske 
124bd1df636SDevin Teske 	/* Optionally chdir(2) into $BSDINSTALL_CHROOT */
125bd1df636SDevin Teske 	chrootdir = getenv("BSDINSTALL_CHROOT");
126bd1df636SDevin Teske 	if (chrootdir != NULL && chdir(chrootdir) != 0) {
12782ac9f2bSDevin Teske 		snprintf(error, sizeof(error),
128bd1df636SDevin Teske 		    "Could not change to directory %s: %s\n",
129bd1df636SDevin Teske 		    chrootdir, strerror(errno));
130f9549860SBaptiste Daroussin 		conf.title = "Error";
13118f20d5dSAlfonso Siciliano 		bsddialog_msgbox(&conf, error, 0, 0);
13218f20d5dSAlfonso Siciliano 		bsddialog_end();
13382ac9f2bSDevin Teske 		return (EXIT_FAILURE);
13457bda1b6SNathan Whitehorn 	}
13557bda1b6SNathan Whitehorn 
1364ff1fc3bSDevin Teske 	/* Set cleanup routine for Ctrl-C action */
1374ff1fc3bSDevin Teske 	act.sa_handler = sig_int;
1384ff1fc3bSDevin Teske 	sigaction(SIGINT, &act, 0);
1392118f387SNathan Whitehorn 
140263660c0SAlfonso Siciliano 	conf.title = "Archive Extraction";
141263660c0SAlfonso Siciliano 	conf.auto_minwidth = 40;
14218f20d5dSAlfonso Siciliano 	pvconf.callback	= extract_files;
14318f20d5dSAlfonso Siciliano 	pvconf.refresh = 1;
144263660c0SAlfonso Siciliano 	pvconf.fmtbottomstr = "%10lli files read @ %'9.1f files/sec.";
14518f20d5dSAlfonso Siciliano 	bsddialog_total_progview = 0;
14618f20d5dSAlfonso Siciliano 	bsddialog_interruptprogview = bsddialog_abortprogview = false;
14718f20d5dSAlfonso Siciliano 	retval = bsddialog_progressview(&conf,
148263660c0SAlfonso Siciliano 	    "\nExtracting distribution files...\n", 0, 0,
149263660c0SAlfonso Siciliano 	    &pvconf, nminibars, dists);
150263660c0SAlfonso Siciliano 
151263660c0SAlfonso Siciliano 	if (retval == BSDDIALOG_ERROR) {
152263660c0SAlfonso Siciliano 		fprintf(stderr, "progressview error: %s\n",
153263660c0SAlfonso Siciliano 		    bsddialog_geterror());
154263660c0SAlfonso Siciliano 	}
15557bda1b6SNathan Whitehorn 
15618f20d5dSAlfonso Siciliano 	bsddialog_end();
15718f20d5dSAlfonso Siciliano 
158dd8ca6b2SBaptiste Daroussin 	free(distribs);
15918f20d5dSAlfonso Siciliano 	free(dists);
1602118f387SNathan Whitehorn 
1612118f387SNathan Whitehorn 	return (retval);
1622118f387SNathan Whitehorn }
1632118f387SNathan Whitehorn 
1644ff1fc3bSDevin Teske static void
sig_int(int sig __unused)1654ff1fc3bSDevin Teske sig_int(int sig __unused)
1664ff1fc3bSDevin Teske {
16718f20d5dSAlfonso Siciliano 	bsddialog_interruptprogview = true;
1684ff1fc3bSDevin Teske }
1694ff1fc3bSDevin Teske 
170bd1df636SDevin Teske /*
171bd1df636SDevin Teske  * Returns number of files in archive file. Parses $BSDINSTALL_DISTDIR/MANIFEST
172bd1df636SDevin Teske  * if it exists, otherwise uses archive(3) to read the archive file.
173bd1df636SDevin Teske  */
1742118f387SNathan Whitehorn static int
count_files(const char * file)17546cc2c02SNathan Whitehorn count_files(const char *file)
17646cc2c02SNathan Whitehorn {
17782ac9f2bSDevin Teske 	static FILE *manifest = NULL;
178bd1df636SDevin Teske 	char *p;
17982ac9f2bSDevin Teske 	int file_count;
18082ac9f2bSDevin Teske 	int retval;
181bd1df636SDevin Teske 	size_t span;
18246cc2c02SNathan Whitehorn 	struct archive_entry *entry;
18382ac9f2bSDevin Teske 	char line[512];
18482ac9f2bSDevin Teske 	char path[PATH_MAX];
18582ac9f2bSDevin Teske 	char errormsg[PATH_MAX + 512];
18618f20d5dSAlfonso Siciliano 	struct bsddialog_conf conf;
18746cc2c02SNathan Whitehorn 
18846cc2c02SNathan Whitehorn 	if (manifest == NULL) {
189bd1df636SDevin Teske 		snprintf(path, sizeof(path), "%s/MANIFEST", distdir);
19046cc2c02SNathan Whitehorn 		manifest = fopen(path, "r");
19146cc2c02SNathan Whitehorn 	}
19246cc2c02SNathan Whitehorn 
19346cc2c02SNathan Whitehorn 	if (manifest != NULL) {
194896a9484SNathan Whitehorn 		rewind(manifest);
19546cc2c02SNathan Whitehorn 		while (fgets(line, sizeof(line), manifest) != NULL) {
196bd1df636SDevin Teske 			p = &line[0];
197bd1df636SDevin Teske 			span = strcspn(p, "\t") ;
198bd1df636SDevin Teske 			if (span < 1 || strncmp(p, file, span) != 0)
19946cc2c02SNathan Whitehorn 				continue;
20046cc2c02SNathan Whitehorn 
20146cc2c02SNathan Whitehorn 			/*
20246cc2c02SNathan Whitehorn 			 * We're at the right manifest line. The file count is
20346cc2c02SNathan Whitehorn 			 * in the third element
20446cc2c02SNathan Whitehorn 			 */
205bd1df636SDevin Teske 			span = strcspn(p += span + (*p != '\0' ? 1 : 0), "\t");
206bd1df636SDevin Teske 			span = strcspn(p += span + (*p != '\0' ? 1 : 0), "\t");
207bd1df636SDevin Teske 			if (span > 0) {
208bd1df636SDevin Teske 				file_count = (int)strtol(p, (char **)NULL, 10);
209bd1df636SDevin Teske 				if (file_count == 0 && errno == EINVAL)
210bd1df636SDevin Teske 					continue;
211bd1df636SDevin Teske 				return (file_count);
212bd1df636SDevin Teske 			}
21346cc2c02SNathan Whitehorn 		}
21446cc2c02SNathan Whitehorn 	}
21546cc2c02SNathan Whitehorn 
216bd1df636SDevin Teske 	/*
217bd1df636SDevin Teske 	 * Either no manifest, or manifest didn't mention this archive.
218bd1df636SDevin Teske 	 * Use archive(3) to read the archive, counting files within.
219bd1df636SDevin Teske 	 */
22018f20d5dSAlfonso Siciliano 	bsddialog_initconf(&conf);
221bd1df636SDevin Teske 	if ((archive = archive_read_new()) == NULL) {
222bd1df636SDevin Teske 		snprintf(errormsg, sizeof(errormsg),
223bd1df636SDevin Teske 		    "Error: %s\n", archive_error_string(NULL));
224263660c0SAlfonso Siciliano 		conf.title = "Extract Error";
22518f20d5dSAlfonso Siciliano 		bsddialog_msgbox(&conf, errormsg, 0, 0);
226bd1df636SDevin Teske 		return (-1);
227bd1df636SDevin Teske 	}
22846cc2c02SNathan Whitehorn 	archive_read_support_format_all(archive);
229ebb8fc42SMartin Matuska 	archive_read_support_filter_all(archive);
230bd1df636SDevin Teske 	snprintf(path, sizeof(path), "%s/%s", distdir, file);
23182ac9f2bSDevin Teske 	retval = archive_read_open_filename(archive, path, 4096);
23282ac9f2bSDevin Teske 	if (retval != ARCHIVE_OK) {
23346cc2c02SNathan Whitehorn 		snprintf(errormsg, sizeof(errormsg),
23446cc2c02SNathan Whitehorn 		    "Error while extracting %s: %s\n", file,
23546cc2c02SNathan Whitehorn 		    archive_error_string(archive));
236263660c0SAlfonso Siciliano 		conf.title = "Extract Error";
23718f20d5dSAlfonso Siciliano 		bsddialog_msgbox(&conf, errormsg, 0, 0);
2384ff1fc3bSDevin Teske 		archive = NULL;
23946cc2c02SNathan Whitehorn 		return (-1);
24046cc2c02SNathan Whitehorn 	}
24146cc2c02SNathan Whitehorn 
24246cc2c02SNathan Whitehorn 	file_count = 0;
24346cc2c02SNathan Whitehorn 	while (archive_read_next_header(archive, &entry) == ARCHIVE_OK)
24446cc2c02SNathan Whitehorn 		file_count++;
24546cc2c02SNathan Whitehorn 	archive_read_free(archive);
2464ff1fc3bSDevin Teske 	archive = NULL;
24746cc2c02SNathan Whitehorn 
24846cc2c02SNathan Whitehorn 	return (file_count);
24946cc2c02SNathan Whitehorn }
25046cc2c02SNathan Whitehorn 
25146cc2c02SNathan Whitehorn static int
extract_files(struct bsddialog_fileminibar * file)25218f20d5dSAlfonso Siciliano extract_files(struct bsddialog_fileminibar *file)
2532118f387SNathan Whitehorn {
25482ac9f2bSDevin Teske 	int retval;
2552118f387SNathan Whitehorn 	struct archive_entry *entry;
25682ac9f2bSDevin Teske 	char path[PATH_MAX];
25782ac9f2bSDevin Teske 	char errormsg[PATH_MAX + 512];
25818f20d5dSAlfonso Siciliano 	struct bsddialog_conf conf;
25918f20d5dSAlfonso Siciliano 
26018f20d5dSAlfonso Siciliano 	bsddialog_initconf(&conf);
2612118f387SNathan Whitehorn 
2624ff1fc3bSDevin Teske 	/* Open the archive if necessary */
2634ff1fc3bSDevin Teske 	if (archive == NULL) {
264bd1df636SDevin Teske 		if ((archive = archive_read_new()) == NULL) {
265bd1df636SDevin Teske 			snprintf(errormsg, sizeof(errormsg),
266bd1df636SDevin Teske 			    "Error: %s\n", archive_error_string(NULL));
267263660c0SAlfonso Siciliano 			conf.title = "Extract Error";
26818f20d5dSAlfonso Siciliano 			bsddialog_msgbox(&conf, errormsg, 0, 0);
26918f20d5dSAlfonso Siciliano 			bsddialog_abortprogview = true;
2704ff1fc3bSDevin Teske 			return (-1);
2712118f387SNathan Whitehorn 		}
2722118f387SNathan Whitehorn 		archive_read_support_format_all(archive);
273ebb8fc42SMartin Matuska 		archive_read_support_filter_all(archive);
274bd1df636SDevin Teske 		snprintf(path, sizeof(path), "%s/%s", distdir, file->path);
27582ac9f2bSDevin Teske 		retval = archive_read_open_filename(archive, path, 4096);
276bd1df636SDevin Teske 		if (retval != 0) {
277bd1df636SDevin Teske 			snprintf(errormsg, sizeof(errormsg),
27818f20d5dSAlfonso Siciliano 			    "Error opening %s: %s\n", file->label,
279bd1df636SDevin Teske 			    archive_error_string(archive));
280263660c0SAlfonso Siciliano 			conf.title = "Extract Error";
28118f20d5dSAlfonso Siciliano 			bsddialog_msgbox(&conf, errormsg, 0, 0);
282263660c0SAlfonso Siciliano 			file->status = BSDDIALOG_MG_FAILED;
28318f20d5dSAlfonso Siciliano 			bsddialog_abortprogview = true;
2844ff1fc3bSDevin Teske 			return (-1);
2854ff1fc3bSDevin Teske 		}
286bd1df636SDevin Teske 	}
2872118f387SNathan Whitehorn 
2884ff1fc3bSDevin Teske 	/* Read the next archive header */
2894ff1fc3bSDevin Teske 	retval = archive_read_next_header(archive, &entry);
2902118f387SNathan Whitehorn 
2914ff1fc3bSDevin Teske 	/* If that went well, perform the extraction */
2924ff1fc3bSDevin Teske 	if (retval == ARCHIVE_OK)
29382ac9f2bSDevin Teske 		retval = archive_read_extract(archive, entry,
2942118f387SNathan Whitehorn 		    ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER |
2952118f387SNathan Whitehorn 		    ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL |
2962118f387SNathan Whitehorn 		    ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS);
2972118f387SNathan Whitehorn 
2984ff1fc3bSDevin Teske 	/* Test for either EOF or error */
2994ff1fc3bSDevin Teske 	if (retval == ARCHIVE_EOF) {
3002118f387SNathan Whitehorn 		archive_read_free(archive);
3014ff1fc3bSDevin Teske 		archive = NULL;
302263660c0SAlfonso Siciliano 		file->status = BSDDIALOG_MG_DONE; /*Done*/;
3034ff1fc3bSDevin Teske 		return (100);
304a5837f2cSNathan Whitehorn 	} else if (retval != ARCHIVE_OK &&
305a5837f2cSNathan Whitehorn 	    !(retval == ARCHIVE_WARN &&
306a5837f2cSNathan Whitehorn 	    strcmp(archive_error_string(archive), "Can't restore time") == 0)) {
307a5837f2cSNathan Whitehorn 		/*
308a5837f2cSNathan Whitehorn 		 * Print any warning/error messages except inability to set
309a5837f2cSNathan Whitehorn 		 * ctime/mtime, which is not fatal, or even interesting,
310a5837f2cSNathan Whitehorn 		 * for our purposes. Would be nice if this were a libarchive
311a5837f2cSNathan Whitehorn 		 * option.
312a5837f2cSNathan Whitehorn 		 */
3134ff1fc3bSDevin Teske 		snprintf(errormsg, sizeof(errormsg),
31418f20d5dSAlfonso Siciliano 		    "Error while extracting %s: %s\n", file->label,
3154ff1fc3bSDevin Teske 		    archive_error_string(archive));
316263660c0SAlfonso Siciliano 		conf.title = "Extract Error";
31718f20d5dSAlfonso Siciliano 		bsddialog_msgbox(&conf, errormsg, 0, 0);
318263660c0SAlfonso Siciliano 		file->status = BSDDIALOG_MG_FAILED; /* Failed */
31918f20d5dSAlfonso Siciliano 		bsddialog_abortprogview = true;
3204ff1fc3bSDevin Teske 		return (-1);
3212118f387SNathan Whitehorn 	}
3222118f387SNathan Whitehorn 
32318f20d5dSAlfonso Siciliano 	bsddialog_total_progview++;
3244ff1fc3bSDevin Teske 	file->read++;
3254ff1fc3bSDevin Teske 
3264ff1fc3bSDevin Teske 	/* Calculate [overall] percentage of completion (if possible) */
32718f20d5dSAlfonso Siciliano 	if (file->size >= 0)
32818f20d5dSAlfonso Siciliano 		return (file->read * 100 / file->size);
3294ff1fc3bSDevin Teske 	else
3304ff1fc3bSDevin Teske 		return (-1);
3312118f387SNathan Whitehorn }
332