学习APUE:第四章文件和目录

本文详细介绍了Linux系统中的文件状态函数如stat、lstat、fstatat,以及它们在获取文件信息、判断文件类型、权限管理和用户/组ID变更等方面的应用。同时讨论了SUID、SUID位、umask、access和chmod等概念及其在文件操作中的作用。
摘要由CSDN通过智能技术生成

本章主要围绕四个函数

struct stat 是一个存放文件状态的结构体

stat是基本的形式 传入文件名,将文件的状态存至buf

fstat 是文件描述符形式

lstat 针对于符号链接文件,返回符号链接有关信息,而不返回链接引用的文件信息

fstatat 比较复杂

参数说明:

  • dirfd:这是一个文件描述符,表示一个目录文件的引用。当dirfd设置为AT_FDCWD时,pathname参数会被解释为相对于当前工作目录的路径。如果pathname是一个绝对路径,那么dirfd参数会被忽略。
  • pathname:这是指向要查询的文件或目录的路径名的指针。
  • buf:这是一个指向stat结构体的指针,该结构体用于保存返回的文件状态信息。这包括文件的类型、权限、索引节点号、设备号、特殊文件的设备编号、链接数、用户ID、组ID以及文件大小等。
  • flag:这是一个标志,用于控制函数的行为。特别是,它决定是否应该跟随符号链接。如果flag设置为AT_SYMLINK_NOFOLLOW,那么fstatat将返回符号链接本身的信息,而不是它指向的文件的信息。

fstatat函数返回一个整数值,表示成功或失败。在成功的情况下,它返回0;在失败的情况下,它返回-1,并设置全局变量errno以指示错误原因。

总的来说,fstatat函数提供了一个灵活的方式来获取文件的状态信息,特别是当需要处理符号链接或相对于特定目录的路径时。

各种文件类型:

下面是一个用lstat函数判断文件类型的例子:

#include"apue.h"


int main(int argc,char *argv[])
{
    int i;
    struct stat buf;
    char *str;
    for (int i = 1; i < argc; i++)
    {
        if(lstat(argv[i],&buf)<0)
        {
            err_ret("lstat error");
            continue;    
        }

        if (S_ISREG(buf.st_mode))
        {
            str="regular";
        }
        else if(S_ISDIR(buf.st_mode))
        {
            str="directory";
        }
        else if (S_ISCHR(buf.st_mode))
        {
            str="character special";
        }
        else if(S_ISBLK(buf.st_mode))
        {
            str="block special";
        }
        else if(S_ISFIFO(buf.st_mode))
        {
            str="FIFO";
        }
        else if(S_ISSOCK(buf.st_mode))
        {
            str="socket";
        }
        else if (S_ISLNK(buf.st_mode))
        {
            str="symbolic link";
        }
        else
        {
            str="** unknown mode **";
        }
        printf("%s is %s\n",argv[i],str);

        
        
        
        
    }
    return 0;
    
}

PS:1.用了lstat而不用stat ,用stat观察不到符号链接

2.buf.st_mode文件模式字,其中有文件的类型信息。 用S_ISXXX来判断文件是否属于某种类型

对于实际用户和有效用户

进程执行时的有效用户和实际用户一般是相等的,由哪个用户执行进程,有效用户和实际用户就是哪个用户

但有的进程设置了SUID位:chmod u+s a.out

使得在执行进程时,有效用户变为了a.out的拥有者,而实际用户还是执行a.out的用户。

st_mode 

使得“当执行此文件时,将进程的有效ID设置为文件所有者的用户ID”——S_ISUID

或者 “当执行此文件时,将进程的有效组ID设置为文件所有者的组ID”——S_ISGID

st_mode还包含了对文件的访问权限位:

PS:相当于shell chmod指令的 u g o

几条规则:

1.用名字打开任意类型的文件,对该名字中包含的每一个目录要有执行权限

eg:为了打开/usr/include/stdio.h 则要对/ usr include具有执行权限

然后对于文件stdio.h也要有适当权限(取决于你想怎么打开它)

2.在目录中创建新文件 需要对目录有写和执行权限

3.要删除一个现有文件,需要对文件所在目录有写、执行权限,要对文件本身不需要有读、写权限

