Linux系统调用六、stat函数与 struct stat 文件信息结构体深度刨析

article/2025/10/8 15:39:09

🎁文章目录

    • 🎈1. inode节点与硬链接
    • 🎈2. stat函数与 struct stat 结构体
    • 🎈3. stat函数实例分析及stat命令
    • 🎈4. 实现 ls -l filename命令
    • 🎈5. 穿透与非穿透

在这里插入图片描述


🎈1. inode节点与硬链接

在这里插入图片描述
通过上图可以看到,硬链接和源文件引用的是同一个inode节点,并且在inode节点中有一条硬链接计数信息,每当inode被引用一次,这个硬链接计数就会加1,我们可以通过ls命令来查看inode节点信息。我们先建立一个文件以及该文件的硬链接,通过ll命令可以查看文件信息(实际上这些信息就是存在inode节点中的信息)。
在这里插入图片描述
可以看到,建立一个硬链接之后,硬链接计数增加了1个。通过ls命令的-i选项可以查看文件的inode节点编号。
在这里插入图片描述
硬链接文件和源文件的inode节点编号一样,说明它们引用的是同一个inode节点。

在上图中的目录项中,有一条信息是类型,如果当前是目录的话,可以继续进入下一级目录。简单举个例子,比如说我们使用vi打开当前目录可以得到下面的内容。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AXC0o1lo-1653311503984)(./Typora_picture_reference/1652516397217.png)]
这里面的三个条目是当前文件夹下的文件,我们可以通过tree命令查看一下当前文件夹./的目录结构
在这里插入图片描述
当我们把光标停在某一文件所在行按回车键就可以查看该文件内容,如果这个文件是目录,就会进入该目录并显示目录下的条目。

比如,进入file.txt文件
在这里插入图片描述
进入目录111
在这里插入图片描述

🎈2. stat函数与 struct stat 结构体

  • 包含头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
  • 函数原型
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
  • 函数功能

    Get file status - These functions return information about a file.

  • 函数参数

    • path:指定文件

    • buf:buf是一个传出参数,也就是一级指针做输出,我们应该先定义一个结构体变量,并把该变量取地址&传给形参。

      struct stat 
      {dev_t     st_dev;     /* ID of device containing file */ino_t     st_ino;     /* inode number */mode_t    st_mode;    /* protection 实际上就是权限位 */nlink_t   st_nlink;   /* number of hard links */uid_t     st_uid;     /* user ID of owner */gid_t     st_gid;     /* group ID of owner */dev_t     st_rdev;    /* device ID (if special file) */off_t     st_size;    /* total size, in bytes 文件大小 */blksize_t st_blksize; /* blocksize for file system I/O 块大小 */blkcnt_t  st_blocks;  /* number of 512B blocks allocated 块的个数 */time_t    st_atime;   /* time of last access 最后访问时间 */time_t    st_mtime;   /* time of last modification 最后修改时间 */time_t    st_ctime;   /* time of last status change 最后状态改变时间 */
      };
      
      • 对于结构体struct stat中的 mode_t st_mode 进行简要介绍(下面并没有全部列出,只列出了部分),首先是判断文件类型的两种方法。第一种是掩码的方式。

        S_IFMT     0170000   bit mask for the file type bit fields
        S_IFSOCK   0140000   socket
        S_IFLNK    0120000   symbolic link 符号链接
        S_IFREG    0100000   regular file 普通文件
        S_IFBLK    0060000   block device 块设备
        S_IFDIR    0040000   directory 目录
        S_IFCHR    0020000   character device 字符设备
        S_IFIFO    0010000   FIFO 管道
        

        这个实际上就是我们ll命令查看文件时,第一列所显示的文件类型,在上面列出的内容中,中间一列数字用来标识文件类型,从S_IFSOCK到S_IFIFO就是我们所熟知的7种文件类型,S_IFMT是文件类型的掩码。通过和S_IFMT的与运算,就可以把标识文件类型的位保留下来(也就是前两个数017,第一个0表示8进制,后面17共四位 1 111 用来标识文件类型,那么S_IFMT用二进制表示就是1111后面加12个0,通过与与运算就把后面12位置为0而保留代表文件类型的四个bit,再把相与的结果与下面的S_IFSOCK到S_IFIFO进行对比来判断文件类型),进而判断文件类型。比如,现在有一个0041100,把它和S_IFMT做与运算结果为

        0041100 & 0170000 =  0040000		(S_IFMT)  (S_IFDIR)
        

        通过结果对比可以得出这是一个目录文件。这是通过掩码的方式来判断文件类型。

        另外一种判断文件类型的方法是使用它为我们提供的宏来判断,7种文件类型判断相关的宏如下所示,这里的m是指stat结构体中的st_mode。

        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.)
        

        最后就是用户、组、其他用户的权限位(4位掩码,第一个0表示8进制)

        S_IRWXU    00700     mask for file owner permissions
        S_IRUSR    00400     owner has read permission
        S_IWUSR    00200     owner has write permission
        S_IXUSR    00100     owner has execute permission
        S_IRWXG    00070     mask for group permissions
        S_IRGRP    00040     group has read permission
        S_IWGRP    00020     group has write permission
        S_IXGRP    00010     group has execute permission
        S_IRWXO    00007     mask for permissions for others (not in group)
        S_IROTH    00004     others have read permission
        S_IWOTH    00002     others have write permission
        S_IXOTH    00001     others have execute permission
        
      • st_mode 各位含义示意图

      在这里插入图片描述

      • 结构体struct stat中的时间time_t也是一个结构体,它的原型如下

        struct timespec
        {_kernel_time_t 	tv_sec; /*seconds 当前时间到1970.1.1 0:0:0的秒数*/long 			tv_nsec; /*nanoseconds 纳秒*/
        }
        
  • 函数返回值

    成功返回0,失败返回-1并设置errno 。On success, zero is returned. On error, -1 is returned, and errno is set appropriately.

