From: Benjamin Lee McQueen Subject: Re: ftp(1): parse fractional seconds in MDTM responses To: Philip Guenther Cc: Tech Date: Thu, 12 Feb 2026 19:23:11 +0100 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