Comment trouver l'heure de création d'un fichier?

64

Je dois trouver l'heure de création d'un fichier. Lorsque j'ai lu certains articles sur ce problème, tous ont mentionné qu'il n'y avait pas de solution (comme Site1 , Site2 ).

Quand j'ai essayé la statcommande, ça dit Birth: -.

Alors, comment puis-je trouver l'heure de création d'un fichier?

nux
la source
2
Gardez à l'esprit qu'il n'est pas garanti que la «date de création» d'un fichier est exacte. Il existe de nombreuses façons de «décaler» les dates de création d'un fichier.
Thomas Ward
1
@ThomasWard Beaucoup plus de façons de falsifier d'autres données de fichier?
Cees Timmerman le

Réponses:

67

Il existe un moyen de connaître la date de création d'un répertoire, procédez comme suit:

  1. Connaître l' inode du répertoire par ls -icommande (disons par exemple son X )

  2. Sachez sur quelle partition votre répertoire est enregistré par df -T /pathcommande (disons qu'il est activé /dev/sda1)

  3. Maintenant, utilisez cette commande: sudo debugfs -R 'stat <X>' /dev/sda1

Vous verrez dans la sortie:

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

crtime est la date de création de votre fichier.

Ce que j'ai testé :

  1. Créé un répertoire à une heure précise.
  2. Y a accédé.
  3. Modifié en créant un fichier.

  4. J'ai essayé la commande et il a donné une heure exacte.

  5. Ensuite, je le modifie et teste à nouveau, le crtime est resté le même, mais modifie et le temps d' accès a changé.
nux
la source
Je poste ceci, parce que j'aime discuter pour que je puisse mieux comprendre, je me demande bien pourquoi les gens disent que Linux ne prend pas cette fonctionnalité en charge
nux
13
Parce que Linux lui-même ne le fait pas. Le système de fichiers ext4 dispose de ces informations mais le noyau ne fournit pas d'API pour y accéder. Apparemment, debugfsil extrait directement du système de fichiers afin qu'il n'ait pas besoin d'utiliser l'API du noyau. Voir ici .
terdon
Je l'ai testé. Cela fonctionnait parfaitement sur le système de fichiers ext4
Fahim Babar Patel
1
On dirait que c'est spécifique à ext4? Cela n'a pas fonctionné avec XFS pour moi.
Quantum7
Le noyau, la glibc et les coreutils sont tous compatibles à statx()compter de mars 2019.
hippietrail Le
55

@Nux a trouvé une excellente solution à cet égard. J'ai décidé d'écrire une petite fonction qui peut être utilisée pour tout exécuter directement. Ajoutez simplement ceci à votre ~/.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
}

