From 1866e46f857c0790bfa2996f75df0f5e08cdb090 Mon Sep 17 00:00:00 2001 From: Nathan Wagner Date: Sat, 16 Feb 2019 15:52:11 +0000 Subject: [PATCH] add options for fetchurl --- crypto/rfc3986.re | 12 ++++++- doc/zpm-fetchurl.8 | 10 ++++-- src/fetchurl.c | 86 +++++++++++++++++++++++++++++++--------------- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/crypto/rfc3986.re b/crypto/rfc3986.re index 463486f..feaf49a 100644 --- a/crypto/rfc3986.re +++ b/crypto/rfc3986.re @@ -205,7 +205,6 @@ int tls_parse_uri(char *s, struct tls_uri *uri) { percent_decode(uri->host); percent_decode(uri->path); percent_decode(uri->query); - if (uri->path == NULL || uri->path[0] == 0) { free(uri->path); @@ -215,10 +214,21 @@ int tls_parse_uri(char *s, struct tls_uri *uri) { return rv; } +#define MARK fprintf(stderr, "%s %s:%d\n", __FILE__, __func__, __LINE__) void tls_free_uri(struct tls_uri *uri) { + if (!uri) return; + free(uri->host); + uri->host = 0; free(uri->path); + uri->path = 0; free(uri->query); + uri->query = 0; free(uri->port); + uri->port = 0; free(uri->scheme); + uri->scheme = 0; + free(uri->fragment); + uri->fragment = 0; + } diff --git a/doc/zpm-fetchurl.8 b/doc/zpm-fetchurl.8 index 4a269b3..8f93859 100644 --- a/doc/zpm-fetchurl.8 +++ b/doc/zpm-fetchurl.8 @@ -1,10 +1,10 @@ -.TH zpm-fetchurl 8 2019-02-15 "ZPM 0.4" +.TH zpm-fetchurl 8 2019-02-16 "ZPM 0.4" .SH NAME zpm-fetchurl \- download files .SH SYNOPSIS .B zpm fetchurl [ -.B -ISkKr +.B -ISkKrOn ] [ .BI -o file @@ -51,6 +51,12 @@ Only download if remote is newer than the file given by path Write the output to the file given by \fIpath\fR. Output is written to stdout by default. .TP +.B \-O +Calculate the output file name from the url. +.TP +.B \-n +Only if newer. Like \-z, except use the output file name, if any. +.TP .B \-f Fail silently on errors. .TP diff --git a/src/fetchurl.c b/src/fetchurl.c index 9d52696..395ce95 100644 --- a/src/fetchurl.c +++ b/src/fetchurl.c @@ -539,6 +539,22 @@ char *pathlast(char *path) { return strndup(last, len); } +static time_t file_mtime(char *path) { + struct stat st; + int rv; + + rv = stat(path, &st); + if (rv == -1) { + if (errno == ENOENT) { + return 0; + } + perror("stat failed:"); + return -1; + } + + return st.st_mtime; +} + int main(int ac, char *av[]) { int sockfd, port = -1, rv; ssize_t ret; @@ -553,7 +569,7 @@ int main(int ac, char *av[]) { struct tls_uri uri = { 0 }; char *outfile = 0; int raw = 0, head = 0; - int out = 1; + int out = 1; /* output file descriptor */ int use_tls = 0; struct io io = { {0}, 0, -1, 0, 0, 0, 0, 0 }; struct TLSContext *clientssl = 0; @@ -567,11 +583,11 @@ int main(int ac, char *av[]) { size_t header_len; char *url = 0; int redirs = 0, redirlimit = 50, printstatus = 0; - int verifypolicy = 1, calcoutfile = 0; + int verifypolicy = 1, calcoutfile = 0, ifnewer = 0; ltc_mp = tfm_desc; - while ((option = getopt(ac, av, "o:OrIfz:#R:SkK")) != -1) { + while ((option = getopt(ac, av, "o:OrIfz:n#R:SkK")) != -1) { switch (option) { case 'o': outfile = optarg; break; case 'O': calcoutfile = 1; break; @@ -582,6 +598,7 @@ int main(int ac, char *av[]) { case 'r': raw = 1; break; case 'f': failsilent = 1; break; case 'z': lmfile = optarg; break; + case 'n': ifnewer = 1; break; case 'R': redirlimit = strtol(optarg, 0, 10); break; case '#': progressbar = 1; break; default: @@ -595,29 +612,13 @@ int main(int ac, char *av[]) { exit(EXIT_FAILURE); } - io.last_modified = 0; - if (lmfile) { - struct stat st; - int rv; - struct tm *mtime; - time_t ts; - - rv = stat(lmfile, &st); - if (rv == -1) { - perror("stat failed:"); - exit(EXIT_FAILURE); - } - ts = st.st_mtime; - io.last_modified = ts; - mtime = gmtime(&ts); - strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime); - } - url = strdup(av[optind]); if (!url) { exit(EXIT_FAILURE); } + io.last_modified = 0; + if (calcoutfile && !outfile) { tls_parse_uri(url, &uri); outfile = pathlast(uri.path); @@ -631,11 +632,24 @@ int main(int ac, char *av[]) { } } - if (outfile) { - out = open(outfile, O_WRONLY|O_CREAT, 0600); - if (out == -1) { - perror("can't open output file:"); + if (ifnewer && outfile && !lmfile) { + lmfile = outfile; + } + + if (lmfile) { + struct tm *mtime; + time_t ts; + + ts = file_mtime(lmfile); + + if (ts == -1) { exit(EXIT_FAILURE); + } else if (ts != 0) { + io.last_modified = ts; + mtime = gmtime(&ts); + strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime); + } else { + lmfile = 0; } } @@ -648,13 +662,13 @@ int main(int ac, char *av[]) { tls_free_uri(&uri); io.response.len = 0; request.len = 0; + eoh = 0; tls_parse_uri(url, &uri); host = uri.host; port = atoi(uri.port); req_file = uri.path; - /* construct request */ if (head) { tls_buffer_append(&request, "HEAD ", 5); @@ -762,12 +776,15 @@ int main(int ac, char *av[]) { parse_header(&io); switch (io.status_code) { + case 304: + break; case 301: case 302: case 303: case 307: free(url); url = strdup(io.redirect); + close(io.socket); continue; break; } @@ -790,6 +807,14 @@ int main(int ac, char *av[]) { } } + if (outfile) { + out = open(outfile, O_WRONLY|O_CREAT, 0600); + if (out == -1) { + perror("can't open output file:"); + exit(EXIT_FAILURE); + } + } + do { write(out, io.response.buffer, io.response.len); ret = io.response.len; @@ -817,7 +842,12 @@ int main(int ac, char *av[]) { if (ret < 0) { fprintf(stderr, "%s read error %zd\n", uri.scheme, ret); } - /* futimens(out, ...) */ + struct timespec ts[2]; + ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT; + ts[1].tv_sec = io.last_modified; + ts[1].tv_nsec = 0; + + futimens(out, ts); close(out); tls_buffer_free(&io.response); break; @@ -834,5 +864,5 @@ int main(int ac, char *av[]) { putc('\n',stderr); } - return io.status_code == 200 ? 0 : EXIT_FAILURE; + return io.status_code < 400 ? 0 : EXIT_FAILURE; } -- 2.40.0