1. 函数stat, fstat, fstatat, lstat

#include <sys/stat.h>
//成功返回0,失败返回-1.
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(const char *restrict pathname, struct stat *restrict buf, int flag);

【1】

  • stat将pathname路径文件的信息结构输出至buf。
  • fstat将已打开文件fd的信息结构输出至buf。
  • lstat将pathname表示的符号链接(指向另一文件)的信息结构输出至buf。
  • fstatat木有看懂 后面补。
    【2】buf的文件结构

2 文件类型

【1】UNIX常用几种文件类型:
(1)普通文件(regular file)
(2)目录文件(directory file):包含其他文件名字和指向 这些文件相关信息 的指针。
(3)块特殊文件(block special file):提供对设备带缓冲的访问,每次以固定长度为单位进行。
(4)字符特殊文件(character special file):提供对设备不带缓冲的访问,每次进行长度可变。
(5)套接字(socket):用于进程之间的网络通信或同一宿主机上进程的非网络通信。
(7)符号链接(symbolic link):指向另一文件。
【2】文件类型包含在stat结构的st_mode成员中,可用宏确认文件类型:

【3】一般直接用lstat,因为stat无法观察到符号链接。

3 设置用户ID和组ID

【1】进程ID包括至少6个:

  • 实际用户ID和实际组ID标识我们是谁,取自口令文件,仅通过超级用户可以改变。通常就是实际用户ID
  • 有效用户ID 有效组ID和附属组ID决定文件访问权限
  • 保存的设置用户ID和保存的设置组ID在执行程序时包含有效用户ID和有效组ID的副本。
    【2】设置用户ID位和设置组ID位都在st_mode中,可用S_ISUID和S_ISGID测试。

4. 文件访问权限

【1】所有类型的文件都有访问权限(而不是只有普通文件)。
【2】每个文件有9个访问权限位,可以分成3类:

st_mode屏蔽 屏蔽位 含义
S_IRWXU 0700 用户读写执行
S_IRUSR 0400 用户读
S_IWUSR 0200 用户写
S_IXUSR 0100 用户执行
S_IRWXG 0070 组读写执行
S_IRGRP 0040 组读
S_IWGRP 0020 组写
S_IXGRP 0010 组执行
S_IRWXO 0007 其他读写执行
S_IROTH 0004 其他读
S_IWOTH 0002 其他写
S_IXOTH 0001 其他执行

【3】用户指文件所有者(owner)。
【4】打开文件夹中的文件需要对当前文件夹有执行权限。
【5】为了在open函数对一个文件指定O_TRUNC标志,必须对该文件有写权限。
【6】为了创建新文件和删除文件,必须对对应目录有些权限和执行权限,而不需要对文件有权限。
【7】所有者ID是文件的性质,进程的有效ID和附属组ID是进程的性质。每次打开、创建和删除文件时,内核会以组的有效ID和有效组ID为基础对文件访问权限测试,过程如下:
①若进程的有效用户ID是0(超级用户),允许;
②若进程的有效用户ID等于文件的所有者ID(即进程拥有此文件),若所有者适当的访问权限位被设置(读操作则用户读应为1,写操作则用户写应为1,执行文件则用户执行位应为1),则允许访问。
③进程有效组ID或进程附属组ID之一等于文件的组ID,若适当的访问权限位被设置,则允许访问。
④其他用户适当的访问权限位被设置,则允许访问。
【8】文件访问权限就是 st_mode 位图中的低 9 位。

大家都知道,在 Linux 系统中文件的权限分为 3 个组:文件属主权限、文件属组权限、其它用户权限,而每个组又分为 4 种权限:读取®、写入(w)、执行(x)、无权(-)。

所以在使用 ls(1) -l 命令时可以得到类似 -rwx-r-xr-x 的权限标志,这个标志就是这样来的。

5 新文件与目录所有权

【1】新文件的组ID取决于它所在的目录的设置组ID位是否被设置。若设置,则新文件的组ID取决于目录的组ID,否则为进程的有效组ID。

6函数access和faccessat

【1】有时进程也希望按其实际用户ID和实际组ID来测试其访问能力。access和faccessat函数就是按实际用户ID和实际组ID进行访问权限测试的(测试过程与4【6】相同,仅仅是将有效换成实际)。

#include <unistd.h>
//成功返回0,失败返回-1
int access(const char *pathname, int mode);
int faccessat(int fd, const char *pathname, int mode, int flag);

【2】

mode 说明
F_OK 测试文件是否存在
R_OK 测试读权限
W_OK 测试写权限
X_OK 测试执行权限

