linux编程里,有三个函数可以获取 文件的属性(包含了文件类型和文件权限等属性)。
三个函数的原型如下:
#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int filedes, struct stat *restrict buf);
int lstat(const char *restrict pathname, struct stat *resstrict buf);
在这三个函数中,都用到了stat 结构体, 这里就介绍一下stat结构体。
struct stat
{
mode_t st_mode; //文件访问权限,类型
ino_t st_ino; //索引节点号
dev_t st_dev; //文件所在设备的设备号
dev_t st_rdev; //文件inode所代表的设备的设备号。
nlink_t st_nlink; //硬链接数
uid_t st_uid; //文件所有者 用户ID
gid_t st_gid; //文件所在组 组ID
off_t st_size; //普通文件,文件大小, Bytes
time_t st_atime; //文件被最后访问(access)的时间
time_t st_mtime; //文件内容最后被修改(modify)的时间
time_t st_ctime; //文件状态最后被修改的时间( status change)
blksize_t st_blksize; //文件所在磁盘的磁盘块大小
blkcnt_t st_blocks; //文件占用块数量
};
通过一下的带参宏定义我们可以通过 st_mode参数判断出文件的类型:
S_ISREG(m) : 是否是普通文件。
S_ISDIR(m) : 是否是目录
S_ISCHR(m) : 是否是字符设备
S_ISBLK(m) : 是否是块设备
S_ISFIFO(m) : 是否是FIFO(命名管道?)
S_ISLNK(m) : 是否是链接
S_ISSOCK(m) : 是否是socket
另外对于文件的读写属性也有如下的宏定义:
S_IRUSR :所有者-读
S_IWUSR :所有者-写
S_IXUSR :所有者-执行
S_IRGRP : 组-读
S_IWGRP : 组-写
S_IXGRP :组-执行
S_IROTH :其他-读
S_IWOTH :其他-写
S_IXOTH :其他-执行
讲完了,stat函数 中最重要的出参 struct stat, 接下来就讲下 函数的返回值
函数返回值:
成功执行返回为0, 如果失败则返回-1, 并且置errno。
errno类型:
EACCES: 搜索权限被拒绝。
EBADF : fd有误
EFAULT : 地址有误
ELOOP : 遍历路径时遇到太多的符号连接
ENAMETOOLONG : path 太长
ENOENT : 路径path为空,或者路径有误。
ENOMEM : no memory
ENOTDIR : 路径非法,其中路径中有不是目录的部分。
然后, stat, fstat, 和lstat 之间的区别是什么呢?
通过函数原型,我们也可以知道一二。
对于stat,它可以仅仅通过文件地址,获取文件属性,而不一定要打开文件; 而fstat 需要将文件打开,获取fd,然后通过fd来获取文件的stat。
对于链接文件, stat获取的文件属性是被链接文件的文件属性,而lstat获取的则是链接文件本身的文件属性。
示例:(来自于http://linux.die.net/man/2/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); }
上述示例中的, S_IF* (S_IFBLK, ....)可以通过 sb.st_mode & S_IFMT 来获取,也可以通过 上边介绍的那些宏定义S_ISREG(m)来获取。
在我现在尝试写的一个webserver 小程序里,就需要通过 stat 来判断 文件是否存在, 文件是否可以执行。
inline int IsExecutable(mode_t mode)
{
return (mode & S_IXOTH );
}.
本文有部分内容来自于:http://linux.die.net/man/2/stat。