Wie finde ich die Erstellungszeit einer Datei?

64

Ich muss die Erstellungszeit einer Datei ermitteln, wenn ich einige Artikel zu diesem Problem lese, in denen alle darauf hinweisen , dass es keine Lösung gibt (z. B. Site1 , Site2 ).

Als ich den statBefehl ausprobierte , heißt es Birth: -.

Wie finde ich die Erstellungszeit einer Datei?

nux
quelle
2
Beachten Sie, dass die Erstellungszeit einer Datei nicht garantiert genau ist. Es gibt viele Möglichkeiten, die Erstellungsdaten einer Datei zu verändern.
Thomas Ward
1
@ThomasWard Mehr als nur Möglichkeiten, andere Dateidaten zu manipulieren?
Cees Timmerman

Antworten:

67

Es gibt eine Möglichkeit, das Erstellungsdatum eines Verzeichnisses zu ermitteln. Führen Sie einfach die folgenden Schritte aus:

  1. Kennen Sie die Inode des Verzeichnisses per ls -iBefehl (sagen wir zum Beispiel sein X )

  2. Wissen, auf welcher Partition Ihr Verzeichnis per df -T /pathBefehl gespeichert ist (sagen wir, es ist eingeschaltet /dev/sda1)

  3. Verwenden Sie nun diesen Befehl: sudo debugfs -R 'stat <X>' /dev/sda1

Sie sehen in der Ausgabe:

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

crtime ist das Erstellungsdatum Ihrer Datei.

Was ich getestet habe :

  1. Erstellt ein Verzeichnis zu einem bestimmten Zeitpunkt.
  2. Zugriff darauf.
  3. Änderte es durch Erstellen einer Datei.

  4. Ich habe das Kommando ausprobiert und es gab eine genaue Zeit.

  5. Dann ändere ich es und teste noch einmal, die Uhrzeit ist gleich geblieben, aber Änderung und Zugriffszeit haben sich geändert.
nux
quelle
Ich poste dies, weil ich gerne diskutiere, damit ich es besser verstehe. Ich frage mich, warum die Leute sagen, dass Linux diese Funktion nicht unterstützt
nux
13
Weil Linux selbst nicht tut. Das ext4-Dateisystem verfügt zwar über diese Informationen, der Kernel bietet jedoch keine API für den Zugriff darauf. Anscheinend wird debugfses direkt aus dem Dateisystem extrahiert, sodass die Kernel-API nicht verwendet werden muss. Sehen Sie hier .
terdon
Ich habe es getestet. Es funktionierte perfekt auf ext4-Dateisystem
Fahim Babar Patel
1
Scheint so, ist ext4 spezifisch? Bei mir hat es mit XFS nicht geklappt.
Quantum7
Der Kernel, Glibc und Coreutils unterstützen jetzt alle statx()ab März 2019.
Hippietrail
54

@Nux hat dafür eine tolle Lösung gefunden, die ihr alle positiv bewerten solltet. Ich habe beschlossen, eine kleine Funktion zu schreiben, mit der alles direkt ausgeführt werden kann. Fügen Sie einfach dieses Ihrem hinzu ~/.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
}

