Bagaimana cara menemukan waktu pembuatan file?

64

Saya perlu menemukan waktu pembuatan file, ketika saya membaca beberapa artikel tentang masalah ini, semua menyebutkan bahwa tidak ada solusi (seperti Site1 , Site2 ).

Ketika saya mencoba statperintah, itu menyatakan Birth: -.

Jadi bagaimana saya bisa menemukan waktu pembuatan file?

nux
sumber
2
Ingatlah bahwa 'waktu pembuatan' file tidak dijamin akurat. Ada banyak cara untuk 'memalsukan' tanggal pembuatan pada file.
Thomas Ward
1
@ThomasWard Banyak lagi cara untuk memalsukan data file lainnya?
Cees Timmerman

Jawaban:

67

Ada cara untuk mengetahui tanggal pembuatan direktori, cukup ikuti langkah-langkah ini:

  1. Ketahui inode direktori dengan ls -iperintah (misalkan X -nya )

  2. Ketahui di partisi mana direktori Anda disimpan oleh df -T /pathperintah (misalkan aktif /dev/sda1)

  3. Sekarang gunakan perintah ini: sudo debugfs -R 'stat <X>' /dev/sda1

Anda akan melihat di output:

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

crtime adalah tanggal pembuatan file Anda.

Apa yang saya uji :

  1. Membuat direktori pada waktu tertentu.
  2. Mengaksesnya.
  3. Dimodifikasi dengan membuat file.

  4. Saya mencoba perintah dan itu memberi waktu yang tepat.

  5. Kemudian saya memodifikasinya, dan menguji lagi, crtime tetap sama, tetapi memodifikasi dan waktu akses berubah.
nux
sumber
Saya memposting ini, karena saya suka membahas sehingga saya bisa mengerti dengan lebih baik, saya heran mengapa orang mengatakan bahwa Linux tidak mendukung fitur ini
nux
13
Karena Linux sendiri tidak. Sistem file ext4 memang memiliki informasi ini tetapi kernel tidak menyediakan API untuk mengaksesnya. Rupanya, debugfsmengekstraknya langsung dari sistem file sehingga tidak perlu menggunakan API kernel. Lihat di sini .
terdon
Saya mengujinya. Ini bekerja dengan sempurna pada sistem file ext4
Fahim Babar Patel
1
Sepertinya ini khusus untuk ext4? Tidak berhasil dengan XFS untuk saya.
Quantum7
Kernel, glibc, dan coreutils semua sekarang mendukung statx()pada Maret 2019.
hippietrail
54

@Nux menemukan solusi hebat untuk ini yang harus Anda upvote semua. Saya memutuskan untuk menulis sedikit fungsi yang dapat digunakan untuk menjalankan semuanya secara langsung. Tambahkan saja ini ke ~/.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
}

Sekarang, Anda dapat menjalankan get_crtimeuntuk mencetak tanggal pembuatan sebanyak mungkin file atau direktori:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014
terdon
sumber
Perhatikan bahwa tanggal pembuatan bukan tanggal pembuatan file asli jika file tersebut adalah salinan (seperti itu adalah dengan tanggal modifikasi). Setelah file disalin, tanggal modifikasi adalah dari aslinya, tetapi tanggal pembuatan adalah dari salinan. (Ada beberapa kesalahpahaman dalam pertanyaan ini: askubuntu.com/questions/529885/… )
Jacob Vlijm
1
@ JacobVlijm, ya, tentu saja. Bukankah itu sudah jelas? Bagaimana bisa sebaliknya? Salinan adalah file baru yang kebetulan memiliki konten yang sama dengan yang lain. Omong-omong modifikasi waktu juga untuk salinan. Ini diatur ke saat salinan dibuat kecuali Anda secara eksplisit memilih untuk tidak menggunakan cp -patau serupa.
terdon
Tentu saja, tetapi pada saat yang sama, itu tidak akan menjadi tidak logis jika, seperti mod. tanggal, di suatu tempat di file tanggal akan disimpan ketika berasal. Saya harus mengakui bahwa saya tidak tahu itu tidak terjadi sampai saya menjawab pertanyaan terkait.
Jacob Vlijm
Baru saja dicoba, saya hanya menyalin file di nautilus, tanggal modifikasi tetap apa adanya, m. tanggal lebih awal dari tanggal pembuatan.
Jacob Vlijm
1
@demongolem ya, versi CentOS dfsepertinya tidak mendukung --outputopsi. Jika demikian, Anda dapat mengganti baris itu dengan fs=$(df foo | awk '{a=$1}END{print a}'dan fungsinya juga akan berfungsi. Yang saya tunjukkan dalam jawaban ini adalah cara untuk membungkus perintah dari jawaban yang diterima dengan cara yang dapat dijalankan secara langsung untuk target file / direktori.
terdon
11

Ketidakmampuan statuntuk menunjukkan waktu pembuatan adalah karena keterbatasan stat(2)panggilan sistem , yang kembali struct tidak menyertakan bidang untuk waktu pembuatan. Dimulai dengan Linux 4.11 (yaitu, 17.10 dan yang lebih baru *), bagaimanapun, panggilan sistem barustatx(2) tersedia, yang tidak termasuk waktu pembuatan dalam struct kembali.

* Dan mungkin pada rilis LTS yang lebih lama menggunakan kernel enablement stack hardware (HWE). Periksa uname -runtuk melihat apakah Anda menggunakan kernel setidaknya pada 4,11 untuk mengkonfirmasi.

Sayangnya, tidak mudah untuk memanggil panggilan sistem secara langsung dalam program C. Biasanya glibc menyediakan pembungkus yang memudahkan pekerjaan, tetapi glibc hanya menambahkan pembungkus untuk statx(2)pada Agustus 2018 (versi 2.28 , tersedia dalam 18.10). Untungnya, @whotwagner menulis contoh program C yang menunjukkan cara menggunakan statx(2)pemanggilan sistem pada sistem x86 dan x86-64. Outputnya adalah format yang sama dengan statdefault, tanpa opsi format apa pun, tetapi mudah untuk memodifikasinya untuk mencetak waktu kelahiran saja.

Pertama, klon:

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

Anda dapat mengkompilasi statx.ckode, atau, jika Anda hanya ingin waktu kelahiran, buat birth.cdi direktori kloning dengan kode berikut (yang merupakan versi minimal dari statx.cpencetakan hanya cap waktu pembuatan termasuk ketepatan nanosecond):

#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;
}

Kemudian:

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

Secara teori ini harus membuat waktu pembuatan lebih mudah diakses:

  • lebih banyak filesystem yang harus didukung daripada hanya ext * ( debugfsadalah alat untuk filesystem ext2 / 3/4, dan tidak dapat digunakan pada yang lain)
  • Anda tidak perlu root untuk menggunakan ini (kecuali untuk menginstal beberapa paket yang diperlukan, seperti makedan linux-libc-dev).

Menguji sistem xfs, misalnya:

$ 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: -

Namun, ini tidak berfungsi untuk NTFS dan exfat. Saya kira sistem file FUSE untuk mereka yang tidak termasuk waktu pembuatan.


Jika, atau lebih tepatnya kapan, glibc menambahkan dukungan untuk statx(2)panggilan sistem, statakan segera menyusul dan kami akan dapat menggunakan perintah biasa statuntuk ini. Tapi saya tidak berpikir ini akan di-backport ke rilis LTS bahkan jika mereka mendapatkan kernel yang lebih baru. Jadi, saya tidak berharap statpada rilis LTS saat ini (14,04, 16,04 atau 18,04) untuk pernah mencetak waktu pembuatan tanpa intervensi manual.

Pada 18.10, bagaimanapun, Anda dapat langsung menggunakan statxfungsi seperti yang dijelaskan dalam man 2 statx(perhatikan bahwa halaman 18.10 salah dalam menyatakan bahwa glibc belum menambahkan pembungkus).

muru
sumber
Terima kasih telah menautkan ke github. Saya mencari beberapa bulan yang lalu ketika 4,11 keluar dan tidak menemukan apa-apa dan kemudian melupakannya.
WinEunuuchs2Unix
@ WinEunuuchs2unix memaafkan dengan melakukan ping tetapi apakah lebih bijaksana untuk bertanya di situs meta mengapa akun muru memiliki perwakilan yang adil 1?
George Udosen
@ GeorgeUdosen Itu mengejutkan! Saya punya firasat mengapa ...
WinEunuuchs2Unix
@GeorgeUdosen Ada pertanyaan meta terbaru tentang penangguhan secara umum dan mereka tidak akan membahas pengguna tertentu: meta.askubuntu.com/questions/18341/... Saya akan masuk ke ruang obrolan sekarang sehingga Anda dapat melakukan percakapan di sana jika Anda ingin.
WinEunuuchs2Unix
Sekarang setelah fitur tersedia, apakah Anda tahu cara memodifikasi bidang itu? Saya dapat mencoba membuat pembungkus ctypes untuk melakukannya dengan python. Terima kasih.
Gringo Suave
3

TL; DR: Jalankan saja: sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>

(Untuk mengetahui fs Anda, jalankan df -T /path/to/your/file, kemungkinan besar itu akan terjadi /dev/sda1).

Versi panjang:

Kami akan menjalankan dua perintah:

  1. Temukan nama nama partisi untuk file Anda.

    df -T /path/to/your/file

    Outputnya akan terlihat seperti ini (nama partisi adalah yang pertama):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. Cari tahu waktu pembuatan untuk file itu.

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

    Dalam output, cari ctime.

Lukasz Czerwinski
sumber