¿Cómo encuentro el tiempo de creación de un archivo?

64

Necesito encontrar el tiempo de creación de un archivo, cuando leí algunos artículos sobre este problema, todos mencionaron que no hay solución (como Site1 , Site2 ).

Cuando probé el statcomando, dice Birth: -.

Entonces, ¿cómo puedo encontrar el tiempo de creación de un archivo?

nux
fuente
2
Tenga en cuenta que no se garantiza que el "tiempo de creación" de un archivo sea exacto. Hay muchas formas de "falsificar" las fechas de creación en un archivo.
Thomas Ward
1
@ThomasWard ¿Mucho más que formas de falsificar otros datos de archivos?
Cees Timmerman

Respuestas:

67

Hay una manera de conocer la fecha de creación de un directorio, solo siga estos pasos:

  1. Conozca el inodo del directorio por ls -icomando (digamos, por ejemplo, su X )

  2. Sepa en qué partición se guarda su directorio por df -T /pathcomando (digamos que está activado /dev/sda1)

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

Verás en la salida:

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

crtime es la fecha de creación de su archivo.

Lo que probé :

  1. Creó un directorio en un momento específico.
  2. Lo accedí.
  3. Lo modificó creando un archivo.

  4. Intenté el comando y me dio una hora exacta.

  5. Luego lo modifico , y pruebo nuevamente, el tiempo de crt se mantuvo igual, pero modificó y el tiempo de acceso cambió.
nux
fuente
Publico esto, porque me gusta discutir para poder entender mejor, me pregunto por qué la gente dice que Linux no es compatible con esta característica
nux
13
Porque Linux no lo hace. El sistema de archivos ext4 tiene esta información, pero el kernel no proporciona una API para acceder a ella. Aparentemente, lo debugfsextrae directamente del sistema de archivos para que no necesite usar la API del núcleo. Ver aquí .
terdon
Lo probé Funcionó perfectamente en el sistema de archivos ext4
Fahim Babar Patel
1
Parece que esto es ext4 específico? No funcionó con XFS para mí.
Quantum7
El kernel, glibc y coreutils ahora son compatibles a statx()partir de marzo de 2019.
hippietrail
55

@Nux encontró una gran solución para esto que todos deberían votar. Decidí escribir una pequeña función que se puede utilizar para ejecutar todo directamente. Solo agrega esto a tu ~/.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
}