新文件和目录的所有权

新文件的组ID有两种选择:

1.进程的有效用户ID

2.所在目录的组ID

函数access和faccessat

使用场景:

一个进程使用设置用户ID或者设置组ID功能作为另一个用户运行时,判断实际用户能否访问一个给定的文件.

access函数的使用方法实例:

#include"apue.h"
#include<fcntl.h>
int main(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");

    return 0;
}

使用sar(非root用户)执行进程时,实际用户与有效用户均是sar

对于/etc/shadow 无论是access还是open都失败了

这里access是测试实际用户的权限,而open测试的是有效用户的权限

将a.out的所有者改成root 并执行chmod u+s后 为a.out设置了SUID位,这使得执行a.out时有效用户会变为root

切换为sar再次执行./a.out /etc/shadow 

此时实际用户为sar,有效用户为root

所以access(实际用户)失败了  而open(有效用户)成功了

umask函数

为进程设置文件模式创建屏蔽字,并返回之前的值(没有出错返回)

 进程创建文件后,文件的权限位是和umask设置的值和creat函数的mode值相与的结果

示例代码如下:

#include"apue.h"
#include<fcntl.h>
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) 
int main()
{
    umask(0);
    if(creat("foo",RWRWRW)<0)
    err_sys("creat error for foo");
    umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
    if(creat("bar",RWRWRW)<0)
    err_sys("creat error for bar");
    return 0;
}

注意:在创建新文件时,creat函数使用的权限(代码中为RWRWRW)并不是真正的文件权限,而是根据mode & ~umask计算出的权限值(先将umask取反后和mode按位与)。这意味着,即使你在creat函数中指定了特定的权限,新文件的实际权限还会受到之前通过umask设置的权限掩码的影响。

 对于foo umask为0  RW为 110 110 110

umask相当于屏蔽掉哪些为 umask为0 表示全不屏蔽,于是 最终的文件foo权限为110 110 110

对于bar umask为000 110 110 RW为110 110 110

最后生成的文件bar权限为 110 000 000

另外:在子进程中改变umask通常不改变父进程(通常为shell)的umask位

函数chmod、fchmod和fchmodat

用于更改现有文件的访问权限

chmod函数示例代码如下:

#include"apue.h"
int main()
{
    struct stat buf;
    if(stat("foo",&buf)<0)
        err_sys("stat error for foo");
    if(chmod("foo",(buf.st_mode&~S_IXGRP)|S_ISGID)<0)
        err_sys("chmod error for foo");
    if(chmod("bar",S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)<0)
        err_sys("chmod error for bar");
    return 0;
}

代码中去掉了foo的组执行权限并设置了SGUID位

为bar设置了用户写、用户读、其他人读的权限 

粘着位或称保存正文位——S_ISVTX

从两个方面来解释粘着位的定义:

对于文件来说,特别是可执行文件,如果设置了S_ISVTX位,那么当程序第一次被执行并终止时,程序的正文部分(即text段或代码段)的一个副本会被保存在交换区(swap分区)。由于交换区中的文件是连续存放的,而非交换区中的文件内容可能分散在磁盘的几个块中,因此,当程序再次被执行时,可以更快地将其正文部分从交换区加载到内存中,从而提高程序的启动速度

对于目录来说,如果设置了S_ISVTX位,那么只有对该目录具有写权限的用户,并且满足一定条件(如拥有该目录下的特定文件、拥有该目录本身或具有超级用户权限),才能删除或重命名该目录下的文件。这种特性有助于保护目录中的文件不被随意删除或重命名,特别是在多用户环境中。例如,在Linux系统中,/tmp和/var/tmp目录默认都设置了粘着位,这使得用户可以在/tmp目录下创建自己的文件,但无法删除或重命名其他用户的文件。

函数chown、fchown、fchownat、lchown

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

fchownat 根据选项来实现chown、lchwon的功能

 

 文件长度

stat结构成员st_size表示以字节为单位的文件长度

只对普通文件、目录文件、符号链接有意义。

普通文件范围 大于0字节

目录文件  通常是一个数的整数倍

符号链接 长度通常是文件名中的实际字节数

文件截断

函数link、linkat、unlink、unlinkat和remove

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值