Maintenant, vous pouvez exécuter get_crtimepour imprimer les dates de création de autant de fichiers ou de répertoires que vous le souhaitez:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014
terdon
la source
Notez que la date de création n'est pas la date de création du fichier original si le fichier est une copie (comme il est avec la date de modification). Une fois qu'un fichier est copié, la date de modification est celle de l'original, mais la date de création est celle de la copie. (Il y a un malentendu dans cette question: askubuntu.com/questions/529885/… )
Jacob Vlijm le
1
@ Jacoboblijm bien, oui, bien sûr. N'est-ce pas évident? Comment pourrait-il en être autrement? Une copie est un nouveau fichier qui a le même contenu qu'un autre. L'heure de modification change également pour une copie en passant. Il est défini au moment où la copie a été créée, sauf si vous choisissez explicitement que cela ne se produise pas avec cp -pou similaire.
terdon
Absolument, mais dans le même temps, ce ne serait pas si peu logique si, comme le mod. date, quelque part dans le fichier, la date serait stockée à l’origine. Je dois admettre que je ne savais pas que ce n'était pas le cas jusqu'à ce que je réponde à la question liée.
Jacob Vlijm
En passant, je viens d’essayer de copier des fichiers dans Nautilus, la date de modification reste telle quelle (était), m. la date est antérieure à la date de création.
Jacob Vlijm
1
@demongolem Oui, la version CentOS de dfne semble pas supporter cette --outputoption. Dans ce cas, vous pouvez remplacer cette ligne par fs=$(df foo | awk '{a=$1}END{print a}'et la fonction fonctionnera également. Tout ce que je montre dans cette réponse est un moyen d'encapsuler la commande à partir de la réponse acceptée d'une manière qui peut être exécutée directement pour les cibles fichier / répertoire.
terdon
11

L'impossibilité d' statafficher l'heure de création est due à la limitation de l' stat(2)appel système , dont la structure de retour n'incluait pas de champ pour l'heure de création. À partir de Linux 4.11 (c'est-à-dire 17.10 et plus récent *), le nouvel statx(2)appel système est disponible, ce qui inclut une heure de création dans sa structure de retour.

* Et éventuellement sur des versions antérieures de LTS utilisant les noyaux de pile d’activation matérielle (HWE). Vérifiez uname -rsi vous utilisez un noyau au moins à 4.11 pour confirmer.

Malheureusement, il n'est pas facile d'appeler des appels système directement dans un programme C. Glibc fournit généralement un wrapper qui facilite le travail, mais elle n’a ajouté un wrapper statx(2)qu’en août 2018 (version 2.28 , disponible en 18.10). Heureusement, @whotwagner a écrit un exemple de programme en C qui montre comment utiliser l' statx(2)appel système sur les systèmes x86 et x86-64. Sa sortie est au même format que celui statpar défaut, sans aucune option de formatage, mais il est simple de le modifier pour n’imprimer que l’heure de naissance.

Commencez par le cloner:

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

Vous pouvez compiler le statx.ccode ou, si vous voulez seulement l'heure de naissance, créer un birth.cdans le répertoire cloné avec le code suivant (qui est une version minimale de l' statx.cimpression uniquement de l'horodatage de création avec une précision à la nanoseconde):

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

Ensuite:

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

En théorie, cela devrait rendre le temps de création plus accessible:

  • il convient de prendre en charge davantage de systèmes de fichiers que les seuls ext * (il debugfss'agit d'un outil pour les systèmes de fichiers ext2 / 3/4 et inutilisable sur d'autres).
  • vous n’avez pas besoin de root pour utiliser ceci (sauf pour installer certains paquets requis, comme makeet linux-libc-dev).

Tester un système xfs, par exemple:

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

Cependant, cela n'a pas fonctionné pour NTFS et exfat. Je suppose que les systèmes de fichiers FUSE pour ceux-ci n'incluaient pas le temps de création.


Si, ou plutôt quand, glibc ajoute le support pour l' statx(2)appel système, statsuivra bientôt et nous pourrons utiliser la statcommande plain old pour cela. Mais je ne pense pas que cela sera reporté dans les versions LTS, même s’ils obtiennent de nouveaux noyaux. Donc, je ne pense pas statà une version actuelle LTS (14,04, 16,04 ou 18,04) à jamais imprimer le temps de création sans intervention manuelle.

Toutefois, le 18.10, vous pouvez utiliser directement la statxfonction comme décrit dans man 2 statx(notez que la page de manuel 18.10 est incorrecte car elle indique que glibc n’a pas encore ajouté le wrapper).

muru
la source
Merci de vous connecter à github. J'ai cherché il y a quelques mois quand 4.11 est sorti et je n'ai rien trouvé, puis je l'ai oublié.
WinEunuuchs2Unix
@ WinEunuuchs2unix pardonnez en cinglant, mais serait-il sage de demander sur le méta-site pourquoi le compte de muru a un représentant juste 1?
George Udosen
@ GeorgeUdosen C'est choquant! J'ai l'intuition de savoir pourquoi ...
WinEunuuchs2Unix
@GeorgeUdosen Il y a récemment une méta-question sur les suspensions et elles ne s'adressent pas à un utilisateur spécifique: meta.askubuntu.com/questions/18341/… . souhait.
WinEunuuchs2Unix
Maintenant que la fonctionnalité est disponible, savez-vous comment modifier ce champ? Je peux essayer de créer un wrapper ctypes pour le faire en python. Merci.
Gringo Suave
3

TL; DR: Il suffit de lancer: sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>

(Pour déterminer votre fs, courez df -T /path/to/your/file, ce sera probablement le cas /dev/sda1).

Version longue:

Nous allons exécuter deux commandes:

  1. Découvrez le nom du nom de la partition pour votre fichier.

    df -T /path/to/your/file

    La sortie va ressembler à ceci (le nom de la partition est en premier):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. Découvrez l'heure de création de ce fichier.

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

    Dans la sortie, recherchez ctime.

Lukasz Czerwinski
la source