常见操作对文件和目录时间戳的影响

hacking skills
作者

zenggyu

发布于

2022-06-04

摘要
介绍常见操作对文件和目录时间戳的影响。

摘要

计算机文件系统一般会为存储于其上的文件和目录记录四个时间戳(有的文件系统可能不支持某些时间戳),包括:

  • 创建时间(birth/create time)
  • 访问时间(access time)
  • 更改时间(modify time)
  • 改动时间(change time)

需要特别说明的是,“更改时间”和“改动时间”的名称相近、容易被混淆,但前者是指文件或目录中所存储的数据发生变化的时间,而后者则指与文件或目录对应的元数据(例如文件名、文件权限、时间戳等)发生变化的时间。

了解上述时间戳的含义、以及常见操作(例如文件或目录的读、写等)对上述时间戳的影响将有助于掌握文件/目录的状态及变化,或指导有关命令的使用等(见本文附录部分)。本文将通过简单的实验,了解不同文件系统上的常见操作对上述时间戳的影响;具体而言,实验将针对EXT4和NTFS两种文件系统展开,它们分别是Linux和Windows系统中最常用的文件系统。

实验设置

实验将在Ubuntu 22.04上进行,其中的stat命令可以用于获取文件或目录的所有时间戳信息;为了更方便地查询和显示时间戳,可以先修改一下该命令的输出格式:

alias stat='stat --printf="创建时间: %w\n访问时间: %x\n更改时间: %y\n改动时间: %z\n"'

实验命令分为两大部分,所针对的对象分别是文件和目录(假设所涉及的文件为file1file2,所涉及的目录为dir1dir2)。这些命令将对前述对象进行常见的操作,并查询操作完成后的各项时间戳结果;为了方便分析时间戳变化情况,每项操作之间设置1秒的间隔。

第一部分命令如下所示,所针对的对象是文件

if [[ -e file1 ]]; then rm file1; fi # 如果文件已存在,则删除
if [[ -e file2 ]]; then rm file2; fi # 如果文件已存在,则删除

printf '\n=== 创建文件 ===\n'
echo ${RANDOM} > file1 && stat file1 && sleep 1

printf '\n=== 访问文件 ===\n'
cat file1 > /dev/null && stat file1 && sleep 1

printf '\n=== 更改文件 ===\n'
echo ${RANDOM} > file1 && stat file1 && sleep 1

printf '\n=== 变更文件名称 ===\n'
mv file1 file2 && stat file2 && sleep 1

printf '\n=== 变更文件权限 ===\n'
chmod a+rwx file2 && stat file2 && sleep 1

第二部分命令如下所示,所针对的对象是目录

if [[ -e dir1 ]]; then rm -r dir1; fi # 如果目录已存在,则删除
if [[ -e dir2 ]]; then rm -r dir2; fi # 如果目录已存在,则删除

printf '\n=== 创建目录 ===\n'
mkdir dir1 && stat dir1 && sleep 1

printf '\n=== 改动目录名称 ===\n'
mv dir1 dir2 && stat dir2 && sleep 1

printf '\n=== 改动目录权限 ===\n'
chmod a+rwx dir2 && stat dir2 && sleep 1

printf '\n=== 在目录内创建文件 ===\n'
echo ${RANDOM} > dir2/file1 && stat dir2 && sleep 1

printf '\n=== 访问目录内的文件 ===\n'
cat dir2/file1 > /dev/null && stat dir2 && sleep 1

printf '\n=== 更改目录内的文件 ===\n'
echo ${RANDOM} > dir2/file1 && stat dir2 && sleep 1

printf '\n=== 变更目录内的文件名称 ===\n'
mv dir2/file1 dir2/file2 && stat dir2 && sleep 1

printf '\n=== 变更目录内的文件权限 ===\n'
chmod a+rwx dir2/file2 && stat dir2 && sleep 1

printf '\n=== 删除目录内的文件 ===\n'
rm dir2/file2 && stat dir2 && sleep 1

接下来,我们将分别在EXT4和NTFS两个文件系统上选择任意路径执行上述命令,然后查看和分析所返回的时间戳及其变化情况。

结果

通过查看实验输出的原始数据(见本文附录),可以整理出 图 1

图 1: 常见操作对不同类型时间戳的影响

