模拟文件系统课程设计

课程设计的实验文档,简单模拟linux文件系统的结构并作简单实现

实验概述

【实验目的及要求】

通过一个简单多用户文件系统的设计,加深理解文件系统的内部功能及内部实现。

【实验原理】

1. 通过对课本第四章文件系统的理解,分析了Unix系统的文件系统的实现原理

2. 对linux c提供的文件系统的操作函数的数据结构,函数功能进行分析

3. 将课本P181 图4-35的图进行代码实现

4. 在linux环境下进行实践,熟悉ls –all 列目录,创建目录,linux c编程

【实验环境】

Linux Ubuntu

VMware 虚拟机

Window 7 操作系统

Eclipse C/C++ IDE

实验内容

【实验方案设计】

为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. 访问文件类型出错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值