Jetzt können Sie get_crtimedie Erstellungsdaten beliebig vieler Dateien oder Verzeichnisse ausdrucken:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014
terdon
quelle
Beachten Sie, dass das Erstellungsdatum nicht das Erstellungsdatum der Originaldatei, wenn die Datei eine Kopie ist (wie es ist mit dem Änderungsdatum). Sobald eine Datei kopiert wurde, stammt das Änderungsdatum vom Original, das Erstellungsdatum jedoch von der Kopie. (Es gibt einige Missverständnisse in dieser Frage: askubuntu.com/questions/529885/… )
Jacob Vlijm
1
@JacobVlijm na ja, natürlich. Ist das nicht offensichtlich? Wie könnte es anders sein? Eine Kopie ist eine neue Datei, die zufällig den gleichen Inhalt wie eine andere hat. Die Änderungszeit ändert sich übrigens auch für eine Kopie. Es wird auf den Zeitpunkt festgelegt, an dem die Kopie erstellt wurde, es sei denn, Sie wählen ausdrücklich, dass dies nicht mit cp -poder ähnlich geschieht .
Terdon
Absolut, aber gleichzeitig wäre es nicht so unlogisch, wenn, wie der Mod. Datum, irgendwo in der Datei wird das Datum gespeichert, an dem es erstellt wurde. Ich muss zugeben, dass ich nicht wusste, dass dies nicht der Fall ist, bis ich die verknüpfte Frage beantwortet habe.
Jacob Vlijm
Ich habe es übrigens gerade versucht, ich habe gerade Dateien in Nautilus kopiert, das Änderungsdatum bleibt wie es ist (war), m. Datum liegt vor dem Erstellungsdatum.
Jacob Vlijm
1
@demongolem Ja, die CentOS-Version von dfscheint diese --outputOption nicht zu unterstützen . In diesem Fall können Sie diese Zeile durch ersetzen, fs=$(df foo | awk '{a=$1}END{print a}'und die Funktion funktioniert auch. Alles, was ich in dieser Antwort zeige, ist eine Möglichkeit, den Befehl von der akzeptierten Antwort so zu trennen, dass er direkt für Datei- / Verzeichnisziele ausgeführt werden kann.
Terdon
11

Die Unfähigkeit stat, die Erstellungszeit anzuzeigen, ist auf die Beschränkung des stat(2)Systemaufrufs zurückzuführen , dessen Rückgabestruktur kein Feld für die Erstellungszeit enthielt. Ab Linux 4.11 (dh 17.10 und neuer *) ist jedoch der neue statx(2)Systemaufruf verfügbar, der in seiner Rückgabestruktur eine Erstellungszeit enthält.

* Und möglicherweise auf älteren LTS-Releases, die den Hardware-Enablement-Stack-Kernel (HWE-Kernel) verwenden. Überprüfen Sie uname -r, ob Sie mindestens bei 4.11 einen Kernel verwenden, um dies zu bestätigen.

Leider ist es nicht einfach, Systemaufrufe direkt in einem C-Programm aufzurufen. Normalerweise bietet glibc einen Wrapper, der die Arbeit erleichtert, aber glibc hat erst statx(2)im August 2018 einen Wrapper hinzugefügt (Version 2.28 , verfügbar ab 18.10). Zum Glück hat @whotwagner ein C-Beispielprogramm geschrieben, das zeigt, wie der statx(2)Systemaufruf auf x86- und x86-64-Systemen verwendet wird. Die Ausgabe hat dasselbe Format wie statdie Standardausgabe, jedoch ohne Formatierungsoptionen. Es ist jedoch einfach, das Format so zu ändern, dass nur die Geburtszeit gedruckt wird.

Zuerst klonen Sie es:

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

Sie können den statx.cCode kompilieren oder, wenn Sie nur die Geburtszeit möchten, birth.cim geklonten Verzeichnis einen mit folgendem Code erstellen (dies ist eine minimale Version des statx.cAusdrucks nur des Erstellungszeitstempels einschließlich der Genauigkeit von Nanosekunden):

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

Dann:

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

Theoretisch sollte dies die Erstellungszeit zugänglicher machen:

  • es sollten mehr Dateisysteme unterstützt werden als nur die ext * -Dateisysteme ( debugfsist ein Tool für ext2 / 3/4-Dateisysteme und für andere nicht verwendbar)
  • Sie benötigen kein root, um dies zu verwenden (außer zum Installieren einiger erforderlicher Pakete, wie makeund linux-libc-dev).

Testen eines XFS-Systems, zum Beispiel:

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

Dies funktionierte jedoch nicht für NTFS und exfat. Ich denke, die FUSE-Dateisysteme für diese enthielten nicht die Erstellungszeit.


Ob oder wann glibc Unterstützung für den statx(2)Systemaufruf hinzufügt , statwird in Kürze folgen, und wir können dafür den einfachen alten statBefehl verwenden. Aber ich glaube nicht, dass dies auf LTS-Releases zurückportiert wird, selbst wenn sie neuere Kernel bekommen. Daher erwarte ich statin keinem aktuellen LTS-Release (14.04, 16.04 oder 18.04), dass die Erstellungszeit jemals ohne manuelles Eingreifen gedruckt wird.

Am 18.10 können Sie die statxFunktion jedoch direkt wie in beschrieben verwenden man 2 statx(beachten Sie, dass die Manpage 18.10 nicht korrekt besagt, dass glibc den Wrapper noch nicht hinzugefügt hat).

muru
quelle
Vielen Dank für den Link zu Github. Ich habe vor ein paar Monaten gesucht, als 4.11 herauskam, nichts gefunden und es dann vergessen.
WinEunuuchs2Unix
@ WinEunuuchs2unix verzeihen durch Ping, aber wäre es ratsam, auf Meta-Site zu fragen, warum Murus Konto eine Wiederholung von nur hat 1?
George Udosen
@GeorgeUdosen Das ist schockierend! Ich habe eine Ahnung, warum ...
WinEunuuchs2Unix
@GeorgeUdosen In letzter Zeit gibt es eine Meta-Frage zu Suspensionen im Allgemeinen, die sich nicht an einen bestimmten Benutzer richtet : meta.askubuntu.com/questions/18341/… Ich gehe jetzt in den Chat-Raum, damit Sie sich dort weiter unterhalten können, wenn Sie möchten Wunsch.
WinEunuuchs2Unix
Möchten Sie wissen, wie Sie dieses Feld ändern können, nachdem die Funktion verfügbar ist? Ich kann versuchen, einen Ctypes-Wrapper zu erstellen, um es in Python zu tun. Vielen Dank.
Gringo Suave
3

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

(Um deine Fs herauszufinden, laufe df -T /path/to/your/file, höchstwahrscheinlich wird es so sein /dev/sda1).

Lange Version:

Wir werden zwei Befehle ausführen:

  1. Ermitteln Sie den Namen der Partition für Ihre Datei.

    df -T /path/to/your/file

    Die Ausgabe wird folgendermaßen aussehen (Partitionsname steht an erster Stelle):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. Finden Sie die Erstellungszeit für diese Datei heraus.

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

    Suchen Sie in der Ausgabe nach ctime.

Lukasz Czerwinski
quelle