Linux 实用小代码,基于stat 来显示文件的metadata

Simple Linux code based on stat to display file metadata

If you want to know the metadata of a file in Linux system, you can check the detail below. 如果你想了解关于Linux 文件的元数据信息,欢迎继续阅读此文.

1 There is a system call named stat which can retrive the metadata of a file; so we can write a simple code to use it to get the file metatda. 我们可以通过写一段简单的代码来使用系统调用 stat, 然后执行它来获取到文件的元数据信息.

1.1 let’ check the struct stat first; so that we can know what info we can retrive by this system call. 首先看一下用到结构体,这样就可以知道可以从中得到一些什么元数据信息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct stat {
dev_t st_dev; /* ID of device containing file - 存储此文件的设备ID, 随后可以通过major,minor 解析*/
ino_t st_ino; /* inode number - inode 号码, 可以理解为索引节点*/
mode_t st_mode; /* file type and mode(detail below) - 文件的类型以及读,写,执行权限(下面st_mode有详细的描述)*/
nlink_t st_nlink; /* number of hard links - 文件对应的硬链接数 */
uid_t st_uid; /* user ID of owner - 文件的用户ID*/
gid_t st_gid; /* group ID of owner - 文件的组ID */
dev_t st_rdev; /* device ID (if special file) - 文件的设备ID, 针对一些特殊的文件(设备文件),比如块,字符等设备*/
off_t st_size; /* total size, in bytes - 文件的大小,以byte为单位*/
blksize_t st_blksize; /* blocksize for filesystem I/O - 文件在文件系统所占块大小*/
blkcnt_t st_blocks; /* number of 512B blocks allocated - 分配的磁盘块,已一个block为512Bytes*/
struct timespec st_atim; /* time of last access - 文件最近的访问时间 */
struct timespec st_mtim; /* time of last modification - 文件最近的修改时间*/
struct timespec st_ctim; /* time of last status change - 文件最近的状态变化时间*/
}

1.2 The file type and mode (st_mode); total 16 bit, the lowest 12bit represent file priviledge and the highest 4 bit represent file type. 文件类型和权限存储在 st_mode 字段中, 其中的低12位储存了对应的文件权限,而高4位则储存了对应文件类型.

1.2.1 st_mode file type 文件类型

1
2
3
4
5
6
7
S_IFSOCK      socket                               套接字文件
S_IFLNK symbolic link 字符链接文件
S_IFREG regular file 常规文件
S_IFBLK block device 块设备文件
S_IFDIR directory 文件夹
S_IFCHR character device 字符文件
S_IFIFO FIFO FIFO文件

1.2.1 st_mode file mode 文件权限

1
2
3
4
5
6
7
8
9
10
11
Owner (also known as user): The permissions granted to the owner of the file. 这个文件的用户的对应权限.

Group: The permissions granted to users who are members of the file’s group. 这个文件的用户组的对应权限

Other: The permissions granted to everyone else. 这个文件的其他用户的对应权限

Read: The contents of the file may be read. 读权限, 表明文件可以被对应的用户读取.

Write: The contents of the file may be changed.写权限,表明文件可以被对应的用户写入.

Execute: The file may be executed. In order to execute a script file, both read and execute permissions are required. 执行权限, 表明文件可以被对应的用户执行.如果对于要执行脚本文件来说,读和执行权限是必须的.

2 Let’s have a quick check against file metadata which displayed by demo app, 快速的通过我们写的例子应用来看一下文件的元数据.

2.1 display the character device file 获取字符设备文件的信息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@sam samapplications]# filemetadata /dev/ttyS0
===================== File Metadata ==============================
Directory: /dev/ttyS0
File type: Character device
Device containing: major=0 minor=5
inode number: 1146
Mode: rw-rw----
Device number (st_rdev): major=4; minor=64
Number of (hard) links: 1
Ownership: UID=0 GID=18
File size: 0 bytes : 0 KB
I/O block size: 4096 bytes
Number of (512B) blocks allocated: 0
Last file access: Sat Jun 15 19:45:34 2019
Last file modification: Sat Jun 15 19:45:34 2019
Last status change: Sat Jun 15 19:45:34 2019
==================================================================

2.2 display block device file; 获取块设备文件的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@sam samapplications]# filemetadata /dev/nvme0n1p2
===================== File Metadata ==============================
Directory: /dev/nvme0n1p2
File type: Block device
Device containing: major=0 minor=5
inode number: 15059
Mode: rw-rw----
Device number (st_rdev): major=259; minor=2
Number of (hard) links: 1
Ownership: UID=0 GID=6
File size: 0 bytes : 0 KB
I/O block size: 4096 bytes
Number of (512B) blocks allocated: 0
Last file access: Sat Jun 15 19:45:34 2019
Last file modification: Sat Jun 15 19:45:34 2019
Last status change: Sat Jun 15 19:45:34 2019
==================================================================

