【实验方案设计】 为linux系统设计一个简单的二级文件系统。要求做到以下几点: (1)可以实现下列几条命令(至少4条); login 用户登陆 dir 列文件目录 create 创建文件 delete 删除文件 open 打开文件 close 关闭文件 read 读文件 write 写文件 (2)列目录时要列出文件名、物理地址、保护码和文件长度; (3)源文件可以进行读写保护。 【实验过程】(实验步骤、记录、数据、分析) (1)首先应确定文件系统的数据结构:主目录、子目录及活动文件等。主目录和子目录都以文件的形式存放于磁盘,这样便于查找和修改。 (2)用户创建的文件,可以编号存储于磁盘上。如file0,file1,file2...并以编号作为物理地址,在目录中进行登记。 本模拟文件系统的自身特点: (1)用户不当可以创建普通的文本文件,还可以创建文件夹进行文件的存放分类,理论上基本实现了多级目录的功能,能够迭代的创建文件夹下去,当然数量是有限制的,或者偏离了老师您给的设计要求,不是二级文件系统,是多级文件系统。 (2)本程序还有很多不足之处,希望老师能够在评阅的过程中给予一定的指出,我会加以改进学习的 程序主要构成部分 (详细代码请看压缩包.cpp后缀的文件) FileSystem的代码实现包括以下几个部分 1. 磁盘块的定义和实现 因为当创建文件的时候,需要在磁盘申请磁盘块进行存储,而在对linux进行使用的过程中,我查找不到直接操作磁盘并对磁盘块进行申请的api,所以自己进行模拟,而这里,磁盘块就是一个记录着固定大小的数组的数据文件,以此来记录磁盘块的使用情况, 这里参考的是磁盘使用位图来记录磁盘块是否被使用的情况。 #define TOTAL_BLOCK 4096
#define BLOCK_UNUSED 4096#define UNDEFIEN 0#define DIRENT_TYPE 1
#define FILE_TYPE 2void initBlock();bool openBlock(unsigned short * block);void saveBlock(unsigned short * block);bool applyBlocks(unsigned short * b,unsigned short * block,int num);bool retrieveBlocks(unsigned short * b,unsigned short * block);bool deleteBlock(unsigned short * b);
2. I节点的定义和实现 I节点在linux中记录着重要的信息,包括文件属性,磁盘块的指针 在这里我也只对i节点进行简单的模拟,i节点的数据结构包括 1) 用户的id 2) I节点创建的时间 3) 访问i节点文件的时间 4) I节点修改时间 5) 指向磁盘块的指针,这里通过数组实现,数组的编号对应磁盘块的地址(备注:可进行设置,这里只是简单实现直接指向磁盘块,没有实现大文件的多次间接块,每个磁盘块存储文本文件的时候一个磁盘块可以存放8字节的信息,有四个磁盘块地址,最多可存放32字节的文本信息;而存放目录文件就是用一个磁盘块存放,也就是4个磁盘块地址使用第一个存放目录文件的磁盘块地址。 6) 文件类型 7) 文件保护信息 8) 连接数(这里我是参考了linux文件系统的ls命令,具体没有实现这个功能) #include<time.h>
#define TOTAL_INODE 1024
#define INODE_TO_BLOCK 4 //每个inode可以映射到4个磁盘块
#define FILE_BLOCK_MAX_LENGTH 8 //每个磁盘块存放的文件类型大小为8字节#define INODE_UNUSERD 1024#define WRITE_ONLY 1
#define READ_ONLY 2
#define WRITE_AND_READ 3struct inode
{unsigned short file_type; //文件类型 目录 或者 文件unsigned short protection; //保护位 读 写 读写同时unsigned int link_num; //指向该节点到目录项unsigned int user_id; //文件所属用户到idunsigned long file_size; //文件的大小unsigned short disk_add[INODE_TO_BLOCK]; //12个磁盘块到地址,每块地址存储的数据到大小是8bytes,支持32bytes的普通文件,还有特定的目录项文件time_t access_time; //文件被最后访问到时间time_t modification_time; //文件最后被修改到时间time_t create_time; //修改原来到结构,改为i节点被确定使用到时间
};void initInode();bool openInode(struct inode * node);void saveInode(struct inode * node);void listInode(struct inode * node);unsigned short createDirentI(struct inode * node,unsigned short * block,struct user * u);unsigned short createFileI(struct inode * node,unsigned short * block,struct user * u,unsigned long size,unsigned short protection);bool deleteInode(struct inode * node,unsigned short * block,unsigned short index);bool setProtection(struct inode * i,unsigned short p);bool setCreateTime(struct inode * i,time_t time);bool setAccessTime(struct inode * i,time_t time);bool setModificationTime(struct inode * i,time_t time);
3. 目录项的定义和实现 目录项在linux系统的定义相对简单,在作业中我也进行了简化,目录项的数据结构有 1) 目录名 最大支持255字节的文件名 2) 目录对应的i节点编号 3) 目录项的类型 定义的代码:
#define UNDEFIEN 0#define DIRENT_TYPE 1
#define FILE_TYPE 2#define DIRENT_NAME_LENGTH_MAX 128
#define TOTAL_DIRENT 64
#define DIRENT_UNDEFIEN 64struct dirent
{unsigned short inode_num;unsigned short dirent_type;char dirent_name[DIRENT_NAME_LENGTH_MAX];
};void initRootD();void saveRoot(struct dirent * d);bool createDirentD(struct dirent * allDirents,const char * name,unsigned short inode_num);bool creatFileD(struct dirent * allDirents,const char * name,unsigned short inode_num);bool isDirentEmpty(struct dirent * allDirents,struct inode * node,int index);unsigned short deleteDir(struct dirent * allDirents,int index);void listDirent(struct dirent * allDirents,struct inode * allInodes);bool openRoot(struct dirent * d);struct dirent * openDir(struct dirent * allDirents,int index,struct inode * node);void saveDir(struct dirent * allDirents,struct inode * allInodes);bool closeDir(struct dirent * allDirents,int index,struct inode * node);void createChildD(unsigned short father_inode_num,unsigned short child_inode_num,unsigned short * disk_add);void createChildF(unsigned short * disk_add,char * file_content);void readFile(struct dirent * allDirents,struct inode * node,int index);int checkDir(struct dirent * allDirents,const char * name);bool openDir(struct dirent * allDirents,struct inode * node,int index);
4. 用户的定义和实现 因为是二级文件系统,通过对二级文件系统的定义了解到二级文件系统的第一级是用户,用户登录后进入文件系统第二级,第二级就是对文件系统的操作。用户的数据结构包括以下几个数据项 1) 用户id 2) 用户名 3) 用户登录密码 由于时间的关系,对用户没有进行过多的设置,创建用户后没有提供修改用户账户密码的功能。。。。。。 #define TOTAL_USER 32 //该文件系统允许到最大用户数目
#define USER_UNDEFINE 32#define USER_NAME_MAX_LENGTH 32 //用户名到最大长度
#define USER_PASSWORD_MAX_LENGTH 16 //密码到最大长度#define SUPERUSER 0struct user
{unsigned int user_id;char user_name[USER_NAME_MAX_LENGTH];char user_password[USER_PASSWORD_MAX_LENGTH];
};int checkUser(struct user * allUsers,const char * name);struct user * login(struct user * allUsers,const char * name,const char * password);bool createUser(struct user * allUsers,const char * name,const char * password);bool deleteUser(struct user * allUsers,struct user * u);void initUser();bool openUser(struct user * u);void listUser(struct user * u);void saveUser(struct user * u);
5. 主程序的实现
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include"user.h"
#include"dirent.h"
#include"block.h"
#include"inode.h"int main(int argc, char * *argv) {if (0) {initUser();initBlock();initRootD();initInode();}struct user allUsers[TOTAL_USER];struct inode allInodes[TOTAL_INODE];struct dirent allDirents[TOTAL_DIRENT];unsigned short allBlocks[TOTAL_BLOCK];struct user * nowUser;int choise;bool controler = true;char name[USER_NAME_MAX_LENGTH];char password[USER_PASSWORD_MAX_LENGTH];char dirent_name[DIRENT_NAME_LENGTH_MAX];char file_name[DIRENT_NAME_LENGTH_MAX];char file_content[INODE_TO_BLOCK * FILE_BLOCK_MAX_LENGTH];printf("---欢迎使用Lee制作的模拟文件系统---\n""本文件系统又命名为YY文件系统\n");//登录和注册的循环while (controler) {if (!openUser(allUsers)) {exit(1);}printf("请选择\n1: 老用户登录\t 2: 新用户注册\t 3:退出\n");scanf("%d", &choise);printf("你的输入是:%d\n", choise);switch (choise) {case 1:printf("欢迎你,老用户\n");printf("请输入用户名:\n");scanf("%s", name);printf("请输入密码:\n");scanf("%s", password);nowUser = login(allUsers, name, password);if (nowUser == NULL) {printf("你输入的用户名或密码有错误\n");continue;} else {if (!openRoot(allDirents)) {printf("读取根目录的时候出错,请重新登录\n");continue;}printf("你已经成功登录到Lee到文件系统\n");//进入文件系统后的循环while (allDirents != NULL && openInode(allInodes)&& openBlock(allBlocks)) {printf("%s@Lee:/\n", nowUser->user_name);listDirent(allDirents, allInodes);if (allDirents[0].inode_num == allDirents[1].inode_num) {printf("请选择\n""1: 创建一个目录\t 2: 进入一个目录\t 3:删除一个目录\n""4:创建一个文件\t 5:打开一个文件\t 6:删除一个文件\n""7:退出\n");} else {printf("请选择\n""1:创建一个目录\t 2:进入一个目录\t 3:删除一个目录\n""4:创建一个文件\t 5:打开一个文件\t 6:删除一个文件\n""7:返回上一级目录\n");}int action;scanf("%d", &action);unsigned short inode_num; //获取分配到到inode的序号unsigned short protection; //设置保护位unsigned short inode_i; //inode到序号int dir_i; //目录项序号unsigned short block_d[INODE_TO_BLOCK]; //删除的block的块序列switch (action) {case 1:printf("请输入目录名:\n");scanf("%s", dirent_name);if (checkDir(allDirents, dirent_name) != DIRENT_UNDEFIEN) {printf("你输入到目录名重复,请重新输入!!\n");continue;}inode_num = createDirentI(allInodes, allBlocks,nowUser);if (inode_num != INODE_UNUSERD) {if (!createDirentD(allDirents, dirent_name,inode_num)) {printf("创建目录项dirent到时候发生ERROR");exit(1);} else {createChildD(allDirents[0].inode_num, inode_num,allInodes[inode_num].disk_add);saveBlock(allBlocks);saveInode(allInodes);saveDir(allDirents, allInodes);printf("成功创建了一个目录\n");}} else {printf("分配INODE的时候发生ERROR");exit(1);}break;case 2:printf("请输入目录名:\n");scanf("%s", dirent_name);dir_i = checkDir(allDirents, dirent_name);if (dir_i == DIRENT_UNDEFIEN) {printf("你输入到目录名有误,请重新输入!!\n");continue;}if (!openDir(allDirents, allInodes, dir_i)) {printf("打开目录的时候出错,请重新尝试!!\n");continue;}break;case 3:printf("请输入要删除的目录名:\n");scanf("%s", dirent_name);dir_i = checkDir(allDirents, dirent_name);if (dir_i == DIRENT_UNDEFIEN) {printf("你输入到目录名有误,请重新输入!!\n");continue;}if (!isDirentEmpty(allDirents, allInodes, dir_i)) {printf("该目录下面有子文件或者子目录,请谨慎删除!!\n");continue;} else {inode_i = deleteDir(allDirents, dir_i);if (inode_i != INODE_UNUSERD) {if (deleteInode(allInodes, block_d, inode_i)) {if (deleteBlock(block_d)) {if (retrieveBlocks(block_d,allBlocks)) {saveBlock(allBlocks);saveInode(allInodes);saveDir(allDirents, allInodes);printf("成功删除了该文件!!\n");}else {printf("重置该文件的磁盘块配置文件出错!!\n");}} else {printf("删除该文件的block出错!!\n");}}} else {printf("删除该文件的dirent出错!!\n");}}break;case 4:printf("请输入文件名:\n");scanf("%s", file_name);if (checkDir(allDirents, file_name) != DIRENT_UNDEFIEN) {printf("你输入到目录名重复,请重新输入!!\n");continue;}printf("请输入文件的内容:\n");scanf("%s", file_content);printf("请设置文件保护信息\n 1:只读\t2:只写\t3:读和写\n");protection = 0; //设置保护位scanf("%hu", &protection);
// printf("%hu\n", protection);inode_num = createFileI(allInodes, allBlocks, nowUser,strlen(file_content), protection);printf("%d\n", inode_num);if (inode_num != INODE_UNUSERD) {if (!creatFileD(allDirents, file_name, inode_num)) {printf("创建目录项dirent到时候发生ERROR");exit(1);} else {createChildF(allInodes[inode_num].disk_add,file_content);saveBlock(allBlocks);saveInode(allInodes);saveDir(allDirents, allInodes);printf("成功创建了一个文件\n");}} else {printf("分配INODE的时候发生ERROR");exit(1);}break;case 5:printf("请输入要读取的文件名:\n");scanf("%s", file_name);dir_i = checkDir(allDirents, file_name);if (dir_i == DIRENT_UNDEFIEN) {printf("你输入的文件名有误,请重新操作!!\n");continue;}readFile(allDirents, allInodes, dir_i);printf("是否对文件进行读写保护位设置\n""请选择\n1: 是\t 2: 否并且退出\n");int operation;scanf("%d", &operation);if (operation == 1) {printf("请设置文件保护信息\n 1:只写\t2:只读\t3:读和写\n");protection = 0; //设置保护位scanf("%hu", &protection);if(setProtection(&allInodes[allDirents[dir_i].inode_num],protection)){saveInode(allInodes);printf("请设置文件保护信息成功\n");}else{printf("请设置文件保护信息失败\n");}}break;case 6:printf("请输入要删除的文件名:\n");scanf("%s", file_name);dir_i = checkDir(allDirents, file_name);if (dir_i == DIRENT_UNDEFIEN) {printf("你输入的文件名有误,请重新操作!!\n");continue;}inode_i = deleteDir(allDirents, dir_i);if (inode_i != INODE_UNUSERD) {if (deleteInode(allInodes, block_d, inode_i)) {if (deleteBlock(block_d)) {if (retrieveBlocks(block_d, allBlocks)) {saveBlock(allBlocks);saveInode(allInodes);saveDir(allDirents, allInodes);printf("成功删除了该文件!!\n");} else {printf("重置该文件的磁盘块配置文件出错!!\n");}} else {printf("删除该文件的block出错!!\n");}}} else {printf("删除该文件的dirent出错!!\n");}break;case 7:if (allDirents[0].inode_num== allDirents[1].inode_num) {//Do nothingprintf("---欢迎你再次使用YY文件系统!---\n");exit(1);} else {dir_i = checkDir(allDirents, ".."); //其实就是重复第二部,打开“..”文件夹if (dir_i == DIRENT_UNDEFIEN) {printf("你输入到目录名有误,请重新输入!!\n");continue;}if (!openDir(allDirents, allInodes, dir_i)) {printf("打开目录的时候出错,请重新尝试!!\n");continue;}}break;default:printf("你的选择有错误,请重新选择!\n");break;}}printf("读取系统目录出错,请重新登录尝试\n");continue;}break;case 2:printf("欢迎你,老用户\n");printf("请输入用户名:\n");scanf("%s", name);while (checkUser(allUsers, name) != USER_UNDEFINE) {printf("你输入到用户名已被注册,请重新输入\n");scanf("%s", name);}printf("请输入密码:\n");scanf("%s", password);if (!createUser(allUsers, name, password)) {printf("注册的过程发生错误,请重新选择\n");} else {saveUser(allUsers);printf("注册成功,请进行登录或其他操作!\n");}break;case 3:controler = false;printf("已经为你退出系统!\n");break;default:printf("你的选择有错误,请重新选择!\n");break;}}}
【运行结果】 截图:(截图省略) 1.登录注册 2.用户注册 3.用户登录 4.进入文件系统后的功能选择 5.进入一个目录 6.在目录下创建目录(目录名可以包含空格) 7.在目录下创建一个文本文件(文件名可以包含空格) 8.打开一个文本文件 9.对文件进行保护位设置 10. 设置为只写之后就不能读取了 11. 删除文本文件 12. 删除一个目录 13. 非根目录可以返回上一级目录 14. 根目录可以退出程序 15. 同名检查,输入同名文件将会被拒绝 16. 访问权限出错 17. 访问文件类型出错 |