《UNIX环境高级编程》笔记 第四章-文件和目录

本文详细介绍了UNIX环境下对文件和目录的各种操作,包括stat、fstat等函数的使用,文件类型如普通文件、目录、特殊文件等,以及文件访问权限、新文件所有权、umask、chmod等函数。此外,还涵盖了符号链接、文件时间、目录操作如mkdir、rmdir以及读取目录项等。通过对这些概念和函数的讲解,深入理解了UNIX系统中文件和目录管理的核心内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 函数stat、fstat、fstatat和lstat

返回指定文件信息

int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
int fstatat(int dirfd, const char *pathname, struct stat *statbuf, int flags);
  • stat函数返回pathname指定的文件信息,并保存在statbuf参数中

  • fstat函数与stat类似,只是通过文件描述符fd标识文件

  • lstat与stat类似,只是当pathname是符号链接时,获得的是符号链接文件本身信息,而不是符号链接指向的文件信息

  • fstatat中,如果pathname是一个绝对路径名,则dirfd参数忽略;如果pathname是一个相对路径名,则dirfd表示该相对路径的起始地址(即dirfd为打开目录文件的文件描述符);如果dirfd设置为AT_FDCWD,则相对路径的起始地址为该进程工作目录。flags参数设置为AT_SYMLINK_NOFOLLOW时,fstatat不会跟随符号链接,而是返回符号链接文件本身信息。

    # define AT_SYMLINK_NOFOLLOW	0x100	/* Do not follow symbolic links.  */
    

struct stat结构体保存了文件的各种信息,以上一个函数均把文件信息保存在该结构体中:

struct stat {
   
    dev_t     st_dev;         /* 文件系统设备号 */
    ino_t     st_ino;         /* inode number */
    mode_t    st_mode;        /* 文件类型和访问权限 */
    nlink_t   st_nlink;       /* 硬链接个数 */
    uid_t     st_uid;         /* 所有者uid */
    gid_t     st_gid;         /* 所有者gid */
    dev_t     st_rdev;        /* 特殊文件(块、字符特殊文件)的实际设备号 */
    off_t     st_size;        /* 文件大小(字节) */
    blksize_t st_blksize;     /* 对文件I/O较合适的块长度 */
    blkcnt_t  st_blocks;      /* 该文件分配的512字节块的数量 */

    struct timespec st_atim;  /* 文件数据最近访问时间 */
    struct timespec st_mtim;  /* 文件数据最近修改时间 */
    struct timespec st_ctim;  /* inode节点状态最近改变时间 */

    #define st_atime st_atim.tv_sec      /* Backward compatibility */
    #define st_mtime st_mtim.tv_sec
    #define st_ctime st_ctim.tv_sec
};

其中timespec结构体按照秒和纳秒定义了时间

struct timespec {
   
	__kernel_time_t	tv_sec;			/* 秒 */
	long		tv_nsec;		/* 纳秒 */
};

2. 文件类型

UNIX系统大多数文件都是普通文件或目录,但也有一些其他文件类型。

文件信息保存在stat结构体的st_mode成员中

2.1 普通文件(regular file)

最常用的文件类型,这种文件包含了某种形式的数据。至于这些数据是文本还是二进制数据,对UNIX内核而言并无区别。

2.2 目录文件(directory file)

这种文件包含了其他文件的名字以及指向与这些文件有关信息的指针。对一个目录文件具有读权限的任意进程都可以读该目录的内容,但是只有内核可以直接写目录文件。

2.3 块特殊文件(block special file)

提供对设备(如磁带)带缓冲的访问,每次访问以固定长度为单位进行。

2.4 字符特殊文件(character special file)

提供对设备不带缓冲的访问,每次访问长度可变。系统中的所有设备要么是字符特殊文件,要么是块特殊文件

2.5 FIFO

这种类型的文件用于进程间通信,有时也称为命名管道

2.6 套接字(socket)

这种类型的文件用于进程间的网络通信,也可以用于在一台宿主机上进程间的非网络通信。

2.7 符号链接(symbolic link)

这种类型文件指向另一个文件,类似于快捷方式。

2.8 文件类型判断

通过stat系统调用获得的文件信息(stat结构体对象)中的st_mode成员,该成员保存了文件类型信息和访问权限。可以通过以下宏判断文件类型

文件类型
S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊文件
S_ISBLK() 块特殊文件
S_ISFIFO() 管道或FIFO
S_ISLNK() 符号链接
S_ISSOCK() 套接字

例子:判断文件类型

int main(int argc, char* argv[]) {
   
    struct stat st;
    stat(argv[1],&st);
    if(S_ISREG(st.st_mode)) {
   
        cout << "普通文件" << endl;
    } else if(S_ISDIR(st.st_mode)) {
   
        cout << "目录文件" << endl;
    } else {
   
        cout << "其他文件" << endl;
    }
}
$ ./a.out  t.txt 
> 普通文件

3. 设置用户ID位和设置组ID位

与一个进程相关的ID有6个

实际用户ID
实际组ID
我们实际上是谁,即执行此进程的实际用户。这两个ID是用户登录时取自口令文件的
有效用户ID
有效组ID
附属组ID
用于文件访问权限检查
保存的设置用户ID
保存的设置组ID
用exec函数保存

