Linux系统调用 - 获取文件状态 (stat, lstat和fstat)
获取文件状态的系统调用有三个,分别是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);
}
==================== 以下是广告 ====================
更多系统详尽的Linux系统编程内容,欢迎订阅GitChat专栏 《攻克Linux系统编程》
更多推荐
所有评论(0)