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
Attachment:
pgpDUzLxGk9WA.pgp
Description: PGP signature
_______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list