Как найти время создания файла?

51

Мне нужно найти время создания файла, когда я прочитал некоторые статьи об этой проблеме, все упомянули, что нет решения (например, Site1 , site2 ).

Когда я попробовал команду stat , она заявляет Birth: - .

Итак, как я могу найти время создания файла?

    
задан nux 21.05.2014 в 16:16
источник

4 ответа

56

Существует способ узнать дату создания каталога, просто выполните следующие действия:

  1. Знайте inode каталога командой ls -i (скажем, например, X )

  2. Знайте, на каком разделе ваш каталог будет сохранен командой df -T /path (скажем, на /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 остался прежним, но изменить и доступ .
ответ дан nux 21.05.2014 в 16:16
источник
51

@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
    
ответ дан terdon 21.05.2014 в 17:29
6

Невозможность stat показать время создания связано с ограничением stat(2) системного вызова , чья структура возврата не включала поле для времени создания. Однако, начиная с Linux 4.11 (т. Е. 17.10 и новее *), новый statx(2) системный вызов , который включает время создания в своей структуре возврата.

* И, возможно, на более старых версиях LTS, использующих ядра стека оборудования (HWE). Проверьте uname -r , чтобы узнать, используете ли ядро хотя бы 4.11 для подтверждения.

К сожалению, вызвать вызовы системы непосредственно в программе C непросто. Обычно glibc предоставляет оболочку, облегчающую работу, но glibc еще не добавил обертку для statx(2) . К счастью, @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 (за исключением установки некоторых необходимых пакетов, например make и linux-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 на любой текущей версии (14.04, 16.04, 17.04, 17.10) будет когда-либо печатать время создания без ручного вмешательства.

    
ответ дан muru 27.11.2017 в 15:52
3

TL; ДР: Просто беги: 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 .

ответ дан Lukasz Czerwinski 14.01.2016 в 21:19