1、stat、fstat、lstat函数头文件及原型
查看男人手册第2册man 2 stat
:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct stat {
dev_t st_dev; /* 包含文件的设备的ID */
ino_t st_ino; /* inode值 */
mode_t st_mode; /* 类型及权限 */
nlink_t st_nlink; /* 硬链接数量 */
uid_t st_uid; /* 所有者的用户ID */
gid_t st_gid; /* 所有者的组ID */
dev_t st_rdev; /* 设备ID(如果是特殊文件) */
off_t st_size; /* 总大小,以byte为单位 */
blksize_t st_blksize; /* 文件系统I/O的块大小 */
blkcnt_t st_blocks; /* 分配的512B块数 */
time_t st_atime; /* 最后访问时间 */
time_t st_mtime; /* 最后修改时间 */
time_t st_ctime; /* 上次状态更改的时间 */
};
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstatat(int dirfd, const char *pathname, struct stat *buf,
int flags);
stat与lstat差别就在于l(link),stat会越过符号链接(软链接)读取源文件,后者则读取软链接文件。关于Linux环境的软硬链接可以参考:https://blog.csdn.net/weixin_44498318/article/details/105399439
可以使用以下宏传递结构体成员st_mode查看文件类型:
S_ISREG(m) 常规文件
S_ISDIR(m) 目录
S_ISCHR(m) 字符设备
S_ISBLK(m) 块设备
S_ISFIFO(m) FIFO文件
S_ISLNK(m) 符号链接
S_ISSOCK(m) 套接字文件
事实上以下就是st_mode字段定义的标志,也可以相“&”来读取文件的属性:
S_IFMT 0170000 文件类型的位遮罩
S_IFSOCK 0140000 套接字
S_IFLNK 0120000 符号连接
S_IFREG 0100000 普通文件
S_IFBLK 0060000 块设备
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符设备
S_IFIFO 0010000 FIFO
S_ISUID 0004000 文件的(set user-id on execution)位
S_ISGID 0002000 文件的(set group-id on execution)位
S_ISVTX 0001000 文件的sticky位
S_IRWXU 00700 文件所有者权限的掩码
S_IRUSR 00400 拥有者读权限
S_IWUSR 00200 拥有者写权限
S_IXUSR 00100 拥有者执行权限
S_IRWXG 00070 文件所在组权限的掩码
S_IRGRP 00040 用户组读权限
S_IWGRP 00020 用户组写权限
S_IXGRP 00010 用户组执行权限
S_IRWXO 00007 其他用户权限的掩码
S_IROTH 00004 其他用户读权限
S_IWOTH 00002 其他用户写权限
S_IXOTH 00001 其他用户执行权限
2、返回值
成功返回0,失败返回-1并且设置错误码errno;
3、示例
先vi file.txt
创建源文件,内容为hello
,然后再ln -s file.txt file.txt.soft
创建一个软链接文件(符号链接)。创建程序,内容如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int fd;
struct stat buf[3];
// stat函数
if( 0 != stat("./file.txt.soft", &buf[0]))
{
printf("stat error!\n");
return -1;
}
printf("stat: The file size is %lu\n", buf[0].st_size);
// fstat函数
fd = open("./file.txt.soft", O_RDWR);
if(fd < 0)
{
printf("open file error!\n");
return -1;
}
if(0 != fstat(fd, &buf[1]))
{
printf("fstat error!\n");
return -1;
}
printf("fstat: The file size is %lu\n", buf[1].st_size);
close(fd);
// lstat函数
if(0 != lstat("./file.txt.soft", &buf[2]))
{
printf("stat error!\n");
return -1;
}
printf("lstat: The file size is %lu\n", buf[2].st_size);
// 比较stat和lstat
if(S_ISLNK(buf[0].st_mode))
printf("stat: It is a link file!\n");
else
printf("stat: It is the file itself!\n");
if(buf[2].st_mode & S_IFLNK)
printf("lstat: It is a link file!\n");
else
printf("lstat: It is the file itself!\n");
return 0;
}
gcc stat.c -o stat
编译后./stat
运行程序查看打印:
stat: The file size is 6
fstat: The file size is 6
lstat: The file size is 8
stat: It is the file itself!
lstat: It is a link file!
4、fstatat
前面可以看到stat和lstat的区别就在于是否会越过符号链接(软链接文件)进行读取。那现在可以继续看fstatat了,主要看参数fd与参数flag:fd为AT_FDCWD时,pathname为相对路径,而若pathname给的是绝对路径,fd被忽略;flag为0时,就相当于stat,会透过符号链接(软链接文件)读取原文件,而等于AT_SYMLINK_NOFOLLOW时,就相当于lstat读取的是软链接文件本身:
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
int main()
{
struct stat buf[2];
if(fstatat(AT_FDCWD, "file.txt.soft", &buf[0], 0) < 0)
{
perror("fstatat1 error");
return -1;
}
// if(fstatat(AT_FDCWD, "file.txt.soft", &buf[1], AT_SYMLINK_NOFOLLOW) < 0) // 两者等价
if(fstatat(AT_FDCWD, "/home/linriming/test/file.txt.soft", &buf[1], AT_SYMLINK_NOFOLLOW) < 0)
{
perror("fstatat2 error");
return -1;
}
if(S_ISLNK(buf[0].st_mode))
printf("flag = 0: It is a link file!\n");
else
printf("flag = 0: It is the file itself!\n");
if(buf[1].st_mode & S_IFLNK)
printf("flag = AT_SYMLINK_NOFOLLOW: It is a link file!\n");
else
printf("flag = AT_SYMLINK_NOFOLLOW: It is the file itself!\n");
return 0;
}
/*
输出结果:
flag = 0: It is the file itself!
flag = AT_SYMLINK_NOFOLLOW: It is a link file!
*/