🎈3. stat函数实例分析及stat命令

下面通过一个实例来演示一下stat函数的使用方法。测试函数如下

/************************************************************>File Name  : getstat.c>Author     : QQ>Company    : QQ>Create Time: 2022年05月14日 星期六 18时37分17秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>int main(int argc, char* argv[])
{if(argc < 2){printf("not found filename\n");return -1;	}struct stat m_status;stat(argv[1], &m_status);return 0;
}

我们可以借助gdb调试器来查看结构体内容,并且借助gdb强大的功能可以很优美的打印出结构体内容。
在这里插入图片描述
我们使用set来设置一下,优美的打印结构体
在这里插入图片描述
该文件的硬链接数为st_nlink=2,我们确实对该文件创建了硬链接
在这里插入图片描述
我们可以看到这里面有一个st_mode=33188,这个就是我们在介绍stat结构体时重点介绍的权限参数,但是这里是十进制显示的,我们可以把它的八进制形式在gdb中打印出来
在这里插入图片描述
我们通过这个8进制数和文件类型掩码、权限掩码分别相与就可以得到这个文件的文件类型以及各用户的权限。

S_IFMT & 0100644 = 0100000 ===>  S_IFREG    0100000

可以看到相与之后的值对应于S_IFREG,也就是说这是个普通文件。

继续往下看 st_uid=0,st_gid=0,这个对应的是用户及组ID,这里要说明的是,我当前使用的是root用户,相应用户的ID可以在 /etc/passwd 中查看,我们可以使用vim编辑器打开文件查看

vim /etc/passwd

在这里插入图片描述
在第一行就可以看到root,后面两个0就对应结构体中的 st_uid=0和st_gid=0 。

继续往下看st_size = 11表示文件大小,可以通过ll命令来验证一下
在这里插入图片描述
再后面是块大小st_blksize = 4096和块的个数st_blocks = 8,那么每个块的大小是512,实际上这两个内容就是记录有多少个512大小的块。

再后面就是三个时间结构体的信息,最近访问时间、最近更改时间、最近状态改动时间。

  • Access 最近访问时间:是指最近的一次访问(读/写等),比如使用cat、touch等命令访问了该文件(访问但是没有修改),那么最近访问时间就会更新;
  • Modify 最近更改时间:是指最近一次文件内容的更改时间;
  • Change 最近状态改动时间:是指最近一次文件属性的更改时间,文件属性的更改包括文件大小、硬链接计数、文件权限等等的修改,并且一般Modify发生改变的时候,Change也会随之变化,因为文件内容的修改一般都会涉及到文件大小等的变化;

如果我们只是用cat查看一下文件,那么只有Access时间会更新;如果我们只是修改文件的权限,比如增加可执行权限,那么只有Change时间更新;如果我们使用重定向往文件中写入内容,那么Modify和Change时间会更新,而Access时间不会更新,因为在重定向的过程中,并没有访问文件。

实际上,上面介绍的这些内容,直接通过stat命令就可以查看
在这里插入图片描述

🎈4. 实现 ls -l filename命令

我们可以通过stat函数来实现 ls -l 命令的功能,下面我们实现查看指定文件的 ls -l 命令,即

ls -l filename

实现代码如下

/************************************************************>File Name  : mls.c>Author     : QQ>Company    : QQ>Create Time: 2022年05月15日 星期日 16时29分01秒>实现目标:-rw-r--r--. 2 root root 11 5月  14 15:02 file.txt
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>int main(int argc, char* argv[])
{if(argc < 2){printf("not found filename\n");return -1;}/*通过stat函数获取文件信息*/struct stat fstatus;stat(argv[1], &fstatus); /*穿透*//*lstat(argv[1], &fstatus); 非穿透 *//*解析文件信息,st_mode st_uid st_gid time*//*-rw-r--r--.*/char stmode[11];memset(stmode, '-', sizeof(stmode));/*使用宏来判断文件属性*/if(S_ISREG(fstatus.st_mode)) /* regular file */{stmode[0] = '-';}if(S_ISDIR(fstatus.st_mode)){stmode[0] = 'd';}if(S_ISCHR(fstatus.st_mode)){stmode[0] = 'c';}if(S_ISBLK(fstatus.st_mode)){stmode[0] = 'b';}if(S_ISFIFO(fstatus.st_mode)){stmode[0] = 'p';}if(S_ISLNK(fstatus.st_mode)){stmode[0] = 'l';}      if(S_ISSOCK(fstatus.st_mode)){stmode[0] = 's';}/*解析权限位*/if(fstatus.st_mode & S_IRUSR) {/*为真表示拥有该权限,否则无权限,因为整块内存已初始化为 - 所以不需要else分支*/stmode[1] = 'r';}if(fstatus.st_mode & S_IWUSR) {stmode[2] = 'w';}if(fstatus.st_mode & S_IXUSR) {stmode[3] = 'x';}if(fstatus.st_mode & S_IRGRP) {stmode[4] = 'r';}if(fstatus.st_mode & S_IWGRP) {stmode[5] = 'w';}if(fstatus.st_mode & S_IXGRP) {stmode[6] = 'x';}if(fstatus.st_mode & S_IROTH) {stmode[7] = 'r';}if(fstatus.st_mode & S_IWOTH) {stmode[8] = 'w';}if(fstatus.st_mode & S_IXOTH) {stmode[9] = 'x';}stmode[10] = '\0';/*获取时间  localtime() 函数(非系统调用)*原型:struct tm *localtime(const time_t *timep);*参数:time_t类型,struct stat中time_t st_atime,这里应该是文件访问时间*返回:struct tm {int tm_sec;          seconds (0-60 )int tm_min;          minutes (0-59) int tm_hour;         hours (0-23) int tm_mday;         day of the month (1-31) int tm_mon;          month (0-11) int tm_year;         year (-1900)  如果要求实际年份,应加上1990int tm_wday;         day of the week sunday=0int tm_yday;         day in the year int tm_isdst;        daylight saving time };*/struct tm* filetime = localtime(&fstatus.st_atim.tv_sec);char timebuf[20] = {0};sprintf(timebuf, "%d月  %d %02d:%02d", \filetime->tm_mon + 1, \filetime->tm_mday, \filetime->tm_hour, \filetime->tm_min);/*打印格式 -rw-r--r--. 2 root root 11 5月  14 15:02 file.txt*/printf("%s %ld %s %s %ld %s %s\n", \stmode, \fstatus.st_nlink, \getpwuid(fstatus.st_uid)->pw_name, \getgrgid(fstatus.st_gid)->gr_name, \fstatus.st_size, \timebuf, \argv[1]);/* 两个函数(非系统调用)struct passwd *getpwuid(uid_t uid); 根据uid获取用户信息struct passwd {char   *pw_name;        username char   *pw_passwd;      user password uid_t   pw_uid;         user ID gid_t   pw_gid;         group ID char   *pw_gecos;       real name char   *pw_dir;         home directory char   *pw_shell;       shell program };struct group *getgrgid(gid_t gid); 根据gid获取组信息struct group {char   *gr_name;        group name char   *gr_passwd;      group password gid_t   gr_gid;         group ID char  **gr_mem;         group members };*/return 0;
}

