从0开始啃APUE-----------文件和目录

第4章 文件和目录

4.1 函数stat、fstat、fstatat和lstat

#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);
//restrict关键字:*pathname中的内容只能由指针pathname修改,其他指向该内存的指针均为无效指针
//返回值:成功,返回0;失败,返回-1
  • stat函数将返回与pathname有关的信息结构。
  • fstat函数获得在描述符fd上打开的文件信息
  • lstat与stat类似,区别只在pathname是符号链接时,lstat返回符号链接信息而不是符号链接所引用的文件信息
  • fstatat幻术为一个相对于当前打开目录的路径名返回文件信息,flag控制是否跟随符号链接
//stat结构体
struct stat{
	mode_t				st_mode;
	ino_t				st_ino;
	dev_t				st_dev;
	dev_t				st_rdev;
	nlink_t				st_nlink;
	uid_t				st_uid;
	gid_t				st_gid;
	off_t				st_size;
	struct timespec		 st_atime;
	struct timespce		 st_mtime;
	struct timespce		 st_ctime;
	blksize_t			st_blksize;
    blkcnt_t			 st_blocks;
};

4.2 文件类型

  1. 普通文件。
  2. 目录文件。包含其他文件名以及指向这些文件有关信息的指针。内核才能直接写目录文件,进程只能更改目录。
  3. 块特殊文件。提供对设备带固定字长缓冲的访问。
  4. 字符特殊文件。提供对设备不带缓冲的访问,访问长度可变。
  5. FIFO。用于进程间通信。
  6. 套接字。用于进程间网络通信。
  7. 符号链接。指向另一个文件。

文件类型信息存储在stat结构体中的st_mode成员

S_ISREG() -> 普通文件
S_ISDIR() -> 目录文件
S_ISCHR() -> 字符特殊文件
S_ISBLK() -> 块特殊文件
S_ISFIFO() -> FIFO
S_ISLNK() -> 符号链接
S_ISSOCK() -> 套接字

4.3 文件访问权限

st_mode还包含了文件访问权限位。

S_IRUSR -> 用户读
S_IWUSR -> 用户写
S_IXUSR -> 用户执行
S_IRGRP -> 组读
S_IWGRP -> 组写
S_IXGRP -> 组执行
S_IROTH -> 其他读
S_IWOTH -> 其他写
S_IXOTH -> 其他执行

规则

  • 用名字打开目录时对该目录下包含的每一目录都应具有执行权限
  • 对文件的读权限与写权限决定了能否对该文件进行读写操作
  • 在目录中创建新文件要求对该目录具有写权限与执行权限
  • 删除现有文件要求对该文件有写权限和执行权限
  • 用exec执行文件要求具有执行权限

进程每次打开、创建或删除文件时,内核会进行文件访问权限测试。

  1. 若进程用户ID为0(超级用户),则允许访问。
  2. 若进程有效用户ID等于文件所有者ID(即进程拥有此文件),则用户位的设置对应进程对此文件的操作权限。
  3. 若进程的有效组ID或进程的附属组ID之一等于文件组ID,则组位的设置对应此文件操作权限。
  4. 若其他用户访问位被设置,则允许访问,否则不允许访问。

以上4步顺序执行。

4.4 新文件和目录的所有权

新文件的用户ID设置为进程有效用户ID,组ID可以是进程有效组ID,也可以是它所在目录的组ID。

4.5 函数access和faccessat

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

access和faccessat函数的作用是按实际用户ID和实际组ID进行权限访问测试。

如果测试文件存在

mode位设置为F_OK

否则

mode位为以下常量按位或

R_OK -> 测试读权限

W_OK -> 测试写权限

X_OK -> 测试执行权限

4.6 函数umask

#include <sys/stat.h>
mode_t umask(mode_t cmask);
//返回值:之前文件模式创建屏蔽字

umask为进程设置文件模式创建屏蔽字,并返回之前值。

其中cmask是9个文件访问权限位中若干个按位或构成的。

用户可以设置umask值来控制所创建文件的默认权限。

4.7 函数chmod、fchmod和fchmodat

#include <sys/stat.h>
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);
//返回值:成功,为0;失败,为-1.

chmod在指定文件上进行操作,而fchmod对已打开的文件进行操作。

改变文件的权限位,要求进程的有效用户ID等于文件所有者ID,或者该进程具有超级用户权限。

4.8 粘着位

如果一个可执行程序文件被设置了粘着位,当程序第一次被执行时,其终止时,程序正文部分的一个副本将被保存在交换区内,这使得下次执行该程序时能够较快的将其载入内存。

