Tuesday, December 24, 2013

Birth date: getting the creation time of an ext4 file

The ext4 file system type stores the actual birth date/time of a file, unlike most other Linux file system types. Normally, one would expect that, using the stat system call, the corresponding stat command would be able to show this birth date.

Unfortunately, this is not the case, as illustrated next (see an earlier post for the code of devof). We use blkid to obtain the type of the file system stored on a device.

$ sudo blkid $(devof file)
/dev/sda2: UUID="bla-bla" TYPE="ext4"
$ stat --format="%w" file
-

It seems that the programs that can/should show a file's birth date are not yet updated. According to this stack exchange entry, only debugfs can currently be used to actually show the birth date.

$ ls -id file # get inode number of file
12061569 file 
$ sudo debugfs -R 'stat <12061569>' $(devof file)
Inode: 12061569   Type: regular    Mode:  0664   Flags: 0x80000
Generation: 2431365914    Version: 0x00000000:00000001
User:  1001   Group:  1001   Size: 551
File ACL: 0    Directory ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x52b9e4e6:597d4918 -- Tue Dec 24 20:47:50 2013
 atime: 0x52b9ebd9:429a6374 -- Tue Dec 24 21:17:29 2013
 mtime: 0x52b9e4e6:57950118 -- Tue Dec 24 20:47:50 2013
crtime: 0x52b9e049:977a1be0 -- Tue Dec 24 20:28:09 2013
Size of extra inode fields: 28
EXTENTS:
(0):27330211

The following lscrtime script shows the birth date for each argument file in such a form that is easy to sort.

#!/bin/bash
readonly USAGE="lscrtime file.."

function fatal() {
  echo "fatal error: $1" 2>&1; exit 1
}

for f
do
  [ -e "$f" ] || fatal "$f not a file";
  ff=$(readlink -f "$f") # follows symlink, yields full path
  inode=$(ls -di "$ff" | awk '{ print $1}')
  dev=$(devof "$ff")
  fstype=$(sudo blkid ${dev} | sed -e 's/.*TYPE="//' -e 's/".*//')

  [ "$fstype" == "ext4" ] || fatal "works only with ext4 FS"

  crtime=$(sudo debugfs -R "stat <${inode}>" $dev 2>/dev/null |
    grep 'crtime:' | sed -e 's/.*-- //'
    )
  birth=$(date --date="$crtime" +"%F %T") # yyy-mm-dd hh:mm:ss
  echo "$birth $f"
done

No comments:

Post a Comment