通常有效用户ID等于实际用户ID,有效组ID等于实际组ID。

将这6个ID**与每个文件的所有者和组所有者区分开来。**这里讲的6个ID是与进程关联的,而与每个文件关联的所有者uid和所有者gid由stat结构体中的st_uid和st_gid指定。

设置用户ID位和设置组ID位:

在stat结构体的文件模式字(st_mode)中设置一个特殊标志,意为当执行此文件时,将进程的有效用户ID设置为文件所有者uid。这个标志就是文件模式字st_mode中的一位:设置用户ID位

与此类似,在文件模式字中可以设置另一个特殊标志,意为当执行此文件时,将进程的有效组ID设置为文件所有者gid。这个标志就是文件模式字st_mode中的一位:设置组ID位。

可以再文件模式字(st_mode)中设置一个特殊标志,意为当执行此文件时,将进程的有效用户ID设置为文件所有者uid。与此类似,在文件模式字中可以设置另一个特殊标志,意为当执行此文件时,将进程的有效组ID设置为文件所有者gid。

比如文件所有者是超级用户,并且设置了该文件的设置用户ID位,那么当执行该文件时,这个进程就拥有超级用户权限(因为有效用户ID设置为了用户所有者uid)。

由于设置用户ID位和设置组ID位都包含在文件stat的st_mode成员中,因此可以使用以下常量通过按位与来判断是否设置了这两个标志位

S_ISUID // 取得S_ISUID位的状态。判断是否设置了设置用户ID位
S_ISGID // 取得S_ISGID位的状态。判断是否设置了设置组ID位
if(S_ISUID & st.st_mode) {
   
    cout << "设置了设置用户ID位" << endl;
} else {
   
    cout << "没有设置设置用户ID位" <<
<think>好的,我现在需要解释用户的问题:“fstatat64 /dev/input/event0 是什么意思”。首先,我得拆解这两个部分:fstatat64/dev/input/event0。 用户可能是在某个系统调用或命令中看到fstatat64,然后跟了一个路径/dev/input/event0。先回忆一下,fstatat64是Linux的系统调用,用于获取文件状态信息,类似于fstat,但可以指定目录文件描述符路径。而/dev/input/event0是输入设备的事件接口,比如键盘或鼠标的事件。 接下来需要明确两者的关联。当调用fstatat64并传入/dev/input/event0时,目的是获取该设备文件的状态信息,比如大小、权限、时间戳等。不过,设备文件的大小可能显示为0,因为这类文件不存储实际数据,而是作为设备驱动的接口。 需要注意用户可能的上下文,比如是否在编程中使用这个系统调用,或者是在调试时遇到相关错误。需要解释系统调用的参数用法,特别是AT_FDCWD标志位的作用。同时,提醒用户权限问题,访问设备文件可能需要root权限。 另外,确认用户是否混淆了命令行工具系统调用。例如,stat命令也可以查看文件信息,但fstatat64是更底层的接口。需要确保回答结构清晰,分点说明,并给出实际例子,比如使用strace跟踪系统调用或stat命令查看文件信息。 最后,总结两者的结合使用场景,比如在程序中动态获取设备文件的状态,并处理可能的错误情况。确保用中文表达,符合用户要求,避免技术术语过于晦涩,同时保持准确性。</think>让我们逐步拆解这个问题的含义: 1. **`fstatat64`** 解析: - 这是Linux系统的底层文件状态查询接口,属于`glibc`库提供的系统调用封装 - 功能:获取指定文件的元数据(metadata),包括: - 文件大小(但设备文件通常显示为0) - 文件类型(字符设备/块设备等) - 权限信息 - 时间戳(最后访问/修改时间) - 参数特点: $$ \text{int fstatat64(int dirfd, const char *pathname, struct stat64 *statbuf, int flags)} $$ - `dirfd`:目录文件描述符,用`AT_FDCWD`表示当前工作目录 - `flags`:可设置`AT_SYMLINK_NOFOLLOW`等标志位 2. **`/dev/input/event0`** 解析: - 这是Linux输入子系统提供的字符设备文件 - 典型特征: - 文件类型:字符设备(可用`ls -l /dev/input/event0`查看,显示`c`开头) - 作用:提供输入设备(如键盘、鼠标、触摸板)的原始事件流 - 权限:通常需要root权限访问(权限位显示`crw-------`) 3. **组合使用场景**: 当程序调用`fstatat64(AT_FDCWD, "/dev/input/event0", &statbuf, 0)`时: - 系统会查询该设备文件的inode信息 - 返回的`stat64`结构体会包含: - `st_rdev`:设备号(包含主/次设备号) - `st_mode`:文件类型权限位 - 时间戳信息(但对动态设备可能不准确) 4. **典型应用场景**: - 输入监控程序初始化时验证设备存在性 - 检测输入设备的热插拔状态变化 - 获取设备唯一标识(通过设备号) 5. **调试建议**: - 使用`strace`跟踪系统调用: ```bash strace -e trace=fstatat64 your_program ``` - 查看设备信息: ```bash stat /dev/input/event0 ls -l /dev/input/event0 ``` 注意:直接操作`/dev/input/event*`需要root权限,普通用户访问可能产生`EPERM`错误。设备文件的状态查询结果可能与常规文件不同,需特别处理设备号解析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值