Here's a patch to add progress bars to file downloads. Like I
mentioned, I'm pretty new to C, so please feel free to tear this apart
and let me know if I'm doing anything in a non-proper way.
Thanks,
Ricky
---
loader2/ftp.c | 42 +++++++++++++++++++++++++++++++++++++++---
loader2/ftp.h | 5 +++--
loader2/loadermisc.c | 12 ++++++++++--
loader2/loadermisc.h | 4 +++-
loader2/method.c | 5 +++--
loader2/method.h | 4 +++-
loader2/urlinstall.c | 16 ++++++++++------
loader2/urls.c | 13 +++++++++----
loader2/urls.h | 8 ++++++--
loader2/windows.c | 42 ++++++++++++++++++++++++++++++++++++++++++
loader2/windows.h | 12 ++++++++++++
11 files changed, 140 insertions(+), 23 deletions(-)
diff --git a/loader2/ftp.c b/loader2/ftp.c
index ce6deb5..ac0725f 100644
--- a/loader2/ftp.c
+++ b/loader2/ftp.c
@@ -346,13 +346,15 @@ int ftpOpen(char *host, int family, char *name, char *password,
* RFC 2428 FTP Extensions for IPv6 and NATs
*/
int ftpGetFileDesc(int sock, struct in6_addr host, int family,
- char * remotename) {
+ char * remotename, long long *size) {
int dataSocket;
struct sockaddr_in dataAddress;
struct sockaddr_in6 dataAddress6;
int i, j;
char * passReply;
char * chptr;
+ char * sizeCommand;
+ char * sizeReply;
char * retrCommand;
int rc;
@@ -458,6 +460,32 @@ int ftpGetFileDesc(int sock, struct in6_addr host, int family,
return FTPERR_FAILED_CONNECT;
}
+ sizeCommand = alloca(strlen(remotename) + 20);
+ sprintf(sizeCommand, "SIZE %s\r\n", remotename);
+ i = strlen(sizeCommand);
+ if (write(sock, sizeCommand, i) != i) {
+ return FTPERR_SERVER_IO_ERROR;
+ }
+ if (ftpCheckResponse(sock, &sizeReply)) {
+ /* No worries, the SIZE command isn't in RFC 959 anyway. */
+ *size = 0;
+ } else {
+ /* We have a SIZE response of the form:
+ * 213 95600640
+ * where 95600640 is the size in bytes.
+ */
+
+ /* Skip to first non-space character */
+ while (isspace(*sizeReply) && *sizeReply) sizeReply++;
+ /* Skip reply code */
+ while (!isspace(*sizeReply) && *sizeReply) sizeReply++;
+ /* Skip any remaining whitespace */
+ while (isspace(*sizeReply) && *sizeReply) sizeReply++;
+ /* sizeReply now points to the beginning of the size */
+ if (sscanf(sizeReply, "%lld", size) != 1) *size = 0;
+ if (*size < 0) *size = 0;
+ }
+
retrCommand = alloca(strlen(remotename) + 20);
sprintf(retrCommand, "RETR %s\r\n", remotename);
i = strlen(retrCommand);
@@ -668,10 +696,11 @@ static char *find_status_code (char *headers)
* by '\r\n', ending with '\r\n'.
*/
int httpGetFileDesc(char * hostname, int port, char * remotename,
- char *extraHeaders) {
+ char *extraHeaders, long long *size) {
char * buf, *headers = NULL;
char *status;
char *hstr;
+ char *contlen;
int family;
struct in_addr addr;
struct in6_addr addr6;
@@ -740,6 +769,13 @@ int httpGetFileDesc(char * hostname, int port, char * remotename,
if (headers) free(headers);
return FTPERR_SERVER_IO_ERROR;
} else if (!strncmp(status, "200", 3)) {
+ contlen = find_header(headers, "Content-Length");
+ if (contlen == NULL) {
+ *size = 0;
+ } else {
+ *size = strtoll(contlen, NULL, 10);
+ }
+ if (*size < 0) *size = 0;
if (status) free(status);
if (headers) free(headers);
return sock;
@@ -760,7 +796,7 @@ int httpGetFileDesc(char * hostname, int port, char * remotename,
logMessage(INFO, "redirecting to %s", redir_loc);
convertURLToUI(redir_loc, &ui);
- retval = httpGetFileDesc (ui.address, -1, ui.prefix, extraHeaders);
+ retval = httpGetFileDesc (ui.address, -1, ui.prefix, extraHeaders, size);
free(redir_loc);
return retval;
} else if (!strncmp(status, "403", 3)) {
diff --git a/loader2/ftp.h b/loader2/ftp.h
index c1e7fcb..9186e88 100644
--- a/loader2/ftp.h
+++ b/loader2/ftp.h
@@ -45,9 +45,10 @@ int ftpOpen(char * host, int family, char * name, char * password,
int port);
int ftpGetFile(int sock, char * remotename, int dest);
int ftpGetFileDesc(int sock, struct in6_addr host, int family,
- char * remotename);
+ char * remotename, long long *size);
int ftpGetFileDone(int sock);
-int httpGetFileDesc(char * hostname, int port, char * remotename, char *extraHeaders);
+int httpGetFileDesc(char * hostname, int port, char * remotename,
+ char *extraHeaders, long long *size);
#endif
diff --git a/loader2/loadermisc.c b/loader2/loadermisc.c
index 1fd7709..a8bf915 100644
--- a/loader2/loadermisc.c
+++ b/loader2/loadermisc.c
@@ -33,12 +33,15 @@
#include <stdlib.h>
#include "log.h"
+#include "windows.h"
-int copyFileFd(int infd, char * dest) {
+int copyFileFd(int infd, char * dest, progressCB pbcb,
+ struct progressCBdata *data, long long total) {
int outfd;
char buf[4096];
int i;
int rc = 0;
+ long long count = 0;
outfd = open(dest, O_CREAT | O_RDWR, 0666);
@@ -52,6 +55,11 @@ int copyFileFd(int infd, char * dest) {
rc = 1;
break;
}
+ count += i;
+
+ if (pbcb && data && total) {
+ pbcb(data, count, total);
+ }
}
close(outfd);
@@ -70,7 +78,7 @@ int copyFile(char * source, char * dest) {
return 1;
}
- rc = copyFileFd(infd, dest);
+ rc = copyFileFd(infd, dest, NULL, NULL, 0);
close(infd);
diff --git a/loader2/loadermisc.h b/loader2/loadermisc.h
index 8094fa7..4461e58 100644
--- a/loader2/loadermisc.h
+++ b/loader2/loadermisc.h
@@ -21,9 +21,11 @@
#define H_LOADER_MISC_H
#include <stdio.h>
#include <stdarg.h>
+#include "windows.h"
int copyFile(char * source, char * dest);
-int copyFileFd(int infd, char * dest);
+int copyFileFd(int infd, char * dest, progressCB pbcb,
+ struct progressCBdata *data, long long total);
char * readLine(FILE * f);
int simpleStringCmp(const void * a, const void * b);
int totalMemory(void);
diff --git a/loader2/method.c b/loader2/method.c
index d5bda57..0310c82 100644
--- a/loader2/method.c
+++ b/loader2/method.c
@@ -442,11 +442,12 @@ int mountStage2(char *stage2path) {
/* copies a second stage from fd to dest and mounts on mntpoint */
int copyFileAndLoopbackMount(int fd, char * dest,
- char * device, char * mntpoint) {
+ char * device, char * mntpoint, progressCB pbcb,
+ struct progressCBdata *data, long long total) {
int rc;
struct stat sb;
- rc = copyFileFd(fd, dest);
+ rc = copyFileFd(fd, dest, pbcb, data, total);
stat(dest, &sb);
logMessage(DEBUGLVL, "copied %" PRId64 " bytes to %s (%s)", sb.st_size, dest,
((rc) ? " incomplete" : "complete"));
diff --git a/loader2/method.h b/loader2/method.h
index 5f6c7a8..0a58a1f 100644
--- a/loader2/method.h
+++ b/loader2/method.h
@@ -46,7 +46,9 @@ void queryIsoMediaCheck(char * isoDir);
void umountStage2(void);
int mountStage2(char *stage2path);
-int copyFileAndLoopbackMount(int fd, char *dest, char *device, char *mntpoint);
+int copyFileAndLoopbackMount(int fd, char *dest, char *device,
+ char *mntpoint, progressCB pbcb,
+ struct progressCBdata *data, long long total);
int getFileFromBlockDevice(char *device, char *path, char * dest);
int unpackCpioBall(char * ballPath, char * rootDir);
diff --git a/loader2/urlinstall.c b/loader2/urlinstall.c
index 4cbb866..5cf9b69 100644
--- a/loader2/urlinstall.c
+++ b/loader2/urlinstall.c
@@ -56,6 +56,8 @@ static int loadSingleUrlImage(struct iurlinfo * ui, char *path,
int fd;
int rc = 0;
char *ehdrs = NULL;
+ long long size;
+ struct progressCBdata *data = NULL;
if (ui->protocol == URL_METHOD_HTTP) {
char *arch = getProductArch();
@@ -70,7 +72,7 @@ static int loadSingleUrlImage(struct iurlinfo * ui, char *path,
}
}
- fd = urlinstStartTransfer(ui, path, ehdrs);
+ fd = urlinstStartTransfer(ui, path, ehdrs, &data, &size);
if (fd == -2) {
if (ehdrs) free (ehdrs);
@@ -89,10 +91,10 @@ static int loadSingleUrlImage(struct iurlinfo * ui, char *path,
}
if (dest != NULL) {
- rc = copyFileAndLoopbackMount(fd, dest, device, mntpoint);
+ rc = copyFileAndLoopbackMount(fd, dest, device, mntpoint, progressCallback, data, size);
}
- urlinstFinishTransfer(ui, fd);
+ urlinstFinishTransfer(ui, fd, &data);
return rc;
}
@@ -274,6 +276,8 @@ int getFileFromUrl(char * url, char * dest,
int fd, rc;
struct networkDeviceConfig netCfg;
char *ehdrs = NULL, *ip = NULL;
+ long long size;
+ struct progressCBdata *data = NULL;
if (kickstartNetworkUp(loaderData, &netCfg)) {
logMessage(ERROR, "unable to bring up network");
@@ -355,14 +359,14 @@ int getFileFromUrl(char * url, char * dest,
}
}
- fd = urlinstStartTransfer(&ui, file, ehdrs);
+ fd = urlinstStartTransfer(&ui, file, ehdrs, &data, &size);
if (fd < 0) {
logMessage(ERROR, "failed to retrieve http://%s/%s%s", ui.address, ui.prefix, file);
retval = 1;
goto err;
}
- rc = copyFileFd(fd, dest);
+ rc = copyFileFd(fd, dest, progressCallback, data, size);
if (rc) {
unlink (dest);
logMessage(ERROR, "failed to copy file to %s", dest);
@@ -370,7 +374,7 @@ int getFileFromUrl(char * url, char * dest,
goto err;
}
- urlinstFinishTransfer(&ui, fd);
+ urlinstFinishTransfer(&ui, fd, &data);
err:
if (file) free(file);
diff --git a/loader2/urls.c b/loader2/urls.c
index 5c75f0d..44148ef 100644
--- a/loader2/urls.c
+++ b/loader2/urls.c
@@ -164,7 +164,8 @@ char *convertUIToURL(struct iurlinfo *ui) {
/* see ftp.c:httpGetFileDesc() for details */
/* set to NULL if not needed */
int urlinstStartTransfer(struct iurlinfo * ui, char *path,
- char *extraHeaders) {
+ char *extraHeaders,
+ struct progressCBdata **data, long long *size) {
int fd, port;
int family = -1;
struct in_addr addr;
@@ -214,14 +215,14 @@ int urlinstStartTransfer(struct iurlinfo * ui, char *path,
return -2;
}
- fd = ftpGetFileDesc(ui->ftpPort, addr6, family, path);
+ fd = ftpGetFileDesc(ui->ftpPort, addr6, family, path, size);
if (fd < 0) {
close(ui->ftpPort);
if (hostname) free(hostname);
return -1;
}
} else {
- fd = httpGetFileDesc(hostname, port, path, extraHeaders);
+ fd = httpGetFileDesc(hostname, port, path, extraHeaders, size);
if (fd < 0) {
if (portstr) free(portstr);
return -1;
@@ -232,6 +233,8 @@ int urlinstStartTransfer(struct iurlinfo * ui, char *path,
if (FL_CMDLINE(flags)) {
printf("%s %s...\n", _("Retrieving"), fileName+1);
+ } else if (*size) {
+ *data = winProgressBar(70, 5, _("Retrieving"), "%s %s...", _("Retrieving"), fileName+1);
} else {
winStatus(70, 3, _("Retrieving"), "%s %s...", _("Retrieving"), fileName+1);
}
@@ -240,7 +243,9 @@ int urlinstStartTransfer(struct iurlinfo * ui, char *path,
return fd;
}
-int urlinstFinishTransfer(struct iurlinfo * ui, int fd) {
+int urlinstFinishTransfer(struct iurlinfo * ui, int fd,
+ struct progressCBdata **data) {
+ if (*data) free(*data);
if (ui->protocol == URL_METHOD_FTP)
close(ui->ftpPort);
close(fd);
diff --git a/loader2/urls.h b/loader2/urls.h
index 75761ac..1ceb35f 100644
--- a/loader2/urls.h
+++ b/loader2/urls.h
@@ -19,6 +19,7 @@
#ifndef H_LOADER_URLS
#define H_LOADER_URLS
+#include "windows.h"
enum urlprotocol_t { URL_METHOD_FTP, URL_METHOD_HTTP };
typedef enum urlprotocol_t urlprotocol;
@@ -40,7 +41,10 @@ char *convertUIToURL(struct iurlinfo *ui);
int setupRemote(struct iurlinfo * ui);
int urlMainSetupPanel(struct iurlinfo * ui);
int urlSecondarySetupPanel(struct iurlinfo * ui);
-int urlinstStartTransfer(struct iurlinfo * ui, char *path, char *extraHeaders);
-int urlinstFinishTransfer(struct iurlinfo * ui, int fd);
+int urlinstStartTransfer(struct iurlinfo * ui, char *path,
+ char *extraHeaders,
+ struct progressCBdata **data, long long *size);
+int urlinstFinishTransfer(struct iurlinfo * ui, int fd,
+ struct progressCBdata **data);
#endif
diff --git a/loader2/windows.c b/loader2/windows.c
index 424f8a7..785146f 100644
--- a/loader2/windows.c
+++ b/loader2/windows.c
@@ -29,6 +29,7 @@
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
+#include <math.h>
#include "windows.h"
@@ -64,4 +65,45 @@ void scsiWindow(const char * driver) {
_("Loading %s driver..."), driver);
}
+void progressCallback(void *pbdata, long long pos, long long total) {
+ struct progressCBdata *data = pbdata;
+ char tickmark[2] = "-";
+ char * ticks = "-\\|/";
+
+ newtScaleSet(data->scale, ceil(pos * 100.0 / total));
+ *tickmark = ticks[(total / (pos + 1)) % 5];
+
+ newtLabelSetText(data->label, tickmark);
+ newtRefresh();
+}
+
+struct progressCBdata *winProgressBar(int width, int height, char *title, char *text, ...) {
+ struct progressCBdata *data;
+ char *buf = NULL;
+ va_list args;
+ int llen;
+ va_start(args, text);
+ if (vasprintf(&buf, text, args) != -1) {
+ va_end(args);
+ newtComponent t, f, scale, label;
+ newtCenteredWindow(width, height, title);
+ t = newtTextbox(1, 1, width - 2, height - 2, NEWT_TEXTBOX_WRAP);
+ newtTextboxSetText(t, buf);
+ llen = strlen(buf);
+ free(buf);
+ label = newtLabel(llen + 1, 1, "-");
+ f = newtForm(NULL, NULL, 0);
+ newtFormAddComponent(f, t);
+ scale = newtScale(3, 3, width - 6, 100);
+ newtFormAddComponent(f, scale);
+ newtDrawForm(f);
+ newtRefresh();
+ data = malloc(sizeof(struct progressCBdata));
+ data->scale = scale;
+ data->label = label;
+ return data;
+ }
+ return NULL;
+}
+
/* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/loader2/windows.h b/loader2/windows.h
index 2400c91..d253233 100644
--- a/loader2/windows.h
+++ b/loader2/windows.h
@@ -20,6 +20,7 @@
#ifndef _WINDOWS_H_
#define _WINDOWS_H_
+#include <newt.h>
#include "lang.h"
void winStatus(int width, int height, char * title, char * text, ...);
@@ -28,4 +29,15 @@ void scsiWindow(const char * driver);
#define errorWindow(String) \
newtWinMessage(_("Error"), _("OK"), String, strerror (errno));
+typedef void (*progressCB)(void *pbdata, long long offset, long long total);
+
+struct progressCBdata {
+ newtComponent scale;
+ newtComponent label;
+};
+
+void progressCallback(void *pbdata, long long pos, long long total);
+
+struct progressCBdata *winProgressBar(int width, int height, char *title, char *text, ...);
+
#endif /* _WINDOWS_H_ */
--
1.5.5.1