[UNIX环境高级编程] 文件和目录

1 引言

上文围绕了普通文件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一样。

2 文件类型

文件类型包含如下几种:
[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() 套接字

3 文件ID和组ID

3.1 设置用户ID和设置组ID

与一个进程相关联的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测试。

3.2 更改文件的用户ID和组ID

下面几个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参数指向的打开文件的所有者,既然它在一个已打开的文件上操作,就不能用于改变符号链接的所有者。

4 文件访问权限

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表示其他。

4.1 访问权限测试

当用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。

4.2 为进程设置文件模式创建屏蔽字

#include 
#include 
// Always succeeds and return previous value of the mask.
mode_t umask(mode_t mask);

4.3 更改现有文件的访问权限

#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函数对已打开的文件进行操作。

4.4 文件访问权限小结

常量 说明 对普通文件的影响 对目录的影响
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

文件系统

符号链接

文件时间

目录

设备特殊文件

你可能感兴趣的:(UNIX环境高级编程读书笔记)