在前面的两篇,我们了解了IO操作的一些基本操作函数,包括open、read和write。
在本篇我们来学习一下文件系统的其他特性和一个文件的属性,涉及的函数功能包括:
我们还会了解一些文件系统相关的数据结构和符号链接(symbolic link)。
1 函数stat、fstat、fstatat、lsat函数#include <sys/stat.h>int stat(const char *restrict pathname, struct stat *restrict buf );int fstat(int fd, struct stat *buf);int lstat(const char *restrict pathname, struct stat *restrict buf );int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);//All four return: 0 if OK, −1 on error
函数功能:
stat返回pathname指定文件的信息;
fstat获取在文件描述符fd上打开的文件信息;
lstat的功能和stat函数类似,只是有一种情况有区别,当pathname指定的文件是一个符号链接的时候,lstat函数获取的文件信息是该符号链接的信息,而不是符号链接所指向文件的信息,在后面我们会了解更多关于符号链接的相关内容;
fstatat:文件描述符fd表示一个父目录,pathame指定父目录下得一个子目录,fstatat函数返回该子目录下的文件统计数。flag用来设置是否查询符号链接所指向的文件,如果flag设置为AT_SYMLINK_NOFOLLOW,则fstatat函数只返回该符号链接的相关信息,如果不设置该标志位,则返回该符号链接指向的文件的相关信息。
是一个关键的输出参数,上面的参数将文件属性填充值该结构体内。结构体如下图所示:
结构体中得每个成员都代表文件的某一个属性,我们会逐个了解属性的具体含义。
2 文件类型(File Type)目前我们了解了两种文件:常规文件(regular files)和文件夹(directory)。
常见的几种文件类型包括:
stat结构体中得st_mode制定了文件的类型。
Example:
#include "apue.h"intmain(int argc, char *argv[]){ int i; struct stat buf; char *ptr; for (i = 1; i < argc; i++) { PRintf("%s: ", argv[i]); if (lstat(argv[i], &buf) < 0) { err_ret("lstat error"); continue; } if (S_ISREG(buf.st_mode)) ptr = "regular"; else if (S_ISDIR(buf.st_mode)) ptr = "directory"; else if (S_ISCHR(buf.st_mode)) ptr = "character special"; else if (S_ISBLK(buf.st_mode)) ptr = "block special"; else if (S_ISFIFO(buf.st_mode)) ptr = "fifo"; else if (S_ISLNK(buf.st_mode)) ptr = "symbolic link"; else if (S_ISSOCK(buf.st_mode)) ptr = "socket"; else ptr = "** unknown mode **"; printf("%s/n", ptr); } exit(0);}
运行截图:
3 设置用户Id(User ID)和组Id(Group ID)每个进程6个甚至更多的ID和它关联。如下表所示:
简要介绍ID的区别:
一般情况下,effective user ID = real user ID,effective group ID = real group ID.
每个文件都由一个所有者,和一个组所有者,分别对应stat数据结构中得字段:st_uid和st_gid。
如果执行程序时,希望effective user(group) ID != real user(group) ID,即希望改变进程的访问资源的权限为文件所有者的访问权限,而不是真实用户的访问权限,可以通过设置mode中两个bit来实现将effective user(group) ID设置为文件所有者(组),这两个bit叫做:set-user-ID位和set-group-ID位。这两个位包含在stat数据结构中得st_mode字段中,可以通过函数S_ISUID和S_ISGID来测试。
4 文件访问权限(File access Permissions)stat数据结构中的st_mode字段中同样包含文件访问权限位。
每个文件有9中权限位:
这些标志位的使用需要注意的事项总结如下:
文件访问权限检测流程:
简单来说,如果进程是该文件的拥有者,则访问是否允许取决于用户访问权限标志位,忽略组权限标志位;如果进程不是该文件的拥有者,但是该进程属于某个有访问权限的组,访问是否允许取决于组权限标志位的设置,忽略other访问权限标志位。
5 新文件和目录的所有权(ownership)新文件的real user ID为创建该文件的进程的effective user ID。
新文件的real group ID的取值取决于:
access和faccessat函数用于测试当前用户(real user,当前登录用户)对某一文件是否有某种操作权限。
函数声明:
#include <unistd.h>int access(const char* pathname, int mode);int faccessat(int fd, const char* pathname, int mode, int flag);
mode的可取值,当为F_OK,测试文件是否存在。
faccessat函数的相关细节:
Example:
#include "apue.h"#include <fcntl.h>intmain(int argc, char *argv[]){ if (argc != 2) err_quit("usage: a.out <pathname>"); if (access(argv[1], R_OK) < 0) err_ret("access error for %s", argv[1]); else printf("read access OK/n"); if (open(argv[1], O_RDONLY) < 0) err_ret("open error for %s", argv[1]); else printf("open for reading OK/n"); exit(0);}
测试:
由于本地mac环境搞不定,所以直接截书上的例子吧。
该例中,当切换到root用户,修改了该文件的所有者为root用户,并且设置了set-user-ID,这样当切换到别的用户时,仍可以以RDONLY方式打开文件,但是由于access是测试当前real user的读权限,当切换到其他用户时,access测试不通过,显示Permission denied。
好吧,直接忽略上面这个例子吧,我没能在自己的机器上重现,只是直接随便翻译书上某一段话。如果有某位高手看懂了,请指点。
小结由于这一章内容比较多,所以打算用三篇来写,这是第一篇,主要介绍了stat函数,access函数,文件类型和各种令人糊涂的ID。
参考资料:
《Advanced Programming in the UNIX Envinronment 3rd》
新闻热点
疑难解答