7
11
2018
14

Linux 下获取文件的创建时间

本文来自依云's Blog,转载请注明。

其实 Linux 是支持文件的创建时间的呢。不过不是所有文件系统都支持,比如 ext4、xfs、btrfs 都支持,zfs、vfat、ntfs 不支持。

但是呢,用户基本上是看不到的。文件系统有记录,但是没有 API 可以获取到这个数据。所以你用 stat 命令的话,会看到「创建时间」一行总是「-」。用 debugfs 搞 ext4 是可以的,但是那个需要 root 权限,并且一不小心会搞坏文件系统。

最近,我阅读内核源码时,忽然发现内核已经通过 4.11 版本引入的 statx 系统调用支持获取创建时间了。字段名里用的是 btime(birth time),没有用 crtime(creation time),也没有用大写的 Btime 呢。

但是 glibc 并没有支持,所以要用 syscall 函数来调用。也不是很复杂。不过我正着手用 Rust 实现的时候,却在内核源码树里找到了 samples/statx/test-statx.c 这么个文件。原来有现成的啊!

gcc 编译一下,还真好用:

>>> statx /
statx(/) = 0
results=fff
  Size: 224             Blocks: 0          IO Block: 4096    directory
Device: fe:01           Inode: 96          Links: 17
Access: (0755/drwxr-xr-x)  Uid:     0   Gid:     0
Access: 2018-07-11 13:33:08.659477830+0800
Modify: 2018-03-30 15:06:02.645864827+0800
Change: 2018-03-30 15:06:02.645864827+0800
 Birth: 2017-06-19 21:07:53.653467000+0800

2019年09月03日更新:现在(coreutils 8.31)stat 命令已经支持创建时间了。

Category: Linux | Tags: linux | Read Count: 18043
Yichao Yu 说:
Jul 11, 2018 07:02:11 PM

https://www.phoronix.com/scan.php?page=news_item&px=Glibc-Statx-Support

Avatar_small
依云 说:
Jul 12, 2018 12:27:49 AM

撒花~(本来想用 emoji 的,然后想起来这里的数据库是 MySQL……

tty 说:
Jul 12, 2018 05:37:37 AM

不会编译 - - 求指导!

Avatar_small
依云 说:
Jul 12, 2018 10:02:43 AM

gcc -O2 -o statx test-statx.c

TaoBeier 说:
Jul 13, 2018 11:29:50 AM

这样方便多了 我一直有这个需求都是 debugfs 来搞

x b y 说:
Jul 13, 2018 03:38:09 PM

好东西,本来想通过crtime来确定客户软件包的安装时间的,因为不知道搞定这个crtime,改用了yum的记录。。。
不过内核还是3.x的这个技术还是不能用。。。

布偶君 说:
Jul 14, 2018 04:29:03 PM

原来你还是没能在 2018 年摆脱 MySQL!
向你祈祷。

黑星 说:
Jul 22, 2018 03:28:44 PM

试着用rust包了一个, 这个只支持4.11+不太方便, 也不知道以后rust会不会标准库就封装它,干脆就把它扔 utils 里了, https://github.com/biluohc/utils/statx

黑星 说:
Jul 22, 2018 03:30:51 PM

https://github.com/biluohc/utils/tree/master/statx

Avatar_small
依云 说:
Jul 22, 2018 07:26:14 PM

呀,你也写了~
PS: 不需要写 C 代码的哦,直接 ffi 调用 syscall 也是可以的。另外,那个 args() 不用转成 String 的,可以直接交给底层用,以便处理乱码文件名。

黑星 说:
Aug 01, 2018 09:38:08 AM

谢谢指导了=_=

那个args确实应该直接使用,习惯性的转成String了,导致要来回倒格式,还有乱码问题。

不过这样写调用c就不用理会各种宏定义什么的了。

另外就是 syscall 的函数签名不清楚。
libc里封装的也有些奇妙,原来c支持变参啊。

[rustc] only foreign functions are allowed to be variadic

pub fn syscall(num: ::c_long, ...) -> ::c_long;

Avatar_small
依云 说:
Aug 01, 2018 09:45:13 AM

对啊,用 syscall 的时候,把参数依次传过去就可以了。C 里一大堆函数都是变参的呢,连 open 都是。那个路径我是直接:

let path: &OsStr = path.as_ref().as_ref();
let path = path.as_bytes().as_ptr();

然后就可以传给 C 用了。

不过这种搞法在非系统 API 上不好办。比如 API 接收一个 C++ 的 std::string,我只好 &str -> &CStr -> const char* -> std::string 这么转过去了。

yetone 说:
Oct 16, 2018 05:49:25 PM

把 charset 改成 utf8mb4 就支持 emoji 了(逃~


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com