获取文件状态的系统调用有三个,分别是stat,fstat和lstat,其实他们的作用是一样的,都是查询某个文件的状态。如果查询成功,会把文件状态的信息填充在一个stat结构体中。他们的函数定义分别如下:
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
可以看到,这三个系统调用用于输出的参数类型是一样的,都是struct stat,其中,state与fstat的区别在于,stat()用文件名来指定要查询的文件,而fstat()用文件描述符来指定目标文件;而stat()与lstat()的区别在于,如果指定的文件是一个符号链接,那么stat会解引用,查询该链接指向的普通文件的属性,而lstat()在遇到符号链接文件是,不去解引用,而是直接返回这个符号链接文件本身的属性。要成功获取到指定文件的状态信息,需要用户对文件存储位置的每一层目录都具有执行和读取权限。
Linux的系统调用中还有很多类似的以 f 和 l 开头的系统调用,他们的区别与作用和stat系列函数都是类似的。
返回参数struct stat的结构定义与各字段的含义分别为:
struct stat {
dev_t st_dev; /* 文件存放的设备ID /
ino_t st_ino; / 索引节点号 /
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; / 文件大小,单位字节,软连接文件的大小是链接名长度 /
blksize_t st_blksize; / 文件使用的存储块大小 /
blkcnt_t st_blocks; / 文件占用的存储块数量,以512字节为单位 /
time_t st_atime; / 最后一次访问的时间 /
time_t st_mtime; / 最后一次内容修改的时间 /
time_t st_ctime; / 最后一次状态变化的时间 */
};
对于st_mode字段,系统定义了一些宏来检查文件的类型:
S_ISREG(m) 检查是否是常规文件
S_ISDIR(m) 检查是否是目录
S_ISCHR(m) 检查是否是字符设备 (如键盘)
S_ISBLK(m) 检查是否是块设备(如硬盘)
S_ISFIFO(m) 是否是命名管道
S_ISLNK(m) 是否是符号链接
S_ISSOCK(m) 是否是套接字
与其他的很多系统调用一样,这几个系统调用都是成功是返回0,否则返回-1,并设置对应的errno,常见的可能出现的errno有:
EACCES:目标文件所在的目录或某个上级目录没有查找权限
EBADF:指定的文件描述符无效.
EFAULT:无效的文件地址
ELOOP:可能遇到了循环引用的软链接文件
ENAMETOOLONG:文件路径名太长.
ENOENT:目录或文件不存在
ENOMEM:内核内存耗尽
ENOTDIR:指定的文件路径上,某个部分不是目录
EOVERFLOW:引用的文件太大了,或者使用的索引节点太多了,或者占用的存储块太多了。
如下是使用stat()系统调用的演示程序:
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
struct stat sb;
if (argc != 2) {
fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (stat(argv[1], &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
switch (sb.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}
printf("I-node number: %ld\n", (long) sb.st_ino);
printf("Mode: %lo (octal)\n",
(unsigned long) sb.st_mode);
printf("Link count: %ld\n", (long) sb.st_nlink);
printf("Ownership: UID=%ld GID=%ld\n",
(long) sb.st_uid, (long) sb.st_gid);
printf("Preferred I/O block size: %ld bytes\n",
(long) sb.st_blksize);
printf("File size: %lld bytes\n",
(long long) sb.st_size);
printf("Blocks allocated: %lld\n",
(long long) sb.st_blocks);
printf("Last status change: %s", ctime(&sb.st_ctime));
printf("Last file access: %s", ctime(&sb.st_atime));
printf("Last file modification: %s", ctime(&sb.st_mtime));
exit(EXIT_SUCCESS);
}
————————————————
版权声明:本文为CSDN博主「|宇文拓>」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yubo112002/article/details/84076277