测试一下效果
在这里插入图片描述

🎈5. 穿透与非穿透

上面介绍了stat函数并通过stat函数实现了 ls -l 命令的功能。我们上面演示了使用自己实现的 ./mls 查看文件信息,假如说使用 ./mls 查看一个链接文件是什么效果呢,下面演示一下。
在这里插入图片描述
通过对比我们可以看到,符号链接(软链接)file.txt.soft的实际大小是8,但是我们自己实现的 ./mls 命令显示的大小是11。实际上,原因是这样的,我们在实现 ./mls 命令的时候是基于stat函数来获取文件信息的,stat函数有一个特性就是在获取链接文件信息的时候会进行穿透,去追溯符号链接的源文件,也就是说我们通过上面的命令 ./mls file.txt.soft 获取到的大小实际上是源文件file.txt的大小,我们可以验证一下。
在这里插入图片描述
那么我们自己如何实现获取符号链接的实际大小呢,这就用到了非穿透函数lstat,只要把上面代码实现中的函数调用stat替换为lstat就可以了,下面测试一下。

lstat(argv[1], &fstatus);

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述



http://chatgpt.dhexx.cn/article/ULJAfNyY.shtml

相关文章

Linux 应用编程之stat 函数

Linux 下可以使用 stat 命令查看文件的属性&#xff0c;其实这个命令内部就是通过调用 stat() 函数来获取文件属性的&#xff0c;stat 函数是 Linux 中的系统调用&#xff0c;用于获取文件相关的信息。&#xff08;可通过"man 2 stat"命令查看&#xff09;&…

