本章主要讲解linux 中 stat函数,另外两个函数fstat和lstat功能和stat函数差不多就不做过多的讲解。
fstat函数与stat函数区别主要在于:fstat只获取普通文件的属性信息,看fstat输入参数便可知
lstat函数与stat函数区别主要在于:lstat获取文件属性中软链接信息是软连接文件本身的属性信息,而stat获取的是软链接文件关联的文件的属性信息
fstat函数和lstat函数原型如下:
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
1.stat函数介绍
/*************************************************
** description:获取文件属性信息
** parameter:
** *pathname:文件路径下文件名字,要被获取属性信息的文件
** *statbuf:获取到的文件属性信息将存放在该内存内
** return:成功:0, 失败:-1;
**************************************************/
int stat(const char *pathname, struct stat *statbuf);
//struct stat
struct stat {
dev_t st_dev; // 文件的设备编号
ino_t st_ino; // inode节点
mode_t st_mode; // 文件的类型和存取的权限, 16位整形数 -> 常用
nlink_t st_nlink; // 连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; // 用户ID
gid_t st_gid; // 组ID
dev_t st_rdev; // (设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; // 文件字节数(文件大小) --> 常用
blksize_t st_blksize; // 块大小(文件系统的I/O 缓冲区大小)
blkcnt_t st_blocks; // block的块数
time_t st_atime; // 最后一次访问时间
time_t st_mtime; // 最后一次修改时间(文件内容)
time_t st_ctime; // 最后一次改变时间(指属性)
};
2. 获取文件类型的宏定义函数
文件的类型信息存储在 struct stat 结构体的 st_mode 成员中,它是一个 mode_t 类型,本质上是一个 16 位的整数。Linux API 中为我们提供了相关的宏函数,通过对应的宏函数可以直接判断出文件是不是某种类型
// 类型是存储在结构体的这个成员中: mode_t st_mode;
// 这些宏函数中的m 对应的就是结构体成员 st_mode
// 宏函数返回值: 是对应的类型返回-> 1, 不是对应类型返回0
S_ISREG(m) is it a regular file? //- 普通文件
S_ISDIR(m) directory? //- 目录
S_ISCHR(m) character device? //- 字符设备
S_ISBLK(m) block device? //- 块设备
S_ISFIFO(m) FIFO (named pipe)? //- 管道
S_ISLNK(m) symbolic link? //- 软连接(Not in POSIX.1-1996.)
S_ISSOCK(m) socket? //- 是否本地套接字文件 (Not in POSIX.1-1996.)
3.获取文件权限
在 stat函数获取到的文件属性struct stat结构体中st_mode 元素记录了该文件的权限,st_mode (16bit长度:0-15bit)中每一个bit都有它的含义,0-2bit:其他人权限, 3-5bit:所属组用户权限,6-8bit:所有者权限, 9-11bit:特殊权限, 12-15bit:文件类型。linux中为方便用于获取对应bit的值,已宏定义每一bit,使用宏定义按位与(&)st_mode 即可获取对应bit的状态值。
宏定义如下所示:
关于变量 st_mode:
- st_mode -- 16位整数
○ 0-2 bit -- 其他人权限
- S_IROTH 0x0004 读权限 100
- S_IWOTH 0x0002 写权限 010
- S_IXOTH 0x0001 执行权限 001
- S_IRWXO 0x0007 掩码, 过滤 st_mode中除其他人权限以外的信息
○ 3-5 bit -- 所属组权限
- S_IRGRP 0x0020 读权限
- S_IWGRP 0x0010 写权限
- S_IXGRP 0x0008 执行权限
- S_IRWXG 0x0038 掩码, 过滤 st_mode中除所属组权限以外的信息
○ 6-8 bit -- 文件所有者权限
- S_IRUSR 0x0100 读权限
- S_IWUSR 0x0080 写权限
- S_IXUSR 0x0040 执行权限
- S_IRWXU 0x01C0 掩码, 过滤 st_mode中除文件所有者权限以外的信息
○ 12-15 bit -- 文件类型
- S_IFSOCK 0xC000 套接字
- S_IFLNK 0xA000 符号链接(软链接)
- S_IFREG 0x8000 普通文件
- S_IFBLK 0x6000 块设备
- S_IFDIR 0x4000 目录
- S_IFCHR 0x2000 字符设备
- S_IFIFO 0x1000 管道
- S_IFMT 0xF000 掩码,过滤 st_mode中除文件类型以外的信息
4.举例代码
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
void stat_st_mode_define(void)
{
printf("其他人权限:\n");
printf("S_IROTH:%04X\n", S_IROTH); //读权限
printf("S_IWOTH:%04X\n", S_IWOTH); //写权限
printf("S_IXOTH:%04X\n", S_IXOTH); //执行权限
printf("S_IRWXO:%04X\n\n", S_IRWXO); //掩码, 过滤 st_mode中除其他人权限以外的信息
printf("所属组权限:\n");
printf("S_IRGRP:%04X\n", S_IRGRP); //读权限
printf("S_IWGRP:%04X\n", S_IWGRP); //写权限
printf("S_IXGRP:%04X\n", S_IXGRP); //执行权限
printf("S_IRWXG:%04X\n\n", S_IRWXG); //掩码, 过滤 st_mode中除所属组权限以外的信息
printf("文件所有者权限:\n");
printf("S_IRUSR:%04X\n", S_IRUSR); //读权限
printf("S_IWUSR:%04X\n", S_IWUSR); //写权限
printf("S_IXUSR:%04X\n", S_IXUSR); //执行权限
printf("S_IRWXU:%04X\n\n", S_IRWXU); //掩码, 过滤 st_mode中除文件所有者权限以外的信息
printf("文件类型:\n");
printf("S_IFSOCK:%04X\n", S_IFSOCK); //套接字
printf("S_IFLNK:%04X\n", S_IFLNK); //符号链接(软链接)
printf("S_IFREG:%04X\n", S_IFREG); //普通文件
printf("S_IFBLK:%04X\n", S_IFBLK); //块设备
printf("S_IFDIR:%04X\n", S_IFDIR); //目录
printf("S_IFCHR:%04X\n", S_IFCHR); //字符设备
printf("S_IFIFO:%04X\n", S_IFIFO); //管道
printf("S_IFMT:%04X\n\n", S_IFMT); //掩码,过滤 st_mode中除文件类型以外的信息
}
int main(int argc, char *argv[])
{
struct stat myst;
char perms[12] = {0};
stat_st_mode_define();
if(-1 == stat("/home/linux", &myst))
{
fprintf(stderr, "stat read file failed :%s\n", strerror(errno));
return -1;
}
printf("st_mode:%04X\n", myst.st_mode);
if(S_ISDIR(myst.st_mode))
{
printf("文件类型:目录\n");
}
if(S_ISREG(myst.st_mode))
{
printf("文件类型:普通文件\n");
}
switch(myst.st_mode & S_IFMT) // 判断文件类型
{
case S_IFIFO:
perms[0] = 'p';
break;
case S_IFCHR:
perms[0] = 'c';
break;
case S_IFDIR:
perms[0] = 'd';
break;
case S_IFBLK:
perms[0] = 'b';
break;
case S_IFREG:
perms[0] = '-';
break;
case S_IFLNK:
perms[0] = 'l';
break;
case S_IFSOCK:
perms[0] = 's';
break;
default:
perms[0] = '?';
break;
}
/*** 判断文件的访问权限 ***/
// 文件所有者
perms[1] = (myst.st_mode & S_IRUSR) ? 'r' : '-';
perms[2] = (myst.st_mode & S_IWUSR) ? 'w' : '-';
perms[3] = (myst.st_mode & S_IXUSR) ? 'x' : '-';
// 文件所属组
perms[4] = (myst.st_mode & S_IRGRP) ? 'r' : '-';
perms[5] = (myst.st_mode & S_IWGRP) ? 'w' : '-';
perms[6] = (myst.st_mode & S_IXGRP) ? 'x' : '-';
// 其他人
perms[7] = (myst.st_mode & S_IROTH) ? 'r' : '-';
perms[8] = (myst.st_mode & S_IWOTH) ? 'w' : '-';
perms[9] = (myst.st_mode & S_IXOTH) ? 'x' : '-';
printf("文件类型与权限:%s\n",(char *)perms);
printf("linkNum:%ld\n", myst.st_nlink); // 硬链接计数
printf("fileUser:%s\n", getpwuid(myst.st_uid)->pw_name); // 文件所有者
printf("fileGrp:%s\n", getgrgid(myst.st_gid)->gr_name); // 文件所属组
printf("stat read file size: %d\n", (int)myst.st_size); // 文件大小
printf("最后一次访问时间:%s\n", ctime(&myst.st_atime));
printf("最后一次修改时间(文件内容):%s\n", ctime(&myst.st_mtime));
printf("最后一次改变时间(指属性):%s\n", ctime(&myst.st_ctime));
return 0;
}
打印信息如下:
其他人权限:
S_IROTH:0004
S_IWOTH:0002
S_IXOTH:0001
S_IRWXO:0007
所属组权限:
S_IRGRP:0020
S_IWGRP:0010
S_IXGRP:0008
S_IRWXG:0038
文件所有者权限:
S_IRUSR:0100
S_IWUSR:0080
S_IXUSR:0040
S_IRWXU:01C0
文件类型:
S_IFSOCK:C000
S_IFLNK:A000
S_IFREG:8000
S_IFBLK:6000
S_IFDIR:4000
S_IFCHR:2000
S_IFIFO:1000
S_IFMT:F000
st_mode:41ED
文件类型:目录
文件类型与权限:drwxr-xr-x
linkNum:17
fileUser:linux
fileGrp:linux
stat read file size: 4096
最后一次访问时间:Sat Dec 11 09:09:41 2021
最后一次修改时间(文件内容):Sat Dec 11 09:09:01 2021
最后一次改变时间(指属性):Sat Dec 11 09:09:01 2021