Como encontro o horário de criação de um arquivo?

61

Eu preciso encontrar o tempo de criação de um arquivo, quando eu li alguns artigos sobre este assunto, todos mencionaram que não há solução (como Site1 , Site2 ).

Quando tentei o comando stat , ele indica Birth: - .

Então, como posso encontrar o horário de criação de um arquivo?

    
por nux 21.05.2014 / 16:16

4 respostas

63

Existe uma maneira de saber a data de criação de um diretório, basta seguir estas etapas:

  1. Conheça o inode do diretório pelo comando ls -i (digamos, por exemplo, seu X )

  2. Saiba em qual partição seu diretório é salvo pelo comando df -T /path (digamos que esteja em /dev/sda1 )

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

Você verá na saída:

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

crtime é a data de criação do seu arquivo.

O que testei :

  1. Criamos um diretório em um horário específico.
  2. Acessado.
  3. Modificado, criando um arquivo.

  4. Eu tentei o comando e deu um horário exato.

  5. Então eu modifico e teste novamente, o crtime permaneceu o mesmo, mas modificar e acessar o tempo mudou.
por nux 21.05.2014 / 16:16
53

@Nux encontrou uma ótima solução para isso, o que você deve rever. Eu decidi escrever uma pequena função que pode ser usada para executar tudo diretamente. Basta adicionar isso ao seu ~/.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
}

Agora, você pode executar get_crtime para imprimir as datas de criação de quantos arquivos ou diretórios desejar:

$ get_crtime foo foo/file 
foo Wed May 21 17:11:08 2014
foo/file    Wed May 21 17:11:27 2014
    
por terdon 21.05.2014 / 17:29
9

A incapacidade de stat de mostrar o tempo de criação é devido à limitação do stat(2) system call , cuja estrutura de retorno não incluiu um campo para o tempo de criação. Começando com o Linux 4.11 (ie, 17.10 e mais recente *), no entanto, o novo statx(2) chamada de sistema está disponível, o que inclui uma hora de criação em sua estrutura de retorno.

* E possivelmente em versões mais antigas do LTS usando os kernels da pilha de ativação de hardware (HWE). Verifique uname -r para ver se você está usando um kernel pelo menos em 4.11 para confirmar.

Infelizmente, 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 apenas adicionou um wrapper para statx(2) em agosto de 2018 (versão 2.28 , disponível em 18.10). 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.

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 mais acessível:

  • mais sistemas de arquivos devem ser suportados do que apenas os ext * ( debugfs é uma ferramenta para sistemas de arquivos ext2 / 3/4 e inutilizável em outros)
  • você não precisa do root para usar isso (exceto para instalar alguns pacotes necessários, como make e linux-libc-dev ).

Testando um sistema xfs, por exemplo:

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

No entanto, isso não funcionou para NTFS e exfat. Eu acho que os sistemas de arquivos FUSE para aqueles não incluíram o tempo de criação.

Se, ou melhor, quando, a glibc adicionar suporte para a chamada do sistema statx(2) , stat seguirá em breve e poderemos usar o comando antigo stat para isso. Mas eu não acho que isso será backportado para as versões LTS, mesmo se eles tiverem novos kernels. Então, eu não espero que stat em qualquer versão atual do LTS (14.04, 16.04 ou 18.04) imprima o tempo de criação sem intervenção manual.

Em 18.10, no entanto, você pode usar diretamente a função statx , conforme descrito em man 2 statx (observe que a página do manual 18.10 está incorreta em afirmar que a glibc ainda não adicionou o wrapper).

    
por muru 27.11.2017 / 15:52
3

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

(Para descobrir seu fs, execute df -T /path/to/your/file , provavelmente será /dev/sda1 ).

Versão longa:

Vamos executar dois comandos:

  1. Descubra o nome do nome da partição para o seu arquivo.

    df -T /path/to/your/file
    

    A saída ficará assim (o nome da partição é o primeiro):

    Filesystem     Type 1K-blocks    Used Available Use% Mounted on
    /dev/<your fs> ext4   7251432 3481272   3509836  50% /
    
  2. Descubra o horário de criação desse arquivo.

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

    Na saída, procure ctime .

por Lukasz Czerwinski 14.01.2016 / 21:19