Australian cloud for business software — built and run in Sydney since 2003

NetLeverage
NetLeverage

File timestamps in backup and restore: mtime, ctime, atime and birth time on Linux

Technical article
Backup & Recovery

About this article: AI-assisted writing, reviewed against the cited sources. This is source research, not a lab validation of the procedures. Check the stated versions and your own recovery requirements before making changes.

Timestamps are the metadata people trust without thinking. An auditor asks when a spreadsheet last changed. A developer asks whether a configuration file is older than the incident. A sync job decides whether to copy a file by comparing its time with the copy's. After a restore, all of these questions get answers, and some of those answers are wrong.

This article concerns ordinary file-level restoration on Linux, not a block-image restore that may retain original inode records. Access and modification times can be set through standard interfaces; ctime is updated by inode changes rather than assigned a historical value. Birth-time support depends on the filesystem and tool. On top of that, the precision of a timestamp depends on the file system and on the backup format, so even a preserved time may come back slightly different.

This guide works through each timestamp from the Linux manual pages, then shows what rsync, GNU tar and cp do with them and what follows for audits, incremental backups and change detection.

Why it matters

Three practical problems come from timestamps that do not survive.

Evidence and audit. If restored files carry the restore date as their modification time, anyone relying on file dates to reconstruct events will be misled.

Incremental backups. Backup tools that select files by a timestamp will treat restored files as new or changed if that timestamp moved. A restore of a large folder can then be followed by an unexpectedly large backup.

Sync and change detection. rsync and similar tools compare times to decide what to copy. If times come back at a coarser precision, the next comparison may see differences that are not real, or miss ones that are.

How it works

The four timestamps

The inode(7) manual page defines them.

mtime, the last modification timestamp, "is changed by file modifications, for example, by mknod(2), truncate(2), utime(2), and write(2) (of more than zero bytes)." Importantly for directories, "the mtime timestamp of a directory is changed by the creation or deletion of files in that directory." And "The mtime timestamp is not changed for changes in owner, group, hard link count, or mode."

ctime, the last status change timestamp, "is changed by writing or by setting inode information (i.e., owner, group, link count, mode, etc.)." Despite the name, it is not a creation time.

atime, the last access timestamp, "is changed by file accesses, for example, by execve(2), mknod(2), pipe(2), utime(2), and read(2) (of more than zero bytes)." The page notes that "Some filesystem types allow mounting in such a way that file and/or directory accesses do not cause an update of the atime timestamp."

btime, the creation or birth timestamp, is "set on file creation and not changed subsequently." The page notes that birth time was not historically present on UNIX systems. Its broad statement about current filesystem prevalence is not a reliable inventory of modern support. The newer statx(2) interface reports it where available. Its manual warns that "the kernel may return fields that weren't requested and may fail to return fields that were requested, depending on what the backing filesystem supports."

What a restore tool can set

Tools set timestamps through system calls such as utimensat(2). utimensat(2) is precise about what that call changes: "times[0] specifies the new" access time and "times[1] specifies the new" modification time. Only atime and mtime can be supplied.

The same page states what happens to the third: "The status change time (ctime) will be set to the current time, even if the other time stamps don't actually change." Setting an old modification time normally updates ctime as well. The same page notes an exception when both requested values are UTIME_OMIT: the timestamps are not modified. There is no ordinary call that sets ctime to a chosen value (our reading of utimensat(2) and inode(7) together). A newly created or modified inode normally has a ctime reflecting those restore operations. Skipped existing files, later changes and block-level restores do not fit a universal restore-date rule.

Birth time cannot be set through utimensat either. It is set when the file is created, which on restore means when the restore created it (our reading of inode(7)). rsync has an option for it, --crtimes (-N), which "tells rsync to set the create times (newness) of the destination files to the same value as the source files." The manual adds the condition: "Your OS & filesystem must support the setting of arbitrary creation (birth) times for this option to be supported." Reading birth time through statx does not establish that it can be assigned during restore. If a tool creates a new inode without a supported birth-time setter, its birth time reflects creation of that inode; overwriting an existing inode may retain an older birth time. Check the actual restore method.