这里特别提一下EXT4和NTFS两个文件系统之间的差异,以及一些实验并未涉及到的要点:

  • EXT4文件系统能记录文件/目录的创建时间,且该时间只受创建操作影响,而NTFS文件系统则不记录该时间;另外:
    • 当把文件/目录从EXT4文件系统移动到NTFS文件系统时,其改动时间会更新、而创建时间会丢失;
    • 当把文件/目录从NTFS文件系统移动到EXT4文件系统时,其改动时间会更新、而创建时间会重新生成且与改动时间一致;
  • 改动文件/目录的权限会影响EXT4文件系统上的改动时间,但不会影响NTFS系统上的改动时间(这是因为后者并不记录文件/目录的权限信息);
  • 在目录中对子文件或子目录进行的各项操作,对前者时间戳所造成的影响是相同的;
  • 文件/目录复制操作对各类时间戳的影响等同于创建操作的影响;
  • 文件/目录移动操作对各类时间戳的影响等同于重命名操作的影响。

附录:时间戳与find命令

find命令可以用来查找时间戳满足特定条件的文件/目录;与时间戳相关的主要参数和用法如下:

  • 创建时间(B):
    • -newerBt "yyyy-mm-dd HH:MM:SS"
  • 访问时间(a):
    • -newerat "yyyy-mm-dd HH:MM:SS"
    • -amin n
  • 更改时间(m):
    • -newermt "yyyy-mm-dd HH:MM:SS"
    • -mmin n
  • 改动时间(c):
    • -newerct "yyyy-mm-dd HH:MM:SS"
    • -cmin n

上述参数的意义如下:

  • -newer*t "yyyy-mm-dd HH:MM:SS" 代表特定时间戳须大于所指定的时间yyyy-mm-dd HH:MM:SS
  • -*min n代表当前时间与文件/目录的特定时间戳之差须恰好处于区间[n-1, n)内(单位:分钟);
  • -*min n中的参数值n前面添加前缀+,代表当前时间与文件/目录的特定时间戳之差须位于区间[n, +∞)内(单位:分钟);
  • -*min n中的参数值n前面添加前缀-,代表当前时间与文件/目录的特定时间戳之差须位于区间[0, n)内(单位:分钟)。

-mmin为例,假设当前时间是2022-06-04 00:00:00,那么:

  • find . -mmin 10可以找到的文件满足:2022-06-03 23:50:00< 更改时间 ≤ 2022-06-03 23:51:00
  • find . -mmin +10可以找到的文件满足:更改时间 ≤ 2022-06-03 23:50:00
  • find . -mmin -10可以找到的文件满足:更改时间 > 2022-06-03 23:50:00

附录:时间戳与touch命令

touch命令可以用来修改文件/目录的某些时间戳;一些要点:

  • touch命令无法修改文件/目录的创建时间;
  • touch命令总是会将文件/目录的改动时间更新为当前时间;
  • touch命令在默认情况下会同时修改访问时间、更改时间和改动时间,并且以当前时间作为修改值;
  • --date="yyyy-mm-dd HH:MM:SS[.SSSSSSS]"参数(例如--date="2022-06-04 00:00:00.0000000")可以指定任意时间(而非当前时间)作为修改值(改动时间的变化不受该参数影响);
  • --time=atime参数可以将修改对象限定为访问时间(改动时间的变化不受该参数影响);
  • --time=mtime参数可以将修改对象限定为更改时间(改动时间的变化不受该参数影响)。

附录:实验原始数据

在EXT4文件系统上执行第一部分命令所返回的结果如下所示:

=== 创建文件 ===
创建时间: 2022-06-04 19:39:55.333521030 +0800
访问时间: 2022-06-04 19:39:55.333521030 +0800
更改时间: 2022-06-04 19:39:55.333521030 +0800
改动时间: 2022-06-04 19:39:55.333521030 +0800

=== 访问文件 ===
创建时间: 2022-06-04 19:39:55.333521030 +0800
访问时间: 2022-06-04 19:39:56.341508657 +0800
更改时间: 2022-06-04 19:39:55.333521030 +0800
改动时间: 2022-06-04 19:39:55.333521030 +0800

=== 更改文件 ===
创建时间: 2022-06-04 19:39:55.333521030 +0800
访问时间: 2022-06-04 19:39:56.341508657 +0800
更改时间: 2022-06-04 19:39:57.349496344 +0800
改动时间: 2022-06-04 19:39:57.349496344 +0800

=== 变更文件名称 ===
创建时间: 2022-06-04 19:39:55.333521030 +0800
访问时间: 2022-06-04 19:39:56.341508657 +0800
更改时间: 2022-06-04 19:39:57.349496344 +0800
改动时间: 2022-06-04 19:39:58.361484032 +0800

