Re: ftp(1): separate file:/ URL handling

2019-12-30 Thread Hiltjo Posthuma
On Thu, Dec 26, 2019 at 10:53:45AM +0100, Jeremie Courreges-Anglas wrote:
> On Thu, Dec 19 2019, Jeremie Courreges-Anglas  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 voidaborthttp(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_thashbytes;
> > +   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);
> > +

Re: ftp(1): separate file:/ URL handling

2019-12-26 Thread Jeremie Courreges-Anglas
On Thu, Dec 19 2019, Jeremie Courreges-Anglas  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_thashbytes;
> + 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

ftp(1): separate file:/ URL handling

2019-12-18 Thread Jeremie Courreges-Anglas


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 voidaborthttp(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_thashbytes;
+   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))
+