El nacimiento está vacío en ext4


83

Estaba leyendo la Birthsección de staty parece que ext4 debería admitirlo, pero incluso un archivo que acabo de crear lo deja vacío.

 ~  % touch test                                                       slave-iv
 ~  % stat test.pl                                                     slave-iv
  File: ‘test.pl’
  Size: 173             Blocks: 8          IO Block: 4096   regular file
Device: 903h/2307d      Inode: 41943086    Links: 1
Access: (0600/-rw-------)  Uid: ( 1000/xenoterracide)   Gid: (  100/   users)
Access: 2012-09-22 18:22:16.924634497 -0500
Modify: 2012-09-22 18:22:16.924634497 -0500
Change: 2012-09-22 18:22:16.947967935 -0500
 Birth: -

 ~  % sudo tune2fs -l /dev/md3 | psp4                                  slave-iv
tune2fs 1.42.5 (29-Jul-2012)
Filesystem volume name:   home
Last mounted on:          /home
Filesystem UUID:          ab2e39fb-acdd-416a-9e10-b501498056de
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash 
Default mount options:    journal_data
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              59736064
Block count:              238920960
Reserved block count:     11946048
Free blocks:              34486248
Free inodes:              59610013
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      967
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
RAID stride:              128
RAID stripe width:        256
Flex block group size:    16
Filesystem created:       Mon May 31 20:36:30 2010
Last mount time:          Sat Oct  6 11:01:01 2012
Last write time:          Sat Oct  6 11:01:01 2012
Mount count:              14
Maximum mount count:      34
Last checked:             Tue Jul 10 08:26:37 2012
Check interval:           15552000 (6 months)
Next check after:         Sun Jan  6 07:26:37 2013
Lifetime writes:          7255 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:           256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
First orphan inode:       55313243
Default directory hash:   half_md4
Directory Hash Seed:      442c66e8-8b67-4a8c-92a6-2e2d0c220044
Journal backup:           inode blocks

¿Por qué mi ext4partición no llena este campo?

Respuestas:


93

El campo se llena (ver más abajo) solo coreutils statno lo muestra. Aparentemente están esperando 1 para la xstat()interfaz .

parches coreutils - aug. 2012 - TODO

stat (1) y ls (1) soporte para la hora de nacimiento. Depende de que xstat () sea proporcionado por el kernel

Puede obtener el tiempo de creación a través de debugfs:

debugfs -R 'stat <inode_number>' DEVICE

por ejemplo, para mi /etc/profileque está encendido /dev/sda2(vea Cómo averiguar en qué dispositivo está un archivo ):

stat -c% i / etc / profile
398264
debugfs -R 'stat <398264>' /dev/sda2
debugfs 1.42.5 (29-Jul-2012)
Inode: 398264   Type: regular    Mode:  0644   Flags: 0x80000
Generation: 2058737571    Version: 0x00000000:00000001
User:     0   Group:     0   Size: 562
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x506b860b:19fa3c34 -- Wed Oct  3 02:25:47 2012
 atime: 0x50476677:dcd84978 -- Wed Sep  5 16:49:27 2012
 mtime: 0x506b860b:19fa3c34 -- Wed Oct  3 02:25:47 2012
crtime: 0x50476677:dcd84978 -- Wed Sep  5 16:49:27 2012
Size of extra inode fields: 28
EXTENTS:
(0):3308774

1 respuesta de Linus en el hilo LKML


77
@Sparhawk: También tuve este problema con un archivo /home/user/path/to/fileporque /homeestaba en una partición separada. En ese caso, la ruta proporcionada statdebe ser relativa a /home. Ejemplo: sudo debugfs -R 'stat user/path/to/file' /dev/sda2. Para deshacernos del manejo de la ruta, podemos proporcionar statel número de inodo en lugar de la ruta:sudo debugfs -R "stat <$(stat -c %i /home/user/path/to/file)>" /dev/sda5
jpfleury

3
¿Se puede usar para obtener el tiempo de creación de archivos desde un sistema de archivos montado en red?
taranaki

1
Entonces, esta no es una marca de tiempo que va más allá de la creación del sistema de archivos. ¿Significa que si un archivo se creó hace 25 años y se copió a través de muchos sistemas físicos o montados diferentes, no hay forma de encontrar la información de la fecha de creación en ninguno de los metadatos? Entonces, ¿la única forma de saber cuándo se creó un archivo es escribirlo en el nombre del archivo? O dentro del contenido? ¿Hay alguna razón para esta no implementación aparentemente extraña?
sinekonata

2
Los metadatos del archivo @sinekonata dependen mucho del sistema (como muestra esta respuesta, cada capa del sistema operativo debe poder procesarlo) y mantenerlo entre copias entre máquinas depende del soporte para ese formato de metadatos por parte de ambos sistemas y la herramienta de copia. Lo que esto significa es: tienes suerte si incluso obtienes el nombre de archivo sin alteraciones. Alternativamente, algunos formatos de archivo le permiten insertar metadatos dentro del archivo (por ejemplo, ID3 ), y eso generalmente funciona bien, pero muchos formatos no tienen esa característica. Finalmente, puede poner el archivo dentro de un archivo como
André Paramés

