Index | Thread | Search

From:
Benjamin Lee McQueen <mcq@disroot.org>
Subject:
Re: ftp(1): parse fractional seconds in MDTM responses
To:
Stuart Henderson <stu@spacehopper.org>, Phillip Guenther <guenther@gmail.com>
Cc:
obsd-tech <tech@openbsd.org>
Date:
Thu, 12 Feb 2026 17:30:31 -0600

Download raw body.

Thread
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?

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:


--- util.c.orig	Thu Feb 12 17:02:44 2026
+++ util.c	Thu Feb 12 17:03:59 2026
@@ -602,16 +602,16 @@
  /*
   * 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;
+	result.tv_nsec = 0;
  #ifndef SMALL
  	if (!debug)
  #endif /* !SMALL */
@@ -619,12 +619,14 @@
  	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,38 @@
  		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;
+
+		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);
  }

  /*
--- cmds.c.orig	Thu Feb 12 17:09:54 2026
+++ cmds.c	Wed Feb 11 18:57:19 2026
@@ -1594,7 +1594,7 @@
  		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	Thu Feb 12 17:13:56 2026
+++ ftp.c	Wed Feb 11 18:56:48 2026
@@ -1204,7 +1204,7 @@
  		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	Thu Feb 12 17:16:29 2026
+++ small.c	Wed Feb 11 18:56:17 2026
@@ -269,7 +269,7 @@
  			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	Thu Feb 12 17:17:11 2026
+++ extern.h	Wed Feb 11 19:42:14 2026
@@ -101,7 +101,7 @@
  	    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 **);

  :wq ben