0

I wonder if there are ways to copy or restore crtime (creation time) for inodes/files/directories in Linux in 2020. I've accidentally deleted a folder while I still have a full disk backup, but neither cp -a, nor rsync can restore/copy files/directories crtimes.

I have found a way to achieve it using debugfs but it's super complicated and I need to automate it (I have hundreds of deleted files/directories).

For the source disk you do this:

# debugfs /dev/sdXX
# stat /path
Inode: 432772   Type: directory    Mode:  0700   Flags: 0x80000
Generation: 3810862225    Version: 0x00000000:00000006
User:  1000   Group:  1000   Project:     0   Size: 4096
File ACL: 0
Links: 5   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x5db96479:184bb16c -- Wed Oct 30 15:22:49 2019
 atime: 0x5b687c70:ee4dff18 -- Mon Aug  6 21:50:56 2018
 mtime: 0x5db96479:184bb16c -- Wed Oct 30 15:22:49 2019
crtime: 0x5b687c70:d35d1348 -- Mon Aug  6 21:50:56 2018
Size of extra inode fields: 32
Extended attributes:
  security.selinux (40)
EXTENTS:
(0):1737229

Remember the crtime, these are two fields, crtime_lo (yes, the first) and crtime_hi (the second)

Then for the destination disk you do this:

# debugfs -w /dev/sdYY
# set_inode_field /path crtime_lo 0x${1st_value_from_earlier}
# set_inode_field /path crtime_hi 0x${2nd_value_from_earlier}

Maybe there's something else I'm missing in the debugfs manual which could help me do that, so I'd be glad if people could help.

-f cmd_file surely seems like a nice way to start but still a little bit too difficult for me.

0
2

I've actually solved it on my own. You never know what you can do till you try :-)

It must be safe to run even when all the filesystems are mounted read-write.

#! /bin/bash

dsk_src=/dev/sdc4 # source disk with original timestamps
mnt_src=/mnt/sdc4 # source disk mounted at this path
dsk_dst=/dev/sda4 # destination disk
directory=user/.thunderbird # the leading slash _must_ be omitted

cd $mnt_src || exit 1

find $directory -depth | while read name; do
    read crtime_lo crtime_hi < <(debugfs -R "stat \"/$name\"" $dsk_src 2>/dev/null | awk '/crtime:/{print $2}' | sed 's/0x//;s/:/ /')

    echo "File: $name"
    echo "crtime_lo: $crtime_lo"
    echo "crtime_hi: $crtime_hi"

    debugfs -w $dsk_dst -R "set_inode_field \"/$name\" crtime_lo 0x$crtime_lo"
    debugfs -w $dsk_dst -R "set_inode_field \"/$name\" crtime_hi 0x$crtime_hi"
done

If people are interested I can adjust the script to allow to use it within one partition as well, e.g. after running cp -a. It's quite easy actually.

4
  • This works if you copy a disk and it does not look nice. It does not work when restoring a backup.
    – schily
    Jun 7 '20 at 17:30
  • Note that using debugfs -w is not safe to use on a mounted filesystem. This is modifying the blocks of the filesystem beneath the kernel, and can result in filesystem corruption (e.g. overwriting other inodes in the same block that may have been modified by the kernel). On the read side, you can use statx() with kernels > 3.10 (IIRC) to read the stx_btime (birth time) field, but there is no kernel interface for storing the crtime/btime on a live filesystem, nor are the ext4 maintainers interested to add one.
    – LustreOne
    Jun 8 '20 at 23:42
  • Using debugfs as shown above is OK for an unmounted filesystem, but using separate debugfs commands can become very inefficient as the filesystem grows large and reading all of the metadata takes a long time. Instead, to make the above more efficient, you can generate just the list of commands, like "echo set_inode_field $name crtime_lo 0x$crtime_lo" and then pipe the whole while loop into "debugfs -w -f /dev/stdin $dsk_dst" so that it runs all of the commands in a single invocation. You could also dump the commands to a file first, to review them before execution.
    – LustreOne
    Jun 8 '20 at 23:45
  • 1
    I haven't checked the kernel code but altering crtime on a mounted filesystem shouldn't be be an issue because you're editing existing inodes internal attributes (not deleting or creating them) which must be safe. I've also confirmed that applying them to over two hundred files haven't caused any issues as a e2fsck run was clean. Piping debugfs commands surely looks like a nice idea but I just needed a quick hack and it worked perfectly. Jun 9 '20 at 13:47
0

If you have a modern tar archive that includes all time stamps, you can do this with star -xp -ctime ... in case you call star as root.

Note that this leẗ́s star cause time storms and should not be done in a serious multi user mode.

See http://schilytools.sourceforge.net/man/man1/star.1.html for moreinformation.

9
  • It does it through the arse though. From the manual: If star is run as root and if -ctime is used with the extract command and the same archive formats, this causes star to try to restore even the ctime of a file by generating time storms. Jun 7 '20 at 15:56
  • Well, this is the only fs and OS independent method to do that job and it works with a backup....
    – schily
    Jun 7 '20 at 17:28
  • I agree however it only does the job with a relatively low precision. The script I wrote for Linux restores crtime with nanosecond precision. Jun 7 '20 at 18:53
  • The precision is better than microseconds if your OS is halfway decent. Note that this is 30 year old code and at that time many OS did not yet give better file time stamp resolution than seconds.
    – schily
    Jun 7 '20 at 20:47
  • 1
    @schily Perhaps it's a good time to add a Linux-specific code path to restore ctime to star!
    – FUZxxl
    Jun 12 '20 at 12:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.