La nascita è vuota su ext4


83

Stavo solo leggendo la Birthsezione di state sembra che ext4 dovrebbe supportarlo, ma anche un file che ho appena creato lo lascia vuoto.

 ~  % 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

Perché la mia ext4partizione non popola questo campo?

Risposte:


93

Il campo viene popolato (vedi sotto) solo coreutils statnon lo visualizza. Apparentemente stanno aspettando 1 per l' xstat()interfaccia .

patch di coreutils - agosto 2012 - TODO

stat (1) e ls (1) supportano il tempo di nascita. Dipende da xstat () fornito dal kernel

Puoi ottenere il tempo di creazione tramite debugfs:

debugfs -R 'stat <inode_number>' DEVICE

ad es. per my /etc/profileche è acceso /dev/sda2(vedi Come scoprire su quale dispositivo si trova un file ):

stat -c% i / etc / profile
398.264
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 risposta di Linus sul thread LKML


7
@Sparhawk: ho avuto questo problema anche con un file /home/user/path/to/fileperché /homeera su una partizione separata. In tal caso, il percorso fornito statdeve essere relativo a /home. Esempio: sudo debugfs -R 'stat user/path/to/file' /dev/sda2. Per eliminare la gestione del percorso, possiamo fornire statil numero di inode anziché il percorso:sudo debugfs -R "stat <$(stat -c %i /home/user/path/to/file)>" /dev/sda5
jpfleury

3
Può essere usato per ottenere i tempi di creazione dei file da un filesystem montato in rete?
Taranaki,

1
Quindi questo non è un timestamp che va oltre la creazione del file system. Significa che se un file è stato creato 25 anni fa e copiato attraverso molti sistemi fisici o montati diversi, non c'è modo di trovare le informazioni sulla data di creazione in nessuno dei metadati? Quindi l'unico modo per sapere quando è stato creato un file è digitarlo nel nome del file? O all'interno del contenuto? C'è qualche motivo per questa non-implementazione apparentemente strana?
sinekonata

2
I metadati del file @sinekonata dipendono molto dal sistema (come mostra questa risposta, ogni livello del sistema operativo deve essere in grado di elaborarlo) e mantenerlo attraverso le copie tra le macchine si basa sul supporto per quel formato di metadati da parte di entrambi i sistemi e lo strumento di copia. Ciò significa che: sei fortunato se ottieni il nome del file non alterato. In alternativa, alcuni formati di file consentono di inserire metadati all'interno del file (ad es. ID3 ), e ciò generalmente ha buoni risultati, ma molti formati non dispongono di tale funzionalità. Infine, puoi inserire il file in un file di archivio come
André Paramés,

1
Si noti che sono richiesti il ​​numero di inode <e >intorno. Sono spesso usati negli esempi per circondare una variabile che dovrebbe essere regolata, ma in questo caso devono essere inseriti letteralmente. Senza di essi, il numero di inode viene trattato come un percorso e viene visualizzato un File not found by ext2_lookuperrore.
marzo

31

L'ho combinato in una semplice funzione shell:

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
    }

È quindi possibile eseguirlo 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 xstatfunzione non è mai stata unita alla linea principale. Tuttavia, una nuova statxchiamata è stata proposta in seguito ed è stata unita in Linux 4.11 . La nuova statx(2)chiamata di sistema include un tempo di creazione nella sua struttura di ritorno. Un wrapper per è statx(2)stato aggiunto a glibc solo in 2.28 (versione agosto 2018) . E il supporto per l'utilizzo di questo wrapper è stato aggiunto in GNU coreutils 8.31 (rilasciato a marzo 2019):

stat ora stampa il tempo di creazione del file quando supportato dal file system, su sistemi GNU Linux con glibc> = 2.28 e 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

Quella che segue è una demo di statxdove userland deve ancora recuperare (vecchi glibc o coreutils). Non è facile chiamare le chiamate di sistema direttamente in un programma C. Tipicamente glibc fornisce un wrapper che semplifica il lavoro, ma per fortuna @whotwagner ha scritto un programma C di esempio che mostra come utilizzare la statx(2)chiamata di sistema su sistemi x86 e x86-64. Il suo output ha lo stesso formato statpredefinito, senza opzioni di formattazione, ma è semplice modificarlo per stampare solo al momento della nascita. (Se hai un glibc abbastanza nuovo, non ti servirà - puoi usarlo statxdirettamente come descritto in man 2 statx).

Innanzitutto, clonalo:

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

Puoi compilare il statx.ccodice o, se vuoi solo l'ora di nascita, creare un birth.cnella directory clonata con il seguente codice (che è una versione minima di statx.cstampa solo il timestamp di creazione che include la precisione dei nanosecondi):

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

Poi:

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

In teoria, ciò dovrebbe rendere il tempo di creazione accessibile su più filesystem rispetto a quelli ext * ( debugfsè uno strumento per filesystem ext2 / 3/4 e inutilizzabile su altri). Ha funzionato per un sistema XFS, ma non per NTFS ed exfat. Suppongo che i filesystem FUSE per quelli non includessero i tempi di creazione.


5

C'è un altro caso in cui il tempo di nascita sarà vuoto / zero / trattino: la dimensione dell'Inodo di Ext4 deve essere di almeno 256 byte per essere memorizzata crtime. Il problema si verifica se inizialmente il file system è stato creato con dimensioni inferiori a 512 MB (la dimensione Inode predefinita sarà 128 byte, vedere /etc/mke2fs.confe mkfs.ext4manpage).

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

e / o

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

Ora controlla l'inode del filesystem (è abbastanza grande da memorizzare crtime?):

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

Informazioni tecniche: nella pagina Layout disco Ext4 , notare che alcuni attributi delle tabelle degli inode sono oltre 0x80 (128).


Corretto (ricordo di averlo letto su Vger ). Il limite di 512 MB è definito mke2fs.calla riga 1275
don_crissti il

2

Per quello che valeva mi sentivo pedante, quindi ho scritto un wrapper bash attorno a stat per supportare silenziosamente il crtime usando debugfs per recuperarlo da un filesystem ext4 sottostante se disponibile. Spero sia robusto. Lo trovi qui .

Nota che una correzione è apparentemente nell'elenco delle cose da fare per Linux come documentato in quello script. Quindi questo wrapper ha una durata nominale solo fino a quando non viene fatto ed è più un esercizio in ciò che è fattibile.


3
Nota che xstat()alla fine è stato aggiunto a Linux, quindi è solo una questione di tempo prima che GNU libc e findaggiunga supporto.
Stéphane Chazelas,

1
Eccezionale! Buone notizie davvero.
Bernd Wechner,

6
Con le scuse per essere pedante, sembra che tu non capisca il significato di "pedante".
Nick,

"eccessivamente preoccupato di piccoli dettagli o formalismi" - come in, la risposta accettata va bene, ma ... formalizziamola. ;-)
Bernd Wechner il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.