Birth is empty on ext4
The field gets populated (see below) only coreutils stat
does not display it. Apparently they're waiting1 for the xstat()
interface.
coreutils patches - aug. 2012 - TODO
stat(1) and ls(1) support for birth time. Dependent on xstat() being provided by the kernel
You can get the creation time via debugfs
:
debugfs -R 'stat <inode_number>' DEVICE
e.g. for my /etc/profile
which is on /dev/sda2
(see How to find out what device a file is on):
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
Time fields meaning:
ctime
: file change time.atime
: file access time.mtime
: file modification time.crtime
: file creation time.
1 Linus' reply on LKML thread
I combined this into a simple shell function:
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
}
You can then run it with
$ 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
The xstat
function never got merged into mainline. However, a new statx
call was proposed later on, and was merged in Linux 4.11. The new statx(2)
system call does include a creation time in its return struct. A wrapper for statx(2)
was added to glibc only in 2.28 (release August 2018). And support for using this wrapper was added in GNU coreutils 8.31 (released March 2019):
stat now prints file creation time when supported by the file system, on GNU Linux systems with glibc >= 2.28 and kernel >= 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
What follows is a demo of statx
where userland has yet to catch up (older glibc or coreutils). It's not easy to call system calls directly in a C program. Typically glibc provides a wrapper that makes the job easy, but Luckily, @whotwagner wrote a sample C program that shows how to use the statx(2)
system call on x86 and x86-64 systems. Its output is the same format as stat
's default, without any formatting options, but it's simple to modify it to print just the birth time. (If you have a new enough glibc, you won't need this - you can use statx
directly as described in man 2 statx
).
First, clone it:
git clone https://github.com/whotwagner/statx-fun
You can compile the statx.c
code, or, if you just want the birth time, create a birth.c
in the cloned directory with the following code (which is a minimal version of statx.c
printing just the creation timestamp including nanosecond precision):
#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;
}
Then:
$ make birth
$ ./birth ./birth.c
1511793291.254337149
$ ./birth ./birth.c | xargs -I {} date -d @{}
Mon Nov 27 14:34:51 UTC 2017
In theory this should make the creation time accessible on more filesystems than just the ext* ones (debugfs
is a tool for ext2/3/4 filesystems, and unusable on others). It did work for an XFS system, but not for NTFS and exfat. I guess the FUSE filesystems for those didn't include the creation time.