/*
 * about sub-second timestamp on FFS
 *  FreeBSD/FFS での timestamp の秒以下分について
 *   by uratan! 2023.5.27
 *    revised: 2023.12.10
 */

各ファイルの timestamp の秒以下分なんですが、 今時はさすがに管理保持しているんだろうなぁとの感触はあるのですが、 man ls にも stat にも strftime にも記述がない、ググっても拾えない…。
というわけで、今回ようやっと自分の手で確認してみました。
以下、FreeBSD 10.2-RELEASE(i386) にての実験的評価結果です、 古くてすいません。

ソースコード調査その1 - stat system-call side

stat system-call の扱う構造体には timestamp の nsec を保持する領域はあるみたい。

/usr/include/sys/stat.h
struct stat {
	 :
	struct	timespec st_atim;	/* time of last access */
	struct	timespec st_mtim;	/* time of last data modification */
	struct	timespec st_ctim;	/* time of last file status change */
	 :
}

/usr/include/sys/_timespec.h
struct timespec {
	time_t	tv_sec;		/* seconds */
	long	tv_nsec;	/* and nanoseconds */
};

ソースコード調査その2 - ls side

ls コマンドでは、-t での新旧ソートでは 秒以下分も比較対象にしているみたいだけれど、

% cd /usr/src/bin/ls/
% fgrep -e tv_sec -e tv_nsec *.[ch]
cmp.c:  if (b->fts_statp->st_mtim.tv_sec >
cmp.c:      a->fts_statp->st_mtim.tv_sec)
cmp.c:  if (b->fts_statp->st_mtim.tv_sec <
cmp.c:      a->fts_statp->st_mtim.tv_sec)
cmp.c:  if (b->fts_statp->st_mtim.tv_nsec >
cmp.c:      a->fts_statp->st_mtim.tv_nsec)
cmp.c:  if (b->fts_statp->st_mtim.tv_nsec <
cmp.c:      a->fts_statp->st_mtim.tv_nsec)
cmp.c:  if (b->fts_statp->st_atim.tv_sec >
...

秒以下分を表示するという処理はいっさい無いよう。

/usr/src/bin/ls/print.c
		 :
		if (f_accesstime)
			printtime(sp->st_atime);
		else if (f_birthtime)
			printtime(sp->st_birthtime);
		else if (f_statustime)
			printtime(sp->st_ctime);
		else
			printtime(sp->st_mtime);
		 :

static void
printtime(time_t ftime)
{
	 :
	strftime(longstring, sizeof(longstring), format, localtime(&ftime));
	fputs(longstring, stdout);
	fputc(' ', stdout);
}

そもそも sys/stat.h には、 秒単位だけ扱う(従来)プログラムのための(後方互換用)マクロまで 用意されているのね。(末尾の'e'有り無しか…、わかりにくい…)

/usr/include/sys/stat.h
#define	st_atime		st_atim.tv_sec
#define	st_mtime		st_mtim.tv_sec
#define	st_ctime		st_ctim.tv_sec

改造 ls で秒以下 timestamp を可視化する

/bin/ls を改造し 秒以下 timestamp も表示するツールを用意します。
オプションは -l (long format) 固定とし、 表示フォーマットは 秒以下 timestamp がつながるように 強制してます。使用例は以下の通り。

/home/uratan/eva % ./my-ls/ls    ss-ts.html
-rw-r--r--  1 uratan  zinc  7028 2023-0527 13:11.28 ss-ts.html

/home/uratan/eva % ./my-ls/ls -l ss-ts.html
-rw-r--r--  1 uratan  zinc  7028 2023-0527 13:11.28,510433000 ss-ts.html

修正差分はこんな感じで my-ls-patch.txt     (ソースコードは /usr/src/bin/ls/ から)

各種コマンドの対応状況の検証

(【注】以下 実行例ですが不要行は少々削ってあります) サンプルが少ないですが、nsec 表示の下3桁は常時ゼロのようなので 分解能はμsec単位程度のようですね。 touch の結果からも 6桁に制限しているくさいので、常用するなら 6桁表示で十分な感じかな。

以上、とりあえず納得!

- * - * -

[2023.12.10 追記]
FreeBSD 14.0-RELEASE(i386) では /usr/local/bin/rsync だけ 秒以下分まで保持されるよう対応してました。 (タイムスタンプ比較も秒以下でさせるなら --modify-window=NUM, -@ の指定が必要)
また ファイル生成で μsec 単位までなのは 10.2R と同様のようですが、 /usr/bin/touch -d は 1nsec まで 9桁フルに扱えるようになってました。
あと上の 10.2R のテストで漏れてましたけど、ftp も秒以下分は保持しないですね。

    uratan@miomio.jp
upward