2.3 display regular file; 获取常规文件的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@sam samapplications]# filemetadata /tmp/rhel-server-7.3-x86_64-dvd.iso
===================== File Metadata ==============================
Directory: /tmp/rhel-server-7.3-x86_64-dvd.iso
File type: Regular file
Device containing: major=259 minor=2
inode number: 1137863993
Mode: rw-r--r--
Number of (hard) links: 1
Ownership: UID=107 GID=107
File size: 3793747968 bytes : 3704832 KB
I/O block size: 4096 bytes
Number of (512B) blocks allocated: 7409672
Last file access: Sat Jun 15 19:45:50 2019
Last file modification: Sun Apr 28 09:11:51 2019
Last status change: Sat Jun 1 21:35:50 2019
==================================================================
[root@sam samapplications]# filemetadata /tmp/metadata-link
===================== File Metadata ==============================
Directory: /tmp/metadata-link
File type: Symbolic (soft) link
Device containing: major=0 minor=40
inode number: 287970
Mode: rwxrwxrwx
Number of (hard) links: 1
Ownership: UID=0 GID=0
File size: 8 bytes : 0 KB
I/O block size: 4096 bytes
Number of (512B) blocks allocated: 0
Last file access: Sat Jun 15 21:58:29 2019
Last file modification: Sat Jun 15 21:58:24 2019
Last status change: Sat Jun 15 21:58:24 2019
==================================================================

3 Source code of filemetadata 我们可以通过源代码看它的具体实现.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
* Draft by Sam at 06-16-2019
* show the metadata of a file
* */
#include <sys/stat.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

/* display the file permision
* mode_t(file type and mode) of statBuffer as a parameter
* */
void disFilePerm(mode_t filePerm){
char userR = 0, userW = 0, userX = 0;
char groupR = 0, groupW = 0, groupX = 0;
char otherR = 0, otherW = 0, otherX = 0;

userR = (filePerm & S_IRUSR) ? 'r' : '-';
userW = (filePerm & S_IWUSR) ? 'w' : '-';
userX = (filePerm & S_IXUSR) ? 'x' : '-';

groupR = (filePerm & S_IRGRP) ? 'r' : '-';
groupW = (filePerm & S_IWGRP) ? 'w' : '-';
groupX = (filePerm & S_IXGRP) ? 'x' : '-';

otherR = (filePerm & S_IROTH) ? 'r' : '-';
otherW = (filePerm & S_IWOTH) ? 'w' : '-';
otherX = (filePerm & S_IXOTH) ? 'x' : '-';

printf("Mode:\t\t\t\t\t%c%c%c%c%c%c%c%c%c\n",userR,userW,userX,groupR,groupW,groupX,otherR,otherW,otherX);

}

/*
* display the stat buffer
* the pointer of statBuffer as parameter
* */
void displayStatInfo(struct stat *statBuffer, const char *filepath){
printf("\n===================== File Metadata ==============================\n\n");
/* print the file type */
printf("Directory:\t\t\t\t%s\n",filepath);
printf("File type:\t\t\t\t");
switch (statBuffer->st_mode & S_IFMT) {
case S_IFREG: printf("Regular file\n"); break;
case S_IFDIR: printf("Directory\n"); break;
case S_IFCHR: printf("Character device\n"); break;
case S_IFBLK: printf("Block device\n"); break;
case S_IFLNK: printf("Symbolic (soft) link\n"); break;
case S_IFIFO: printf("FIFO or pipe\n"); break;
case S_IFSOCK: printf("Socket\n"); break;
default: printf("Unknown file type\n"); break;
}
printf("Device containing:\t\t\tmajor=%ld minor=%ld\n",(long) major(statBuffer->st_dev), (long) minor(statBuffer->st_dev));
printf("inode number:\t\t\t\t%ld\n", (long) statBuffer->st_ino);
disFilePerm(statBuffer->st_mode);
if (S_ISCHR(statBuffer->st_mode) || S_ISBLK(statBuffer->st_mode)){
printf("Device number (st_rdev):\t\tmajor=%ld; minor=%ld\n",(long) major(statBuffer->st_rdev), (long) minor(statBuffer->st_rdev));
}
printf("Number of (hard) links:\t\t\t%ld\n", (long) statBuffer->st_nlink);
printf("Ownership:\t\t\t\tUID=%ld GID=%ld\n", (long) statBuffer->st_uid, (long) statBuffer->st_gid);
printf("File size:\t\t\t\t%lld bytes : %lld KB\n", (long long) statBuffer->st_size, statBuffer->st_size/1024);
printf("I/O block size:\t\t\t\t%ld bytes\n", (long) statBuffer->st_blksize);
printf("Number of (512B) blocks allocated:\t%lld\n", (long long) statBuffer->st_blocks);
printf("Last file access:\t\t\t%s", ctime(&statBuffer->st_atime));
printf("Last file modification:\t\t\t%s", ctime(&statBuffer->st_mtime));
printf("Last status change:\t\t\t%s", ctime(&statBuffer->st_ctime));
printf("\n==================================================================\n\n");
}

/*
* return data
* 1 for Invalid patameters
* 2 for lstat error
* 0 for sucess
* */
int main(int argc, char *argv[]){
struct stat statBuffer;
if (argc != 2 || argv[1] == NULL){
printf("Usage: filemetadata <FILENAME> \n");
return 1;
}

/* just use lstat to show the info; because lstat() is identical to stat(), except that if pathname is a symbolic link, then it returns information about the link
* itself, not the file that it refers to.
*/
if (lstat(argv[1], &statBuffer) == -1){
perror("filemetadata");
return 2;
}

displayStatInfo(&statBuffer, argv[1]);
return 0;
}

Ok, we know the Metadata of a file via stat system call as discripted above; you can please try the code and modify to study more about that.
到此为止,我们初步了解了Linux 文件的元数据大概有些什么信息,以及如何通过stat系统调用来获取它们. 如果向要深入了解,可以尝试修改上面的代码并编译看能否取更有意思的输出.

To know more? you can follow my wechat public account ADVANZONE.
想要了解更多? 欢迎关注 Addos 微信公众号获取更多的,有意思的玩意咯 :-)