Narodziny są puste na ext4

83

Właśnie czytałem Birthsekcję stati wydaje się, że ext4 powinien ją obsługiwać, ale nawet plik, który właśnie utworzyłem, pozostawia pusty.

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

Dlaczego moja ext4partycja nie wypełnia tego pola?

ksenoterracid
źródło

Odpowiedzi:

93

Pole zostanie zapełnione (patrz poniżej) tylko coreutils statgo nie wyświetla. Najwyraźniej czekają 1 na xstat()interfejs .

łatki coreutils - sierpień. 2012 - DO ZROBIENIA

obsługa statystyk (1) i ls (1) dla czasu urodzenia. Zależy od xstat () dostarczanego przez jądro

Możesz uzyskać czas utworzenia poprzez debugfs:

debugfs -R 'stat <inode_number>' DEVICE

np. dla mojego, /etc/profilektóry jest włączony /dev/sda2(zobacz Jak dowiedzieć się, na jakim urządzeniu znajduje się plik ):

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 Odpowiedź Linusa w wątku LKML

don_crissti
źródło
7
@Sparhawk: Miałem też ten problem z plikiem, /home/user/path/to/fileponieważ /homebył na osobnej partycji. W takim przypadku podana ścieżka statmusi być względna /home. Przykład: sudo debugfs -R 'stat user/path/to/file' /dev/sda2. Aby pozbyć się obsługi ścieżki, możemy podać statnumer i-węzła zamiast ścieżki:sudo debugfs -R "stat <$(stat -c %i /home/user/path/to/file)>" /dev/sda5
jpfleury 17.04.2014
3
Czy można to wykorzystać, aby uzyskać czas tworzenia plików z podłączonego do sieci systemu plików?
taranaki,
1
Więc nie jest to znacznik czasu wykraczający poza stworzenie systemu plików. Oznacza to, że jeśli plik został utworzony 25 lat temu i skopiowany przez wiele różnych systemów fizycznych lub zamontowanych, w ogóle nie ma możliwości znalezienia informacji o dacie utworzenia w żadnej z metadanych? Więc jedynym sposobem, aby wiedzieć, kiedy plik został utworzony, jest wpisanie go w nazwie pliku? Lub w treści? Czy jest jakiś powód tego pozornie dziwnego braku wdrożenia?
sinekonata
2
Metadane pliku @sinekonata są bardzo zależne od systemu (jak pokazuje ta odpowiedź, każda warstwa systemu operacyjnego musi być w stanie je przetworzyć), a przechowywanie ich między kopiami między komputerami zależy od obsługi tego formatu metadanych przez oba systemy i narzędzie do kopiowania. Oznacza to, że: masz szczęście, jeśli nazwa pliku nie jest zniekształcona. Alternatywnie, niektóre formaty plików umożliwiają wstawianie metadanych wewnątrz pliku (np ID3 ), oraz że generalnie prowadzi dobrze, ale wiele formatów nie mają takiej funkcji. Na koniec możesz umieścić plik w pliku archiwum, takim jak
André Paramés
1
Należy pamiętać, że numer <i >-węzła są wymagane. Są one często używane w przykładach do otaczania zmiennej, którą należy dostosować, ale w tym przypadku należy je wprowadzić dosłownie. Bez nich numer i-węzła jest traktowany jako ścieżka i pojawia się File not found by ext2_lookupbłąd.
mivk
31

Połączyłem to w prostą funkcję powłoki:

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
    }

Następnie możesz go uruchomić

$ 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
terdon
źródło
22

xstatFunkcja nigdy nie połączyły się Mainline. Jednak nowe statxwywołanie zostało zaproponowane później i zostało połączone w Linuksie 4.11 . Nowe statx(2)wywołanie systemowe zawiera czas utworzenia w strukturze zwracanej. Opakowanie statx(2)zostało dodane do glibc dopiero w wersji 2.28 (wydanie sierpień 2018) . Wsparcie dla używania tego opakowania zostało dodane w GNU coreutils 8.31 (wydany w marcu 2019):

