统调用stat/fstat:从i节点获得文件的状态信息
从i节点获得文件的状态信息
- stat得到指定路径名的文件的i节点
- fstat得到已打开文件的i节点
stat和fstat将数据放入调用者提供的stat结构中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(const char *pathname, struct stat *buf); int fstat(int fd, struct stat *buf); struct stat { dev_t st_dev; /* 存储该文件的块设备的设备号ID */ ino_t st_ino; /* inode号 */ mode_t st_mode; /* 访问权限及文件类型 */ nlink_t st_nlink; /* link数 */ uid_t st_uid; /* 文件主ID */ gid_t st_gid; /* 组ID */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* 文件大小(字节数)*/ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* 分配的512字节尺寸块个数 */ struct timespec st_atim; /* access时间 */ struct timespec st_mtim; /* modification时间 */ struct timespec st_ctim; /* change时间 */ };
|
结构体stat
st_dev:存储该文件的块设备的设备号,包括主设备号与次设备号
例如stat命令显示文件Device: 821h/2081d
十六进制0821,主设备号8(高字节),次设备号33(低字节), /dev/sdc1
1 2
| ls -l /dev | grep '^b.* 8, *33' brw-rw---- 1 root disk 8, 33 Nov 18 10:40 sdc1
|
st_mode域:16比特
文件的基本存取权限和SUID/SGID权限(11比特)以及文件的类型(若干比特)
文件类型判st_mode & S_IFMT
S_IFREG 普通磁盘文件
S_IFDIR 目录文件
S_IFCHR 字符设备文件
S_IFIFO 管道文件
S_IFLNK 符号连接文件
st_size与st_blocks
程序可以通过st_size获取文件大小。
一般情况:st_size ≤ st_blocks * 512
稀疏文件:st_size > st_blocks * 512
st_ctim,st_atim,st_mtim域
Linux中存储这三个时间的精度为纳秒
“a访问”:读,执行(有些系统为了效率做懒惰处理,不更新,但不早于m时间)
“m修改”:文件内容修改。写文件
“c改变”:i节点信息变化。写文件,修改权限/link数/文件主等(m变,c也变)
目录访问
早期的UNIX象普通磁盘文件那样open()打开目录read()读取
现在的系统不再这样操作,而是直接使用封装好的库函数
目录访问的一组库函数
1 2 3 4
| #include <dirent.h> DIR *opendir(char *dirname); struct dirent *readdir(DIR *dir); int closedir(DIR *dir);
|
opendir打开目录得到句柄(NULL表示失败)
readdir获取一个目录项
- 返回值指针指向的dirent结构体(返回NULL表示已经读到目录尾)
- dirent结构体:记录i节点号和文件名(d_ino和d_name成员)
访问结束:用closedir关闭不再使用的目录句柄。
目录访问程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h> #include <dirent.h> #include <errno.h> #include <stdlib.h>
int main(int argc, char *argv[]) { DIR *dir; struct dirent *entry; if (argc != 2) { fprintf(stderr, "Usage : %s <dirname>\n", argv[0]); exit(1); } if ((dir = opendir(argv[1])) == NULL) { printf("Open directory \"%s\": %s (ERROR %d)\n", argv[1], strerror(errno), errno); exit(1); } while ((entry = readdir(dir)) != NULL) printf("%d %s\n", entry->d_ino, entry->d_name); closedir(dir); }
|
运行效果:
1 2 3 4 5 6 7 8 9 10
| [root@localhost Linux命令风格;文件系统]# ./dir . 524351 . 524325 .. 524413 useEnv 524326 openfile 524446 useEnvC 524336 openfile.c 524346 dir 524353 dir.c [root@localhost Linux命令风格;文件系统]#
|
利用目录访问和stat调用来 编程构造自己的工具
- 目录访问:可以穷举一个目录中的所有项目,可得文件名及节点号
- stat调用:可以根据文件名获得文件i节点中的状态信息
由此,可以编程构造诸如ls, rm, find等类似的工具,并理解系统命令是如何实现的。