Precision

The inode(7) page explains resolution: "Nanosecond timestamps are supported on XFS, JFS, Btrfs, and ext4 (since Linux 2.6.23). Nanosecond timestamps are not supported in ext2, ext3, and Reiserfs." And "On filesystems that do not support subsecond timestamps, the nanosecond fields in the stat and statx structures are returned with the value 0."

When a tool sets a time on a coarser file system, utimensat(2) explains the rounding: "Updated file timestamps are set to the greatest value supported by the filesystem that is not greater than the specified time." In other words, times are truncated, never rounded up.

Backup formats have their own precision. The POSIX standard for the pax archive format describes the classic header field: "The mtime field shall be the modification time of the file at the time it was archived. It is the ISO/IEC 646:1991 standard representation of the octal value of the modification time obtained from the stat() function." That is an integer number of seconds. The extended pax header can carry more: its time value is a "decimal representation of the time in seconds since the Epoch. If a ('.') decimal point character is present, the digits to the right of the point shall represent the units of a subsecond timing granularity". On reading, "the pax utility shall truncate the time of a file to the greatest value that is not greater than the input header file time."

So a nanosecond timestamp on XFS, archived in a format that stores whole seconds, comes back with its fraction cut off. That rarely matters to people, but it matters to programs that compare times exactly.

Access time and reading for backup

A backup reads every file it copies, and reading can update atime. Since Linux 2.6.30 the default is gentler. The mount(8) manual's relatime entry says "Access time is only updated if the previous access time was earlier than or equal to the current modify or change time." and "Since Linux 2.6.30, the kernel defaults to the behavior provided by this option (unless noatime was specified)". The same relatime entry adds that access time is updated when it is more than one day old. With noatime, the system will "Do not update inode access times on this filesystem".

Tools have their own measures. rsync offers --open-noatime, which opens files "with the O_NOATIME flag (on systems that support it) to avoid changing the access time of the files that are being transferred." GNU tar has --atime-preserve, with a warning attached: "--atime-preserve=replace works on most systems, but it also restores the data modification time and updates the status change time. Hence it doesn’t interact with incremental dumps nicely". The option summary puts it more strongly: "on most platforms restoring the access time also updates the status change time, which means that this option is incompatible with incremental backups." The other method, --atime-preserve=system, "avoids changing the access time in the first place, if the operating system supports this."

Directory times

Because creating a file changes its directory's mtime, restoring files into a directory moves that directory's time unless the tool sets it afterwards (our reading of inode(7)). GNU tar has --delay-directory-restore, which will "Delay setting modification times and permissions of extracted directories until the end of extraction." rsync's --omit-dir-times (-O) does the opposite, telling rsync "to omit directories when it is preserving modification, access, and create times", and the manual advises it where "NFS is sharing the directories on the receiving side". Directory times are therefore a deliberate choice, not a default to assume.

What the common tools do

rsync. Modification times are preserved with --times (-t), included in -a. The manual explains why it matters for the next run: "a missing -t (or -a) will cause the next transfer to behave as if it used --ignore-times (-I), causing all files to be updated." Access times need --atimes (-U), which will "set the access (use) times of the destination files to the same value as the source files." Birth times need --crtimes (-N), with the support condition above. By default rsync uses a "quick check" that "checks if each file's size and time of last modification match between the sender and receiver."

Precision in that check is set by --modify-window. "The default is 0, which matches just integer seconds. If you specify a negative value (and the receiver is at least version 3.1.3, released January 2018) then nanoseconds will also be taken into account." For FAT targets, "Specifying 1 is useful for copies to/from MS Windows FAT filesystems, because FAT represents times with a 2-second resolution".

