备份和恢复文件/目录的时间戳?

备份和恢复文件/目录的时间戳?

我们需要备份文件和目录的a/c/mtime-stamps,并且能够在必要时恢复它们。

备份命令的示例可以是:

$ timestamp backup --all-stamps --incl-dir-stamps --recursive out.stampbak file.bin /dir/with/files/

恢复可能是:

$ timestamp restore --all-stamps out.stampbak

是否存在这样的命令来实现我正在寻找的结果?尽管我相信大多数文件系统都停留在纳秒级,但纳秒级精度是首选,或者其他更精细的精度。 POSIX 合规性也很重要,因为我们需要 BSD 和 GNU/Linux 系统上的时间戳进行备份/恢复。


编辑:为了澄清一些事情,我列出的文件系统在很大程度上保留了文件目前直到我最终可以将它们移动到主 ZFS 服务器。这就是让我们考虑保留时间戳的可能性的原因将数据迁移到 ZFS。万一邮票在传输过程中发生变化(我们使用 HTTP、FTP、SMB 等多种方法),我们希望确保它们可以恢复到应有的状态。即使在传输后,将时间戳保留为小型备份也是有益的,因此无论文件最终将存储在 ZFS 上,问题仍然是仅支持/恢复时间戳。备份中可以省略权限和组信息。

用于备份时间戳的操作系统包括 macOS Mojave 10.14.6、Ubuntu Server 18.04.5 LTS、Debian 10.2/7.8、FreeBSD 12.2 和 CentOS 8。恢复将主要在 FreeBSD(ZFS 服务器主机)上进行,我认为其他任何地方都不需要。如果有帮助的话,我有几个驱动器,其中的文件位于 NTFS 分区上。是否需要运行一个小型 Windows 实例来正确备份这些时间戳?

此外,我的印象是大多数文件系统都使用 atime、ctime 和 mtime,而不使用其他文件系统(我认为这最终在文件系统之间有所不同)。我的目标是如果可能的话,保存并恢复所有这些。

我提到了 POSIX 合规性,因为该工具可以在任一平台上使用——如果我之前的描述不正确或不充分,我深表歉意。我还以为 ctime = 创建/出生时间,我现在看到它是更改时间。

最需要保留的时间戳是创建/出生时间和修改时间。访问时间也很好,更改时间是最不重要的,但仍然有帮助。再次,我为这个错误道歉,我仍在学习。


编辑2:本文我学到了这个:

  • 大多数文件系统中没有保留文件创建时间戳 - 这意味着您无法运行“显示在特定日期创建的所有文件”之类的命令。这就是说,通常可以从 ctime 和 mtime 推断出相同的结果(如果它们匹配 - 这可能意味着文件的创建时间)。

  • 创建新文件或目录时,通常将所有三个时间(atime、ctime 和 mtime)配置为捕获当前时间。

由于目标文件系统将是 ZFS,其中将恢复文件/目录的时间戳,因此最好至少保存 atime、ctime、mtime,以防保存时间戳的文件系统不存储出生时间。

答案1

如果你有 GNU find 和 Perl 可用,你可以用它们来组装一些东西。-printfto 的动作可以find打印时间戳,Perl 有utime修改时间戳的功能。或者两种,一种是内置的,另一种是 Time::HiRes 模块中的,后者支持亚秒级精度。

一些用于测试的文件:

$ find . -printf '%A@ %T@ %p\n'
1631866504.4180281370 1631866763.5380257720 .
1631866763.5380257720 1631866768.2101700800 ./dir
1631866768.2101700800 1631866768.2101700800 ./dir/bar.txt
1631866760.2619245850 1631866760.2619245850 ./foo.txt

将时间戳保存到文件中:

$ find . -printf '%A@ %T@ %p\0' > ../times

让我们丢弃时间戳:

$ touch -d 1999-01-01 **/*
$ find . -printf '%A@ %T@ %p\n'
1631866771.6022748540 1631866763.5380257720 .
915141600.0000000000 915141600.0000000000 ./dir
915141600.0000000000 915141600.0000000000 ./dir/bar.txt
915141600.0000000000 915141600.0000000000 ./foo.txt

并从文件中重新加载它们:

$ perl -MTime::HiRes=utime -0 -ne 'chomp; my ($atime, $mtime, $file) = split(/ /, $_, 3); utime $atime, $mtime, $file;'    < ../times
1631866771.6022748950 1631866763.5380258560 .
1631866771.6022748950 1631866768.2101700310 ./dir
1631866768.2101700310 1631866768.2101700310 ./dir/bar.txt
1631866760.2619245050 1631866760.2619245050 ./foo.txt

该文件仅包含以 NUL 结尾的字段以及 atime、mtime 和文件名,以及utime每组值的 Perl 代码片段调用。

使用 NUL 作为终止符,它应该能够处理任意文件名,但请注意,我在这里使用\n代替来\0打印输出,这不适用于该 Perl 代码片段,因为它需要 NUL,而不是换行符。

另外,我完全忽略了 ctime,因为据我所知,它无论如何都不能用utime()/设置utimensat()。对于任何出生时间戳都相同。

答案2

正如之前所讨论的,设置 和 类似的唯一方法ctime是从内核内部进行设置,而用户态接口有充分的理由不允许设置超出atime和 的时间戳mtime。如果您想保留ctimecrtime,可以使用ZFS/send和来完成ZFS/receive,但这需要双方都已经有 ZFS。

让我重复一下我相信你喜欢做的事情:

  • 将现有文件系统复制到另一个位置

  • 稍后在执行此复制或恢复不同程序时atime保留时间戳。mtime

您可以通过运行任何备份/恢复方法,然后运行另一个恢复时间戳的程序,或者运行能够正确恢复时间戳的备份/恢复方法来完成此操作。

star是一个成熟的备份工具,可以帮助您完成这两种方法。

如果您想使用star备份和恢复文件系统(包括时间戳),请查看手册页:http://schilytools.sourceforge.net/man/man1/star.1.html

如果您想单独保存和恢复时间戳,则需要在运行备份之前保存时间戳,因为备份很可能会影响atime所有文件的值。

  • 要保存目录树中所有文件的所有时间戳,只需运行:

    star -c -dump -meta f=timestamparchive.tar .
    
  • 要将所有时间戳恢复到新位置,请运行:

    star -xU -meta f=timestamparchive.tar
    

第一个命令创建的存档文件使用大约。每个文件 1.5 KB。第二个命令将从存档中已存在的所有文件中恢复所有时间戳,但不会触及文件内容。

BTW:我是《star》的作者,已经有39年了。

答案3

“ls --full-time”命令给出文件的完整时间戳,可以使用“awk”格式化并使用“date”保存到以当前时间命名的文件中:

ls --full-time | awk '{print $6"\t"$7"\t"$9}' > timestamps.output.`date +%Y-%m-%d_%k:%M:%S.%N`

这会产生类似的结果:

timestamps.output.2021-09-16_16:33:05.363928457:

2021-09-16  16:13:40.988062443  file1
2021-09-16  16:13:45.408053173  file2
2021-09-16  16:13:49.496044596  file3
2021-09-16  16:13:52.628038023  file4

这将允许您跟踪文件时间戳随时间的变化。当然,您可以根据自己的喜好设置时间戳的格式。

您还可以使用“git”存储库来跟踪 timestamp.output 文件随时间的变化。

相关内容