A bit late...

Move file: URL handling into its own function.  This simplifies
url_get() and would have prevented problems with bogus redirections.

file_get() unrolls the code previously used in url_get(), except the
#ifndef SMALL bits were stripped out.  file: support is mainly
(only?) used in the installer which is built with SMALL defined.
Resuming an incomplete file: transfer sounds nuts.

I felt a bit guilty about copying dubious code, there are some changes
that ought to be applied to url_get() too:
- write(2) can't return 0, can it? (something old about non-blocking
  sockets maybe?).  Anyway, no need to handle 0 explicitely.
- allocate buf before setjmp instead of marking it volatile
- save_errno/warnc dance if read(2) fails

This survived make release on amd64 and a bsd.rd upgrade with sets
on 'disk'.  The resulting ftp(1) binary size decreases.

Comments/ok?


Index: fetch.c
===================================================================
--- fetch.c.orig
+++ fetch.c
@@ -68,6 +68,7 @@ struct tls;
 #include "ftp_var.h"
 #include "cmds.h"
 
+static int     file_get(const char *, const char *);
 static int     url_get(const char *, const char *, const char *, int);
 static int     save_chunked(FILE *, struct tls *, int , char *, size_t);
 static void    aborthttp(int);
@@ -182,6 +183,125 @@ tooslow(int signo)
 }
 
 /*
+ * Copy a local file (used by the OpenBSD installer).
+ * Returns -1 on failure, 0 on success
+ */
+static int
+file_get(const char *path, const char *outfile)
+{
+       struct stat      st;
+       int              fd, out, rval = -1, save_errno;
+       volatile sig_t   oldintr, oldinti;
+       const char      *savefile;
+       char            *buf = NULL, *cp;
+       const size_t     buflen = 128 * 1024;
+       off_t            hashbytes;
+       ssize_t          len, wlen;
+
+       direction = "received";
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1) {
+               warn("Can't open file %s", path);
+               return -1;
+       }
+
+       if (fstat(fd, &st) == -1)
+               filesize = -1;
+       else
+               filesize = st.st_size;
+
+       if (outfile != NULL)
+               savefile = outfile;
+       else {
+               if (path[strlen(path) - 1] == '/')      /* Consider no file */
+                       savefile = NULL;                /* after dir invalid. */
+               else
+                       savefile = basename(path);
+       }
+
+       if (EMPTYSTRING(savefile)) {
+               warnx("No filename after directory (use -o): %s", path);
+               goto cleanup_copy;
+       }
+
+       /* Open the output file.  */
+       if (!pipeout) {
+               out = open(savefile, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+               if (out == -1) {
+                       warn("Can't open %s", savefile);
+                       goto cleanup_copy;
+               }
+       } else
+               out = fileno(stdout);
+
+       if ((buf = malloc(buflen)) == NULL)
+               errx(1, "Can't allocate memory for transfer buffer");
+
+       /* Trap signals */
+       oldintr = NULL;
+       oldinti = NULL;
+       if (setjmp(httpabort)) {
+               if (oldintr)
+                       (void)signal(SIGINT, oldintr);
+               if (oldinti)
+                       (void)signal(SIGINFO, oldinti);
+               goto cleanup_copy;
+       }
+       oldintr = signal(SIGINT, abortfile);
+
+       bytes = 0;
+       hashbytes = mark;
+       progressmeter(-1, path);
+
+       /* Finally, suck down the file. */
+       oldinti = signal(SIGINFO, psummary);
+       while ((len = read(fd, buf, buflen)) > 0) {
+               bytes += len;
+               for (cp = buf; len > 0; len -= wlen, cp += wlen) {
+                       if ((wlen = write(out, cp, len)) == -1) {
+                               warn("Writing %s", savefile);
+                               signal(SIGINFO, oldinti);
+                               goto cleanup_copy;
+                       }
+               }
+               if (hash && !progress) {
+                       while (bytes >= hashbytes) {
+                               (void)putc('#', ttyout);
+                               hashbytes += mark;
+                       }
+                       (void)fflush(ttyout);
+               }
+       }
+       save_errno = errno;
+       signal(SIGINFO, oldinti);
+       if (hash && !progress && bytes > 0) {
+               if (bytes < mark)
+                       (void)putc('#', ttyout);
+               (void)putc('\n', ttyout);
+               (void)fflush(ttyout);
+       }
+       if (len == -1) {
+               warnc(save_errno, "Reading from file");
+               goto cleanup_copy;
+       }
+       progressmeter(1, NULL);
+       if (verbose)
+               ptransfer(0);
+       (void)signal(SIGINT, oldintr);
+
+       rval = 0;
+
+cleanup_copy:
+       free(buf);
+       if (out >= 0 && out != fileno(stdout))
+               close(out);
+       close(fd);
+
+       return rval;
+}
+
+/*
  * Retrieve URL, via the proxy in $proxyvar if necessary.
  * Returns -1 on failure, 0 on success
  */