现在的系统扩展了粘着位的使用范围,允许针对目录进行粘着位,但是必须满足如下条件之一:

  1. 拥有此文件
  2. 拥有此目录
  3. 是超级用户

4.9 函数chown、fchown、fchownat和lchown

#include <unistd.h>
int chown(const char* pathname, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int fchownat(int fd, const char* pathname, uid_t owner, gid_t group, int flag);
int lchown(const char* pathname, uid_t owner, gid_t group);
//返回值:成功,返回0;失败,返回-1

以上几个chown用于更改文件的用户ID和组ID,如果owner和group中任意一个为-1则对应的ID不变。

如果所引用文件为符号链接文件,则lchown和fchownat更改符号链接本身而不是该链接指向的文件。

4.10 文件长度

stat结构成员st_size表示以字节为单位的文件长度。此字段只针对普通文件、目录和符号链接有意义。

对于符号链接来说,文件长度是在文件名中的实际字数。

4.11 文件截断

#include <unistd.h>
int truncate(const char* pathname, off_t length);
int ftruncate(int fd, off_t length);
//返回值:成功,返回0;失败,返回-1

以上两个函数将一个现有文件截断为length长度。

4.12 文件系统

在这里插入图片描述

一个分区包含一个文件系统

在这里插入图片描述

  • 上图中两个目录项指向同一个i节点,每个i节点中都有一个计数器,记录指向i节点的目录数,当计数减少至0时方可删除该文件。在stat结构中,链接计数包含在st_nlink成员中,基本数据类型为nlink_t,此种链接成为硬链接。
  • 对应的另一种链接类型为符号链接,符号链接文件的实际内容为该符号链接所指向的文件的名字
  • i节点中包含了与文件相关的全部信息包括:文件类型、文件访问权限位、文件长度和指向文件数据块的指针;而文件名和i节点编号则存放在目录项中
  • 目录项中的i节点编号指向同一文件系统中相应的i节点,一个目录项不能指向另一个文件系统的i节点
  • 在不更改文件系统的情况下为文件重命名,只需要构造一个指向现有i节点的新目录项,然后删除老目录项即可

4.13 函数link、linkat、unlink、unlinkat和remove

#include <unistd.h>
int link(const char* existingpath, const char* newpath);
int linkat(int efd, const char* existingpath, int nfd, const char* newpath, int flag);
//返回值:成功,返回0;失败,返回-1

这两个函数创建一个新目录项newpath,引用现有文件existingpath,如果newpath已经存在则报错。

注意:只创建newpath中的最后一个分量,路径中的其他部分应该已经存在。

创建新目录项和增加链接计数应该是一个原子操作。

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

以上两个函数用于删除现有目录项,但必须对包含该目录项的目录具有写和执行权限。

只有当链接计数为0时才能删除文件内容。只要有进程打开该文件,其内容就无法删除。

关闭一个文件时,内核首先检查打开该文件的进程个数;如果计数为0,内核检查其链接计数;如果计数也为0,则删除该文件内容。

利用此特性可以创建临时文件,即进程open一个文件,然后立即调用unlink,当进程终止或者关闭该文件时,文件即被删除。unlink无法删除符号链接所引用的文件。

#include <stdio.h>
int remove(const char* pathname);
//返回值:成功,返回0;失败,返回-1

remove函数也可以解除一个文件或者目录的链接。

4.14 符号链接

硬链接直接指向文件的i节点,但是硬链接有其自身的一些限制

  • 硬链接通常要求链接和文件处在同一个文件系统
  • 只有超级用户才能创建指向目录的硬链接

符号链接则没有以上两种限制。

4.15 创建和读取符号链接

#include <unistd.h>
int symlink(const char* actualpath, const char* sympath);
int symlinkat(const char* actualpath, int fd, const char* sympath);
//返回值:成功,返回0;失败,返回-1

函数创建一个指向actualpath的新目录项sympath,创建此符号链接并不要求actualpath已存在。

#include <unistd.h>
ssize_t readlink(const char* restrict pathname, char* restrict buf, size_t bufsize);
ssize_t readlinkat(int fd, constchar* restrict pathname, char* restrict buf, size_t bufsize);
//返回值:成功,返回读取字节数;失败,返回-1

如果函数成功执行,返回读入buf的字节数。

4.16 文件的时间

  • atime–文件数据最后访问时间 read
  • mtime–文件数据最后修改时间 write
  • ctime–i节点状态最后更改时间 chmod、chown
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值