stat.st_dev的陷阱

来源:互联网 发布:网络摄像头破解 编辑:程序博客网 时间:2024/05/14 17:22


最近在写一个跨平台的文件操作类,其中有一项是获得某目录所在磁盘的剩余空间大小。


在linux上我采用了如下实现:

1. 使用stat(path, &st1)获得该目录的属性,其中的st1.st_dev为该目录所在设备(磁盘)的设备号

2. 使用fp = setmntent(_PATH_MNTTAB) -> mnt = getmntent(fp) 枚举所有挂接点

3. 使用stat(mnt->mnt_fname, &st2)获得挂接设备的属性,其中的st2.st_rdev为该设备的设备号

4. 比较st1.st_dev和st2.st_rdev,如果相等则认为该目录属于设备mnt->mnt_fname

5. 使用statvfs(mnt->mnt_fname, &stfs)获得该设备的文件系统属性,剩余空间大小等于stfs.f_bsize * stfs.f_bavail


起初没有发现什么问题,但后来发现对于一些特殊目录,比如/dev、/proc等,stat函数取到的设备号是无效的数字,对于stat命令也是得到同样的结果。

如:

~$ stat /dev
  File: "/dev"
  Size: 4040            Blocks: 0          IO Block: 4096   目录
Device: 5h/5d   Inode: 4           Links: 17
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2012-09-28 00:22:24.627012017 +0800
Modify: 2012-09-28 00:18:54.207012002 +0800
Change: 2012-09-28 00:18:54.207012002 +0800


可以看到设备号居然是0:5(主设备号为0!),这显然很奇怪。

如是我找啊找,终于在man proc里面找到了:

       /proc/[pid]/mountinfo (since Linux 2.6.26)
              This file contains information about mount points.  It contains lines of the form:

              36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
              (1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)

              The numbers in parentheses are labels for the descriptions below:

              (1)  mount ID: unique identifier of the mount (may be reused after umount(2)).

              (2)  parent ID: ID of parent mount (or of self for the top of the mount tree).

              (3)  major:minor: value of st_dev for files on file system (see stat(2)).

于是我:

~$ cat /proc/self/mountinfo
14 19 0:14 / /sys rw,nosuid,nodev,noexec,relatime - sysfs none rw
15 19 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc none rw
16 19 0:5 / /dev rw,relatime - devtmpfs none rw,size=248400k,nr_inodes=62100,mode=755
17 16 0:11 / /dev/pts rw,nosuid,noexec,relatime - devpts none rw,gid=5,mode=620,ptmxmode=000
18 14 0:15 / /sys/fs/fuse/connections rw,relatime - fusectl fusectl rw


原因找到了。


不过最后我放弃了上述方案去获取磁盘剩余空间,而是直接使用statvfs(path, &stfs) -> stfs.f_bsize * stfs.f_bavail就可以了……

看来我绕了一个大圈,不过却也发现了stat.st_dev的一个潜在的陷阱。