【实验方案设计】 为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 2
void 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 3
struct inode
{
unsigned short file_type; //文件类型 目录 或者 文件
unsigned short protection; //保护位 读 写 读写同时
unsigned int link_num; //指向该节点到目录项
unsigned int user_id; //文件所属用户到id
unsigned 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 64
struct 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 0
struct 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 nothing
printf("---欢迎你再次使用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. 访问文件类型出错 |