Ahora, puede ejecutar get_crtimepara imprimir las fechas de creación de tantos archivos o directorios como desee:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014
terdon
fuente
Tenga en cuenta que la fecha de creación no es la fecha de creación del archivo original si el archivo es una copia (como lo es con la fecha de modificación). Una vez que se copia un archivo, la fecha de modificación es del original, pero la fecha de creación es de la copia. (Hay algunos malentendidos en esta pregunta: askubuntu.com/questions/529885/… )
Jacob Vlijm
1
@JacobVlijm bueno, sí, por supuesto. ¿No es eso obvio? ¿Cómo podría ser de otra manera? Una copia es un archivo nuevo que tiene el mismo contenido que otro. El tiempo de modificación también cambia para una copia por cierto. Se establece en el momento en que se creó la copia, a menos que elija explícitamente que eso no suceda utilizando cp -po similar.
terdon
Absolutamente, pero al mismo tiempo, no sería tan lógico si, como el mod. fecha, en algún lugar del archivo, la fecha se almacenaría cuando se originó. Debo admitir que no sabía que ese no era el caso hasta que respondí la pregunta vinculada.
Jacob Vlijm
Por cierto, solo intenté, simplemente copié archivos en nautilus, la fecha de modificación permanece como está (era), m. La fecha es anterior a la fecha de creación.
Jacob Vlijm
1
@demongolem sí, la versión CentOS de dfno parece admitir la --outputopción. En ese caso, puede reemplazar esa línea con fs=$(df foo | awk '{a=$1}END{print a}'y la función funcionará también. Todo lo que estoy mostrando en esta respuesta es una forma de ajustar el comando de la respuesta aceptada de una manera que se puede ejecutar directamente para los objetivos de archivo / directorio.
terdon
11

La incapacidad de statmostrar el tiempo de creación se debe a la limitación de la stat(2)llamada al sistema , cuya estructura de retorno no incluyó un campo para el tiempo de creación. A partir de Linux 4.11 (es decir, 17.10 y posterior *), sin embargo, la nueva statx(2)llamada del sistema está disponible, lo que incluye un tiempo de creación en su estructura de retorno.

* Y posiblemente en versiones anteriores de LTS utilizando los núcleos de la pila de habilitación de hardware (HWE). Verifique uname -rsi está utilizando un núcleo al menos a 4.11 para confirmar.

Desafortunadamente, no es fácil llamar a las llamadas del sistema directamente en un programa en C. Por lo general, glibc proporciona un contenedor que facilita el trabajo, pero glibc solo agregó un contenedor para statx(2)agosto de 2018 (versión 2.28 , disponible en 18.10). Afortunadamente, @whotwagner escribió un programa C de muestra que muestra cómo usar la statx(2)llamada del sistema en sistemas x86 y x86-64. Su salida es el mismo formato que statel predeterminado, sin ninguna opción de formato, pero es simple modificarlo para imprimir solo la hora de nacimiento.

Primero, clónalo:

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

Puede compilar el statx.ccódigo o, si solo desea la hora de nacimiento, crear un birth.cen el directorio clonado con el siguiente código (que es una versión mínima de statx.cimpresión solo la marca de tiempo de creación, incluida la precisión de nanosegundos):

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

Entonces:

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

En teoría, esto debería hacer que el tiempo de creación sea más accesible:

  • Se deben admitir más sistemas de archivos que solo los ext * ( debugfses una herramienta para sistemas de archivos ext2 / 3/4, e inutilizable en otros)
  • no necesita root para usar esto (excepto para instalar algunos paquetes requeridos, como makey linux-libc-dev).

Probar un sistema xfs, por ejemplo:

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

Sin embargo, esto no funcionó para NTFS y exfat. Supongo que los sistemas de archivos FUSE para aquellos no incluyeron el tiempo de creación.


Si, o más bien cuándo, glibc agrega soporte para la statx(2)llamada al sistema, statseguirá pronto y podremos usar el statcomando anterior para esto. Pero no creo que esto sea compatible con las versiones de LTS, incluso si obtienen núcleos más nuevos. Por lo tanto, no espero que staten cualquier corriente versión LTS (14.04, 16.04 y 18.04) para imprimir cada vez el tiempo de creación sin intervención manual.

Sin embargo, en 18.10, puede usar directamente la statxfunción como se describe en man 2 statx(tenga en cuenta que la página de manual 18.10 es incorrecta al indicar que glibc aún no ha agregado el contenedor).

muru
fuente
Gracias por vincular a github. Busqué hace unos meses cuando salió 4.11 y no encontré nada y luego lo olvidé.
WinEunuuchs2Unix
@ WinEunuuchs2unix perdona haciendo ping pero ¿sería prudente preguntar en el sitio meta por qué la cuenta de muru tiene un representante justo 1?
George Udosen
@GeorgeUdosen ¡Eso es impactante! Aunque tengo el presentimiento de por qué ...
WinEunuuchs2Unix
@GeorgeUdosen Hay una meta pregunta reciente sobre suspensiones en general y no se dirigirán a un usuario específico: meta.askubuntu.com/questions/18341/ ... Voy a entrar en la sala de chat ahora para que pueda continuar la conversación allí si usted deseo.
WinEunuuchs2Unix
Ahora que la función está disponible, ¿sabría cómo modificar ese campo? Puedo intentar crear un contenedor de ctypes para hacerlo en python. Gracias.
Gringo Suave
3

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

(Para averiguar tu fs, corre df -T /path/to/your/file, lo más probable es que sea /dev/sda1).

Versión larga:

Vamos a ejecutar dos comandos:

  1. Averigüe el nombre del nombre de la partición para su archivo.

    df -T /path/to/your/file

    El resultado se verá así (el nombre de la partición es el primero):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. Descubra el tiempo de creación para ese archivo.

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

    En la salida, busque ctime.

Lukasz Czerwinski
fuente