O nascimento está vazio no ext4

75

Eu estava lendo na seção Birth de stat e parece que o ext4 deve suportá-lo, mas mesmo um arquivo que acabei de criar o deixa vazio.

 ~  % 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 que minha partição ext4 não preenche este campo?

    
por xenoterracide 08.10.2012 / 05:48

5 respostas

81

O campo é preenchido (veja abaixo) apenas coreutils stat não o exibe. Aparentemente eles estão esperando 1 pelo xstat() interface .

patches do coreutils - ago. 2012 - TODO

stat(1) and ls(1) support for birth time. Dependent on xstat() being provided by the kernel

Você pode obter o horário de criação por meio de debugfs :

debugfs -R 'stat <inode_number>' DEVICE

por exemplo. para meu /etc/profile , que está em /dev/sda2 (consulte Como descobrir em qual dispositivo um arquivo está ):

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 Resposta do Linus em LKML discussão

    
por 08.10.2012 / 07:04
28

Combinei isso em uma função de shell simples:

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
    }

Você pode, então, executá-lo com

$ 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
    
por 21.05.2014 / 17:37
14

A função xstat nunca foi mesclada na linha principal. No entanto, uma nova chamada statx foi proposta mais tarde e era mesclado no Linux 4.11 . A nova chamada de sistema statx(2) inclui uma hora de criação em sua estrutura de retorno.

No entanto, o userland ainda precisa recuperar o atraso - não é fácil chamar chamadas do sistema diretamente em um programa em C. Normalmente, a glibc fornece um wrapper que facilita o trabalho, mas a glibc adicionou um wrapper para statx(2) apenas em 2.28 (lançamento em agosto de 2018) . Felizmente, @whotwagner escreveu um exemplo de programa em C que mostra como usar a chamada do sistema statx(2) em x86 e x86-64 sistemas. Sua saída é o mesmo formato que o padrão stat , sem nenhuma opção de formatação, mas é simples modificá-lo para imprimir apenas a hora de nascimento. (Se você tem um glibc novo o suficiente, você não precisará disso - você pode usar statx diretamente como descrito em man 2 statx ).

Primeiro, clone-o:

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

Você pode compilar o código statx.c ou, se desejar apenas a hora de nascimento, criar um birth.c no diretório clonado com o código a seguir (que é uma versão mínima de statx.c imprimindo apenas o timestamp de criação incluindo a precisão de nanossegundos):

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

Então:

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

Em teoria, isso deve tornar o tempo de criação acessível em mais sistemas de arquivos do que apenas os ext * ( debugfs é uma ferramenta para sistemas de arquivos ext2 / 3/4 e inutilizável em outros). Ele funcionou para um sistema XFS, mas não para NTFS e exfat. Eu acho que os sistemas de arquivos FUSE para aqueles não incluíram o tempo de criação.

Agora que a glibc tem suporte para a chamada do sistema statx(2) , stat seguirá em breve e poderemos usar o comando antigo stat para isso.

    
por 27.11.2017 / 16:24
3

Há outro caso em que o horário de nascimento estará vazio / zero / traço: o tamanho do Inode do Ext4 deve ser de pelo menos 256 bytes para armazenar crtime . O problema ocorre se você criou inicialmente o sistema de arquivos menor que 512MB (o tamanho padrão do Inode será 128 bytes, veja /etc/mke2fs.conf e mkfs.ext4 manpage).

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

e / ou

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

Agora verifique o inode do sistema de arquivos (é grande o suficiente para armazenar crtime ?):

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

Informações técnicas: na página Layout de disco Ext4 , observe que alguns atributos do inode as tabelas estão além de 0x80 (128).

    
por 27.03.2015 / 21:59
1

Por que vale a pena eu estava me sentindo pedante, então escrevi um wrapper em torno do stat para silenciosamente suportar o crtime usando o debugfs para buscá-lo a partir de um sistema de arquivos ext4 subjacente, se disponível. Eu espero que seja robusto. Encontre aqui:

link

Note que uma correção é ostensivamente na lista de tarefas para o Linux, conforme documentado no script. Portanto, este wrapper tem uma duração nominal apenas até que isso seja feito e é mais um exercício do que é factível.

    
por 03.06.2017 / 11:31