=== 变更文件权限 ===
创建时间: 2022-06-04 19:39:55.333521030 +0800
访问时间: 2022-06-04 19:39:56.341508657 +0800
更改时间: 2022-06-04 19:39:57.349496344 +0800
改动时间: 2022-06-04 19:39:59.369471825 +0800

在EXT4文件系统上执行第二部分命令所返回的结果如下所示:

=== 创建目录 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:35.289072605 +0800
改动时间: 2022-06-04 19:40:35.289072605 +0800

=== 改动目录名称 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:35.289072605 +0800
改动时间: 2022-06-04 19:40:36.297062381 +0800

=== 改动目录权限 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:35.289072605 +0800
改动时间: 2022-06-04 19:40:37.309052164 +0800

=== 在目录内创建文件 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:38.317042043 +0800
改动时间: 2022-06-04 19:40:38.317042043 +0800

=== 访问目录内的文件 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:38.317042043 +0800
改动时间: 2022-06-04 19:40:38.317042043 +0800

=== 更改目录内的文件 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:38.317042043 +0800
改动时间: 2022-06-04 19:40:38.317042043 +0800

=== 变更目录内的文件名称 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:41.341011984 +0800
改动时间: 2022-06-04 19:40:41.341011984 +0800

=== 变更目录内的文件权限 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:41.341011984 +0800
改动时间: 2022-06-04 19:40:41.341011984 +0800

=== 删除目录内的文件 ===
创建时间: 2022-06-04 19:40:35.289072605 +0800
访问时间: 2022-06-04 19:40:35.289072605 +0800
更改时间: 2022-06-04 19:40:43.356992204 +0800
改动时间: 2022-06-04 19:40:43.356992204 +0800

在NTFS文件系统上执行第一部分命令所返回的结果如下所示:

=== 创建文件 ===
创建时间: -
访问时间: 2022-06-04 19:43:08.877972600 +0800
更改时间: 2022-06-04 19:43:08.878376100 +0800
改动时间: 2022-06-04 19:43:08.878376100 +0800

=== 访问文件 ===
创建时间: -
访问时间: 2022-06-04 19:43:09.888572000 +0800
更改时间: 2022-06-04 19:43:08.878376100 +0800
改动时间: 2022-06-04 19:43:08.878376100 +0800

=== 更改文件 ===
创建时间: -
访问时间: 2022-06-04 19:43:09.888572000 +0800
更改时间: 2022-06-04 19:43:10.896982500 +0800
改动时间: 2022-06-04 19:43:10.896982500 +0800

=== 变更文件名称 ===
创建时间: -
访问时间: 2022-06-04 19:43:09.888572000 +0800
更改时间: 2022-06-04 19:43:10.896982500 +0800
改动时间: 2022-06-04 19:43:11.908138800 +0800

=== 变更文件权限 ===
创建时间: -
访问时间: 2022-06-04 19:43:09.888572000 +0800
更改时间: 2022-06-04 19:43:10.896982500 +0800
改动时间: 2022-06-04 19:43:11.908138800 +0800

在NTFS文件系统上执行第二部分命令所返回的结果如下所示:

=== 创建目录 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:45.218992200 +0800
改动时间: 2022-06-04 19:43:45.218992200 +0800

=== 改动目录名称 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:45.218992200 +0800
改动时间: 2022-06-04 19:43:46.230585300 +0800

=== 改动目录权限 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:45.218992200 +0800
改动时间: 2022-06-04 19:43:46.230585300 +0800

=== 在目录内创建文件 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:48.248456300 +0800
改动时间: 2022-06-04 19:43:48.248456300 +0800

=== 访问目录内的文件 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:48.248456300 +0800
改动时间: 2022-06-04 19:43:48.248456300 +0800

=== 更改目录内的文件 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:48.248456300 +0800
改动时间: 2022-06-04 19:43:48.248456300 +0800

=== 变更目录内的文件名称 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:51.279710000 +0800
改动时间: 2022-06-04 19:43:51.279710000 +0800

=== 变更目录内的文件权限 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:51.279710000 +0800
改动时间: 2022-06-04 19:43:51.279710000 +0800

=== 删除目录内的文件 ===
创建时间: -
访问时间: 2022-06-04 19:43:45.218992200 +0800
更改时间: 2022-06-04 19:43:53.293592700 +0800
改动时间: 2022-06-04 19:43:53.293592700 +0800