Download raw body.
ftp(1): parse fractional seconds in MDTM responses
On 2026/02/12 17:30, Benjamin Lee McQueen wrote:
> sorry for the bad formatting and incompatible diff,
> i'll put the new one here
>
> On 260212-123226, Stuart Henderson wrote:
> > also, ftp(1) changes (at least outside of !small) need testing on
> > ramdisks, see release(8) for info on building
> just to clarify, you want me to build and test the full installation
> media?
Somebody needs to, it can't be committed without checking that.
Generally it's easier if the person sending the diff does it because
they'll need that environment to test if it needs fixing..
> i don't know if i have the time currently to do this.
> can somebody else with a buildenv test this?
>
> either way here's the diff:
diff was mangled by your MTA (which used "format=flowed"). I hand
applied, fixed some >80 column lines, and renamed result back to the
original rtime as it doesn't seem to need changing, I can try it in
'make release' next time I'm running one..
Index: cmds.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/cmds.c,v
diff -u -p -r1.85 cmds.c
--- cmds.c 8 Mar 2023 04:43:11 -0000 1.85
+++ cmds.c 13 Feb 2026 09:42:45 -0000
@@ -1594,7 +1594,7 @@ modtime(int argc, char *argv[])
code = -1;
return;
}
- mtime = remotemodtime(argv[1], 1);
+ mtime = remotemodtime(argv[1], 1).tv_sec;
if (mtime != -1)
fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
code = mtime;
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.bin/ftp/extern.h,v
diff -u -p -r1.54 extern.h
--- extern.h 21 May 2024 05:00:48 -0000 1.54
+++ extern.h 13 Feb 2026 09:42:45 -0000
@@ -101,7 +101,7 @@ void recvrequest(const char *, const cha
const char *, int, int);
char *remglob(char **, int, char **);
off_t remotesize(const char *, int);
-time_t remotemodtime(const char *, int);
+struct timespec remotemodtime(const char *, int);
void reset(int, char **);
void rmthelp(int, char **);
void sethash(int, char **);
Index: ftp.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/ftp.c,v
diff -u -p -r1.109 ftp.c
--- ftp.c 8 Mar 2023 04:43:11 -0000 1.109
+++ ftp.c 13 Feb 2026 09:42:45 -0000
@@ -1204,7 +1204,7 @@ break2:
if (bytes > 0)
ptransfer(0);
if (preserve && (closefunc == fclose)) {
- mtime = remotemodtime(remote, 0);
+ mtime = remotemodtime(remote, 0).tv_sec;
if (mtime != -1) {
struct timespec times[2];
Index: small.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/small.c,v
diff -u -p -r1.13 small.c
--- small.c 8 Mar 2023 04:43:11 -0000 1.13
+++ small.c 13 Feb 2026 09:42:45 -0000
@@ -269,7 +269,7 @@ usage:
if (ret == 0) {
time_t mtime;
- mtime = remotemodtime(argv[1], 0);
+ mtime = remotemodtime(argv[1], 0).tv_sec;
if (mtime == -1)
goto freegetit;
if (stbuf.st_mtime >= mtime) {
Index: util.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/util.c,v
diff -u -p -r1.99 util.c
--- util.c 21 Dec 2025 07:29:03 -0000 1.99
+++ util.c 13 Feb 2026 09:42:45 -0000
@@ -602,16 +602,16 @@ remotesize(const char *file, int noisy)
/*
* determine last modification time (in GMT) of remote file
*/
-time_t
+struct timespec
remotemodtime(const char *file, int noisy)
{
- int overbose;
- time_t rtime;
- int ocode;
+ struct timespec rtime;
+ int ocode, overbose;
overbose = verbose;
ocode = code;
- rtime = -1;
+ rtime.tv_sec = -1;
+ rtime.tv_nsec = 0;
#ifndef SMALL
if (!debug)
#endif /* !SMALL */
@@ -619,12 +619,14 @@ remotemodtime(const char *file, int nois
if (command("MDTM %s", file) == COMPLETE) {
struct tm timebuf;
int yy, mo, day, hour, min, sec;
+ char *cp, *ep;
+ long frac, nsec;
+ int i, multiplier, num_digits;
/*
* time-val = 14DIGIT [ "." 1*DIGIT ]
* YYYYMMDDHHMMSS[.sss]
* mdtm-response = "213" SP time-val CRLF / error-response
*/
- /* TODO: parse .sss as well, use timespecs. */
char *timestr = reply_string;
/* Repair `19%02d' bug on server side */
@@ -649,15 +651,40 @@ remotemodtime(const char *file, int nois
timebuf.tm_mon = mo - 1;
timebuf.tm_year = yy - 1900;
timebuf.tm_isdst = -1;
- rtime = mktime(&timebuf);
- if (rtime == -1 && (noisy
+
+ cp = strchr(reply_string, '.');
+ if (cp != NULL) {
+ cp++;
+ ep = cp;
+ while (isdigit((unsigned char)*ep))
+ ep++;
+ num_digits = ep - cp;
+ if (num_digits == 0 || num_digits > 9)
+ nsec = 0;
+ else {
+ frac = 0;
+ for (i = 0; i < num_digits; i++)
+ frac = frac * 10 + (cp[i] - '0');
+ multiplier = 1;
+ for (i = num_digits; i < 9; i++)
+ multiplier *= 10;
+ nsec = frac * multiplier;
+ }
+ } else
+ nsec = 0;
+
+ rtime.tv_sec = mktime(&timebuf);
+ rtime.tv_nsec = nsec;
+ if (rtime.tv_sec == -1 && (noisy
#ifndef SMALL
|| debug
#endif /* !SMALL */
))
- fprintf(ttyout, "Can't convert %s to a time.\n", reply_string);
+ fprintf(ttyout, "Can't convert %s to a time.\n",
+ reply_string);
else
- rtime += timebuf.tm_gmtoff; /* conv. local -> GMT */
+ /* conv. local -> GMT */
+ rtime.tv_sec += timebuf.tm_gmtoff;
} else if (noisy
#ifndef SMALL
&& !debug
@@ -667,7 +694,7 @@ remotemodtime(const char *file, int nois
fputc('\n', ttyout);
}
verbose = overbose;
- if (rtime == -1)
+ if (rtime.tv_sec == -1)
code = ocode;
return (rtime);
}
ftp(1): parse fractional seconds in MDTM responses