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


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.