精通Unix下C语言之文件系统结构
Unix文件的存储由“目录--i节点--数据块”三级组成,其中目录存储了文件的层次结构,数据块存储了文件的具体内容信息,i节点是连接文件层次结构与其数据内容的桥梁。
Unix下的文件包括了文件类型、文件访问权限、文件属主ID、文件属组ID、文件链接数、文件长度和文件时间等信息,这些信息存储在文件对应的i节点中。
1.1 文件系统的结构
磁盘包含着一个或多个分区,每个分区都有一个文件系统。Unix文件系统将磁盘空间分为一系列大小想通的块(block),全部块可分为引导块、超级块、i节点区(inode区)和数据区等四个部分。
1.引导块
引导块位于文件系统的第0块物理块,即文件卷的第一扇区,不属于文件系统管辖,存在文件系统的引导代码。
2.超级块
超级块位于文件系统的第1号物理块、紧跟引导块之后,描述文件系统本身的结构信息。超级块的数据结构一般定义在文件“filsys.h”中,/usr/include/sys/filsys.h
struct filsys
{
Ushort s_isize;/*磁盘索引节点区所占用的数据块数*/
daddr_t si_fsize;/*整个文件系统的数据块数*/
short s_nfree;/*在空闲块登录表中当前登记的空闲块数目*/
daddr_t s_free[NICFREE];/*空闲块登记表*/
short s_ninode;/*空闲索引节点数*/
ino_t s_inode[NICFREE];/*空闲节点登记表*/
chars_flock; /*加锁标志位*/
.
.
.
.
};
3.i节点区(inode区)
i节点区位于超级块之后,长度犹超级块中的s_isize中决定,它描述文件的属性,如长度、属主、属组、数据块表盒最近访问时间等。i节点的数据结构一般定义在"ino.h"/* /usr/include/sys/ino.h*/
struct dinode
{
ushort di_mode;/*文件类型与权限*/
short di_nlink;/*文件链接数*/
ushort di_uid;/*文件属主id*/
ushort di_gid;/*文件属组ID*/
off_t di_size;/*文件长度*/
char di_addr[NADDR_BYTES];/*文件磁盘块地址列表*/
char di_gen;/*file generation number*/
time_t di_atime;/*文件最近访问时间*/
time_t di_mtime;/*文件最近修改时间*/
time_t di_ctime;/*文件状态最近改变时间*/
};
文件系统通过i节点对文件进行控制和管理。其中,每个文件对应一个i节点,每个i节点具有唯一的节点号,记录了文件的属性和内容在磁盘上的存储位置。但文件名并不记录在i节点里,而是存储在目录文件中。
4.数据区
文件数据区中各数据块的空闲情况由超级块记录,文件系统利用超级块中的记录完成对数据块的分配和回收。
1.2 磁盘文件
磁盘文件读取工作原理
ex:命令cat T1.c的执行过程为例,总数一下unix文件的读取过程
1st step:在当前目录文件中查找文件"T1.c"机器对应的i节点编号,假设为1109;
2nd step:在i节点表中读取第1109号节点
3rd:读取i节点中文件属性、访问权限等信息
4th: 读取i节点中磁盘地址表,按照三级索引规则在数据区读取文件内容。
1.3文件属性
Unix的文件属性信息,都存储于i节点中,随着文件的操作而自动改变。一般情况下,我们能读取i节点的内容,但不能直接改变它。
1.文件属性函数族
#include<sys/types.h>
#include<sys/stat.h>
int stat(const char *path, struct stat *buf);
int fstat(int fildes,struct stat *buf);
int lstat(const char *path,struct stat *buf);
结构stat定义在文件"stat.h"如代码如下:/*/usr/include/sys/stat.h*/
strcut stat
{
...
dev_t st_dev;/*文件常驻设备ID*/
ino_t st_ino;/*i节点编号*/
mode_t st_mode;/*文件类型与权限*/
nlink_t st_mode;/*文件链接数*/
uid_t st_uid;/*文件属主ID*/
gid_t st_gid;/*文件属组ID*/
dev_t st_rdev;/*特别文件(字符文件或块文件)设备号*/
off_t st_size;/*文件长度*/
time_t st_atime;
time_t st_mtime;
time_t st_ctime;/*文件最近改变时间*/
};
2.文件类型
在Unix中,文件按类型可以分为普通文件(regular file)、目录文件(directory file)、管道文件(pipe file)、设备文件(dev file)、符号链接文件(char character file)和SOCKET文件。文件的类型属性在st_mode域中,占用4bit,各种文件类型的标志定义在文件"stat.h".
常数宏(S_IFMT)分别为S_IFREG、S_IFDIR、S_IFIFO、IF_BLK、S_IFCHR、S_IFSOCK.
在Unix中,已知结构stat的文件类型字段为st_mode,判断文件类型的方法有2种:
1) if((st_mode & _S_IFMT)==S_IFREG)是普通文件
else 不是
2) if(S_ISREG(st_mode))是普通文件
else不是
ex:设计函数GetFileType,功能是判断输入的文件类型,并转化为Unix文件标志,如下:
int GetFileType(mode_t st_mode,char *resp)
{
if(resp==null) return 0;
if(S_ISDIR(st_mode)) resp[0]='d';
else if(S_ISCHAR(st_mode)) resp[0]='c';
......
return 1;
}
3.文件访问权限
文件的全部访问权限可标志为三组共9个二进制数,其中第一组描述了用户权限,第二组内权限,第三组为其他用户权限。为了方便书写,通常也使用一个八进制数来代替一组权限。
在Unix中,已知结构stat的文件权限字段为st_mode,判断该文件访问权限的方法如下:
if(st_mode & S_IXUSR) 文件具有属主执行权限
else不具有
ex:设计函数GetFileMode,功能是判断输入的文件权限,并转化为Unix权限标志,如下:
int GetFileMode(mode_t st_mode,char *resp)
{
if(resp==null) return 0;
memset(resp,'-',9);
if(st_mode & S_IRUSR) resp[0]='r';
if(st_mode & S_IWUSR) resp[1]='w';
....
return 1;
}
4.文件其它属性
在i节点记录的文件属性还包括文件属主ID,文件属组ID、文件链接数、文件长度和文件时间等信息。
int GetFileOtheAttr(struct stat info,char * resp)
{
struct tm *mtime;
if(resp==null)return 0;
mtime=localtime(&info.st_mtime);
return (sprintf(resp,"%3d %6d %11d %04d %02d %02d",
info,st_nlink,infor.st_uid,info.st_gid,info.st_size,
mtime->tm_year +1900,mtime->tm_mon+1,mtime->tm_mday));
}
设计类似于Unix命令中的“ls -l”的程序lsl,显示指定文件的属性信息,如下:
#include<stdio.h>
#include<sys/type.h>
#include<sys/stat.h>
#include<time.h>
int GetFileType(mode_t st_mode,char *resp);
int GetFileMode(mode_t st_mode,char *resp);
int GetFileOtherAttr(mode_t st_mode,char *resp);
void main()
{
struct stat info;
char buf[100];
if(arg!=2)
{
fprintf(stderr,"lsl filename/n");
return ;
}
memset(buf,0,sizeof(buf));
if(lstat(argv[1],&info)==0)
{
p+=GetFileType(info.st_mode,p);
p+=GetFileMode(info.st_mode,p);
p+=GetFileOtherAttr(info,p);
printf("%s %s/n",buf,arg[1]);
}
else fprintf(sterr,"open file failed./n");
}