中文手册
名称
inode-文件inode信息
说明
每个文件都有一个inode(index node,索引节点),其中包含有关该文件的元数据。应用程序可以使用stat(2)(或相关调用)或statx(2)检索此元数据,stat(2)返回stat结构,statx(2)返回statx结构。
以下是通常在文件inode中找到或与之关联的信息,其名称与stat(2)或statx(2)返回的相应结构字段名称一致。
Device where inode resides(inode所在的设备)
stat.st_dev; statx.stx_dev_minor and statx.stx_dev_major
每个inode(以及相关文件)都位于文件系统,文件系统位于设备上。设备通过其主ID(标识设备的常规类)和次ID(标识常规类中的特定实例)的组合来标识。
Inode number
stat.st_ino; statx.stx_ino
文件系统中的每个文件都有一个唯一的inode编号。Inode编号只保证在文件系统中是唯一的(即,不同的文件系统可能使用相同的Inode编号,这就是硬链接不能跨越文件系统边界的原因)。此字段包含文件的inode编号。
File type and mode
stat.st_mode; statx.stx_mode
请参阅下面关于文件类型和模式的讨论。
Link count(链接数)
stat.st_nlink; statx.stx_nlink
此字段包含指向文件的硬链接数。使用 link(2) 创建指向现有文件的其他链接。
User ID
st_uid stat.st_uid; statx.stx_uid
此字段记录文件所有者的User ID。对于新创建的文件,文件User ID是创建过程的有效用户标识。可以使用chown(2)更改文件的用户标识。
Group ID
stat.st_gid; statx.stx_gid
inode记录文件的组所有者的ID。对于新创建的文件,文件组ID是父目录的组ID或创建进程的有效组ID,具体取决于是否在父目录上设置了set-group-ID位(见下文)。可以使用chown(2)更改文件的组ID。
Device represented by this inode(此inode表示的设备)
stat.st_rdev; statx.stx_rdev_minor and statx.stx_rdev_major
如果这个文件代表一个设备,那么inode会记录该设备的主ID和次ID。
File size
stat.st_size; statx.stx_size
此字段以字节为单位给出文件的大小(如果是常规文件或符号链接)。符号链接的大小是它包含的路径名的长度,没有终止的空字节。
Preferred block size for I/O(I/O的首选块大小)
stat.st_blksize; statx.stx_blksize
该字段提供“首选”块大小,以提高文件系统I/O效率(以较小的块写入文件可能会导致效率低下的读取-修改-重写)
Number of blocks allocated to the file(分配给文件的块数)
stat.st_blocks; statx.stx_size
此字段表示分配给文件的块数,以512字节为单位(当文件有缺陷时,此值可能小于st_size/512)
POSIX.1标准注意到stat结构的st_blocks成员的单位没有被标准定义。在许多实现中,它是512字节;在一些系统中,使用不同的单位,例如1024。此外,每个文件系统的单位可能不同。
Last access timestamp (atime)
stat.st_atime; statx.stx_atime
这是文件的最后访问时间戳。它是通过文件访问来更改的,例如execve(2)、mknod(2)、pipe(2)、utime(2)和read(2)(大于零字节)。其他接口,如mmap(2),可以更新atime时间戳,也可以不更新。
一些文件系统类型允许以这样一种方式装载:文件和/或目录访问不会导致atime时间戳的更新。(请参阅mount(8)中的noatime、nodiratime和relatime,以及mount(2)中的相关信息)此外,如果使用O_NOATIME标志打开文件,则不会更新atime时间戳;请参阅open(2)。
File creation (birth) timestamp (btime)
(not returned in the stat structure); statx.stx_btime
文件的创建时间戳。这是在文件创建时设置的,以后不会更改。
btime时间戳在UNIX系统上历史上并不存在,而且目前大多数Linux文件系统都不支持它。
Last modification timestamp (mtime)
stat.st_mtime; statx.stx_mtime
这是文件的最后一次修改时间戳。它通过修改文件来更新,例如mknod(2)、truncate(2)、utime(2)和write(2)(大于零字节)。此外,目录的mtime时间戳通过在该目录中创建或删除文件而改变。mtime时间戳不会因所有者、组、硬链接数或模式的改变而改变。
Last status change timestamp (ctime)
stat.st_ctime; statx.stx_ctime
这是文件的最后状态更改时间戳。它可以通过写入或设置inode信息(即所有者、组、链接数、模式等)来更改。
XFS、JFS、Btrfs和ext4(自Linux 2.6.23以来)支持纳秒时间戳。ext2、ext3和Reiserfs中不支持纳秒时间戳。为了以纳秒精度返回时间戳,stat和statx结构中的时间戳字段被定义为包含纳秒分量的结构。详见stat(2)和statx(2)。在不支持亚秒时间戳的文件系统上,stat和statx结构中的纳秒字段返回值0。
The file type and mode(文件类型和模式)
stat.st_mode字段包括文件类型和模式。
POSIX将对应于掩码S_IFMT(见下文)的stat.st_mode位称为文件类型,将对应于掩码07777(8进制)的12位称为文件模式位,将最低有效9位(0777)称为文件权限位。
文件类型定义了以下掩码值:
S_IFMT 0170000(8进制) 文件类型bit字段的位掩码
S_IFSOCK 0140000 socket
S_IFLNK 0120000 符号链接
S_IFREG 0100000 普通文件
S_IFBLK 0060000 块设备
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符设备
S_IFIFO 0010000 FIFO
因此,要测试常规文件(例如),可以编写:
stat(pathname, &sb);
if ((sb.st_mode & S_IFMT) == S_IFREG) {
/* Handle regular file */
}
由于上述形式的测试是常见的,POSIX定义了额外的宏,以便更简洁地编写符合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?
因此,前面的代码片段可以重写为:
stat(pathname, &sb);
if (S_ISREG(sb.st_mode)) {
/* Handle regular file */
}
如果定义了以下任何功能测试宏,则会提供上述大多数文件类型测试宏的定义:_BSD_SOURCE, _SVID_SOURCE,或 _DEFAULT_SOURCE。此外,如果定义了 _XOPEN_SOURCE ,则会提供除 S_IFSOCK 和 S_ISSOCK() 之外的所有上述宏的定义。
S_IFSOCK 的定义也可以通过定义值为500或更大的 _XOPEN_SOURCE 或(因为glibc 2.24)同时定义 _XOPEN_SOURCE 和 _XOPEN_SOURCE_EXTENDED 来公开。
如果定义了以下任何特性测试宏,则 S_ISSOCK() 的定义是公开的:_BSD_SOURCE(在glibc 2.19及更早版本中)、_DEFAULT_SOURCE(在glibc 2.20及更高版本中)、_XOPEN_SOURCE的值为500或更大、_POSIX_C_SOURCE的值为200112L或更大,或(自glibc 2.24以来)通过定义 _XOPEN_SOURCE 和 _XOPEN_SOURCE_EXTENDED。
st_mode 字段的文件模式组件定义了以下掩码值:
S_ISUID 04000 set-user-ID bit (see execve(2))
S_ISGID 02000 set-group-ID bit (see below)
S_ISVTX 01000 sticky bit (see below)
S_IRWXU 00700 owner has read, write, and execute permission
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 group has read, write, and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others (not in group) have read, write, and
execute permission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
set-group-ID位(S_ISGID)有几个特殊用途。对于一个目录,它表示BSD语义将用于该目录:在那里创建的文件从目录继承其组ID,而不是从创建进程的有效组ID继承,并且在那里创建的目录也将设置S_ISGID位。对于可执行文件,set-group-ID位导致执行该文件的进程的有效组ID发生改变,如execve(2)所述。对于未设置组执行位(S_IXGRP)的文件,set-group-ID位表示强制文件/记录锁定。
目录上的粘性位(S_ISVTX)意味着该目录中的文件只能由文件所有者、目录所有者和特权进程重命名或删除。
个人理解
背景:inode在文件系统的位置
物理硬盘是怎么抽象成文件系统的呢?
总共经历了3层抽象:
第一层是从磁盘到分区。每个分区都可以看作是一个独立的磁盘;
第二层是从分区到块。分区就是磁盘,磁盘上面分好扇区,为每个磁盘块编号,编号可以使系统能够计算磁盘上的每个块,我们可以把磁盘视为一系列块的组合。
第三层是从块到3个区域的划分。Unix将这些磁盘块分成了3个部分:超级块,i节点表,数据区。超级块存放文件系统本身的信息,i节点表存放文件属性,数据区存放文件内容。所有的inode节点都有相同的大小,i节点表是这些结构的一个列表。文件系统的每个文件在该表中都有一个inode节点。
示例
本来想再写点啥,但刚刚发现一篇文章写的挺好,写的挺好的文章,连我俩的例子都差不多,都是按照man 2 stat的示例改的。
#include <stdio.h>
#include <sys/stat.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: ");
if ((sb.st_mode & S_IFMT) == S_IFREG)
{
/* Handle regular file */
printf("%o, regular file\n",S_IFREG);
printf("inode %lu\n", sb.st_ino);
printf("st_mode is %o\n", sb.st_mode);
}
else if (S_ISDIR(sb.st_mode))
{
printf("%o, directory\n",S_IFDIR);
printf("inode %lu\n", sb.st_ino);
printf("st_mode is %o\n", sb.st_mode);
}
else if (S_ISCHR(sb.st_mode))
{
printf("%o, character device\n",S_IFCHR);
printf("inode %lu\n", sb.st_ino);
printf("st_mode is %o\n", sb.st_mode);
}
else if (S_ISBLK(sb.st_mode))
{
printf("%o, block device\n",S_IFBLK);
printf("inode %lu\n", sb.st_ino);
printf("st_mode is %o\n", sb.st_mode);
}
else if (S_ISFIFO(sb.st_mode))
{
printf("%o, FIFO (named pipe)\n",S_IFIFO);
printf("inode %lu\n", sb.st_ino);
printf("st_mode is %o\n", sb.st_mode);
}
else
printf("unknown\n");
}
在系统中找到一个管道文件,就拿它做实验了
# ll -i /run/initctl
21784 prw------- 1 root root 0 Jan 8 08:18 /run/initctl
编译执行
# gcc test.c -o test
# ./test /run/initctl
File type: 10000, FIFO (named pipe)
inode 21784
st_mode is 10600
第一行的文件类型与man手册中的
S_IFIFO 0010000 FIFO
是一致的,表示管道文件。
第二行是inode值,与ls结果一致。
第三行st_mode用8进制表示为10600,其中的10000代表管道文件,0600是0400和0200之和,表示文件拥有者有读写权限。
累了,就这样吧,就这么多吧。
参考文档
https://man7.org/linux/man-pages/man7/inode.7.html
https://linux.die.net/man/2/stat
https://blog.csdn.net/astrotycoon/article/details/8679676