使用“rsync”命令时为什么要使用“--modify-window=1”?

使用“rsync”命令时为什么要使用“--modify-window=1”?

根据微软,

当文件从 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 的格式为fdiskmkfs -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 --updatecp --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

相关内容