L'incapacità di stat
mostrare il tempo di creazione è dovuta alla limitazione della stat(2)
chiamata di sistema , la cui struttura di ritorno non includeva un campo per il tempo di creazione. A partire da Linux 4.11 (ovvero, 17.10 e successivi *), tuttavia, è disponibile la nuova statx(2)
chiamata di sistema , che include un tempo di creazione nella sua struttura di ritorno.
* E possibilmente su versioni precedenti di LTS usando i kernel HWE (Hardware Enablement Stack). Controlla uname -r
se stai usando un kernel almeno alla 4.11 per confermare.
Sfortunatamente, non è facile chiamare le chiamate di sistema direttamente in un programma C. In genere glibc fornisce un wrapper che semplifica il lavoro, ma glibc ha aggiunto un wrapper solo per statx(2)
agosto 2018 (versione 2.28 , disponibile in 18.10). Fortunatamente, @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 stat
predefinito, senza opzioni di formattazione, ma è semplice modificarlo per stampare solo il momento della nascita.
Innanzitutto, clonalo:
git clone https://github.com/whotwagner/statx-fun
Puoi compilare il statx.c
codice o, se vuoi solo l'ora di nascita, creare un birth.c
nella directory clonata con il seguente codice (che è una versione minima di statx.c
stampa 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 questo dovrebbe rendere il tempo di creazione più accessibile:
- dovrebbero essere supportati più filesystem di quelli ext * (
debugfs
è uno strumento per filesystem ext2 / 3/4, e inutilizzabile su altri)
- non hai bisogno di root per usare questo (tranne che per l'installazione di alcuni pacchetti richiesti, come
make
e linux-libc-dev
).
Test di un sistema xfs, ad esempio:
$ 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: -
Tuttavia, questo non ha funzionato per NTFS ed exfat. Immagino che i filesystem FUSE per quelli non includessero i tempi di creazione.
Se, o meglio quando, glibc aggiunge il supporto per la statx(2)
chiamata di sistema, stat
seguirà presto e saremo in grado di usare il semplice stat
comando precedente per questo. Ma non credo che questo verrà riportato nelle versioni LTS anche se ottengono kernel più recenti. Quindi, non mi aspetto che stat
su nessuna versione attuale di LTS (14.04, 16.04 o 18.04) venga mai stampato il tempo di creazione senza intervento manuale.
Su 18.10, tuttavia, è possibile utilizzare direttamente la statx
funzione come descritto in man 2 statx
(si noti che la manpage 18.10 non è corretta nell'affermare che glibc non ha ancora aggiunto il wrapper).