-/* $OpenBSD: extern.h,v 1.51 2019/05/16 12:44:17 florian Exp $ */
+/* $OpenBSD: extern.h,v 1.52 2021/02/02 12:58:42 robert Exp $ */
/* $NetBSD: extern.h,v 1.17 1997/08/18 10:20:19 lukem Exp $ */
/*
char *remglob2(char **, int, char **, FILE **ftemp, char *type);
int ruserpass(const char *, char **, char **, char **);
void sendrequest(const char *, const char *, const char *, int);
+ssize_t http_time(time_t, char *, size_t);
#endif /* !SMALL */
extern jmp_buf abortprox;
#ifndef SMALL
extern int NCMDS;
+extern int server_timestamps;
#endif /* !SMALL */
extern char *__progname; /* from crt0.o */
-/* $OpenBSD: fetch.c,v 1.199 2021/01/01 17:39:54 chrisz Exp $ */
+/* $OpenBSD: fetch.c,v 1.200 2021/02/02 12:58:42 robert Exp $ */
/* $NetBSD: fetch.c,v 1.14 1997/08/18 10:20:20 lukem Exp $ */
/*-
#include <unistd.h>
#include <util.h>
#include <resolv.h>
+#include <utime.h>
#ifndef NOSSL
#include <tls.h>
const char *scheme;
char *locbase;
struct addrinfo *ares = NULL;
+ char tmbuf[32];
+ time_t mtime = 0;
+ struct stat stbuf;
+ struct tm lmt = { 0 };
+ struct timespec ts[2];
#endif /* !SMALL */
struct tls *tls = NULL;
int status;
if (verbose)
fprintf(ttyout, "Requesting %s\n", origline);
#ifndef SMALL
- if (resume) {
- struct stat stbuf;
-
- if (stat(savefile, &stbuf) == 0)
- restart_point = stbuf.st_size;
- else
+ if (resume || timestamp) {
+ if (stat(savefile, &stbuf) == 0) {
+ if (resume)
+ restart_point = stbuf.st_size;
+ if (timestamp)
+ mtime = stbuf.st_mtime;
+ } else {
restart_point = 0;
+ mtime = 0;
+ }
}
#endif /* SMALL */
ftp_printf(fin,
if (port && strcmp(port, "80") != 0)
ftp_printf(fin, ":%s", port);
#endif /* !NOSSL */
+
+#ifndef SMALL
+ if (mtime && (http_time(mtime, tmbuf, sizeof(tmbuf)) != 0))
+ ftp_printf(fin, "\r\nIf-Modified-Since: %s", tmbuf);
+#endif /* SMALL */
+
ftp_printf(fin, "\r\n%s%s\r\n",
buf ? buf : "", httpuseragent);
if (credentials)
}
break;
#ifndef SMALL
+ case 304: /* Not Modified */
+ warnx("File is not modified on the server");
+ goto cleanup_url_get;
case 416: /* Requested Range Not Satisfiable */
warnx("File is already fully retrieved.");
goto cleanup_url_get;
cp[strcspn(cp, " \t")] = '\0';
if (strcasecmp(cp, "chunked") == 0)
chunked = 1;
+#ifndef SMALL
+#define LAST_MODIFIED "Last-Modified: "
+ } else if (strncasecmp(cp, LAST_MODIFIED,
+ sizeof(LAST_MODIFIED) - 1) == 0) {
+ cp += sizeof(LAST_MODIFIED) - 1;
+ cp[strcspn(cp, "\t")] = '\0';
+ if (strptime(cp, "%a, %d %h %Y %T %Z", &lmt) == NULL)
+ server_timestamps = 0;
+#endif /* !SMALL */
}
free(buf);
}
free(sslhost);
#endif /* !NOSSL */
ftp_close(&fin, &tls, &fd);
- if (out >= 0 && out != fileno(stdout))
+ if (out >= 0 && out != fileno(stdout)) {
+#ifndef SMALL
+ if (server_timestamps && lmt.tm_zone != 0) {
+ ts[0].tv_nsec = UTIME_NOW;
+ ts[1].tv_nsec = 0;
+ setenv("TZ", lmt.tm_zone, 1);
+ if (((ts[1].tv_sec = mktime(&lmt)) != -1) &&
+ (futimens(out, ts) == -1))
+ warnx("Unable to set file modification time");
+ }
+#endif /* !SMALL */
close(out);
+ }
free(buf);
free(pathbuf);
free(proxyhost);
-.\" $OpenBSD: ftp.1,v 1.121 2020/09/06 09:15:04 tb Exp $
+.\" $OpenBSD: ftp.1,v 1.122 2021/02/02 12:58:42 robert Exp $
.\" $NetBSD: ftp.1,v 1.22 1997/08/18 10:20:22 lukem Exp $
.\"
.\" Copyright (c) 1985, 1989, 1990, 1993
.\"
.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
-.Dd $Mdocdate: September 6 2020 $
+.Dd $Mdocdate: February 2 2021 $
.Dt FTP 1
.Os
.Sh NAME
.Sm on
.Ar ...
.Nm ftp
-.Op Fl C
+.Op Fl CTu
.Op Fl c Ar cookie
.Op Fl N Ar name
.Op Fl o Ar output
.It Fl s Ar sourceaddr
Set the source address for connections, which is useful on machines
with multiple interfaces.
+.It Fl T
+Send an
+.Dq If-Modified-Since
+header to the remote to determine if the remote file's timestamp
+has changed.
.It Fl t
Enables packet tracing.
.It Fl U Ar useragent
as the User-Agent for HTTP(S) URL requests.
If not specified, the default User-Agent is
.Dq OpenBSD ftp .
+.It Fl u
+Disable setting the local file's timestamps based
+on the
+.Dq Last-Modified
+header.
+By default the local file's timestamps are set to match those
+from the remote.
.It Fl V
Disable verbose mode, overriding the default of enabled when input
is from a terminal.
-/* $OpenBSD: ftp_var.h,v 1.45 2020/09/01 12:33:48 jca Exp $ */
+/* $OpenBSD: ftp_var.h,v 1.46 2021/02/02 12:58:42 robert Exp $ */
/* $NetBSD: ftp_var.h,v 1.18 1997/08/18 10:20:25 lukem Exp $ */
/*
extern size_t cursor_argc; /* location of cursor in margv */
extern size_t cursor_argo; /* offset of cursor in margv[cursor_argc] */
extern int resume; /* continue transfer */
+extern int timestamp; /* send an If-Modified-Since header */
extern char *srcaddr; /* source address to bind to */
#endif /* !SMALL */
-/* $OpenBSD: main.c,v 1.135 2020/09/06 09:49:11 tb Exp $ */
+/* $OpenBSD: main.c,v 1.136 2021/02/02 12:58:42 robert Exp $ */
/* $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $ */
/*
size_t cursor_argo;
int resume;
char *srcaddr;
+int timestamp;
#endif /* !SMALL */
char *cookiefile;
int connect_timeout;
+#ifndef SMALL
+/* enable using server timestamps by default */
+int server_timestamps = 1;
+#endif
+
#ifndef NOSSL
char * const ssl_verify_opts[] = {
#define SSL_CAFILE 0
el = NULL;
hist = NULL;
resume = 0;
+ timestamp = 0;
srcaddr = NULL;
marg_sl = sl_init();
#endif /* !SMALL */
httpuseragent = NULL;
while ((ch = getopt(argc, argv,
- "46AaCc:dD:EeN:gik:Mmno:pP:r:S:s:tU:vVw:")) != -1) {
+ "46AaCc:dD:EeN:gik:Mmno:pP:r:S:s:TtU:uvVw:")) != -1) {
switch (ch) {
case '4':
family = PF_INET;
#endif /* !SMALL */
break;
+#ifndef SMALL
+ case 'T':
+ timestamp = 1;
+ break;
+#endif /* !SMALL */
case 't':
trace = 1;
break;
errx(1, "Can't allocate memory for HTTP(S) "
"User-Agent");
break;
+ case 'u':
+ server_timestamps = 0;
+ break;
#endif /* !SMALL */
case 'v':
-/* $OpenBSD: util.c,v 1.94 2020/10/18 20:35:18 naddy Exp $ */
+/* $OpenBSD: util.c,v 1.95 2021/02/02 12:58:42 robert Exp $ */
/* $NetBSD: util.c,v 1.12 1997/08/18 10:20:27 lukem Exp $ */
/*-
}
return 0;
}
+
+#ifndef SMALL
+ssize_t
+http_time(time_t t, char *tmbuf, size_t len)
+{
+ struct tm tm;
+
+ /* New HTTP/1.1 RFC 7231 prefers IMF-fixdate from RFC 5322 */
+ if (gmtime_r(&t, &tm) == NULL)
+ return 0;
+ else
+ return (strftime(tmbuf, len, "%a, %d %h %Y %T %Z", &tm));
+}
+#endif /* !SMALL */