根据微软,
当文件从 NTFS 驱动器复制到 FAT 驱动器时,必须进行一些文件时间戳舍入;文件时间戳四舍五入到下一个偶数秒。
(剪断)
NTFS 时间戳:7 小时 31 分 0 秒 001。
FAT 时间戳变为 7 小时 31 分 2 秒 000。
然而,man rsync
说
--修改窗口
比较两个时间戳时,如果它们的差异不超过修改窗口值,则 rsync 会将时间戳视为相等。通常为 0(用于精确匹配),但您可能会发现在某些情况下将其设置为更大的值很有用。特别是,当与 MS Windows FAT 文件系统(表示时间分辨率为 2 秒)之间传输时,--modify-window=1 非常有用(允许时间最多相差 1 秒)。
我认为--modify-window=2
这是正确的选择,因为不是执行“舍入”而是执行“天花板”。谁能告诉我我是否正确?
相关或不相关信息:
在我的环境中,FAT32 USB 中文件的 mtime 分辨率为 1 秒,并且“地板”已完成,但我不知道原因。 USB 的格式为fdisk
和mkfs -t fat -F 32
。文件从 Linux Mint 传输到 Volumio。我使用 . 检查时间戳date -r +%s.%N
。
补充:
我又找到了一个信息。rsync的可靠邮件线程说
时间戳永远是 vfat 上的一个问题。它的分辨率为 1 或 2 秒,因此 --modify-window=2 是常见的解决方案。
但这man rsync
与 StackExchange 上有许多推荐的公认答案相矛盾--modify-window=1
。现在我很困惑。
答案1
为了避免对“modify_window”的工作方式产生任何混淆,它会在任一方向进行检查。 (如果您想在源代码中阅读此内容,请检查 util.c :: cmp_time()。)
这意味着,
- 如果 A 比 B 新,则检查 A 是否仍比 B + update_window 新。
- 如果 B 比 A 更新,它会检查 B 是否仍然比 A + modify_window 更新。
假设原始 A 的时间为 123,但您的备份文件系统很糟糕,因此副本 B 最终的时间为 122(使 A 比 B 更新)或时间 124(使 B 比 A 更新)。
当modify_window = 1 时会发生什么?
- 如果 A (123) 比 B (122) 新,则检查 A (123) 是否仍比 B (122+1 = 123) 新。
- 如果 B (124) 比 A (123) 新,则检查 B (124) 是否仍比 A (123+1 = 124) 新。
在这两种情况下,结果是相同的,因此,modify_window = 1 足以使时间在任一方向上偏差一秒。
根据 rsync 手册页,这对于 FAT32 来说应该足够好了。
根据你引用的文档(将122变成124,到底是什么),这还不够好。
所以这个还没有定论。
通过实验,在 Linux 中使用 NTFS(-3g) 和 FAT32,modify_window = 1 似乎工作正常。
我的测试设置是这样的:
truncate -s 100M ntfs.img fat32.img
mkfs.ntfs -F ntfs.img
mkfs.vfat -F 32 fat32.img
mount -o loop ntfs.img /tmp/ntfs/
mount -o loop fat32.img /tmp/fat32/
因此,100M NTFS/FAT32 文件系统。
创建一千个具有各种时间戳的文件:
cd /tmp/ntfs
for f in {000..999}
do
sleep 0.0$RANDOM # widens the timestamp range
touch "$f"
done
例如:
# stat --format=%n:%y 111 222 333
111:2018-08-10 20:19:10.011984300 +0200
222:2018-08-10 20:19:13.553878700 +0200
333:2018-08-10 20:19:17.765753000 +0200
根据你的说法,20:19:10.011
应该出现为2018-08-10 20:19:12.000
.
那么让我们看看会发生什么。首先,将所有这些文件复制到 FAT32。
# rsync -a /tmp/ntfs/ /tmp/fat32/
然后我注意到时间戳实际上是准确的,直到您卸载并重新安装:
# umount /tmp/fat32
# mount -o loop fat32.img /tmp/fat32
比较:
# stat --format=%n:%y /tmp/{ntfs,fat32}/{111,222,333}
/tmp/ntfs/ 111:2018-08-10 20:19:10.011984300 +0200
/tmp/fat32/ 111:2018-08-10 20:19:10.000000000 +0200
/tmp/ntfs/ 222:2018-08-10 20:19:13.553878700 +0200
/tmp/fat32/ 222:2018-08-10 20:19:12.000000000 +0200
/tmp/ntfs/ 333:2018-08-10 20:19:17.765753000 +0200
/tmp/fat32/ 333:2018-08-10 20:19:16.000000000 +0200
所以这看起来就像是让我感到震惊。我不知道 Windows 是否会以同样的方式执行此操作,但这就是使用 Linux 和 rsync 时发生的情况。
再次复制时 rsync 会做什么:
# rsync -av --dry-run /tmp/ntfs/ /tmp/fat32
sending incremental file list
./
000
001
002
035
036
...
963
964
997
998
999
因此列表中存在一些空白,但总的来说,它会重新复制相当多的文件。
使用 时--modify-window=1
,列表为空:
# rsync -av --dry-run --modify-window=1 /tmp/ntfs/ /tmp/fat32/
sending incremental file list
./
因此,至少对于 Linux,手册页是准确的。偏移量似乎永远不会大于 1。(好吧,是一加分数,但这也被忽略了。)
那么,您应该使用--modify-time=2
吗?直到你可以通过实验证明这实际上是一种可能的情况。即便如此,也很难说清楚。首先,这是一个可怕的黑客攻击,时间窗口越大,错过真正的修改的可能性就越大。
甚至--modify-time=1
已经忽略了与 FAT32 时间戳舍入方式无关的更改 - 因为它是双向的,但 FAT32 只能进行楼层,而 rsync 在复制到 FAT32 时会忽略这一点(目标文件只能是旧文件),反之亦然。从 FAT32 复制时亦然(目标文件只能是较新的文件)。
似乎不存在更好地处理这个问题的选择。
我还尝试在内核源代码中跟踪这种行为,不幸的是,注释(在 linux/fs/fat/misc.c 中)没有提供太多内容。
/*
* The epoch of FAT timestamp is 1980.
* : bits : value
* date: 0 - 4: day (1 - 31)
* date: 5 - 8: month (1 - 12)
* date: 9 - 15: year (0 - 127) from 1980
* time: 0 - 4: sec (0 - 29) 2sec counts
* time: 5 - 10: min (0 - 59)
* time: 11 - 15: hour (0 - 23)
*/
因此,根据此,FAT 时间戳使用 5 位表示秒,因此您只能得到 32 种可能的状态,其中使用了 30 种。转换是通过简单的位移位完成的。
在 fs/fat/misc.c:: fat_time_unix2fat()
/* 0~59 -> 0~29(2sec counts) */
tm.tm_sec >>= 1;
所以 0 是 0,1 是 0,2 是 1,3 是 1,4 是 2,依此类推...
在 fs/fat/misc.c:: fat_time_fat2unix()
second = (time & 0x1f) << 1;
与上述相反,它0x1f
是位掩码,仅抓取 FAT 时间的位 0-4,表示 0-29 秒。
如果这与应有的不同,我在评论中看不到任何内容。
Raymond Chen 发表了一篇有趣的文章,讲述了为什么 Windows 会费尽心思对时间进行四舍五入:https://blogs.msdn.microsoft.com/oldnewthing/20140903-00/?p=83
好的,但是为什么时间戳总是增加到最接近的两秒间隔?为什么不四舍五入到最接近的两秒间隔?这样,时间戳变化最多为一秒。
因为四舍五入到最近的间隔意味着文件可能会在时间上倒退,这会产生其自身的问题。 (因果关系可能会成为一种拖累。)
据此,Windowsxcopy
工具有一个/D
标志,表示“仅复制源文件(如果比目标文件新)”。基本上什么rsync --update
或cp --update
会做什么。
将时间向下舍入,使文件看起来像是过去 1 秒创建的(就像 Linux 中那样),会导致每次运行该命令时都重新复制文件。将时间向上舍入可以解决这个问题。
OTOH Windows 解决方案在将这些文件复制回来时也会让您同样头疼。它会复制比实际更新的文件,然后您必须小心汇总不会发生两次。
无论你做什么,它总是错误的,无法正确存储时间戳的文件系统只是一个麻烦。
答案2
上面的所有数学计算都证明,如果您的 fat32 分区舍入/截断/天花板为 1 秒,--modify-window=1
那么就是正确的答案。尽管如此:在我的 fat32 分区上,我找不到任何带有奇数秒的文件...:
ls -Rla --time-style=full-iso | grep '[13579]\.000000000 ' | wc -l
尽管:
ls -Rla --time-style=full-iso | grep '[02468]\.000000000 ' | wc -l
显示那里有很多文件。
我坚持:--modify-window=2