Download raw body.
ftp(1): parse fractional seconds in MDTM responses
hello tech@,
index: util.c cmds.c ftp.c small.c extern.h
this diff implements the TODO to parse optional fractional seconds
from FTP MDTM timestamp response.
the diff changes remotemodtime() to return struct timespec instead
of time_t so fractional part isn't lost. also updates all callers
to use .tv_sec.
tested with custom ftp server using fractional timestamp.
diff:
--- util.c.orig Wed Feb 11 19:45:14 2026
+++ /usr/src/usr.bin/ftp/util.c Wed Feb 11 19:29:46 2026
@@ -602,12 +602,11 @@ 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;
+ struct timespec result;
- time_t rtime;
- int ocode;
+ int ocode, overbose;
overbose = verbose;
ocode = code;
- rtime = -1;
+ result.tv_sec = -1;
#ifndef SMALL
if (!debug)
#endif /* !SMALL */
verbose = -1;
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 +653,31 @@ remotemodtime(const char *file, int noisy)
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++;
+ frac = strtol(cp, &ep, 10);
+ if (*ep != '\0' && !isspace((unsigned char)*ep))
+ nsec = 0;
+ else {
+ num_digits = ep - cp;
+ multiplier = 1;
+ for (i = 0; i < (9 - num_digits); i++)
+ multiplier *= 10;
+ nsec = frac * multiplier;
+ }
+ } else
+ nsec = 0;
+
+ result.tv_sec = mktime(&timebuf);
+ result.tv_nsec = nsec;
+ if (result.tv_sec == -1 && (noisy
#ifndef SMALL
|| debug
#endif /* !SMALL */
))
fprintf(ttyout, "Can't convert %s to a time.\n", reply_string);
else
- rtime += timebuf.tm_gmtoff; /* conv. local -> GMT */
+ result.tv_sec += timebuf.tm_gmtoff; /* conv. local -> GMT */
} else if (noisy
#ifndef SMALL
&& !debug
@@ -667,9 +687,9 @@ remotemodtime(const char *file, int noisy)
fputc('\n', ttyout);
}
verbose = overbose;
- if (rtime == -1)
+ if (result.tv_sec == -1)
code = ocode;
- return (rtime);
+ return (result);
}
/*
--- cmds.c.orig Wed Feb 11 19:45:15 2026
+++ /usr/src/usr.bin/ftp/cmds.c Wed Feb 11 18:57:19 2026
@@ -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;
--- ftp.c.orig Wed Feb 11 19:45:16 2026
+++ /usr/src/usr.bin/ftp/ftp.c Wed Feb 11 18:56:48 2026
@@ -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];
--- small.c.orig Wed Feb 11 19:45:17 2026
+++ /usr/src/usr.bin/ftp/small.c Wed Feb 11 18:56:17 2026
@@ -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) {
--- extern.h.orig Wed Feb 11 19:45:17 2026
+++ /usr/src/usr.bin/ftp/extern.h Wed Feb 11 19:42:14 2026
@@ -101,7 +101,7 @@ void recvrequest(const char *, 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 **);
ok?
--- util.c.orig Wed Feb 11 19:45:14 2026
+++ /usr/src/usr.bin/ftp/util.c Wed Feb 11 19:29:46 2026
@@ -602,12 +602,11 @@ 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;
+ struct timespec result;
- time_t rtime;
- int ocode;
+ int ocode, overbose;
overbose = verbose;
ocode = code;
- rtime = -1;
+ result.tv_sec = -1;
#ifndef SMALL
if (!debug)
#endif /* !SMALL */
verbose = -1;
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 +653,31 @@ remotemodtime(const char *file, int noisy)
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++;
+ frac = strtol(cp, &ep, 10);
+ if (*ep != '\0' && !isspace((unsigned char)*ep))
+ nsec = 0;
+ else {
+ num_digits = ep - cp;
+ multiplier = 1;
+ for (i = 0; i < (9 - num_digits); i++)
+ multiplier *= 10;
+ nsec = frac * multiplier;
+ }
+ } else
+ nsec = 0;
+
+ result.tv_sec = mktime(&timebuf);
+ result.tv_nsec = nsec;
+ if (result.tv_sec == -1 && (noisy
#ifndef SMALL
|| debug
#endif /* !SMALL */
))
fprintf(ttyout, "Can't convert %s to a time.\n", reply_string);
else
- rtime += timebuf.tm_gmtoff; /* conv. local -> GMT */
+ result.tv_sec += timebuf.tm_gmtoff; /* conv. local -> GMT */
} else if (noisy
#ifndef SMALL
&& !debug
@@ -667,9 +687,9 @@ remotemodtime(const char *file, int noisy)
fputc('\n', ttyout);
}
verbose = overbose;
- if (rtime == -1)
+ if (result.tv_sec == -1)
code = ocode;
- return (rtime);
+ return (result);
}
/*
--- cmds.c.orig Wed Feb 11 19:45:15 2026
+++ /usr/src/usr.bin/ftp/cmds.c Wed Feb 11 18:57:19 2026
@@ -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;
--- ftp.c.orig Wed Feb 11 19:45:16 2026
+++ /usr/src/usr.bin/ftp/ftp.c Wed Feb 11 18:56:48 2026
@@ -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];
--- small.c.orig Wed Feb 11 19:45:17 2026
+++ /usr/src/usr.bin/ftp/small.c Wed Feb 11 18:56:17 2026
@@ -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) {
--- extern.h.orig Wed Feb 11 19:45:17 2026
+++ /usr/src/usr.bin/ftp/extern.h Wed Feb 11 19:42:14 2026
@@ -101,7 +101,7 @@ void recvrequest(const char *, 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 **);
ftp(1): parse fractional seconds in MDTM responses