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

64

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

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

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

Nux
источник
2
Имейте в виду, что «время создания» файла не обязательно будет точным. Есть много способов «подделать» даты создания файла.
Томас Уорд
1
@ThomasWard Много больше, чем способы выдумки других данных файла?
Сис Тиммерман

Ответы:

67

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

  1. Знать индекс каталога по 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. Затем я изменяю его и снова тестирую, время ожидания осталось прежним, но изменилось и время доступа изменилось.
Nux
источник
Я публикую это, потому что мне нравится обсуждать, чтобы я мог лучше понять, мне интересно, почему люди говорят, что Linux не поддерживает эту функцию
nux
13
Потому что самого Linux нет. Файловая система ext4 имеет эту информацию, но ядро ​​не предоставляет API для доступа к ней. По-видимому, debugfsизвлекает его непосредственно из файловой системы, поэтому ему не нужно использовать API ядра. Смотрите здесь .
Тердон
Я проверял это. Он отлично работал на файловой системе ext4
Фахим Бабар Патель
1
Похоже, это специфично для ext4? Это не работает с XFS для меня.
Quantum7
Все ядро, glibc и coreutils теперь поддерживаются statx()с марта 2019 года.
hippietrail
55

@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/… )
Джейкоб Влейм,
1
@JacobVlijm ну да, конечно. Разве это не очевидно? Как может быть иначе? Копия - это новый файл, содержимое которого совпадает с другим. Время модификации также меняется для копии, кстати. Он устанавливается на момент создания копии, если вы явно не решите, чтобы это не происходило с использованием cp -pили подобным.
Тердон
Абсолютно, но в то же время, это не было бы так нелогично, как, например, мод. дата, где-то в файле дата будет сохранена, когда она возникла. Я должен признать, что я не знал, что это не так, пока я не ответил на связанный вопрос.
Джейкоб Влейм
Только что попробовал, кстати, я просто скопировал файлы в nautilus, дата модификации остается как есть (была), м.б. дата раньше даты создания.
Джейкоб Влейм,
1
@demongolem да, версия CentOS dfне поддерживает эту --outputопцию. В этом случае вы можете заменить эту строку на, fs=$(df foo | awk '{a=$1}END{print a}'и функция также будет работать. Все, что я показываю в этом ответе, - это способ обернуть команду из принятого ответа таким образом, чтобы ее можно было запустить непосредственно для целей файла / каталога.
Тердон
11

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

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

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

Однако в 18.10 вы можете напрямую использовать statxфункцию, как описано в man 2 statx(обратите внимание, что man-страница 18.10 неверна, заявив, что glibc еще не добавил оболочку).

Мур
источник
Спасибо за ссылку на github. Я искал несколько месяцев назад, когда вышел 4.11 и ничего не нашел, а потом забыл об этом.
WinEunuuchs2Unix
@ WinEunuuchs2unix прости, пингуясь, но было бы разумно спросить на мета-сайте, почему аккаунт Муру имеет репутацию просто 1?
Джордж Удосен
@ GeorgeUdosen Это шокирует! У меня есть догадка, почему ...
WinEunuuchs2Unix
@GeorgeUdosen Недавно был задан мета-вопрос о приостановках в целом, и они не будут адресованы конкретному пользователю: meta.askubuntu.com/questions/18341/… Сейчас я иду в чат, чтобы вы могли продолжить там разговор, если вы пожелает.
WinEunuuchs2Unix
Теперь, когда функция доступна, знаете ли вы, как изменить это поле? Я могу попытаться создать оболочку ctypes, чтобы сделать это в python. Благодарю.
Гринго Суаве
3

TL; DR: Просто беги: sudo debugfs -R 'stat /path/to/your/file' /dev/<your 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.

Лукаш Червинский
источник