pytorch stat

stat的作用是输出下面的参数 from torchstat import stat net FaceParseNet34(pretrainedTrue) stat(net, (3, 256, 256))

stat

stat 用于显示文件或者文件系统的状态 例如用stat grubaa64.efi 就可以看到文件的大小等信息

stat函数(stat、fstat、lstat)

#include <sys/types.h> #include <sys/stat.h> #include <unistd.h> //需包含头文件 有如下三个函数的函数原型&#xff1a; int stat(const char *path, struct stat *buf); 第一个形参&#xff1a;指出文件&#xff08;文件路径&#xff09;&…

stat函数

文章目录 (一)struct stat 结构体(二) st_mode 变量(三) struct timespec 结构体 Linux 下可以使用 stat 命令查看文件的属性&#xff0c;其实这个命令内部就是通过调用 stat()函数来获取文件属性的&#xff0c;stat 函数是 Linux 中的系统调用&#xff0c;用于获取文件相关的信…

Linux命令之stat命令

一、stat命令简介 stat命令用于显示文件的状态信息。stat命令的输出信息比ls命令的输出信息要更详细。stat命令可以查看的信息包括&#xff1a; File&#xff1a;显示文件名Size&#xff1a;显示文件大小Blocks&#xff1a;文件使用的数据块总数IO Block&#xff1a;IO块大小r…

面经 - 计算机网络知识点

文章目录 资料协议层次应用层HTTP缓存机制强制缓存对比缓存 HTTP无状态Cookie & Sessioncookiesession DNS解析HTTP方法keep-alive和非keep-alive区别HTTP长连接和短连接HTTP方法GET和POST区别HTTP和HTTPS从地址栏输入URL到显示页面都发生了什么? HTTP3.0&#xff08;可靠…

计算机网络期末总复习知识点

概述 互联网的2个重要基本特点&#xff1a;连通性&#xff08;connectivity&#xff09;和资源共享&#xff08;sharing&#xff09;。端系统之间的两种通信方式&#xff1a;客户/服务器方式&#xff08;Client/Server方式、C/S方式&#xff09;、对等方式&#xff08;Peer to…

计算机网络基础知识点

1.网络介绍 由通信介质将地理位置不同、相互独立的计算机连接起来&#xff0c;实现数据和资源共享。 2.网络分类 2.1 按照拓扑结构分类 1.总线型 &#xff08;一根线上串好多计算机&#xff09;特点&#xff1a;两端信号终结器&#xff0c;分叉处有T型头 2.环形 网络效率…

