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位" <<