上文围绕了普通文件I/O进行了讨论——打开文件、读文件或写文件。本文将描述文件系统的其他特征和文件的性质。将从stat函数开始,stat结构中的大多数成员都是基本系统数据类型,逐个分解stat结构的每一个成员以了解文件的所有属性。
使用stat函数最多的地方可能就是[ls -ls]命令,可以获得一个文件的全部信息。
本文主要讨论4个stat函数以及它们的返回信息。
struct stat
{
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* file type and mode */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond * precision for the following timestamp fields. * For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
#include
#include
#include
// return 0 or -1 if an error occurred.
int stat(const char* pathname, struct stat* buf);
int fstat(int fd, struct stat* buf);
int lstat(const char* pathname, struct stat* buf);
#include
#include
// return 0 or -1 if an error occurred.
int fstatat(int dirfd, const char* pathname, struct stat* buf, int flags);
一旦给出pathname,stat函数将返回与此文件有关的信息结构。fstat函数获得已在描述符fd上打开文件的有关信息。lstat函数类似于stat,但是当命名的文件是一个符号链接时,lstat返回该符号链接的有关信息,而不是由该符号链接引用的文件的信息。
fstatat函数为一个相对于当前打开目录(由fd参数指定)的路径名返回文件统计信息。flag参数控制着是否跟随着一个符号链接。当AT_SYMLINK_NOFOLLOW标志被设置时,fstatat不会跟随符号链接,而是返回符号链接本身的信息。如果fd参数的值是AT_FDCWD,并且pathname参数是一个相对路径名,fstatat会计算相对于当前目录的pathname参数;如果pathname参数是一个绝对路径,fd参数就会被忽略。这两种情况下,fstatat的作用就跟stat或lstat一样。
文件类型包含如下几种:
[1] 普通文件
[2] 目录文件
[3] 块特殊文件:提供对设备带缓冲的访问,每次访问以固定长度为单位进行
[4] 字符特殊文件:提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件
[5] FIFO:这种类型的文件用于进程间通信,有时也成为命名管道
[6] 套接字:这种类型的文件用于进程间的网路通信,也可用于在一台宿主机上进程之间的非网络通信
[7] 符号链接:这种类型的文件指向另一个文件
文件类型信息保存在stat结构的st_mode成员中,下表中的宏参数都是stat结构中st_mode成员的可取值。
宏 | 文件类型 |
---|---|
S_ISREG() | 普通文件 |
S_ISDIR() | 目录文件 |
S_ISCHR() | 字符特殊文件 |
S_ISBLK() | 块特殊文件 |
S_ISFIFO() | 管道或FIFO |
S_ISLNK() | 符号链接 |
S_ISSOCK() | 套接字 |
与一个进程相关联的ID有6个或更多,包括:
实际用户ID和实际组ID:标识我们究竟是谁;
有效用户ID、有效组ID和附属组ID:决定了我们的文件访问权限;
保存的设置用户ID和保存的设置组ID:在执行一个程序时包含了有效用户ID和有效组ID的副本。
通常:有效用户ID等于实际用户ID,有效组ID等于实际组ID。
每个文件有一个所有者和组所有者,所有者由stat结构中的st_uid指定,组所有者由st_gid指定。
设置用户ID位以及设置组ID位都包含在文件的st_mode值中,这两位可分别用常量S_ISUID和S_ISGID测试。
下面几个chown函数可用于更改文件的用户ID和组ID。
#include
// return 0 or -1 if an error occurred.
int chown(const char* path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char* path, uid_t owner, gid_t group);
#include
#include
// return 0 or -1 if an error occurred.
int fchownat(int dirfd, const char* pathname, uid_t owner, gid_t group, int flags);
除了所引用文件为符号链接外,这4个函数的操作类似。在符号链接情况下,lchown和fchownat(设置了AT_SYMLINK_NOFOLLOW标志)更改符号链接本身的所有者,而不是符号链接所指向的文件的所有者。
fchown函数改变fd参数指向的打开文件的所有者,既然它在一个已打开的文件上操作,就不能用于改变符号链接的所有者。
st_mode值也包含了对文件的访问权限位。当提及文件时,指的是前面所提到的任何类型的文件。所有文件类型都有访问权限。
每个文件有9个访问权限位,可分为三类。
st_mode屏蔽 | 含义 |
---|---|
S_IRUSR | 用户读 |
S_IWUSR | 用户写 |
S_IXUSR | 用户执行 |
S_IRGRP | 组读 |
S_IWGRP | 组写 |
S_IXGRP | 组执行 |
S_IROTH | 其他读 |
S_IWOTH | 其他写 |
S_IXOTH | 其他执行 |
chmod命令可以修改这9个权限位,用u表示用户,用g表示组,用o表示其他。
当用open函数打开一个文件时,内核以进程的有效用户ID和有效组ID为基础执行其访问权限测试。有时,进程也希望按其实际用户ID和实际组ID来测试其访问能力。
access和fassessat函数是按实际用户ID和实际组ID进行访问权限测试的。
#include
// return 0 or -1 if an error occurred.
int access(const char* pathname, int mode);
#include
#include
// return 0 or -1 if an error occurred.
int faccessat(int dirfd, const char* pathname, int mode, int flags);
测试文件是否存在,mode位F_OK;否则是下表所列常量的按位或
mode | 说明 |
---|---|
R_OK | 测试读权限 |
W_OK | 测试写权限 |
X_OK | 测试执行权限 |
flag参数可以用于改变faccessat的行为,如果flag设置位AT_EACCESS,访问检查用的时调用进程的有效用户ID和有效组ID,而不是实际用户ID和实际组ID。
#include
#include
// Always succeeds and return previous value of the mask.
mode_t umask(mode_t mask);
#include
// return 0 or -1 if an error occurred.
int chmod(const char* path, mode_t mode);
int fchmod(int fd, mode_t mode);
#include
#include
// return 0 or -1 if an error occurred.
int fchmodat(int dirfd, const char* pathname, mode_t mode, int flags);
chmod函数在指定的文件上进行操作。
fchmod函数对已打开的文件进行操作。
常量 | 说明 | 对普通文件的影响 | 对目录的影响 |
---|---|---|---|
S_ISUID | 设置ID | 执行时设置有效用户ID | 未使用 |
S_ISGID | 设置组ID | 若组执行位设置则执行设置有效组ID,否则使强制性锁起作用(若支持) | 将在目录中创建的新文件的组ID设置为目录的组ID |
S_ISVTX | 黏着位 | 在交换区缓存程序正文(若支持) | 限止在目录中删除和重命名文件 |
S_IRUSR | 用户读 | 许可用户读文件 | 许可用户读目录项 |
S_IWUSR | 用户写 | 许可用户读文件 | 许可用户在目录中删除和创建文件 |
S_IXUSR | 用户执行 | 许可用户读文件 | 许可用户在目录中搜索给定路径名 |
S_IRGRP | 组读 | 许可组读文件 | 许可组读目录项 |
S_IWGRP | 组写 | 许可组读文件 | 许可组在目录中删除和创建文件 |
S_IXGRP | 组执行 | 许可组读文件 | 许可组在目录中搜索给定路径名 |
S_IROTH | 其他读 | 许可其他读文件 | 许可其他读目录项 |
S_IWOTH | 其他写 | 许可其他读文件 | 许可其他在目录中删除和创建文件 |
S_IXOTN | 其他执行 | 许可其他读文件 | 许可其他在目录中搜索给定路径名 |
S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR
S_IRWXG = S_IRGRP | S_IWGRP | S_IXGRP
S_IRWXO = S_IROTH | S_IWOTH | S_IXOTH