web-dev-qa-db-fra.com

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

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

Lorsque j'ai essayé la commande stat, elle indique Birth: -.

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

62
nux

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 la commande ls -i (disons par exemple que son X)

  2. Savoir sur quelle partition votre répertoire est enregistré à l'aide de la commande df -T /path (disons qu'il est sur /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 reste identique, mais modifie et accès le temps a changé.
64
nux

@Nux a trouvé ne excellente solution pour ce que vous devriez tous invoquer. 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_crtime pour imprimer les dates de création d’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
53
terdon

L'incapacité de stat à afficher l'heure de création est due à la limitation de l'appel système stat(2) , dont la structure de retour n'incluait pas de champ pour l'heure de création. Cependant, à partir de Linux 4.11 (c'est-à-dire 17.10 et plus récent *), , le nouvel appel système statx(2) 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 -r pour voir si 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 la tâche, mais elle n’a ajouté un wrapper que pour statx(2) en août 2018 (version 2.28 , disponible en 18.10). Heureusement, @whotwagner a écrit un exemple de programme C qui montre comment utiliser l'appel système statx(2) sur des systèmes x86 et x86-64. Sa sortie est au même format que celui par défaut de stat, sans aucune option de formatage, mais il est simple de le modifier pour n'imprimer que l'heure de la naissance.

Commencez par le cloner:

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

Vous pouvez compiler le code statx.c ou, si vous voulez seulement l'heure de naissance, créer un birth.c dans le répertoire cloné avec le code suivant (qui est une version minimale de statx.c n'imprimant que 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 faut prendre en charge davantage de systèmes de fichiers que uniquement ceux ext * (debugfs est un outil destiné aux systèmes de fichiers ext2/3/4 et inutilisable sur d'autres).
  • vous n'avez pas besoin de root pour l'utiliser (à l'exception de l'installation de certains paquetages requis, tels que make et 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'appel système statx(2), stat suivra bientôt et nous pourrons utiliser la vieille commande stat en clair 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 prévois pas stat sur aucune des versions actuelles de LTS (14.04, 16.04 ou 18.04) pour toujours imprimer l'heure de création sans intervention manuelle.

Cependant, le 18.10, vous pouvez utiliser directement la fonction statx comme décrit dans man 2 statx (notez que la page de manuel 18.10 est incorrecte en indiquant que glibc n'a pas encore ajouté le wrapper).

9
muru

TL; DR: Il suffit d'exécuter: Sudo debugfs -R 'stat /path/to/your/file' /dev/<your fs>

(Pour déterminer votre fs, exécutez df -T /path/to/your/file, ce sera très probablement /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.

3
Lukasz Czerwinski