[PATCH] Add a progress bar to file downloads.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux