Come trovo l'ora di creazione di un file?


64

Ho bisogno di trovare il tempo di creazione di un file, quando ho letto alcuni articoli su questo problema, tutti menzionati che non esiste una soluzione (come Site1 , Site2 ).

Quando ho provato il statcomando, si afferma Birth: -.

Quindi, come posso trovare l'ora di creazione di un file?


2
Tieni presente che non è garantito che il "tempo di creazione" di un file sia accurato. Esistono molti modi per "trascinare" le date di creazione su un file.
Thomas Ward

1
@ThomasWard Molti altri modi di confondere altri dati di file?
Cees Timmerman,

Risposte:


67

C'è un modo per conoscere la data di creazione di una directory, basta seguire questi passaggi:

  1. Conoscere l' inode della directory tramite ls -icomando (diciamo ad esempio la sua X )

  2. Scopri su quale partizione la tua directory viene salvata dal df -T /pathcomando (diciamo che è attiva /dev/sda1)

  3. Ora usa questo comando: sudo debugfs -R 'stat <X>' /dev/sda1

Vedrai nell'output:

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

crtime è la data di creazione del tuo file.

Cosa ho testato :

  1. Creata una directory in un momento specifico.
  2. Acceduto.
  3. Modificato creando un file.

  4. Ho provato il comando e mi ha dato un tempo esatto.

  5. Quindi lo modifico e riprovo , il crtime è rimasto lo stesso, ma il tempo di modifica e di accesso è cambiato.

Pubblico questo, perché mi piace discutere in modo da poter capire meglio, mi chiedo perché la gente dice che Linux non supporta questa funzionalità
nux

13
Perché Linux stesso no. Il filesystem ext4 ha queste informazioni ma il kernel non fornisce un'API per accedervi. Apparentemente, lo debugfsestrae direttamente dal filesystem in modo che non abbia bisogno di usare l'API del kernel. Vedi qui .
terdon

L'ho provato. Funzionava perfettamente sul file system ext4
Fahim Babar Patel,

1
Sembra che questo sia ext4 specifico? Non ha funzionato con XFS per me.
Quantum7

Il kernel, glibc e coreutils ora supportano tutti statx()da marzo 2019.
hippietrail,

55

@Nux ha trovato un'ottima soluzione per questo, che dovresti valutare. Ho deciso di scrivere una piccola funzione che può essere utilizzata per eseguire tutto direttamente. Aggiungi questo al tuo ~/.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
}

Ora puoi eseguire get_crtimeper stampare le date di creazione di tutti i file o directory che desideri:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014

Si noti che la data di creazione non è la data di creazione del file originale se il file è una copia (come è con la data di modifica). Una volta copiato un file, la data di modifica è dall'originale, ma la data di creazione è dalla copia. (c'è qualche malinteso in questa domanda: askubuntu.com/questions/529885/… )
Jacob Vlijm

1
@JacobVlijm bene, sì, certo. Non è ovvio? Come potrebbe essere altrimenti? Una copia è un nuovo file che ha gli stessi contenuti di un altro. A proposito, anche il tempo di modifica cambia per una copia. È impostato sul momento in cui la copia è stata creata a meno che tu non scelga esplicitamente che ciò non accada usando cp -po simili.
Terdon

Assolutamente, ma allo stesso tempo, non sarebbe così logico se, come il mod. data, da qualche parte nel file la data verrebbe memorizzata al momento della sua origine. Devo ammettere che non sapevo che non fosse così fino a quando non ho risposto alla domanda collegata.
Jacob Vlijm,

Ho appena provato, ho appena copiato i file in nautilus, la data di modifica rimane com'è (era), m. la data è precedente alla data di creazione.
Jacob Vlijm,

1
@demongolem sì, la versione CentOS di dfnon sembra supportare l' --outputopzione. In tal caso, puoi sostituire quella linea con fs=$(df foo | awk '{a=$1}END{print a}'e anche la funzione funzionerà. Tutto ciò che sto mostrando in questa risposta è un modo per racchiudere il comando dalla risposta accettata in un modo che può essere eseguito direttamente per destinazioni file / directory.
terdon

11

