一、概述
- unix系统中,每打开一个文件,内核会使用三种数据结构来表示这个文件:进程表、v节点和i节点。
- linux只保留了unix中的i节点来维护打开的文件;
二、i节点和struct stat结构体
linux的i节点信息存储在struct stat结构体中,可以通过man 2 stat来查看这个结构体的内容,如下:
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 filesystem 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 */
};
- st_dev 表示该文件所存在设备的id;
- st_ino i节点编号,每一个文件都有唯一的i节点编号;
- st_mode 文件的权限,如0777表示所有的用户具有可读可写和可执行权限,这个位还指明了文件的类型,可以和以下宏组合使用:
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.)
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
S_ISUID 0004000 set-user-ID bit
S_ISGID 0002000 set-group-ID bit (see below)
S_ISVTX 0001000 sticky bit (see below)
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_nlink 硬链接的个数;
- st_uid 拥有者组id;
- st_gid 拥有者组id;
- st_rdev 设备id;
- st_size 设备的大小,以字节为单位,如果文件时一个符号链接,那么这个值的大小是它路径名的长度;
- st_blksize
- st_blocks
- st_atime 最后访问时间
- st_mtime 最后修改时间
- st_ctime 上一次访问的时间
最后的三个时间可以使用localtime函数转换成标准的北京时间:
#include <time.h>
struct tm *localtime(const time_t *timep);
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 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
三、stat函数和stat命令
3.1、stat函数
使用stat函数可以得到对应文件的struct stat结构体,函数原型如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
这三个函数的区别在于,stat用来获取指定路径的文件信息,lstat函数和stat的作用完全相同,但是当lstat函数的pathname是一个符号链接时,lstat得到的信息是这个符号链接本身的信息,而不是这个符号链接指向的文件信息。fstat可以根据已经打开文件的描述符获取文件信息。
- 首先我们在当前目录下新建一个text文件,并在文件中随便写入一些内容::
touch text
vim text
2.使用stat函数读取text文件的内容
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
void check_file_type(mode_t mode)
{
printf("File Type:");
switch(mode & S_IFMT)
{
case S_IFSOCK:
printf("socket\r\n");
break;
case S_IFLNK:
printf("symbolic link\r\n");
break;
case S_IFREG:
printf("regular file\r\n");
break;
case S_IFBLK:
printf("block file\r\n");
break;
case S_IFDIR:
printf("directory\r\n");
break;
case S_IFCHR:
printf("character device\r\n");
break;
case S_IFIFO:
printf("FIFO\r\n");
break;
default :
printf("unknown file type\r\n");
break;
}
}
void check_file_permission(mode_t mode,char * perm)
{
perm[0]='?';//先获取类型
switch(mode & S_IFMT){
case S_IFSOCK:
perm[0]='s';
break;
case S_IFLNK:
perm[0]='l';
break;
case S_IFREG:
perm[0]='-';
break;
case S_IFBLK:
perm[0]='b';
break;
case S_IFDIR:
perm[0]='d';
break;
case S_IFCHR:
perm[0]='c';
break;
case S_IFIFO:
perm[0]='p';
break;
}
if(mode & S_IRUSR)
perm[1]='r';
if(mode & S_IWUSR)
perm[2]='w';
if(mode & S_IXUSR)
perm[3]='x';
if(mode & S_IRGRP)
perm[4]='r';
if(mode & S_IWGRP)
perm[5]='w';
if(mode & S_IXGRP)
perm[6]='x';
if(mode & S_IROTH)
perm[7]='r';
if(mode & S_IWOTH)
perm[8]='w';
if(mode & S_IXOTH)
perm[9]='x';
perm[10]='\0';
}
int main()
{
int ret = -1;
struct tm *tim;
char pem[] = "----------";
struct stat stabuf;
char pathname[] = "text";
stat(pathname,&stabuf);
printf("Inode Number:%d\r\n",stabuf.st_ino);
printf("Hard Links:%d\r\n",stabuf.st_nlink);
check_file_type(stabuf.st_mode);
check_file_permission(stabuf.st_mode,pem);
printf("File Permission:%s\r\n",pem);
printf("User ID:%u\r\n",stabuf.st_uid);
printf("Group ID:%u\r\n",stabuf.st_gid);
printf("Device ID:%u\r\n",stabuf.st_rdev);
printf("File Size:%d\r\n",stabuf.st_size);
printf("Block Size:%d\r\n",stabuf.st_blksize);
printf("Block Nums:%d\r\n",stabuf.st_blocks);
tim = localtime(&stabuf.st_atime);
printf("Acess Time:%04d-%02d-%02d %02d:%02d:%02d %02d\r\n",tim->tm_year+1900,tim->tm_mon+1,tim->tm_mday,tim->tm_hour,tim->tm_min,tim->tm_sec,tim->tm_isdst);
tim = localtime(&stabuf.st_mtime);
printf("Modify Time:%04d-%02d-%02d %02d:%02d:%02d %02d\r\n",tim->tm_year+1900,tim->tm_mon+1,tim->tm_mday,tim->tm_hour,tim->tm_min,tim->tm_sec,tim->tm_isdst);
tim = localtime(&stabuf.st_atime);
printf("Change Time:%04d-%02d-%02d %02d:%02d:%02d %02d\r\n",tim->tm_year+1900,tim->tm_mon+1,tim->tm_mday,tim->tm_hour,tim->tm_min,tim->tm_sec,tim->tm_isdst);
}
3.编译上面的代码并执行后,紧接着使用stat命令查看文件的信息,得到如下结果,可以看出使用stat函数和stat命令得到的文件信息是一致的。
4.给text文件建立一个硬链接,在shell中执行ln text tex,然后查看文件信息,可以看到文件的硬链接变为了2。
ln text tex
图中文件的i节点编号和前面的不一致是因为我把text文件从共享文件夹中拷贝到了/home目录,使用vmtool共享文件夹是无法创建硬链接的,会提示如下错误:
ln: failed to create hard link ‘tex’ => ‘text’: Operation not permitted
3.2、stat命令
stat命令在shell中使用,它具有和stat函数大致相同的功能,但比stat函数的使用更加灵活和多样化,在shll终端中使用man stat可以查看比较详细的介绍。
stat命令我们通常不需要添加任何参数就可以查看文件的详细信息,在shell中执行如下指令:
stat text
其它选项
- -f 查看文件系统信息而非文件信息;
- -c 查看指定格式的文件信息,如stat -c %i text表示只查看文件的i节点信息;
- -t 将文件信息以简略形式输出到shell终端