1
Tenga en cuenta que se requieren <y >alrededor del número de inodo. A menudo se usan en ejemplos para rodear una variable que debe ajustarse, pero en este caso deben ingresarse literalmente. Sin ellos, el número de inodo se trata como una ruta y obtiene un File not found by ext2_lookuperror.
mivk

31

Combiné esto en una función de shell simple:

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
    }

Luego puedes ejecutarlo con

$ get_crtime foo foo/file /etc/
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014
/etc/   Wed Aug  1 20:42:03 2012

22

La xstatfunción nunca se fusionó con la línea principal. Sin embargo, statxmás adelante se propuso una nueva llamada , que se fusionó en Linux 4.11 . La nueva statx(2)llamada del sistema incluye un tiempo de creación en su estructura de retorno. Se statx(2)agregó un contenedor para glibc solo en 2.28 (lanzamiento en agosto de 2018) . Y se agregó soporte para usar este contenedor en GNU coreutils 8.31 (lanzado en marzo de 2019):

stat ahora imprime el tiempo de creación de archivos cuando es compatible con el sistema de archivos, en sistemas GNU Linux con glibc> = 2.28 y kernel> = 4.11.

% stat --version
stat (GNU coreutils) 8.31
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Michael Meskes.
% stat /
  File: /
  Size: 4096            Blocks: 8          IO Block: 4096   directory
Device: b302h/45826d    Inode: 2           Links: 17
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2019-06-06 20:03:12.898725626 +0900
Modify: 2019-05-28 05:15:44.452651395 +0900
Change: 2019-05-28 05:15:44.452651395 +0900
 Birth: 2018-06-07 20:35:54.000000000 +0900

Lo que sigue es una demostración de statxdonde userland aún tiene que ponerse al día (glibc o coreutils más antiguos). 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 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. (Si tiene un glibc lo suficientemente nuevo, no lo necesitará; puede usarlo statxdirectamente como se describe en man 2 statx).

Primero, clónalo:

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

Puede compilar el statx.ccódigo, o, si lo que desea el momento del nacimiento, crear una birth.cen el directorio clonado con el siguiente código (que es una versión mínima de statx.cimpresión sólo la fecha y hora de creación incluyendo 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 accesible en más sistemas de archivos que solo los ext * ( debugfses una herramienta para sistemas de archivos ext2 / 3/4, e inutilizable en otros). Funcionó para un sistema XFS, pero no para NTFS y exfat. Supongo que los sistemas de archivos FUSE para aquellos no incluyeron el tiempo de creación.


5

Hay otro caso en el que el tiempo de nacimiento estará vacío / cero / guión: el tamaño del Inode de Ext4 debe ser de al menos 256bytes para almacenar crtime. El problema se produce si inicialmente creó el sistema de archivos de menos de 512 MB (el tamaño predeterminado de Inode será de 128 bytes, ver /etc/mke2fs.confy página de mkfs.ext4manual).

stat -c '%n: %w' testfile
testfile: -  

y / o

stat -c '%n: %W' testfile
testfile: 0

Ahora verifique el inodo del sistema de archivos (¿es lo suficientemente grande como para almacenarlo crtime?):

tune2fs -l $(df . --output=source | grep ^/) | grep "Inode size:"
Inode size:           128

Información técnica: en la página Diseño de disco Ext4 , tenga en cuenta que algunos atributos de las tablas de inodo están más allá de 0x80 (128).


Correcto (recuerdo haber leído sobre esto en vger ). El límite de 512 MB se define en la mke2fs.clínea 1275
don_crissti

2

Por lo que vale, me sentía pedante, así que escribí un contenedor de bash alrededor de stat para admitir silenciosamente crtime usando debugfs para recuperarlo de un sistema de archivos ext4 subyacente si está disponible. Espero que sea robusto. Encuéntralo aquí .

Tenga en cuenta que una solución está aparentemente en la lista de tareas pendientes para Linux como se documenta en ese script. Por lo tanto, esta envoltura tiene una vida útil nominal solo hasta que se hace y es más un ejercicio de lo que se puede hacer.


3
Tenga en cuenta que xstat()finalmente se ha agregado a Linux, por lo que es solo cuestión de tiempo antes de la libc de GNU y findagregue soporte para ella.
Stéphane Chazelas

1
¡Increíble! Buenas noticias de hecho.
Bernd Wechner

66
Con disculpas por ser pedante, parece no entender el significado de "pedante".
Nick

"demasiado preocupado con detalles minuciosos o formalismos" - como en, la respuesta aceptada está bien, pero ... formalicémosla. ;-)
Bernd Wechner
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.