如何找到文件的创建时间?


64

当我阅读有关此问题的一些文章时,我需要查找文件的创建时间,所有文章都提到没有解决方案(例如Site1Site2)。

当我尝试该stat命令时,它显示为 Birth: -

那么,如何找到文件的创建时间呢?


2
请记住,不能保证文件的“创建时间”是准确的。有很多方法可以“捏造”文件上的创建日期。
托马斯·沃德

1
@ThomasWard除了对其他文件数据进行伪造之外,还有其他方法吗?
Cees Timmerman

Answers:


67

有一种方法可以知道目录的创建日期,只需执行以下步骤:

  1. 通过命令知道目录的索引节点ls -i(例如说它的X

  2. 知道目录是通过df -T /path命令保存在哪个分区上的(假设它在on上 /dev/sda1

  3. 现在使用以下命令: sudo debugfs -R 'stat <X>' /dev/sda1

您将在输出中看到:

crtime: 0x4e81cacc:966104fc -- mon Sep 27 14:38:28 2013

crtime 是文件的创建日期。

我测试了什么

  1. 在特定时间创建目录。
  2. 访问了它。
  3. 通过创建文件对其进行了修改。

  4. 我尝试了命令,它给出了确切的时间。

  5. 然后,我对其进行修改,然后再次进行测试,crtime保持不变,但是修改访问时间发生了变化。

我发布此消息,是因为我喜欢讨论以便可以更好地理解,我不知道为什么人们会说Linux不支持此功能
2014年

13
因为Linux本身没有。ext4文件系统确实具有此信息,但是内核不提供访问它的API。显然,debugfs直接从文件系统中提取它,因此它不需要使用内核的API。看这里
terdon

我测试了 它在ext4文件系统上完美运行
Fahim Babar Patel

1
好像是ext4特定的?对我而言,它不适用于XFS。
Quantum7

statx()截至2019
均受

54

@Nux为此找到了一个不错的解决方案,所有人都应该赞成。我决定编写一个小函数,可以直接运行所有函数。只需将此添加到您的 ~/.bashrc

get_crtime() {

    for target in "${@}"; do
        inode=$(stat -c '%i' "${target}")
        fs=$(df  --output=source "${target}"  | tail -1)
        crtime=$(sudo debugfs -R 'stat <'"${inode}"'>' "${fs}" 2>/dev/null | 
        grep -oP 'crtime.*--\s*\K.*')
        printf "%s\t%s\n" "${target}" "${crtime}"
    done
}

现在,您可以运行get_crtime以打印任意数量的文件或目录的创建日期:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014

请注意,创建日期是不是原始文件的创建日期,如果该文件是复印件(喜欢它与修改日期)。复制文件后,修改日期来自原始文件,但创建日期来自复制文件。(在这个问题上,这有一些误解:askubuntu.com/questions/529885/…
Jacob Vlijm 2014年

1
@JacobVlijm好吧,当然可以。那不是很明显吗?怎么会这样呢?副本是一个新文件,恰好具有与另一个文件相同的内容。顺便说一句,修改时间也会更改副本。除非您明确选择不要使用cp -p或类似方式创建副本,否则它将设置为创建副本的那一刻。
terdon

绝对可以,但是与此同时,如果不是像mod那样,那并不是不合逻辑的。日期,日期在文件中的某处,它是从日期开始存储的。我必须承认,直到我回答了链接的问题,我才知道情况并非如此。
Jacob Vlijm 2014年

只是尝试了一下,我只是在鹦鹉螺中复制了文件,修改日期保持原样(原样),m。日期早于创建日期。
Jacob Vlijm 2014年

1
@demongolem是的,CentOS版本df似乎不支持该--output选项。在这种情况下,您可以用替换该行,fs=$(df foo | awk '{a=$1}END{print a}'该功能也将正常工作。我在此答案中显示的是一种将可以直接对文件/目录目标运行的方式包装已接受答案中的命令的方法。
terdon

11

无法stat显示创建时间是由于stat(2)系统调用的限制,系统调用的返回结构未包含创建时间字段。但是,从Linux 4.11(即17.10和更高版本*)开始,可以使用新的statx(2)系统调用,该调用的返回结构中确实包含创建时间。

*并且可能在使用硬件启用堆栈(HWE)内核的较早的LTS版本中。检查uname -r是否至少在4.11上使用内核以进行确认。

不幸的是,在C程序中直接调用系统调用并不容易。通常,glibc提供了一个使工作轻松的包装器,但是glibc仅statx(2)在2018年8月添加了一个包装器(版本2.28,在18.10中可用)。幸运的是,@ whotwagner编写了一个示例C程序,该程序演示了如何statx(2)在x86和x86-64系统上使用系统调用。其输出格式与stat默认格式相同,没有任何格式设置选项,但修改它以仅打印出生时间很简单。

首先,克隆它:

git clone https://github.com/whotwagner/statx-fun

您可以编译statx.c代码,或者,如果您只想要出生时间,请birth.c使用以下代码在克隆的目录中创建一个(这是statx.c仅打印创建时间戳(包括纳秒精度)的最小版本):

#define _GNU_SOURCE
#define _ATFILE_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include "statx.h"
#include <time.h>
#include <getopt.h>
#include <string.h>

// does not (yet) provide a wrapper for the statx() system call
#include <sys/syscall.h>

/* this code works ony with x86 and x86_64 */
#if __x86_64__
#define __NR_statx 332
#else
#define __NR_statx 383
#endif

#define statx(a,b,c,d,e) syscall(__NR_statx,(a),(b),(c),(d),(e))

int main(int argc, char *argv[])
{
    int dirfd = AT_FDCWD;
    int flags = AT_SYMLINK_NOFOLLOW;
    unsigned int mask = STATX_ALL;
    struct statx stxbuf;
    long ret = 0;

    int opt = 0;

    while(( opt = getopt(argc, argv, "alfd")) != -1)
    {
        switch(opt) {
            case 'a':
                flags |= AT_NO_AUTOMOUNT;
                break;
            case 'l':
                flags &= ~AT_SYMLINK_NOFOLLOW;
                break;
            case 'f':
                flags &= ~AT_STATX_SYNC_TYPE;
                flags |= AT_STATX_FORCE_SYNC;
                break;
            case 'd':
                flags &= ~AT_STATX_SYNC_TYPE;
                flags |= AT_STATX_DONT_SYNC;
                break;
            default:
                exit(EXIT_SUCCESS);
                break;
        }
    }

    if (optind >= argc) {
        exit(EXIT_FAILURE);
    }

    for (; optind < argc; optind++) {
        memset(&stxbuf, 0xbf, sizeof(stxbuf));
        ret = statx(dirfd, argv[optind], flags, mask, &stxbuf);
        if( ret < 0)
        {
            perror("statx");
            return EXIT_FAILURE;
        }
        printf("%lld.%u\n", *&stxbuf.stx_btime.tv_sec, *&stxbuf.stx_btime.tv_nsec);
    }
    return EXIT_SUCCESS;
}

然后:

$ make birth
$ ./birth ./birth.c
1511793291.254337149
$ ./birth ./birth.c | xargs -I {} date -d @{}
Mon Nov 27 14:34:51 UTC 2017

从理论上讲,这应该使创建时间更容易访问:

  • 除了ext *之外,还应该支持更多的文件系统(这debugfs是ext2 / 3/4文件系统的工具,在其他系统上不可用)
  • 您不需要root即可使用它(除了安装某些必需的软件包,例如makelinux-libc-dev)。

测试xfs系统,例如:

$ truncate -s 1G temp; mkfs -t xfs temp; mkdir foo; sudo mount temp foo; sudo chown $USER foo
$ touch foo/bar
$ # some time later
$ echo > foo/bar
$ chmod og-w foo/bar
$ ./birth foo/bar | xargs -I {} date -d @{}
Mon Nov 27 14:43:21 UTC 2017
$ stat foo/bar                             
  File: foo/bar
  Size: 1           Blocks: 8          IO Block: 4096   regular file
Device: 700h/1792d  Inode: 99          Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/ muru)      Gid: ( 1000/ muru)
Access: 2017-11-27 14:43:32.845579010 +0000
Modify: 2017-11-27 14:44:38.809696644 +0000
Change: 2017-11-27 14:44:45.536112317 +0000
 Birth: -

但是,这不适用于NTFS和exfat。我猜那些的FUSE文件系统不包括创建时间。


如果glibc添加了对statx(2)系统调用的支持,或者将在以后发布,那么stat我们将能够使用普通的旧stat命令。但是我不认为这会被移植到LTS版本中,即使它们确实获得了更新的内核。因此,我不希望stat任何当前的LTS版本(14.04、16.04或18.04)上打印创建时间而无需人工干预。

但是,在18.10上,您可以statx按照所述直接使用该函数man 2 statx(请注意,18.10联机帮助页指出glibc尚未添加包装器是不正确的)。


感谢您链接到github。几个月前,我搜索了4.11,但没有找到任何内容,然后就忘记了。
WinEunuuchs2Unix

@ WinEunuuchs2unix通过ping来原谅,但在元站点上询问为什么muru的帐户具有正义代表1
乔治·乌德森

@GeorgeUdosen令人震惊!我直觉为什么会这样
WinEunuuchs2Unix

@GeorgeUdosen最近有一个有关暂停的一般性元问题,它们不会解决特定用户:meta.askubuntu.com/questions/18341/…我现在要进入聊天室,因此如果您愿意,可以在那里进行对话希望。
WinEunuuchs2Unix

现在该功能可用,您是否知道如何修改该字段?我可能会尝试创建一个ctypes包装器以在python中完成它。谢谢。
Gringo Suave

3

TL; DR: 只需运行: sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>

(要弄清楚您的fs,请运行df -T /path/to/your/file,很可能是/dev/sda1)。

长版:

我们将运行两个命令:

  1. 找出文件的分区名称的名称。

    df -T /path/to/your/file

    输出将如下所示(分区名称为第一):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. 找出该文件的创建时间。

    sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>
    

    在输出中,查找ctime

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.