fs.stat birthtime/birthtimeMs in Linux and MacOS

Viewed 820

One of the properties of the fs.Stats object that is returned when one calls fs.stat is birthtime and birthtimeMs, which I'm assuming is when the file was created.

Stats {
  dev: 2114,
  ino: 48064969,
  mode: 33188,
  nlink: 1,
  uid: 85,
  gid: 100,
  rdev: 0,
  size: 527,
  blksize: 4096,
  blocks: 8,
  atimeMs: 1318289051000.1,
  mtimeMs: 1318289051000.1,
  ctimeMs: 1318289051000.1,
  birthtimeMs: 1318289051000.1,              // this value
  atime: Mon, 10 Oct 2011 23:24:11 GMT,
  mtime: Mon, 10 Oct 2011 23:24:11 GMT,
  ctime: Mon, 10 Oct 2011 23:24:11 GMT,
  birthtime: Mon, 10 Oct 2011 23:24:11 GMT } // and this value all the way down here

I'm wondering whether or not birthtime and birthtimeMs is used and reliably returned in UNIX or Linux and MacOS environments?

1 Answers

I'm also curios about this question, so I did a little experiment on macOS and Linux. Here are my observations.

First, create the file:

touch foo

Check the times, birth time is the same as others, which is expected.

> const fs = require("fs")
undefined
> fs.statSync("foo")
Stats {
  ...
  atimeMs: 1643199913195.383,
  mtimeMs: 1643199913195.383,
  ctimeMs: 1643199913195.383,
  birthtimeMs: 1643199913195.383,
  atime: 2022-01-26T12:25:13.195Z,
  mtime: 2022-01-26T12:25:13.195Z,
  ctime: 2022-01-26T12:25:13.195Z,
  birthtime: 2022-01-26T12:25:13.195Z
}

Update the file by echo:

echo bar > foo

Check again, mtime and ctime is updated, birth time remains the same, so far so good.

> fs.statSync("foo")
Stats {
  ...
  atimeMs: 1643199913195.383,
  mtimeMs: 1643199961947.3816,
  ctimeMs: 1643199961947.3816,
  birthtimeMs: 1643199913195.383,
  atime: 2022-01-26T12:25:13.195Z,
  mtime: 2022-01-26T12:26:01.947Z,
  ctime: 2022-01-26T12:26:01.947Z,
  birthtime: 2022-01-26T12:25:13.195Z
}

Edit the file with vi, then check again, something unexpected happens:

> fs.statSync("foo")
Stats {
  ...
  atimeMs: 1643199990663.3806,
  mtimeMs: 1643199990663.3806,
  ctimeMs: 1643199990667.3806,
  birthtimeMs: 1643199990663.3806,
  atime: 2022-01-26T12:26:30.663Z,
  mtime: 2022-01-26T12:26:30.663Z,
  ctime: 2022-01-26T12:26:30.667Z,
  birthtime: 2022-01-26T12:26:30.663Z
}

The birth time and all other times are all updated, it seems that a new file is created! After a little digging, I found out that vim is actually always copy backup files back and forth by default, so the btime is tampered. After I set set backupcopy=yse as instructed, btime is no longer updated.

> fs.statSync("foo")
Stats {
  ...
  atimeMs: 1643201126739.3442,
  mtimeMs: 1643201129323.3442,
  ctimeMs: 1643201129327.3442,
  birthtimeMs: 1643200860799.3528,
  atime: 2022-01-26T12:45:26.739Z,
  mtime: 2022-01-26T12:45:29.323Z,
  ctime: 2022-01-26T12:45:29.327Z,
  birthtime: 2022-01-26T12:41:00.799Z  // not the same as other times
}

It seems that birthtime is stable on macOS Monterey and Ubuntu with 4.15 kernel. But programs like vim which are using backup files will break the functionality, be aware of that.

According to an answer here, btime was added in Linux 4.11.

Related