Як знайти час створення файлу?


64

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

Коли я спробував statкоманду, він констатує Birth: -.

Тож як я можу знайти час створення файлу?


2
Майте на увазі, що час створення файлу не гарантується точним. Існує багато способів "підробити" дати створення файлу.
Thomas Ward

1
@ThomasWard Багато іншого, ніж способи підробки інших файлових даних?
Cees Timmerman

Відповіді:


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. Потім я модифікую його та ще раз тестую , час роботи залишився колишнім, але змінити та змінити час доступу .

Я публікую це, тому що мені подобається обговорювати, щоб я міг краще зрозуміти, мені цікаво, чому люди кажуть, що Linux не підтримує цю функцію
nux

13
Тому що сам Linux цього не робить. Файлова система ext4 має цю інформацію, але ядро ​​не надає API для доступу до неї. Мабуть, debugfsвитягує його безпосередньо з файлової системи, тому не потрібно використовувати API ядра. Дивіться тут .
тердон

Я тестував це. Він прекрасно працював у файловій системі ext4
Фахім Бабар Патель

1
Здається, це специфічно для ext4? Для мене це не працювало з XFS.
Quantum7

Ядро, glibc та coreutils тепер підтримуються statx()станом на березень 2019 року.
hippietrail

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/… )
Яків Влійм,

1
@JacobVlijm добре, так, звичайно. Хіба це не очевидно? Як могло бути інакше? Копія - це новий файл, який просто має той самий вміст, що й інший. До речі, час модифікації також змінюється для копії. Він встановлюється в момент, коли копія була створена, якщо ви прямо не вирішите, щоб це не сталося з використанням cp -pабо подібного.
terdon

Абсолютно, але в той же час це було б не так нелогічно, якби, як і мод. дата, десь у файлі дата зберігатиметься, коли вона зародилася. Мушу визнати, що не знав, що це не так, поки я не відповів на пов'язане питання.
Яків Влійм

Щойно спробував, до речі, я просто копіював файли в nautilus, дата модифікації залишається такою, якою вона є (була), m. дата є раніше, ніж дата створення.
Яків Влійм

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(зауважте, що сторінка 18.10 невірна, заявивши, що glibc ще не додав обгортку).


Дякуємо за посилання на github. Я шукав кілька місяців тому, коли вийшов 4.11 і нічого не знайшов, а потім забув про це.
WinEunuuchs2Unix

@ WinEunuuchs2unix пробачте за допомогою pinging, але чи було б розумно запитати на мета-сайті, чому в обліковому записі Муру є лише відповідь 1?
Джордж Удосен

@GeorgeUdosen Це шокує! У мене є
здагадка,

@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>

(Щоб розібратися у вашому фс, біжіть 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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.