【3】在pathnome为绝对路径 或者 fd取值为AT_FDCWD而pathname参数为相对路径 情况下,两个函数是相同的。 否则,faccessat计算相对于(fd参数指向的)打开目录的pathname。
【4】flag用来改变faccessat的行为。若为AT_EACCESS则检查用有效ID而非实际ID。
【5】chmod u+s [文件名],为文件增加用户(u)写(s)权限。

7. 函数umask

#include <sys/stat.h》
mode_t umask(mode_t cmask);

【1】参数cmask是由4-6列出的9个常量中的若干个或构成,open和creat的mode参数也如此。可以用按位或运算符指定多个模式:

st_mode屏蔽 屏蔽位 含义
S_IRWXU 0700 用户读写执行
S_IRUSR 0400 用户读
S_IWUSR 0200 用户写
S_IXUSR 0100 用户执行
S_IRWXG 0070 组读写执行
S_IRGRP 0040 组读
S_IWGRP 0020 组写
S_IXGRP 0010 组执行
S_IRWXO 0007 其他读写执行
S_IROTH 0004 其他读
S_IWOTH 0002 其他写
S_IXOTH 0001 其他执行

【2】cmask中的权限会被关闭;
【3】最终权限为 mode & ~umask。
【4】umask 值越大,权限越低。

8函数chmod、fchmod和fchmodat

这三个函数使我们可以更改先有文件的访问权限

#include<sys/stat.h>
//成功返回0,失败返回-1
int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
int fchmodat(int fd,const char *pathname, mode_t mode, int flag);

【1】chmod对指定文件进行操作
【2】fchmod对已打开的文件进行操作
【3】当pathname为绝对路径或fd取值为AT_FDCWD而pathname为相对路径时,fchmodat与chmod相同,否则fchmodat计算相对于(fd指向的)打开目录的pathname。
【4】当flag为AT_SYMLINK_NOFOLLOW时,fchmodat不跟随符号链接。
【5】进程的邮箱用户ID必须等于文件的所有者ID或拥有超级用户权限,才可以改变文件权限位。
【6】mode的文件访问权限位比4-6多6个,如下:

st_mode屏蔽 屏蔽位 含义
S_ISUID 执行时设置用户ID
S_ISGID 执行时设置组ID
S_ISVTX 保存正文(粘着位)
S_IRWXU 0700 用户读写执行
S_IRUSR 0400 用户读
S_IWUSR 0200 用户写
S_IXUSR 0100 用户执行
S_IRWXG 0070 组读写执行
S_IRGRP 0040 组读
S_IWGRP 0020 组写
S_IXGRP 0010 组执行
S_IRWXO 0007 其他读写执行
S_IROTH 0004 其他读
S_IWOTH 0002 其他写
S_IXOTH 0001 其他执行

举例使用:

if(stat("foo", &statbuf)<0)
	err_sys("stat error for foo")
//打开执行时设置组ID且关闭组执行
if(chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
	err_sys("chmod error for foo“)

【7】解释S_ISUID和S_ISGID: 默认情况下创建目录/文件时, 使用当前进程的gid 来设置目录和文件的属主,例如有目录/opt/tmp 其属组(不是属主) 为wwwgroup, 用户user1 对这个目录有写权限.
有进程以user1为EUID, group1 为EGUID运行, 在/opt/tmp/ 目录下创建了目录 dir1
则/opt/tmp/dir1 在默认情况下属组为group1
如果/opt/tmp 目录S_ISGID置位, 则上例中, 创建出来的目录/opt/tmp/dir1 属组为wwwgroup, 且S_ISGID 被置位.

9. 函数chown、fchown、fchownat和lchown(chown函数族)

以下函数用于更改文件的用户ID和组ID。函数之间的区别与之前基本相同,按照fun、ffun、ffunat、lfun规律。

#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
int fchown(int fd, uid owner, gid_t group);
int fchownat(int fd, const char *pathname, uid owner, gid_t group)😉
int lchown(onst char *pathname, uid_t owner, gid_t group);

【1】只能超级用户进程使用,普通用户不仅无法修改别人文件的所有者,也无权修改自己文件的所有者。(不确定?)

10. 文件长度

【1】stat结构中st_size以字节为单位,只对普通文件、目录文件和符号链接有意义。
【2】目录一般是一个数的整数倍,符号链接是文件名的实际字节数(如usr/lib为7)
【3】空洞是设置的偏移量超过文件尾端并写入数据造成的,文件长度依然是正常值(du -s查看),但显示所使用磁盘空间总量会较大(ls -l查看)。若实际程序复制这个文件,则空洞会被填满。