Index | Thread | Search

From:
Benjamin Lee McQueen <mcq@disroot.org>
Subject:
Re: ftp(1): parse fractional seconds in MDTM responses
To:
Philip Guenther <guenther@gmail.com>
Cc:
Tech <tech@openbsd.org>
Date:
Thu, 12 Feb 2026 19:23:11 +0100

Download raw body.

Thread
On 2026-02-12 05:43, Philip Guenther wrote:

This doesn't correctly handle more than 9 digits after the decimal 
point.

Using strtol() should be avoided since supporting a "timestamp" of
"20260212044126.   -34" is not useful.
ok.
the new diff uses manual parsing.
also, i can't test the code and I had to generate the diff
in a github codespace on my phone.

--- util.c      2026-02-12 17:23:52.915431814 +0000
+++ utility.c   2026-02-12 18:06:29.259810577 +0000
@@ -602,16 +602,15 @@
  /*
   * 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 result;
+       int ocode, overbose;
+
         overbose = verbose;
         ocode = code;
-       rtime = -1;
+       result.tv_sec = -1;
  #ifndef SMALL
         if (!debug)
  #endif /* !SMALL */
@@ -619,14 +618,15 @@
         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 */
                 while (!isspace((unsigned char)*timestr))
                         timestr++;
@@ -649,15 +649,40 @@
                 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;
+                               if (nsec < 0 || nsec >= 1000000000L) /* 
Do I need this? */
+                                       nsec = 0;
+                       }
+       } 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 +692,9 @@
                 fputc('\n', ttyout);
         }
         verbose = overbose;
-       if (rtime == -1)
+       if (result.tv_sec == -1)
                 code = ocode;
-       return (rtime);
+       return (result);
  }

  /*

is this in the right direction?

my bad if the formatting is off