计算机网络知识点总结-第一章:概述

1.计算机网络在信息时代的作用 互联网基本特点&#xff1a; 连通性&#xff1a;互联网上用户不管距离多远&#xff0c;都能通信&#xff0c;就像这些用户终端都彼此连通 共享性&#xff1a;指资源共享&#xff0c;包含信息、软件、硬件等共享&#xff0c;就像资源在用户身边 计…

计算机网络知识总结

目录 一&#xff1a;计算机网络分类 二&#xff1a;网络拓扑结构 三&#xff1a;ISO/OSI模型&#xff08;七层模型&#xff09; 四&#xff1a;五层模型 五&#xff1a;五层模型和七层模型对比 六&#xff1a;TCP/IP协议族 一&#xff1a;计算机网络分类 局域网&#xff…

计算机网络期末考试知识点汇总

一、TCP五层协议 1.体系结构 2.各层功能&#xff08;精简版&#xff09; 应用层:为应用程序提供各种功能&#xff0c;有各种协议表示层:数据格式转化&#xff0c;数据编码&#xff0c;解压&#xff0c;解密等会话层:建立&#xff0c;管理&#xff0c;维护会话&#xff0c;流量…

计算机网络知识整理-计算机网络概述(计算机网络入门参考指南)

第1章 计算机网络概述 1.1为什么要学习计算机网络 在当前的互联网时代&#xff0c;计算机网络已经成为了我国的一项重要的通信基础设施&#xff0c;无论是你是在校的计算机专业大学生&#xff0c;还是正在从事网络相关工作的从业人员&#xff0c;计算机网络的学习都是十分重要…

计算机网络知识点复习(适合春招面试复习)

计算机网络知识点 HTTP协议HTTP协议各版本之间的区别**HTTP1.0默认是短链接。****HTTP1.1默认持久连接。****HTTP2.0****HTTP3.0** HTTPS的过程HTTP是如何保存用户状态&#xff0c;Cookie和Session OSI体系结构TCP的三次握手和四次挥手三次握手四次挥手2MSL时间SYN泛洪攻击解决…

计算机网络知识点汇总(谢希仁 第七版)

目录 第一章 概述 重要内容 计算机网络的一些相关知识 互联网概述 因特网的标准化工作 互联网的组成 计算机网络的类别 计算机网络的性能指标 计算机网络的体系结构——-分层次的体系结构 第二章 物理层 重要内容 物理层的基本概念 数据通信的基本知识 信道复用技…

计算机网络知识点全面总结(有这一篇就够了!!!)

一、计算机网络概述 1.1 计算机网络的分类 按照网络的作用范围&#xff1a;广域网&#xff08;WAN&#xff09;、城域网&#xff08;MAN&#xff09;、局域网&#xff08;LAN&#xff09;&#xff1b; 按照网络使用者&#xff1a;公用网络、专用网络。 1.2 计算机网络的层次结…

计算机网络基本知识汇总

概述 OSI分层&#xff08;7层&#xff09; 物理层、数据链路层、网络层、运输层、会话层、表示层、应用层 TCP/IP分层&#xff08;4层&#xff09; 网络接口层、网络层、运输层、应用层 五层协议&#xff08;5层&#xff09; 物理层、数据链路层、网络层、运输层、应用层…

计算机网络知识

计算机网络的组成 IP&#xff1a; ip地址是有网络地址【前面部分】主机地址【后面部分】组成子网掩码&#xff1a;子网掩码和ip地址做&与运算&#xff0c;结果和ip一致的部分就是网络地址&#xff0c;结果不一致的表示网段范围默认网关&#xff1a;默认网关相当于你路由的…

计算机网络知识点汇总(王道)

目录 第 1 章 计算机网络概述 1.1 计算机网络的组成 1.2 计算机网络的分类 1.3 性能指标 1.3.1 带宽 1.3.2 吞吐量 1.3.3 时延 1.3.4 时延带宽积(链路容量) 1.3.5 往返时延RTT​ 1.3.6 利用率 1.4 分层结构 1.4.1 OSI参考模型&#xff08;7层&#xff09; 1.4.2 T…