@@ -191,7 +311,7 @@ url_get(const char *origline, const char
        char pbuf[NI_MAXSERV], hbuf[NI_MAXHOST], *cp, *portnum, *path, ststr[4];
        char *hosttail, *cause = "unknown", *newline, *host, *port, *buf = NULL;
        char *epath, *redirurl, *loctail, *h, *p, gerror[200];
-       int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1;
+       int error, i, isftpurl = 0, isredirect = 0, rval = -1;
        int isunavail = 0, retryafter = -1;
        struct addrinfo hints, *res0, *res;
        const char * volatile savefile;
@@ -239,12 +359,6 @@ url_get(const char *origline, const char
 #ifndef SMALL
                scheme = FTP_URL;
 #endif /* !SMALL */
-       } else if (strncasecmp(newline, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
-               host = newline + sizeof(FILE_URL) - 1;
-               isfileurl = 1;
-#ifndef SMALL
-               scheme = FILE_URL;
-#endif /* !SMALL */
        } else if (strncasecmp(newline, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0) 
{
 #ifndef NOSSL
                host = newline + sizeof(HTTPS_URL) - 1;
@@ -256,32 +370,25 @@ url_get(const char *origline, const char
                scheme = HTTPS_URL;
 #endif /* !SMALL */
        } else
-               errx(1, "url_get: Invalid URL '%s'", newline);
-
-       if (isfileurl && redirect_loop > 0)
-               errx(1, "Redirection to local file not permitted");
+               errx(1, "%s: URL not permitted", newline);
 
-       if (isfileurl) {
-               path = host;
-       } else {
-               path = strchr(host, '/');               /* Find path */
-               if (EMPTYSTRING(path)) {
-                       if (outfile) {                  /* No slash, but */
-                               path=strchr(host,'\0'); /* we have outfile. */
-                               goto noslash;
-                       }
-                       if (isftpurl)
-                               goto noftpautologin;
-                       warnx("No `/' after host (use -o): %s", origline);
-                       goto cleanup_url_get;
-               }
-               *path++ = '\0';
-               if (EMPTYSTRING(path) && !outfile) {
-                       if (isftpurl)
-                               goto noftpautologin;
-                       warnx("No filename after host (use -o): %s", origline);
-                       goto cleanup_url_get;
+       path = strchr(host, '/');               /* Find path */
+       if (EMPTYSTRING(path)) {
+               if (outfile) {                          /* No slash, but */
+                       path = strchr(host,'\0');       /* we have outfile. */
+                       goto noslash;
                }
+               if (isftpurl)
+                       goto noftpautologin;
+               warnx("No `/' after host (use -o): %s", origline);
+               goto cleanup_url_get;
+       }
+       *path++ = '\0';
+       if (EMPTYSTRING(path) && !outfile) {
+               if (isftpurl)
+                       goto noftpautologin;
+               warnx("No filename after host (use -o): %s", origline);
+               goto cleanup_url_get;
        }
 
 noslash:
@@ -324,7 +431,7 @@ noslash:
        }
 #endif /* !SMALL */
 
-       if (!isfileurl && proxyenv != NULL) {           /* use proxy */
+       if (proxyenv != NULL) {         /* use proxy */
 #ifndef NOSSL
                if (ishttpsurl) {
                        sslpath = strdup(path);
@@ -381,112 +488,6 @@ noslash:
                path = newline;
        }
 
-       if (isfileurl) {
-               struct stat st;
-
-               fd = open(path, O_RDONLY);
-               if (fd == -1) {
-                       warn("Can't open file %s", path);
-                       goto cleanup_url_get;
-               }
-
-               if (fstat(fd, &st) == -1)
-                       filesize = -1;
-               else
-                       filesize = st.st_size;
-
-               /* Open the output file.  */
-               if (!pipeout) {
-#ifndef SMALL
-                       if (resume)
-                               out = open(savefile, O_CREAT | O_WRONLY |
-                                       O_APPEND, 0666);
-
-                       else
-#endif /* !SMALL */
-                               out = open(savefile, O_CREAT | O_WRONLY |
-                                       O_TRUNC, 0666);
-                       if (out < 0) {
-                               warn("Can't open %s", savefile);
-                               goto cleanup_url_get;
-                       }
-               } else
-                       out = fileno(stdout);
-
-#ifndef SMALL
-               if (resume) {
-                       if (fstat(out, &st) == -1) {
-                               warn("Can't fstat %s", savefile);
-                               goto cleanup_url_get;
-                       }
-                       if (lseek(fd, st.st_size, SEEK_SET) == -1) {
-                               warn("Can't lseek %s", path);
-                               goto cleanup_url_get;
-                       }
-                       restart_point = st.st_size;
-               }
-#endif /* !SMALL */
-
-               /* Trap signals */
-               oldintr = NULL;
-               oldinti = NULL;
-               if (setjmp(httpabort)) {
-                       if (oldintr)
-                               (void)signal(SIGINT, oldintr);
-                       if (oldinti)
-                               (void)signal(SIGINFO, oldinti);
-                       goto cleanup_url_get;
-               }
-               oldintr = signal(SIGINT, abortfile);
-
-               bytes = 0;
-               hashbytes = mark;
-               progressmeter(-1, path);
-
-               if ((buf = malloc(buflen)) == NULL)
-                       errx(1, "Can't allocate memory for transfer buffer");
-
-               /* Finally, suck down the file. */
-               i = 0;
-               oldinti = signal(SIGINFO, psummary);
-               while ((len = read(fd, buf, buflen)) > 0) {
-                       bytes += len;
-                       for (cp = buf; len > 0; len -= i, cp += i) {
-                               if ((i = write(out, cp, len)) == -1) {
-                                       warn("Writing %s", savefile);
-                                       signal(SIGINFO, oldinti);
-                                       goto cleanup_url_get;
-                               } else if (i == 0)
-                                       break;
-                       }
-                       if (hash && !progress) {
-                               while (bytes >= hashbytes) {
-                                       (void)putc('#', ttyout);
-                                       hashbytes += mark;
-                               }
-                               (void)fflush(ttyout);
-                       }
-               }
-               signal(SIGINFO, oldinti);
-               if (hash && !progress && bytes > 0) {
-                       if (bytes < mark)
-                               (void)putc('#', ttyout);
-                       (void)putc('\n', ttyout);
-                       (void)fflush(ttyout);
-               }
-               if (len != 0) {
-                       warn("Reading from file");
-                       goto cleanup_url_get;
-               }
-               progressmeter(1, NULL);
-               if (verbose)
-                       ptransfer(0);
-               (void)signal(SIGINT, oldintr);
-
-               rval = 0;
-               goto cleanup_url_get;
-       }
-
        if (*host == '[' && (hosttail = strrchr(host, ']')) != NULL &&
            (hosttail[1] == '\0' || hosttail[1] == ':')) {
                host++;
@@ -1272,12 +1273,17 @@ auto_fetch(int argc, char *argv[], char
                if (url == NULL)
                        errx(1, "Can't allocate memory for auto-fetch.");
 
+               if (strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
+                       if (file_get(url + sizeof(FILE_URL) - 1, outfile) == -1)
+                               rval = argpos + 1;
+                       continue;
+               }
+
                /*
-                * Try HTTP URL-style arguments first.
+                * Try HTTP URL-style arguments next.
                 */
                if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||
-                   strncasecmp(url, HTTPS_URL, sizeof(HTTPS_URL) -1) == 0 ||
-                   strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
+                   strncasecmp(url, HTTPS_URL, sizeof(HTTPS_URL) -1) == 0) {
                        redirect_loop = 0;
                        retried = 0;
                        if (url_get(url, httpproxy, outfile, lastfile) == -1)


-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to