diff is full of spaces which should be tabs.
On 2026/02/22 22:07, Benjamin Lee McQueen wrote:
> hello,
>
> i updated the patch, to actually show the parsed fractional seconds.
>
> here is the format it will show in (timestamp not date)
>
> 06:00:00.PARSED_FRACTIONAL_SECONDS
>
> here is the diff:
>
> Index: cmds.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/ftp/cmds.c,v
> diff -u -p -u -p -r1.85 cmds.c
> --- cmds.c 8 Mar 2023 04:43:11 -0000 1.85
> +++ cmds.c 18 Feb 2026 22:48:04 -0000
> @@ -1587,19 +1587,39 @@ sizecmd(int argc, char *argv[])
> void
> modtime(int argc, char *argv[])
> {
> - time_t mtime;
> -
> + struct timespec mtime;
> if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
> fprintf(ttyout, "usage: %s file\n", argv[0]);
> code = -1;
> return;
> }
> - mtime = remotemodtime(argv[1], 1);
> - if (mtime != -1)
> - fprintf(ttyout, "%s\t%s", argv[1],
> asctime(localtime(&mtime)));
> - code = mtime;
> -}
> + mtime = remotemodtime(argv[1], 1);
> + if (mtime.tv_sec != -1) {
> + char timebuf[64];
> + struct tm *tm;
> +
> + tm = localtime(&mtime.tv_sec);
> + strftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", tm);
>
> + if (mtime.tv_nsec == 0) {
> + fprintf(ttyout, "%s\t%s %d\n", argv[1], timebuf,
> + tm->tm_year + 1900);
> + } else {
> + char nsbuf[16];
> + char *end;
> +
> + snprintf(nsbuf, sizeof(nsbuf), "%09ld",
> mtime.tv_nsec);
> + end = nsbuf + strlen(nsbuf) - 1;
> + while (end > nsbuf && *end == '0')
> + end--;
> + *(end + 1) = '\0';
> + fprintf(ttyout, "%s\t%s.%s %d\n", argv[1],
> timebuf,
> + nsbuf, tm->tm_year + 1900);
> + }
> +
> + }
> + code = mtime.tv_sec;
> +}
> /*
> * Show status on remote machine
> */
> Index: extern.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/ftp/extern.h,v
> diff -u -p -u -p -r1.54 extern.h
> --- extern.h 21 May 2024 05:00:48 -0000 1.54
> +++ extern.h 18 Feb 2026 22:48:04 -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 -u -p -r1.109 ftp.c
> --- ftp.c 8 Mar 2023 04:43:11 -0000 1.109
> +++ ftp.c 18 Feb 2026 22:48:04 -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 -u -p -r1.13 small.c
> --- small.c 8 Mar 2023 04:43:11 -0000 1.13
> +++ small.c 18 Feb 2026 22:48:04 -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 -u -p -r1.99 util.c
> --- util.c 21 Dec 2025 07:29:03 -0000 1.99
> +++ util.c 18 Feb 2026 22:48:04 -0000
> @@ -602,29 +602,32 @@ 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;
> + overbose = verbose;
> + ocode = code;
> + rtime.tv_sec = -1;
> + rtime.tv_nsec = 0;
> #ifndef SMALL
> if (!debug)
> #endif /* !SMALL */
> verbose = -1;
> if (command("MDTM %s", file) == COMPLETE) {
> - struct tm timebuf;
> - int yy, mo, day, hour, min, sec;
> + fprintf(ttyout, "DEBUG: reply_string = '%s'\n",
> reply_string);
> + 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 +652,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,11 +695,10 @@ remotemodtime(const char *file, int nois
> fputc('\n', ttyout);
> }
> verbose = overbose;
> - if (rtime == -1)
> + if (rtime.tv_sec == -1)
> code = ocode;
> return (rtime);
> }
> -
> /*
> * Ensure file is in or under dir.
> * Returns 1 if so, 0 if not (or an error occurred).
>
> :wq ben
>
> i also attached it if the formatting gets messed up.
>
> although i still haven't tested on ramdisks
>
> -ben
> ? cmds.d
> ? cmdtab.d
> ? complete.d
> ? cookie.d
> ? domacro.d
> ? fetch.d
> ? ftp
> ? ftp.d
> ? list.d
> ? main.d
> ? ruserpass.d
> ? small.d
> ? stringlist.d
> ? util.d
> Index: cmds.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/ftp/cmds.c,v
> diff -u -p -u -p -r1.85 cmds.c
> --- cmds.c 8 Mar 2023 04:43:11 -0000 1.85
> +++ cmds.c 18 Feb 2026 22:48:04 -0000
> @@ -1587,19 +1587,39 @@ sizecmd(int argc, char *argv[])
> void
> modtime(int argc, char *argv[])
> {
> - time_t mtime;
> -
> + struct timespec mtime;
> if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
> fprintf(ttyout, "usage: %s file\n", argv[0]);
> code = -1;
> return;
> }
> - mtime = remotemodtime(argv[1], 1);
> - if (mtime != -1)
> - fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
> - code = mtime;
> -}
> + mtime = remotemodtime(argv[1], 1);
> + if (mtime.tv_sec != -1) {
> + char timebuf[64];
> + struct tm *tm;
> +
> + tm = localtime(&mtime.tv_sec);
> + strftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", tm);
>
> + if (mtime.tv_nsec == 0) {
> + fprintf(ttyout, "%s\t%s %d\n", argv[1], timebuf,
> + tm->tm_year + 1900);
> + } else {
> + char nsbuf[16];
> + char *end;
> +
> + snprintf(nsbuf, sizeof(nsbuf), "%09ld",
> mtime.tv_nsec);
> + end = nsbuf + strlen(nsbuf) - 1;
> + while (end > nsbuf && *end == '0')
> + end--;
> + *(end + 1) = '\0';
> + fprintf(ttyout, "%s\t%s.%s %d\n", argv[1],
> timebuf,
> + nsbuf, tm->tm_year + 1900);
> + }
> +
> + }
> + code = mtime.tv_sec;
> +}
> /*
> * Show status on remote machine
> */
> Index: extern.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/ftp/extern.h,v
> diff -u -p -u -p -r1.54 extern.h
> --- extern.h 21 May 2024 05:00:48 -0000 1.54
> +++ extern.h 18 Feb 2026 22:48:04 -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 -u -p -r1.109 ftp.c
> --- ftp.c 8 Mar 2023 04:43:11 -0000 1.109
> +++ ftp.c 18 Feb 2026 22:48:04 -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 -u -p -r1.13 small.c
> --- small.c 8 Mar 2023 04:43:11 -0000 1.13
> +++ small.c 18 Feb 2026 22:48:04 -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 -u -p -r1.99 util.c
> --- util.c 21 Dec 2025 07:29:03 -0000 1.99
> +++ util.c 18 Feb 2026 22:48:04 -0000
> @@ -602,29 +602,32 @@ 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;
> + overbose = verbose;
> + ocode = code;
> + rtime.tv_sec = -1;
> + rtime.tv_nsec = 0;
> #ifndef SMALL
> if (!debug)
> #endif /* !SMALL */
> verbose = -1;
> if (command("MDTM %s", file) == COMPLETE) {
> - struct tm timebuf;
> - int yy, mo, day, hour, min, sec;
> + fprintf(ttyout, "DEBUG: reply_string = '%s'\n",
> reply_string);
> + 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 +652,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,11 +695,10 @@ remotemodtime(const char *file, int nois
> fputc('\n', ttyout);
> }
> verbose = overbose;
> - if (rtime == -1)
> + if (rtime.tv_sec == -1)
> code = ocode;
> return (rtime);
> }
> -
> /*
> * Ensure file is in or under dir.
> * Returns 1 if so, 0 if not (or an error occurred).