L'incapacità di statmostrare il tempo di creazione è dovuta alla limitazione della stat(2)chiamata di sistema , la cui struttura di ritorno non includeva un campo per il tempo di creazione. A partire da Linux 4.11 (ovvero, 17.10 e successivi *), tuttavia, è disponibile la nuova statx(2)chiamata di sistema , che include un tempo di creazione nella sua struttura di ritorno.

* E possibilmente su versioni precedenti di LTS usando i kernel HWE (Hardware Enablement Stack). Controlla uname -rse stai usando un kernel almeno alla 4.11 per confermare.

Sfortunatamente, non è facile chiamare le chiamate di sistema direttamente in un programma C. In genere glibc fornisce un wrapper che semplifica il lavoro, ma glibc ha aggiunto un wrapper solo per statx(2)agosto 2018 (versione 2.28 , disponibile in 18.10). Fortunatamente, @whotwagner ha scritto un programma C di esempio che mostra come utilizzare la statx(2)chiamata di sistema su sistemi x86 e x86-64. Il suo output ha lo stesso formato statpredefinito, senza opzioni di formattazione, ma è semplice modificarlo per stampare solo il momento della nascita.

Innanzitutto, clonalo:

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

Puoi compilare il statx.ccodice o, se vuoi solo l'ora di nascita, creare un birth.cnella directory clonata con il seguente codice (che è una versione minima di statx.cstampa solo il timestamp di creazione che include la precisione dei nanosecondi):

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

Poi:

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

In teoria questo dovrebbe rendere il tempo di creazione più accessibile:

  • dovrebbero essere supportati più filesystem di quelli ext * ( debugfsè uno strumento per filesystem ext2 / 3/4, e inutilizzabile su altri)
  • non hai bisogno di root per usare questo (tranne che per l'installazione di alcuni pacchetti richiesti, come makee linux-libc-dev).

Test di un sistema xfs, ad esempio:

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

Tuttavia, questo non ha funzionato per NTFS ed exfat. Immagino che i filesystem FUSE per quelli non includessero i tempi di creazione.


Se, o meglio quando, glibc aggiunge il supporto per la statx(2)chiamata di sistema, statseguirà presto e saremo in grado di usare il semplice statcomando precedente per questo. Ma non credo che questo verrà riportato nelle versioni LTS anche se ottengono kernel più recenti. Quindi, non mi aspetto che statsu nessuna versione attuale di LTS (14.04, 16.04 o 18.04) venga mai stampato il tempo di creazione senza intervento manuale.

Su 18.10, tuttavia, è possibile utilizzare direttamente la statxfunzione come descritto in man 2 statx(si noti che la manpage 18.10 non è corretta nell'affermare che glibc non ha ancora aggiunto il wrapper).


Grazie per il collegamento a Github. Ho cercato qualche mese fa quando è uscito il 4.11 e non ho trovato nulla e poi me ne sono dimenticato.
WinEunuuchs2Unix,

@ WinEunuuchs2unix perdona con il ping ma sarebbe saggio chiedere sul meta sito perché l'account di Muru ha un rappresentante di solo 1?
George Udosen,

@GeorgeUdosen È scioccante! Ho un'idea del perché, però ...
WinEunuuchs2Unix il

@GeorgeUdosen C'è una recente meta domanda sulle sospensioni in generale e non si rivolgono a un utente specifico: meta.askubuntu.com/questions/18341/… Adesso vado nella chat room in modo da poter continuare la conversazione lì se desiderio.
WinEunuuchs2Unix il

Ora che la funzione è disponibile, sapresti come modificare quel campo? Potrei provare a creare un wrapper Ctypes per farlo in Python. Grazie.
Gringo Suave,

3

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

(Per capire la tua fs, corri df -T /path/to/your/file, molto probabilmente lo sarà /dev/sda1).

Versione lunga:

Eseguiremo due comandi:

  1. Scopri il nome del nome della partizione per il tuo file.

    df -T /path/to/your/file

    L'output sarà simile al seguente (il nome della partizione è il primo):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. Scopri l'ora di creazione per quel file.

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

    Nell'output, cercare ctime.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.