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.