On Thu, Dec 19 2019, Jeremie Courreges-Anglas <[email protected]> wrote:
> 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?
Still looking for feedback, else I'll resort to crowdtesting. ;)
>
> 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