GNU tar. tar records modification times and restores them by default on extraction. The -m (--touch) option overrides that: tar "leaves the data modification times of the files it extracts as the times when the files were extracted, instead of setting it to the times recorded in the archive." When creating archives, --mtime makes tar "use date as the modification time of members when creating archives, instead of their actual modification times." Both are useful in their place and wrong in a restore whose times matter.

tar's time-based selection options show how selection depends on which time is used. --newer adds files "that have changed since date", while --newer-mtime selects by modification time rather than also considering status-change time. For files recreated or changed during restoration, a new ctime can cause status-based selection to include them again.

cp. GNU cp's --preserve=timestamps will "Preserve the times of last access and last modification, when possible." It names only access and modification times.

Selection by mtime is not content hashing. A program can change bytes and reset mtime; matching size and time likewise does not prove identical content. For audits, preserve provenance and independent logs because these timestamps are mutable records, not tamper-proof evidence.

A worked example

This is an illustration, not a measured case.

An accounting firm keeps client files on a Linux file server with XFS. A client folder of 40,000 files, about 300 GB, is damaged and is restored from a nightly archive in the classic tar format.

The restore is done carefully: modification times are restored, ownership is correct, and the folder looks the way it did. Three things are still different.

Assume this restore creates new inodes and does not set historical birth times. First, their birth times reflect those new creations. A staff member who checks creation dates for a compliance question sees that every document in the folder was apparently created the day of the restore.

Second, the recreated files' ctimes reflect the restore's inode operations. That night, the firm's backup job, which selects files by any status change, backs up all 300 GB again.

Third, the archive stored whole seconds, so the restored modification times have lost their fractions. If all 40,000 source mtimes had nonzero fractions, a sync job comparing nanoseconds against the retained original copy could report 40,000 time differences, despite identical contents. With rsync at its default --modify-window of 0, the same comparison would be at whole seconds and would see no timestamp difference, assuming the integer seconds and other compared attributes match.

None of this is a failure of the restore. It is what the system calls and formats allow. The firm's fix is to document it: record which times were preserved, recreated or subsequently changed; neither ctime nor birth time is a universal restoration audit log, plan for the large backup after a large restore, and make sure sync comparisons use a precision that both ends can hold.

A planning checklist

These are our recommendations, drawn from the sources above.

  1. Decide which timestamps matter for each data set: usually mtime; sometimes atime; occasionally birth time for compliance.
  2. Use a backup format that keeps the precision you need. Check whether your tool writes extended pax time records or whole seconds.
  3. Restore to a file system with at least the source's timestamp precision.
  4. With rsync, keep -t (or -a). Add -U only if access times matter, and -N only where the target supports birth times.
  5. Set rsync's --modify-window deliberately: 0 for whole seconds, negative for nanoseconds, 1 for FAT.
  6. With tar, avoid -m during extraction if original mtimes are required, and avoid overriding source mtimes with --mtime during archive creation. Decide on directory times explicitly.
  7. Be careful with tar's --atime-preserve=replace in any job that feeds incremental backups.
  8. Record the restoration method and expected ctime/birth-time effects. Preserve original timestamp metadata separately when historical evidence matters.
  9. Expect the next backup after a large restore to be large if it selects by status change. Plan the capacity.
  10. After a restore, spot-check times with a tool that shows full resolution, and compare against the source record.

Risks and limits

  • ctime has no ordinary historical setter here. This does not describe block-image restoration, skipped files or later inode changes.
  • Birth-time reporting and setting differ. Check statx support and the restore tool separately; this article does not inventory every kernel/filesystem combination.
  • Precision loss is silent. Truncation causes no error.
  • Clock problems. Time zones, clock skew between servers and dates far in the future or past are not covered here.
  • Scope. Windows and macOS timestamps, NTFS times seen through Linux drivers, and backup products with their own metadata stores were not researched.

Sources