文件系统ls实现与内核编码.docx
《文件系统ls实现与内核编码.docx》由会员分享,可在线阅读,更多相关《文件系统ls实现与内核编码.docx(26页珍藏版)》请在冰豆网上搜索。
文件系统ls实现与内核编码
文件系统ls实现与内核编码
一.设计目的
操作系统是控制和管理计算机硬件和软件资源的虚拟机,其中的文件系统是对软件和设备进行管理的系统,文件系统是操作系统中非常重要的一个模块,它的实现占用了操作系统源码的最大编码量,其好坏也直接影响着用户对操作系统的感受程度。
通过对操作系统课程设计的实践,进一步加深对文件系统的认识和理解,并在此基础上培养学生的工程应用能力。
实验分别从用户态和内核态两个层实践文件系统的部分功能。
二.设计内容
1.使用Linux编程实现用户态下带参数的ls命令功能
ls命令支持以下功能:
①支持-l参数;
②输出结果按字典排序;
③列出“.”文件,支持-a参数,在没有-a时候不显示隐藏文件;
④显示记录总数;
⑤支持对给定的目录进行操作,如ls/tmp;
⑥正确显示文件特殊属性suid、sgid和sticky;
⑦支持-u参数,它会显示出文件的最后访问时间;
⑧当关掉一个文件的读权限,就不能打开这个文件来读。
如果从一个终端登录,打开一个文件,保持文件的打开状态,然后从另外的终端登录,去掉文件的读权限,看会出现什么情况。
编写一个程序,先用open()打开一个文件,用read()读一些内容,调用sleep()等待20s以后,再读一些内容,从另外的终端,再等待的20s内去掉文件的读权限,这样会有什么结果?
2.编写内核模块显示目录或文件的信息。
⑴调试《Linux操作系统原理与应用》第8章文件系统P215的例子
⑵给内核模块传入参数path,其中path为绝对路径
①当path为目录时,显示目录对应的dentrey结构中的相关信息(可打印的信息);
②当path为文件时,显示文件对应的indoe结构中的相关信息(可打印的信息);
③当路径错误时,有错误提示信息。
三.概要设计
1.功能模块图;
⑴实现ls命令功能
⑵编写内核模块
①编写内核模块,打印super_block结构中一些域的值。
(课本上的例子)
②给内核模块传入参数path,其中path为绝对路径
2.各个模块详细的功能描述。
⑴实现ls命令功能
①ls-l:
每个文件单独占一行,显示文件的详细属性信息
②ls-a:
显示包括隐藏文件在内的所有文件
③ls-u:
显示出文件的最后访问时间
④ls:
显示的文件名按字典顺序排序
⑤ls/指定目录:
显示当前目录下的内容
⑥ls-lu:
每个文件单独占一行,显示文件的详细属性信息,并且显示出文件的最后访问时间
⑦ls-la:
显示包括隐藏文件在内的所有文件的详细属性信息
⑧ls-lua:
显示包括隐藏文件在内的所有文件的详细属性信息,并且显示出文件的最后访问时间
⑨chmod权限文件名:
修改文件的权限,并且显示出此文件是否受suid,sgid和sticky的控制
⑩chmod权限(3位)在一终端运行程序,读取文件信息,在另一终端修改文件权限,看结果。
⑵编写内核模块
①编写内核模块,打印super_block结构中一些域的值。
(课本上的例子)
遍历系统中的超级块:
list_head结构类型的字段名称为s_list。
list_entry宏通过指向list_head节点的地址来得到外部超级块的首地址。
获取系统中个超级块的地址,获得某个子进程的地址,打印文件系统所在的主设备号和次设备号和文件系统名。
遍历打印每个超级块中的所有
索引节点号,打印索引结点。
②给内核模块传入参数path,其中path为绝对路径
path=路径时,显示如下信息:
●目录项标志
●哈希表
●短目录名
●目录项长度
●目录项名
●目录项计数器的引用
path=文件时,显示如下信息:
●文件索引节点的数量
●文件类型和权限
●用户ID
●用户组ID
●指定文件系统的读写访问标志
●文件大小
●索引节点的状态
●硬链接数
●引用记数
●文件的块数
●版本号
●以位为单位的块大小
错误信息显示:
Openfilefailed
四.详细设计
1.功能函数的调用关系图
⑴ls命令
①错误处理函数,打印出错误所在行的行数和错误信息
voidmy_error(constchar*error_string,intline);
②获取文件属性
voidshow_file_attribute(structstatbuf,char*file_name,intflag_u)
③输出文件的文件名,若命令中没有-l选项,则输出文件时要保证上下对齐
voidshow_file_columns(char*file_name)
④根据命令行参数(存放在flag中)和完整路径名(存放在pathname中)显示目标文件
voidshow_file(intflag,char*pathname)
⑤为显示某个目录下的文件做准备,path:
要显示的目录
voidshow_file_dir(intflag_param,char*path)
⑵编写内核模块
①编写内核模块,打印super_block结构中一些域的值。
(课本上的例子)
②给内核模块传入参数path,其中path为绝对路径
2.各功能函数的数据流程图
⑴ls命令
②获取文件属性
voidshow_file_attribute(structstatbuf,char*file_name,intflag_u)
③输出文件的文件名,若命令中没有-l选项,则输出文件时要保证上下对齐
voidshow_file_columns(char*file_name)
④根据命令行参数(存放在flag中)和完整路径名(存放在pathname中)显示目标文件
voidshow_file(intflag,char*pathname)
⑤为显示某个目录下的文件做准备,path:
要显示的目录
voidshow_file_dir(intflag_param,char*path)
⑵编写内核模块
①编写内核模块,打印super_block结构中一些域的值。
(课本上的例子)
②给内核模块传入参数path,其中path为绝对路径
●文件信息
●目录信息
3.重点设计及编码
⑴ls命令
重点设计:
为显示某个目录下的文件做准备,path:
要显示的目录
编码:
voidshow_file_dir(intflag_param,char*path)
{
DIR*dir;//对目录进行操作
structdirent*ptr;//对目录的数据项进行操作
intcount=0;
charfilenames[256][PATH_MAX+1],temp[PATH_MAX+1];
chartempfile[PATH_MAX+1];
structstatbuf;
intatime[PATH_MAX+1],temp1;
//获取该目录下文件总数和最长的文件名
dir=opendir(path);
if(dir==NULL){
my_error("opendir",__LINE__);
}
while((ptr=readdir(dir))!
=NULL){//对整个目录进行遍历
if(filename_maxlend_name))
filename_maxlen=strlen(ptr->d_name);
count++;
}
closedir(dir);
if(count>256)
my_error("这个目录下的文件太多了",__LINE__);
inti,j,length=strlen(path);
//获取该目录下所有的文件名
dir=opendir(path);
for(i=0;iptr=readdir(dir);
if(ptr==NULL){
my_error("readdir",__LINE__);//__LINE__:
预编译器内置宏,表示行数
}
strcpy(tempfile,path);
strcat(tempfile,ptr->d_name);
if(lstat(tempfile,&buf)==-1){
my_error("lstat",__LINE__);
}
atime[i]=buf.st_atime;
strncpy(filenames[i],path,length);//保存文件路径
filenames[i][length]='\0';
strcat(filenames[i],ptr->d_name);//d_name:
当前目录下所有文件/子目录
filenames[i][length+strlen(ptr->d_name)]='\0';
}
//文件名按最后访问时间进行排序
if(flag_param==PARAM_U||(flag_param==PARAM_U+PARAM_A)){
for(i=0;ifor(j=i+1;jif(atime[i]{
temp1=atime[i];
atime[i]=atime[j];
atime[j]=temp1;
strcpy(tempfile,filenames[i]);
strcpy(filenames[i],filenames[j]);
strcpy(filenames[j],tempfile);
}
}
}
}else{
//文件名按字母顺序存储于filenames
for(i=0;ifor(j=0;jif(strcmp(filenames[j],filenames[j+1])>0){
strcpy(temp,filenames[j+1]);
temp[strlen(filenames[j+1])]='\0';
strcpy(filenames[j+1],filenames[j]);
filenames[j+1][strlen(filenames[j])]='\0';
strcpy(filenames[j],temp);
filenames[j][strlen(temp)]='\0';
}
}
}
for(i=0;ishow_file(flag_param,filenames[i]);
closedir(dir);
//如果命令中没有-l选项,打印一个换行符
if((flag_param&PARAM_L)==0)
printf("\n");
else
printf("总记录数是:
%d\n",(int)sum/2);
}
⑵编写内核模块
①编写内核模块,打印super_block结构中一些域的值。
(课本上的例子)
重点设计:
遍历系统中的超级块
编码:
list_for_each(pos,(structlist_head*)SUPER_BLOCKS_ADDRESS){
//list_entry宏通过指向list_head节点的地址来得到外部超级块的首地址
//list_head结构类型的字段名称为s_list
//获取系统中个超级块的地址
sb=list_entry(pos,structsuper_block,s_list);//某个子进程的地址
//打印文件系统所在的主设备号和次设备号
printk("\ndev_t:
%d:
%d\n",MAJOR(sb->s_dev),MINOR(sb->s_dev));
//打印文件系统名
printk("file_typename:
%s",sb->s_type->name);
//遍历打印每个超级块中的所有索引节点号
list_for_each(linode,&sb->s_inodes){
pinode=list_entry(linode,structinode,i_sb_list);
count++;
printk("%lu\t",pinode->i_ino);//打印索引结点
②给内核模块传入参数path,其中path为绝对路径
重点设计:
打开文件
编码:
staticintkernel_file_open(char*path)
{
//O_DIRECTORY如果参数所指的文件并非为一目录,则打开文件失败
//以目录的形式打开
file=filp_open(path,O_DIRECTORY,0);
if(IS_ERR(file))
{
file=filp_open(path,O_RDWR|O_CREAT,0777);
if(IS_ERR(file))
{
printk("Openfile%sfailed..\n",path);//路径错误
return0;
}
//文件
printk("openfilesuccess!
\n");
printk("Pathoffile:
%s",path);
kernel_file_info();
printk("ending!
\n");
filp_close(file,NULL);
return1;
}
else
{
//目录
printk("\nThisisadiretory!
\n");
printk("Pathofdirectory:
%s",path);
kernel_dir_info();
printk("ending!
\n");
filp_close(file,NULL);
return0;
}
五.测试数据及运行结果
1.正常测试数据和运行结果
⑴ls命令
①ls
②ls-l并显示总记录数
③ls-a
④ls-u
⑤ls-ul
⑥ls-ua
⑦ls-la
⑧ls-lau
⑨ls/tmp
⑩ls-l文件名.c修改文件的属性并看suid,sgid,sticky是否起作用了。
⑪修改文件权限
读取3.txt中的内容
修改3.txt的权限
再读取3.txt
修改3.txt权限
再读取3.txt
⑵编写内核模块
①编写内核模块,打印super_block结构中一些域的值。
(课本上的例子)
●插入:
insmod
●卸载:
rmmod
●显示:
dmesg
●运行结果:
显示主设备号,次设备号,文件类型名和索引节点数量。
②给内核模块传入参数path,其中path为绝对路径
●调试
●path=文件
●path=目录
●当目录中没有文件时,会自动创建指定文件
●路径错误时,报错
2.异常测试数据及运行结果
⑴ls命令
⑵编写内核模块
①编写内核模块,打印super_block结构中一些域的值。
(课本上的例子)
②给内核模块传入参数path,其中path为绝对路径
六.调试情况,设计技巧及体会
1.改进方案
●在使用Linux编程实现用户态下带参数的ls命令功能的过程中,我实现了基本要求和部分高级要求,使得ls的部分命令可以实现,但是我的代码没有实现ls-R递归地列出目录中所有的文件包含子目录中的文件和输出结果分栏排序,每栏的宽度由这一栏最长的文件名决定,显示的栏数还受终端显示器的的宽度影响,每一列尽可能的等宽。
这样让显示结果看上去不是那么的整齐。
为了使显示结果看起来整齐并且代码功能强大,在代码中添加递归,遍历等和调用系统中的一些宏来实现-R和控制终端大小。
●在内核传参的实验过程中,我的代码实现了路径为目录和文件的传参并且在传入路径错误时会报错,但是不能实现当指定目录中没有某个文件时,不能自动创建这个文件,通过修改代码,我的代码实现了这个功能。
2.体会
通过本次课程设计,让我对ls有了进一步的了解和认识,通过编写ls代码,实现用户态下带参数的ls命令功能,让我对ls下参数有了更深的了解。
通过内核模块传参的代码,让我对linux下内核模块中dentry目录项和file文件结构体有了进一步的了解和认识。
经过这为期两周的linux课程设计,让我对linux有了更深,更进一步的了解和掌握,让我对ls命令中的参数和内核模块中一些宏和结构体有了一定的了解和掌握,这为我以后的学习打下了坚实的基础。
本次的linux课程设计增长了我的见识,让我的知识面更宽更广。
七.参考文献
[1]DANIELP.BOVET&MARCOCESATI.深入理解LINUX内核[M].陈莉君,张琼声,张宏伟,译.第三版.北京:
中国电力出版社,2007:
825-831.
[2]Documentation/x86/boot.txt
[3]鸟哥.鸟哥的Linux私房菜[M].王世江,改编.第三版.北京:
人民邮电出版社,2011:
293-399,596-608.
[4]RichardBlum.汇编语言程序设计[M].马朝晖译.北京:
机械工业出版社,2006.
[5]http:
//elinux.org/images/d/d2/Tools-and-technique-for-reducing-bootup-time.pdf
八.附录:
源代码(电子版)