stat drukuje teraz czas tworzenia pliku, jeśli jest obsługiwany przez system plików, w systemach GNU Linux z glibc> = 2.28 i jądrem> = 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

Poniżej znajduje się demonstracja tego, statxgdzie użytkownik musi jeszcze nadrobić zaległości (starsze glibc lub coreutils). Nie jest łatwo wywoływać wywołania systemowe bezpośrednio w programie C. Zazwyczaj glibc zapewnia opakowanie, które ułatwia zadanie, ale na szczęście @whotwagner napisał przykładowy program C, który pokazuje, jak używać statx(2)wywołania systemowego w systemach x86 i x86-64. Jego format wyjściowy jest taki sam, jak statdomyślny, bez żadnych opcji formatowania, ale łatwo go zmodyfikować, aby wydrukować tylko datę urodzenia. (Jeśli masz wystarczająco dużo nowego glibc, nie będziesz go potrzebować - możesz użyć statxbezpośrednio zgodnie z opisem w man 2 statx).

Najpierw sklonuj:

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

Możesz skompilować statx.ckod lub, jeśli chcesz tylko czas urodzenia, utworzyć birth.cw sklonowanym katalogu następujący kod (który jest minimalną wersją statx.cdrukowania tylko znacznika czasu utworzenia, w tym precyzji nanosekundowej):

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

Następnie:

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

Teoretycznie powinno to uczynić czas tworzenia dostępnym na większej liczbie systemów plików niż tylko ext * ( debugfsjest narzędziem do systemów plików ext2 / 3/4 i nie nadaje się do użytku na innych). Działa dla systemu XFS, ale nie dla NTFS i exfat. Wydaje mi się, że systemy plików FUSE dla tych nie zawierały czasu utworzenia.

muru
źródło
5

Jest inny przypadek, w którym czas narodzin będzie pusty / zero / myślnik: rozmiar i-węzła Ext4 musi wynosić co najmniej 256 bajtów crtime. Problem występuje, jeśli początkowo utworzono system plików mniejszy niż 512 MB (domyślny rozmiar i-węzła to 128 bajtów, patrz /etc/mke2fs.confi strona mkfs.ext4podręcznika).

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

i / lub

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

Teraz sprawdź i-węzeł systemu plików (czy jest wystarczająco duży do przechowywania crtime?):

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

Informacje techniczne: Na stronie Układ dysku Ext4 zwróć uwagę, że niektóre atrybuty tabel i-węzłów przekraczają 0x80 (128).

Franklin Piat
źródło
Prawidłowo (pamiętam, że czytałem o tym na Vger ). Limit 512 MB jest zdefiniowany w mke2fs.clinii 1275
don_crissti
2

Dla tego, co warto, czułem się pedantyczny, więc napisałem bash otoki wokół statystyki, aby w milczeniu wspierać crime za pomocą debugfs, aby pobrać go z bazowego systemu plików ext4, jeśli jest dostępny. Mam nadzieję, że jest solidny. Znajdź je tutaj .

Zauważ, że poprawka znajduje się na liście rzeczy do zrobienia dla Linuksa, jak udokumentowano w tym skrypcie. Więc to opakowanie ma nominalną żywotność tylko do momentu, gdy zostanie to zrobione i jest bardziej ćwiczeniem w tym, co jest wykonalne.

Bernd Wechner
źródło
3
Zauważ, że xstat()ostatecznie został dodany do Linuksa, więc to tylko kwestia czasu, zanim GNU libc finddoda wsparcie dla niego.
Stéphane Chazelas,
1
Niesamowite! Rzeczywiście dobre wieści.
Bernd Wechner
6
Z przeprosinami za pedantyczne wydaje się, że nie rozumiesz znaczenia „pedantyczny”.
Nick
„nadmiernie zaniepokojony drobiazgowymi szczegółami lub formalizmami” - jak w tym przypadku, zaakceptowana odpowiedź jest w porządku, ale ... sformalizujmy ją. ;-)
Bernd Wechner,