用C/C++写一个Linux文件系统模拟器
- 1. 程序演示
- 1. 登录--login
- 2. 切换目录--- cd
- 3. 展示文件列表---ls
- 4. 查看物理块使用情况以及物理块存储内容 — df
- 5. cd命令的延伸 :
- 6. 查看当前目录名和父目录名 —— now
- 7. 创建文件—— touch
- 8. 打开文件 —— open
- 9. 查看当前活动文件 —— ASL
- 10. 写文件操作 —— write
- 11. 读文件的全部内容 —— cat
- 12. head -num 读取文件头num行
- 13. tail -num 读取头文件num行
- 14. 关闭文件 —— close
- 15. 递归查找文件 —— find
- 16. 复制文件 —— cp
- 17. 移动文件 —— move
- 18. 创建文件夹 —— mkdir
- 19. 删除文件夹 —— rm -rf
- 20. 删除文件 —— rm -f
- 2. 代码部分
- 2.1 本项目使用的结构体
- 2.1.1 用户结构
- 2.1.2 文件控制块
- 2.1.3 文件结构
- 2.1.4 物理块结构
- 2.1.5 活动符号名表
- 2.2 完整代码
- 3.结语
1. 程序演示

home目录下包含如下文件

其中root文件夹内存有account.txt,用于存储用户登录信息,在虚拟磁盘初始化时将之读入用户组结构并用于验证登录。

运行程序:

1. 登录–login
运行程序后只能先登录才能进行操作,不然会系统提示进行登录,输入help可以查看命令帮助文件。

2. 切换目录— cd
3. 展示文件列表—ls

对应本地真实目录可知,初始化成功,目录树建立成功,且各个文件/文件夹的大小、路径、文件类型、读写权限、所属用户都初始化成功!


4. 查看物理块使用情况以及物理块存储内容 — df



df命令中展示了已占用物理块的存储内容:
(1)complete file of xxx : 表明该物理块存储了一个完整的文件
(2)parts of xxx: 表明该物理块存储了一个文件的部分内容
(3)IndexBlock of xxx: 表明该物理块为索引物理块
可见初始化时占用物理块为462块,大约占用了虚拟磁盘462KB的空间,由于在该虚拟磁盘中文件夹都单独占用一个索引物理块,且所有的索引物理块不存储具体文件内容,故其空间开支稍大于实际空间开支,可由比较本地实际目录大小(436KB)可证明。

5. cd命令的延伸 :
(1)cd ./ :返回当前目录
(2)cd …/ :返回上一级目录
(3)cd home :返回用户根目录
6. 查看当前目录名和父目录名 —— now

7. 创建文件—— touch

同时在本地文件中也进行了创建文件的操作

8. 打开文件 —— open
9. 查看当前活动文件 —— ASL

若输入的文件名不正确会有相应提示。
10. 写文件操作 —— write
(1) write -a 追加写入文件
(2) write -c 覆盖写入文件

若是没有将文件打开就要写入则会提示先将文件打开;

成功写入。
注意在写入文件后,文件的大小以及所属父目录的大小都得到更新。

11. 读文件的全部内容 —— cat

若没有将文件打开就进行读操作则会进行提示。

下面读取inode.txt为例,由于文件较长,只截取开头和结尾部分(inode.txt为编写该项目的过程中留下的一份备份txt文件):


12. head -num 读取文件头num行
13. tail -num 读取头文件num行

14. 关闭文件 —— close

15. 递归查找文件 —— find

16. 复制文件 —— cp

本地文件夹同步实现了复制操作

而且物理块也实现了相应的变化,增加了新文件占用的物理块:

17. 移动文件 —— move


18. 创建文件夹 —— mkdir

19. 删除文件夹 —— rm -rf
在新建的OSmenu文件夹中新建两个文件(一个创建,一个通过复制创建)后进行删除


本地文件夹中也同步了操作
下面进行删除,可以将文件夹以及其中的文件都删掉

文件夹也同步了该操作

20. 删除文件 —— rm -f

本地文件夹也同步了相应操作

2. 代码部分
2.1 本项目使用的结构体
代码中使用到的结构体信息如下:
2.1.1 用户结构
用户结构体中包含用户的用户名和密码,以及该用户的个人根目录。
`typedef struct User_Type
{
string username;//用户名
string password;//密码
struct FSct_Type *userFile;//指向该用户的"根"目录
}User;
2.1.2 文件控制块
该文件控制块结构在文件结构中的集合构成了文件目录。
typedef struct FCB{
User *Owner[12];//指向用户数据结构User的指针
int innerNum; //内部号
string fileName; //文件名
string type; // 文件类型
double length; //文件长度
long int authority; //读写权限
int phNum; //物理块号
struct PHB_Type *firstBlock; //首物理块
}FCB;
2.1.3 文件结构
文件结构中包含了以下信息:
(1)文件的名称;
(2)文件的路径;
(3)文件的所属用户组(考虑到可以实现文件共享);
(4)以及该目录下的文件目录表(由12个文件控制块组成,即限制了每个文件夹最多放置12个文件);
(5)文件内容(由于文件类型较多,此处的文件内容暂时用”parts of xxx”等来替代);
(6)子文件/子目录指针(与文件控制块fcb相对应,共12个);
(7)父目录指针(只有一个);
typedef struct FSct_Type{
string fileName;
string filePath;
User *Owner[12]; //用户账号
FCB *fcb[12]; //文件目录
char content[50]; //文件内容
struct FSct_Type *child[12]; //指针数组,指向二级文件结构
struct FSct_Type *pre; //指针,指向父目录
}FSct;
2.1.4 物理块结构
物理块结构包含了以下信息:
(1)物理块号;
(2)每个物理块的大小:该项目规定每个物理块的大小为1024B,即1KB;
(3)物理块状态标识符,空闲状态为0,占用状态为0;
(4)物理块索引表:当所存储的文件大小大于1KB时,其首物理块存储一个物理块索引表;
(5)索引指针:当所存储的文件大小大于1KB时,指向其他实际存储文件信息的物理块;
(8)物理块所存内容:由于文件类型较多,并不一定都可按字符读出保存到虚拟磁盘,此处的文件内容暂时用”parts/complete/index of xxx”等来替代。
typedef struct PHB_Type{
long int phNum; //物理块号
long int chunckSize = 1024; //每个块大小为1024B 即1KB
int state = 0; //物理块状态标识符
long int indexList[300]; //该块所保存的索引表
struct PHB_Type *child[300]; //索引表指向的块
string content;//该块所保存的内容
}PHB;
2.1.5 活动符号名表
活动符号名表用于存储打开文件的信息,该结构包含以下信息:
(1)文件名;
(2)对应文件控制块的内部号;
(3)文件路径(便于区分不同目录下的同名文件);
(4)指向活动文件表的指针。
typedef struct Active_symbol_list{
string fileName;
int innerNum;//内部号
string path;//文件路径
struct Active_file_list *afl;
struct Active_symbol_list *next;
}ASL;
2.1.6活动文件表
活动文件表用于存储文件目录的及本条目,即文件控制块。
typedef struct Active_file_list{
FCB *fcb;//由基本文件目录项(FCB块)组成的数组
struct Active_file_list *next;
}AFL;
2.2 完整代码
#include <pthread.h>
#define NUM_THREADS 1 //多线程并发数
#include <iostream>
#include<fstream>
#include<string>
#include<cstring>
#include<iomanip>
#include <malloc.h>
#include <vector>
#include <io.h>
#include <Windows.h>
#include <sys\stat.h>
using namespace std;
#define BUFFER_SIZE string homePath("C:\\Users\\SeanWayen\\Desktop\\home");
string path("C:\\Users\\SeanWayen\\Desktop\\home");
string tmpPath = homePath;//用户数据结构
typedef struct User_Type
{string username;//用户名string password;//密码struct FSct_Type *userFile;//指向该用户的"根"目录 ,即在注册或从文件导入数据生成一个 用户时要给用户指向一个文件
}User;//文件控制块
typedef struct FCB{User *Owner[12];//指向用户数据结构User的指针 int innerNum;//内部号 string fileName;//文件名 string type;// 文件类型 double length;//文件长度 long int authority;//读写权限 int phNum; //物理块号 struct PHB_Type *firstBlock;
}FCB;//文件结构
typedef struct FSct_Type{int i;string fileName;string filePath; User *Owner[12];//用户账号 FCB *fcb[12]; //文件目录 char content[50];//文件内容 (待处理) struct FSct_Type *child[12];//指针数组,指向二级文件结构 struct FSct_Type *parent;//指针,指向父目录 struct FSct_Type *pre;//指针,指向父目录
}FSct;//物理块结构
typedef struct PHB_Type{long int phNum;//物理块号 (在程序初始化时要自动生成) long int chunckSize = 1024;//每个块大小为1024B 即1KBint state = 0;//初始化时 所有块都为0表示空闲,被占用时状态为1 long int indexList[300];//该块所保存的索引表 struct PHB_Type *child[30];//索引表指向的块 string content;//该块所保存的内容
}PHB; //活动符号名表
typedef struct Active_symbol_list{string fileName;int innerNum;//内部号 string path;//文件路径 struct Active_file_list *afl;struct Active_symbol_list *next;
}ASL;//活动文件表
typedef struct Active_file_list{FCB *fcb;//由基本文件目录项(FCB块)组成的数组 struct Active_file_list *next;
}AFL; PHB phBlock[1024*1024];//一共2^20个block,每个block大小为1KB,虚拟磁盘共1GB
User uGroup[12];//用户组数组,后期要将文件中的用户读入
FSct *UserFile[12];//12个用户对应12个用户根目录
//FSct *home = (FSct *)malloc(sizeof(FSct));//home目录
FSct *home = new FSct;
string userPath[12];
ASL *Shead = new ASL;//活动符号名表 表头
AFL *Fhead = new AFL;//活动文件表 表头
int FileNum_Curr = 0; //当前文件数目 //引导函数
void help(){cout <<endl; cout << "*******************欢迎使用多级文件系统*******************" << endl<<endl;cout << " 命令 说明 " << endl;cout << " login 登录 " << endl;cout << " cd 更改当前目录 " << endl;cout << " ls 展示文件列表 " << endl;cout << " touch 创建文件 " << endl;cout << " rm -f 删除文件 " << endl;cout << " mkdir 创建目录 " << endl;cout << " rm -rf 递归地删除目录及其文件 " << endl;cout << " open 打开文件 " << endl; cout << " close 关闭文件 " << endl;cout << " cat 读文件到控制台 " << endl; cout << " tail -num 显示文件尾num行 " << endl;cout << " head -num 显示文件头num行 " << endl;cout << " write -c 写入文件(覆盖) " << endl;cout << " write -a 写入文件(追加) " << endl; cout << " find 递归地查找文件 " << endl;cout << " cp 复制文件 " << endl;cout << " move 移动文件 " << endl;cout << " export 导出文件 " << endl;cout << " import 导入文件 " << endl<<endl;cout << "*******************欢迎使用多级文件系统*******************" << endl;cout <<endl;
} //查看用户组
void check_uGroup(){cout<<"——————————" <<endl<<"查看用户组"<<endl;for(int i=0; i<sizeof(uGroup); i++){if(uGroup[i].username.length()!=0){cout<<"uGroup["<<i<<"]:"<<endl;cout<<"username:"<<uGroup[i].username<<endl;cout<<"password:"<<uGroup[i].password<<endl;}else{break;}}cout<<"——————————" <<endl;
}//查看物理块使用情况
void check_phBlock(){cout<<"——————————" <<endl<<"查看物理块使用情况"<<endl;double Use = 0.0;double NotUse = 0.0;double UsingRate;cout<<"已被使用的物理块号:"<<endl; for(long int i=0; i<1024*1024; i++){if(phBlock[i].state==1){cout<<i<<"|";Use++;}else{NotUse++;}}UsingRate = Use/(Use+NotUse);cout<<endl<<"已使用物理块数目:"<<Use<<endl;cout<<"空闲物理块数目:"<<NotUse<<endl; cout<<"物理块总数:"<<Use+NotUse<<endl; cout<<"磁盘利用率:"<< UsingRate<<endl;cout<<"——————————" <<endl;
}//读取用户组uGroup信息 int account(string path){ifstream in(path);string line;int i=0;if(in) // 有该文件while (getline (in, line)){string info = line;string ID = info.substr(0,info.find_first_of(","));string PW = info.substr(info.find_first_of(",")+1,info.length());uGroup[i].username = ID;uGroup[i].password = PW;//cout<<"账号:"<<uGroup[i].username<<endl<<"密码:"<<uGroup[i].password<<endl; i++;//cout<< line <<endl;} else // 没有该文件cout <<"no such file" << endl;in.close();return i;
}int index(){int num = -1;int flag= 0;while(num == -1){cout<<"localhost: " ;string tmpOrder;cin>>tmpOrder;//登录界面 if(tmpOrder == "login"){cout<<"user: ";string ID;cin>>ID;cout<<"passwords: ";string PW;cin>>PW;for(int i=0;i<sizeof(uGroup);i++){if(uGroup[i].username == ID && uGroup[i].password == PW){num = i;flag =1 ;break;}}}else if(tmpOrder == "help"){help();}else{cout<<"please login first !"<<endl;}
}if(flag == 0){cout<<"No such account!"<<endl; return -1;} else if(flag == 1){cout<<"Login succed !"<<endl;return num;}
}int REGISTER()//(1)向用户组增添新成员 (2)初始化该用户的文件目录 //目前相当于初始化
{cout << "请输入用户名:";string userName;cin >> userName;cout << "请输入密码:";string passWord;cin >> passWord;for(int i=0; i<sizeof(uGroup); i++){if (uGroup[i].username == userName){cout<<i<<endl;cout<< uGroup[i].username<<endl;cout << "注册失败,该用户名已存在" << endl;break;}if(uGroup[i].username.length()==0){uGroup[i].username = userName;uGroup[i].password = passWord;cout << "注册成功" << endl;home->fcb[i] = new FCB;home->fcb[i]->innerNum = i;home->fcb[i]->fileName = uGroup[i].username;//强制命名为用户名,用户无权限修改该名称home->fcb[i]->authority = 666;//默认新建目录权限home->fcb[i]->type = "dir";//文件类型为目录 home->fcb[i]->phNum = i;// 假设一级目录 默认块号 为i,物理块i中存储一个索引表; home->fcb[i]->firstBlock = new PHB;//将该FCB指向其首物理块home->fcb[i]->firstBlock->state = 1; //表示此块已被占用 home->fcb[i]->firstBlock->phNum = i;//物理块内部标识的物理块号phBlock[i]. state = 1; //在物理外存上进行标识,方便为新文件分配空间 phBlock[i].content = "用户根目录"+i; home->child[i] = new FSct;home->child[i]->fileName = uGroup[i].username;home->child[i]->Owner[0] = new User;//为用户文件中的结构体指针开辟空间 home->child[i]->Owner[0]->username=uGroup[i].username;break; }}return 1;
}//获取文件大小
double get_length(string filePath){double sizeKB = 0;ifstream fin( filePath );if( fin.is_open() ){fin.seekg( 0, ios::end );double size = fin.tellg();if(size == 0){sizeKB = 0;}else{sizeKB = size/1024;}fin.close();}return sizeKB;
}//递归计算文件夹大小
double getDirSize(string path)//获取path下所有文件的名称 ,包含递归查询所有的子目录下的文件 ,但不包含目录
{//文件句柄intptr_t hFile = 0;vector<string> files; //文件信息struct _finddata_t fileinfo;string p;double filesize;int i = 0;if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1){do{if ((fileinfo.attrib & _A_SUBDIR))//判断是否是文件夹 {//如果是目录,递归查找if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0){filesize +=getDirSize(p.assign(path).append("\\").append(fileinfo.name));}}else{//如果不是,把文件绝对路径存入vector中filesize += get_length(path+"\\"+fileinfo.name);}} while (_findnext(hFile, &fileinfo) == 0);_findclose(hFile);}return filesize;
}//给一级目录的文件长度赋值
void Give_Length(){string path("C:\\Users\\SeanWayen\\Desktop\\home"); intptr_t hFile = 0;struct _finddata_t fileinfo;string p;int i=0;if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1){do{if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0){string filePath(path+"\\"+fileinfo.name);if ((fileinfo.attrib & _A_SUBDIR))//是文件夹 {double sizeKB = getDirSize(filePath); //递归计算文件夹大小 home->fcb[i]->length = sizeKB;i++ ; }else{double sizeKB = get_length(filePath);home->fcb[i]->length = sizeKB;i++ ; }}} while (_findnext(hFile, &fileinfo) == 0);_findclose(hFile);//cout<<endl;}
}void ls_alh(){//详细展示文件信息,待修改的问题还有两个:(1)KB和MB和GB的单位需要写一个switch/if-elseif转换 (2)文件夹的大小返回值仍为0,还需递归计算文件夹大小 int j=0;while(home->fcb[j]){//cout<<i<<endl; cout<<home->fcb[j]->type<<'\t'<<home->fcb[j]->authority<<"\t"<<home->fcb[j]->fileName<<"\t";if(home->fcb[j]->length < 512 && home->fcb[j]->length > 0.01){cout<<setprecision(3)<< home->fcb[j]->length<<"KB"<<"\t";}else if(home->fcb[j]->length > 512){cout<<setprecision(3)<< (home->fcb[j]->length)/1024 <<"MB"<<"\t";//如果文件大于1024KB则按照MB单位输出 }else if(home->fcb[j]->length < 0.01){cout<<setprecision(3)<< (home->fcb[j]->length)*1024 <<"B"<<"\t";//如果文件大于1024KB则按照MB单位输出 }cout<<home->fcb[j]->fileName<<'\t'<<endl;j++;}
}string ID_path = "C:\\Users\\SeanWayen\\Desktop\\home\\root\\account.txt";//一级目录(用户目录)初始化(每个文件夹占一个物理块,该物理块内部存储文件夹中内容列表)
void Initial(string path){//先读入用户组信息int userNum = account(ID_path); Shead->next = NULL;Fhead->next =NULL;vector<string> fileNames;cout<<"初始化... "<<endl;//文件句柄intptr_t hFile = 0;int key = 0;//文件信息struct _finddata_t fileinfo;string p;if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1){do{if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0){userPath[key]=(path+"\\"+fileinfo.name);key++;// cout<<fileinfo.name<<" ";for(int i=0; i<sizeof(uGroup); i++){if(uGroup[i].username == fileinfo.name){home->fcb[i] = new FCB;home->fcb[i]->innerNum = i;home->fcb[i]->fileName = uGroup[i].username;//强制命名为用户名,用户无权限修改该名称home->fcb[i]->authority = 666;//默认新建目录权限if ((fileinfo.attrib & _A_SUBDIR)){home->fcb[i]->type = "dir";//文件类型为目录 }else{home->fcb[i]->type ="—";//可以分的更细致 }home->fcb[i]->phNum = i;// 假设一级目录 默认块号 为i,物理块i中存储一个索引表; home->fcb[i]->Owner[0]=new User;home->fcb[i]->Owner[0]->username=uGroup[i].username;//开辟物理块 home->fcb[i]->firstBlock = new PHB;//将该FCB指向其首物理块home->fcb[i]->firstBlock->state = 1; //表示此块已被占用 home->fcb[i]->firstBlock->phNum = i;//物理块内部标识的物理块号phBlock[i]. state = 1; //在物理外存上进行标识,方便为新文件分配空间 phBlock[i].content = ("User Directory: "+home->fcb[i]->fileName); home->child[i] = new FSct;// home->child[i]->parent = home;home->child[i]->fileName = fileinfo.name;home->child[i]->filePath = (path+"\\"+fileinfo.name);home->child[i]->Owner[0] = new User;//为用户文件中的结构体指针开辟空间 home->child[i]->Owner[0]->username=uGroup[i].username;break; }} } } while (_findnext(hFile, &fileinfo) == 0);_findclose(hFile);//cout<<endl;}Give_Length();
}//给二级目录的文件下所有文件长度赋值 (递归)
void Give_Length_Sec_ByTree(string path,FSct *tmpFile){intptr_t hFile = 0;struct _finddata_t fileinfo;string p;int i=0;if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1){do{if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0){string filePath(path+"\\"+fileinfo.name);if ((fileinfo.attrib & _A_SUBDIR))//是文件夹 {double sizeKB = getDirSize(filePath); //递归计算文件夹大小 tmpFile->fcb[i]->length = sizeKB; i++ ; }else{double sizeKB = get_length(filePath);tmpFile->fcb[i]->length = sizeKB;i++ ; }}} while (_findnext(hFile, &fileinfo) == 0);_findclose(hFile);// cout<<endl;}
}//给二级文件系统(用户目录系统)下 的文件分配物理块 (递归)
void setBlock_ByTree(FSct *tmpFile){
for(int i = 0; i<12;i++){if(tmpFile->fcb[i] != NULL){if(tmpFile->fcb[i]->type == "—"){if(tmpFile->fcb[i]->length < 1){tmpFile->fcb[i]->firstBlock->content = ("complete file of "+tmpFile->fcb[i]->fileName);long int phNum = tmpFile->fcb[i]->firstBlock->phNum;//注意一下动态分配数组已限定一个文件的最大大小string tmpContent = ("complete of "+tmpFile->fcb[i]->fileName);phBlock[phNum].content =tmpContent;}else if(tmpFile->fcb[i]->length > 1){//先处理在初始化就分配好的块 tmpFile->fcb[i]->firstBlock->content = ("IndexBlock of "+tmpFile->fcb[i]->fileName);long int phNum = tmpFile->fcb[i]->firstBlock->phNum;//注意一下动态分配数组已限定一个文件的最大大小phBlock[phNum].content = ("IndexBlock of "+tmpFile->fcb[i]->fileName);int count = tmpFile->fcb[i]->length/1.0;if(tmpFile->fcb[i]->length > count+0.5) count++;//count为实际要为该文件分配的块数 int tmpNum = 0;for(long int num=0;num < 1024*1024; num++){if(phBlock[num].state==0 && tmpNum<=count){phBlock[num].state = 1;string tmpContent = ("Parts file of "+tmpFile->fcb[i]->fileName);phBlock[num].content = tmpContent;int first = tmpFile->fcb[i]->firstBlock->phNum;phBlock[first].indexList[tmpNum] = num; //还要处理动态分配数组 tmpNum++;}if(tmpNum == count) break;}}}else if(tmpFile->fcb[i]->type == "dir") {tmpFile->fcb[i]->firstBlock->content = ("DirBlock of "+tmpFile->fcb[i]->fileName);long int phNum = tmpFile->fcb[i]->firstBlock->phNum;//这里的firstBlock在初始化的时候已经分配了 string tmpContent = ("DirBlock of"+tmpFile->fcb[i]->fileName);phBlock[phNum].content =tmpContent;// tmpFile->child[i] = new FSct;//在初始化的时候这个结点就已经开辟了 //递归分配物理块 // setBlock_ByTree(tmpFile->child[i]); //这不用递归!!!因为递归的出口是文件而不是文件夹!在初始化中进行一次递归即可!!! }}}
}//二级目录初始化(每个文件夹占一个物理块,该物理块内部存储文件夹中内容列表) (递归)
void Initial_Sec_ByTree(string path, FSct *TMPFILE, FSct *parentFile, int key){vector<string> fileNames;//cout<<"初始化"+path+"下包括目录的所有文件结构 "<<endl;//文件句柄intptr_t hFile = 0;//文件信息struct _finddata_t fileinfo;string p;if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1){do{if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0){for(int i=0; i<12; i++){ //12是一个文件夹中文件的最大限制 if(TMPFILE->fcb[i] == NULL){FSct *tmpFile = new FSct;tmpFile = TMPFILE;//在每个循环中new一个新结点,相当于复位,但是空间开支多了 tmpFile->child[i] = new FSct;tmpFile->child[i]->fileName = fileinfo.name;tmpFile->child[i]->filePath = (path+"\\"+tmpFile->child[i]->fileName);tmpFile->fcb[i] = new FCB;tmpFile->fcb[i]->innerNum = i;tmpFile->fcb[i]->fileName = fileinfo.name;tmpFile->fcb[i]->authority = 666;//默认新建目录权限if ((fileinfo.attrib & _A_SUBDIR)){ //要对此处做递归初始化 tmpFile->fcb[i]->type = "dir";//文件类型为目录 }else{tmpFile->fcb[i]->type ="—";//可以分的更细致 }//处理物理块的分配 for(long int num=0;num<1024*1024;num++){// 需要去找一个空闲块号 if(phBlock[num].state == 0 ){//cout<<num<<endl; tmpFile->fcb[i]->phNum = num;phBlock[num].state = 1;// cout<<"初始化成功,(首)物理块号为:"<<tmpFile->fcb[i]->phNum<<" ";// cout<<"文件类型:"<<tmpFile->fcb[i]->type<<endl; //开辟物理块 tmpFile->fcb[i]->firstBlock = new PHB;//将该FCB指向其首物理块tmpFile->fcb[i]->firstBlock->state = 1; //表示此块已被占用 tmpFile->fcb[i]->firstBlock->phNum = num;//物理块内部标识的物理块号break; //注意这个break要写在if语句的里面 } }tmpFile->fcb[i]->Owner[0]=new User;tmpFile->fcb[i]->Owner[0]->username = uGroup[key].username;if(tmpFile->fcb[i]->type == "dir" ){//如果是文件,递归初始化一下 //tmpFile->child[i]->parent = tmpFile;FSct *newFile = new FSct;newFile = tmpFile->child[i];Initial_Sec_ByTree((path+"\\"+fileinfo.name),newFile,tmpFile,key);}break; }} } } while (_findnext(hFile, &fileinfo) == 0);_findclose(hFile);//cout<<endl;}Give_Length_Sec_ByTree(path,TMPFILE);setBlock_ByTree(TMPFILE); }//二级文件 的ls-alh
void ls_alh_ByTree(FSct *tmpFile){//详细展示文件信息 key是home->child[key]中的索引 for(int j=0;j<12;j++){if(tmpFile->fcb[j]){cout<<tmpFile->fcb[j]->type<<'\t'<<tmpFile->fcb[j]->authority<<"\t"<<tmpFile->fcb[j]->Owner[0]->username<<"\t";if(tmpFile->fcb[j]->length < 512 && tmpFile->fcb[j]->length > 0.01){cout<<setprecision(3)<< tmpFile->fcb[j]->length<<"KB"<<"\t";}else if(tmpFile->fcb[j]->length > 512){cout<<setprecision(3)<< (tmpFile->fcb[j]->length)/1024 <<"MB"<<"\t";//如果文件大于1024KB则按照MB单位输出 }else if(tmpFile->fcb[j]->length < 0.01){cout<<setprecision(3)<< (tmpFile->fcb[j]->length)*1024 <<"B"<<"\t";//如果文件大于1024KB则按照MB单位输出 }cout<<tmpFile->fcb[j]->fileName<<'\t'<<tmpFile->child[j]->filePath<<endl;}}cout<<"————————————————————————————————————"<<endl;
}void setParent_ByTree(FSct *tmpPath){for(int i=0;i<12;i++){if(tmpPath->fcb[i]){if(tmpPath->fcb[i]->type == "dir"){setParent_ByTree(tmpPath->child[i]);}tmpPath->child[i]->pre=tmpPath; }}
}void setParent(){for(int i=0;i<12;i++){if(home->fcb[i]){home->child[i]->pre=home; }}
}void Initial_Sec_All(){cout<<"构建目录结构树并分配物理块..."<<endl;for(int key=0;key<12;key++){if(!userPath[key].empty()){FSct *tmpFile = new FSct;tmpFile = home->child[key];Initial_Sec_ByTree(userPath[key],tmpFile,home,key);//ls_alh_ByTree(tmpFile);}}cout<<"初始化成功!请先登录!输入help可查看命令帮助文本..."<<endl;
}void check_Block_Content(){for(long int i=0;i<1024*1024; i++){if(phBlock[i].state == 1){cout<<"物理块"<<i<<"存储的内容:"<<phBlock[i].content<<endl; }}
}void walkAll(FSct *tmpFile){cout<<"*****************************************************************"<<endl;for(int i=0;i<12;i++){if(tmpFile->fcb[i]){ls_alh_ByTree(home->child[i]);}}cout<<"*****************************************************************"<<endl;//一些具有代表性的测试样例 /*cout<<home->child[0]->child[0]->fileName<<endl;cout<<home->child[2]->child[0]->child[0]->pre->fileName<<endl;cout<<home->child[2]->child[0]->child[0]->child[0]->pre->fileName<<endl;cout<<home->child[2]->child[0]->child[0]->child[0]->fileName<<endl;*/cout<<"*****************************************************************"<<endl;}//创建文档文件函数
void create_txt(string path){ ofstream File;char *tmp = &path[0];File.open(tmp);File.close();
}//对一个文件(非目录)的简单非递归删除
void rm_f(string realFilePath,FSct *tmpF,int i){//在这里做删除操作,要注意(1)根据其长度释放其firstBlock中的indexList中的物理块 (2)将其从文件目录(*fcb[12])中 删除 (3)释放其在文件结构中的child结点 char *savePath = &realFilePath[0];if(remove(savePath)==0){cout<<"删除成功"<<endl;}else {cout<<"删除失败"<<endl;}//(1)根据其长度释放其firstBlock中的indexList中的物理块(其实不需要长度,根据索引表释放即可)int first = tmpF->fcb[i]->firstBlock->phNum;if(phBlock[first].indexList[0]){ //如果索引表存在,按照索引表删 for(int k=0;k<300;k++){if( phBlock[first].indexList[k] ){phBlock[phBlock[first].indexList[k]].state = 0;phBlock[phBlock[first].indexList[k]].content = "";}}phBlock[first].state = 0;phBlock[first].content = "";//(2)将其从文件目录(*fcb[12])中 删除free(tmpF->fcb[i] );tmpF->fcb[i] = NULL;//(3)释放其在文件结构中的child结点 free(tmpF->child[i]);tmpF->child[i] = NULL;}else{//如果不存在索引表,那么这个文件整个内容都存在firstBlock物理块 // cout<<"索引表不存在!" <<endl;phBlock[first].state = 0;phBlock[first].content = "";//(2)将其从文件目录(*fcb[12])中 删除free(tmpF->fcb[i] );tmpF->fcb[i] = NULL;//(3)释放其在文件结构中的child结点 free(tmpF->child[i]);tmpF->child[i] = NULL;}
} //递归删除一个文件夹
void rm_rf(string realFilePath,FSct *tmpF,int j) {FSct *Origin = tmpF;for(int i=0;i<12;i++){if(!tmpF->child[j]->fcb[i]) {continue;}else{}if(tmpF->child[j]->child[i] && tmpF->child[j]->fcb[i]->type == "—" ) {string newFilePath = tmpF->child[j]->child[i]->filePath;rm_f(newFilePath,tmpF->child[j],i);}else if(tmpF->child[j]->child[i] && tmpF->child[j]->fcb[i]->type == "dir" ) {string newFilePath = tmpF->child[j]->child[i]->filePath;//对目录进行递归,直到找到文件 rm_rf(newFilePath,tmpF->child[j],i);//待文件删完了之后还要释放目录的结点 int first = tmpF->child[j]->fcb[i]->firstBlock->phNum;phBlock[first].state = 0;phBlock[first].content = "";//(2)将其从文件目录(*fcb[12])中 删除free(tmpF->child[j]->fcb[i] );tmpF->child[j]->fcb[i] = NULL;//(3)释放其在文件结构中的child结点 free(tmpF->child[j]->child[i]);tmpF->child[j]->child[i] = NULL;bool flag = RemoveDirectory(newFilePath.c_str()); }}string dirPath = Origin->child[j]->filePath;int first = Origin->fcb[j]->firstBlock->phNum;phBlock[first].state = 0;phBlock[first].content = "";//(2)将其从文件目录(*fcb[12])中 删除free(Origin->fcb[j] );Origin->fcb[j] = NULL;// cout<<"文件控制块的j值:"<<j<<endl; //(3)释放其在文件结构中的child结点 free(Origin->child[j]);Origin->child[j] = NULL;bool flag = RemoveDirectory(dirPath.c_str());}//find命令 (递归查找)
int find(string path,string fileName,string username)
{vector<string> fileNames;//文件句柄intptr_t hFile = 0;//文件信息struct _finddata_t fileinfo;string p;int flag = 0; if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1){do{if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)if ((fileinfo.attrib & _A_SUBDIR))//判断是否是文件夹 {if(fileName == fileinfo.name){string realPath = path+"\\"+fileinfo.name+"\\";cout<<fileinfo.name<<"\\:\t"<<realPath<<endl;flag=1;}else{string newPath = path+"\\"+fileinfo.name;int num = find(newPath,fileName,username);flag = num;//这个递归的出口不传值的话只要是二层以下的文件夹回调,都会使得flag被从新赋值成开头定义的flag=0; }}else{if(fileName == fileinfo.name){string realPath = path+"\\"+fileinfo.name;cout<<fileinfo.name<<":"<<realPath<<endl;flag=1;}}} while (_findnext(hFile, &fileinfo) == 0);_findclose(hFile);}return flag;}//返回一个文本的行数
int getlineNum(string path){ifstream in(path);string line;int i=0;if(in) // 有该文件while (getline (in, line)) i++;else // 没有该文件cout <<"no such file" << endl;in.close();return i;
}//读文件命令
int cat(string path){SetConsoleOutputCP(65001);ifstream in(path);string line;int i=0;if(in) // 有该文件while (getline (in, line)){i++;cout<< line <<endl;} else // 没有该文件cout <<"no such file" << endl;in.close();SetConsoleOutputCP(936);return i;
}//读取文件头num行
int head(string path,int num){SetConsoleOutputCP(65001);ifstream in(path);string line;int i=0;if(in) // 有该文件while (getline (in, line)){i++;cout<< line <<endl;if(i>num){break;}} else // 没有该文件cout <<"no such file" << endl;in.close();//system("pause");SetConsoleOutputCP(936);return i;
}//读取文件尾几行
int tail(string path,int num){SetConsoleOutputCP(65001);ifstream in(path);string line;int i=0;if(in) // 有该文件while (getline (in, line)){i++;if(i>=num){cout<< line <<endl;}} else // 没有该文件cout <<"no such file" << endl;in.close();//system("pause");SetConsoleOutputCP(936);return i;
}//按照文件绝对路径递归查找
FSct * search(FSct *find,string dst_real_dir){FSct *result;for(int i=0;i<12;i++){//如果结点不存在或结点类型是文件则直接跳过 if(!find->fcb[i] || find->fcb[i]->type == "—") continue;else if(find->child[i]->filePath == dst_real_dir && find->fcb[i]->type == "dir"){result = find->child[i]; break;//操作结束直接break }else if(find->child[i]->filePath != dst_real_dir && find->fcb[i]->type == "dir"){result = search(find->child[i],dst_real_dir);}}return result;
}//在cp和move指令中处理输入路径(虚拟路径->真实路径)
string deal_path(string dst_path,string f){//cout<<"源字符串:"<<dst_path<<endl;//cout<<"真实路径前缀:"<<f<<endl; int last = dst_path.find_last_of("\\");//cout<<"last :"<<last<<endl;int first = dst_path.find_first_of("\\");//cout<<"first: "<<first<<endl;string dst_dir = dst_path.substr(first,last-first);//这个是目标文件夹路径 //cout<<"标文件夹路径 :"<<dst_dir<<endl;string dst_fileName = dst_path.substr(last+1,dst_path.length());//cout<<"新生成的文件名:"<< dst_fileName<<endl;string dst = f+dst_dir;//cout<<"真实的路径:"<<dst<<endl;return dst;
}//copy函数
void copy(string source,string destination){char *src = &source[0];char *dst = &destination[0];CopyFile(src,dst,FALSE);//false代表覆盖,true不覆盖
}//覆盖 写文件
void cover(string path){ofstream ofs; //2.创建流对象 cout<<"请输入写入内容并以#end结束:"<<endl;ofs.open(path,ios::out);//3.打开文件(out模式为覆盖) string content;while(1){cin>>content; if(content != "#end")ofs<<content<<" ";else break;}ofs.close();//4.关闭文件
} //追加 写文件
void app(string path){ofstream ofs; //2.创建流对象 cout<<"请输入写入内容并以#end结束:"<<endl;ofs.open(path,ios::app);//3.打开文件(app模式为追加)string content;ofs<<endl;while(1){cin>>content; if(content != "#end")ofs<<content<<" ";else break;}ofs.close();//4.关闭文件
} //控制台函数
void cd(User u,FSct *f){string username = u.username;string tmpPath = f->fileName;FSct *tmpF;// = new FSct;FSct *preF;tmpF = f;preF = f;string prePath = tmpPath;if(f->fcb[0]){string f_path = f->child[0]->filePath.substr(0,f->child[0]->filePath.find_last_of("\\"));f->filePath = f_path;}while(1){cout<<"localhost@"<<tmpPath<<":";string tmpOrder;cin>> tmpOrder;//__________________________________________________cdif(tmpOrder == "cd"){string newPath;cin>>newPath;if(newPath == "home"){tmpPath = f->fileName;tmpF = f;preF = f;}else if(newPath == "../"){if(prePath.empty()){cout<<"No such file !"<<endl;}else{tmpPath = prePath;//prePath需要更新int num = prePath.find_last_of("\\");prePath = prePath.substr(0,num); string old_path = tmpF->filePath;string tf = old_path.substr(0,old_path.find_last_of("\\"));if(preF==f){tmpF = f;}else{tmpF = search(f,tf);}string pf = tf.substr(0,tf.find_last_of("\\"));int judge = 0;for(int i=0;i<12;i++){if(!f->fcb[i]) continue;else if(tmpF->fileName == f->child[i]->fileName){preF = f;judge = 1;}}if(judge == 0)preF = search(f,pf);if(preF == NULL || tmpF == f){preF = f;}} }else if(newPath == "./"){ }else{//if(newPath的确存在)int flag = 0;for(int i=0;i<12;i++){if(tmpF->fcb[i] && tmpF->fcb[i]->fileName == newPath &&tmpF->fcb[i]->type == "dir"){flag = 1;prePath = tmpPath;tmpPath += "\\"+newPath; if(tmpF->child[i]->child[1]){FSct *sec = tmpF->child[i]->child[1];preF = tmpF;FSct *t = tmpF->child[i]; tmpF = t;tmpF->pre = preF;tmpF->child[1] = sec;}else{preF = tmpF;FSct *t = tmpF->child[i]; tmpF = t;tmpF->pre = preF;}break;}if(tmpF->fcb[i] && tmpF->fcb[i]->fileName == newPath &&tmpF->fcb[i]->type == "—"){cout<<"Not a directory!"<<endl; flag = 1;}}if(flag == 0){cout<<"No such file !"<<endl;}}}
//__________________________________________________cdelse if(tmpOrder == "help"){help();}//__________________________________________________lselse if(tmpOrder == "ls"){ls_alh_ByTree(tmpF);}
//__________________________________________________ls//__________________________________________________touch(注意这里创建的是一个空文件,不用考虑给其所属的文件夹增长,但在后续操作中需要给其父目录增长)else if(tmpOrder == "touch"){string tmpFileName;cin>>tmpFileName;string realFilePath = tmpF->filePath+"\\"+tmpFileName;create_txt(realFilePath); //创建完了还不算完,还要在虚拟磁盘上有所体现for(int i=0;i<12;i++){if(tmpF->fcb[i] == NULL){//文件控制块FCB的处理 tmpF->fcb[i] = new FCB;tmpF->fcb[i]->innerNum = i;tmpF->fcb[i]->fileName = tmpFileName;tmpF->fcb[i]->authority = 666;tmpF->fcb[i]->type = "—";tmpF->fcb[i]->length = 0;//创建文件的时候是空文件,长度为零 tmpF->fcb[i]->Owner[0] = new User;tmpF->fcb[i]->Owner[0]->username = u.username;//文件结构的处理tmpF->child[i] = new FSct;tmpF->child[i]->fileName = tmpFileName;tmpF->child[i]->filePath = realFilePath;//物理块的处理 for(long int num=0; num<1024*1024; num++){if(phBlock[num].state == 0){tmpF->fcb[i]->phNum = num;phBlock[num].state = 1;phBlock[num].content = ("complete of "+ tmpFileName);//开辟物理块 tmpF->fcb[i]->firstBlock = new PHB;//将该FCB指向其首物理块tmpF->fcb[i]->firstBlock->state = 1; //表示此块已被占用 tmpF->fcb[i]->firstBlock->phNum = num;//物理块内部标识的物理块号cout<<"文件"<<tmpF->child[i]->fileName<<"创建成功,(首)物理块号为:"<<tmpF->fcb[i]->phNum<<" "<<endl;break; //注意这个break要写在if语句的里面 }} break;}} }//__________________________________________________touch(创建文件)//__________________________________________________write命令 (写文件)else if(tmpOrder == "write"){string Option;cin>> Option;string file_name;cin>>file_name;int flag;for(int i=0;i<12;i++){if(!tmpF->fcb[i]) continue;else if(file_name == tmpF->fcb[i]->fileName){ //在文件结构中找到该文件 flag=1;ASL *p = Shead->next;while(p){if(p->fileName == file_name){ // 在文件活动名表 和 活动符号表中找到该文件 string file_path = p->path;//分类 ,是追加还是覆盖if(Option == "-a"){app(file_path);flag = 2;} else if(Option == "-c"){cover(file_path);flag = 2;}//更新长度tmpF->fcb[i]->length = get_length(file_path);for(int j=0;j<12;j++){if(!tmpF->pre->fcb[j]) continue;else if(tmpF->pre->child[j]->filePath == tmpF->filePath){tmpF->pre->fcb[j]->length += get_length(file_path);}}//根据新长度更新物理块 if(tmpF->fcb[i]->length < 1){//处理在初始化就分配好的块 tmpF->fcb[i]->firstBlock->content = ("complete file of "+tmpF->fcb[i]->fileName);long int phNum = tmpF->fcb[i]->firstBlock->phNum;string tmpContent = ("complete file of "+tmpF->fcb[i]->fileName);phBlock[phNum].content =tmpContent;}else if(tmpF->fcb[i]->length > 1){//先处理在初始化就分配好的块 tmpF->fcb[i]->firstBlock->content = ("IndexBlock of "+tmpF->fcb[i]->fileName);long int phNum = tmpF->fcb[i]->firstBlock->phNum;phBlock[phNum].content = ("IndexBlock of "+tmpF->fcb[i]->fileName);int count = tmpF->fcb[i]->length/1.0;if(tmpF->fcb[i]->length > count+0.5) count++;//count为实际要为该文件分配的块数 //再处理根据索引表还要分配的块 int tmpNum = 0;for(long int num=0;num < 1024*1024; num++){if(phBlock[num].state==0 && tmpNum<=count){phBlock[num].state = 1;string tmpContent = ("Parts file of "+tmpF->fcb[i]->fileName);phBlock[num].content = tmpContent;int first = tmpF->fcb[i]->firstBlock->phNum;phBlock[first].indexList[tmpNum] = num; //还要处理动态分配数组 tmpNum++;}if(tmpNum == count) break;}}break;}else{p=p->next;}} }}if(flag == 0){cout<<"No such file!"<<endl;}else if(flag == 1){cout<<"file hasNot been opend !"<<endl;}}
//__________________________________________________now(查看当前文件结构) else if(tmpOrder == "now"){cout<<"当前文件结构:"<<tmpF->fileName<<endl;cout<<"当前文件父结构:"<<preF->fileName<<endl;
}//__________________________________________________now(查看当前文件结构) //__________________________________________________df(查看磁盘使用情况) else if(tmpOrder == "df") {check_Block_Content();check_phBlock();}
//__________________________________________________df(查看磁盘使用情况)//__________________________________________________rm -f/-rf(删除文件/目录)else if(tmpOrder == "rm"){ //删除文件或者文件夹的时候记得要处理其物理块 string Option;cin>>Option;if(Option == "-f") //rm -f:删除文件 {string tmpFileName;cin>>tmpFileName;string realFilePath = tmpF->filePath+"\\"+tmpFileName;for(int i=0;i<12;i++){if(tmpF->child[i] && tmpF->child[i]->fileName == tmpFileName){if(tmpF->fcb[i]->type == "—"){rm_f(realFilePath,tmpF,i);//删除一个文件的操作 }else if(tmpF->fcb[i]->type == "dir"){cout<<"Not a File!It is a directory !"<<endl;break;}break; }}}else if(Option == "-rf") //rm -rf(删除文件夹) {cout<<"in rm -rf process"<<endl; string tmpFileName;cin>>tmpFileName;string realFilePath = tmpF->filePath+"\\"+tmpFileName;for(int i=0;i<12;i++){if(tmpF->fcb[i] && tmpF->child[i]->fileName == tmpFileName && tmpF->fcb[i]->type == "dir"){rm_rf(realFilePath,tmpF,i);break;}}} }//__________________________________________________rm -f/-rf(删除文件/目录)//__________________________________________________mkdir (创建文件夹) else if(tmpOrder == "mkdir"){string tmpFileName;cin>>tmpFileName;string realFilePath = tmpF->filePath+"\\"+tmpFileName;bool flag = CreateDirectory(realFilePath.c_str(), NULL);if(flag == true){cout<<"创建文件夹成功!"<<endl; }else{cout<<"创建文件夹失败!"<<endl;} //创建完了还不算完,还要在虚拟磁盘上有所体现for(int i=0;i<12;i++){if(tmpF->fcb[i] == NULL){tmpF->fcb[i] = new FCB;tmpF->fcb[i]->innerNum = i;tmpF->fcb[i]->fileName = tmpFileName;tmpF->fcb[i]->authority = 666;tmpF->fcb[i]->type = "dir";tmpF->fcb[i]->length = 0;tmpF->fcb[i]->Owner[0] = new User;tmpF->fcb[i]->Owner[0]->username = u.username;//文件结构的处理tmpF->child[i] = new FSct;tmpF->child[i]->fileName = tmpFileName; tmpF->child[i]->filePath = realFilePath;//物理块的处理 for(long int num=0; num<1024*1024; num++){if(phBlock[num].state == 0){tmpF->fcb[i]->phNum = num;phBlock[num].state = 1;phBlock[num].content = ("DirBlock of "+ tmpFileName);//开辟物理块 tmpF->fcb[i]->firstBlock = new PHB;//将该FCB指向其首物理块tmpF->fcb[i]->firstBlock->state = 1; //表示此块已被占用 tmpF->fcb[i]->firstBlock->phNum = num;//物理块内部标识的物理块号cout<<"文件夹"<<tmpF->child[i]->fileName<<"创建成功,(首)物理块号为:"<<tmpF->fcb[i]->phNum<<" "<<endl;break; //注意这个break要写在if语句的里面 }} break;}} }
//__________________________________________________mkdir (创建文件夹) //__________________________________________________find命令 else if(tmpOrder == "find"){string fileName;cin>>fileName;int flag = find(tmpF->filePath,fileName,u.username);//cout<<"flag:"<<flag<<endl; if(flag == 0){cout<<"-bash- : NO such file!"<<endl;}}
//__________________________________________________find命令 //__________________________________________________open命令 else if(tmpOrder == "open") {int flag = 0;string file_name;cin>>file_name;for(int i=0;i<12;i++){if(tmpF->fcb[i] == NULL) continue;else{//找到目标文件,做打开操作 if(tmpF->child[i]->fileName == file_name && tmpF->fcb[i]->type == "—"){//cout<<"Found!"<<endl;//对活动文件表分配AFL *t = Fhead;//cout<<"Found!"<<endl;while(t->next != NULL){t = t->next;}//循环结束后p指向最后一个结点//cout<<"Found!"<<endl;t->next = new AFL;//cout<<"Found!"<<endl;t = t->next;t->fcb = tmpF->fcb[i];//cout<<"Found!"<<endl;t->next = NULL;//对符号名表分配 ASL *p = Shead;while(p->next != NULL){p = p->next;}//循环结束后p指向最后一个结点p->next = new ASL;p=p->next;p->fileName = tmpF->child[i]->fileName;p->path = tmpF->child[i]->filePath; p->innerNum = tmpF->fcb[i]->innerNum;p->next = NULL;p->afl = t;FileNum_Curr++; flag = 1;cout<<p->fileName<<"文件已打开,当前活动文件数:"<< FileNum_Curr<<endl;}else if(tmpF->child[i]->fileName == file_name && tmpF->fcb[i]->type == "dir"){cout<<"Not a file! It's a directory!"<<endl;flag = 1; }}}if(flag == 0){cout<<"No such file!"<<endl;}}//__________________________________________________open命令 //__________________________________________________close命令 else if(tmpOrder == "close"){string file_name;cin>>file_name;ASL *p = Shead;int flag = 0;while(p->next){if(p->next->fileName == file_name){cout<<"Remove from ASL!"<<endl;ASL *tmp = p->next;p->next = tmp->next;delete(tmp);flag = 1;break;}else{p = p->next;}}if(flag == 1){AFL *t = Fhead;while(t->next){if(t->next->fcb->fileName == file_name){cout<<"Remove from AFL!"<<endl;AFL *tmp = t->next;t->next = tmp->next;delete(tmp);FileNum_Curr--;cout<<"关闭文件成功!"<<'\t'<<"当前活动文件数:"<<FileNum_Curr<<endl; }else{t = t->next;}} }else{cout<<"关闭文件失败!"<<endl;} }//__________________________________________________close命令 //__________________________________________________ASL命令 (查看活动符号名表)else if(tmpOrder == "ASL"){cout<<"当前活动文件数:"<<FileNum_Curr<<endl;ASL *p = Shead->next;if(!p){cout<<"当前没有活动文件"<<endl; }else{int i=1;while(p){cout<<"("<<i<<") 文件名:"<<p->fileName<<'\t'<<"文件内部号:"<<p->innerNum<<'\t'<<"路径:"<<p->path<<endl;p=p->next;i++; }}} //__________________________________________________ASL命令 (查看活动符号名表)//__________________________________________________cat命令 (读文件)else if(tmpOrder == "cat"){string file_name;cin>>file_name;int flag;for(int i=0;i<12;i++){if(!tmpF->fcb[i]) continue;else if(file_name == tmpF->fcb[i]->fileName){flag=1;ASL *p = Shead->next;while(p){if(p->fileName == file_name){string file_path = p->path;int tmpnum = cat(file_path);//int tmpnum2 = getlineNum(path);flag = 2;break;}else{p=p->next;}} }}if(flag == 0){cout<<"No such file!"<<endl;}else if(flag == 1){cout<<"file hasNot been opend !"<<endl;}} //__________________________________________________cat命令 (读文件)//__________________________________________________head命令 (读文件头几行)else if(tmpOrder == "head"){string Option;cin>>Option;string file_name;cin>>file_name;string subOption = Option.substr(1,Option.length());int num = stoi(subOption.c_str());//将string强制转为int int flag = 0;for(int i=0;i<12;i++){if(!tmpF->fcb[i]) continue;else if(file_name == tmpF->fcb[i]->fileName){flag=1;ASL *p = Shead->next;while(p){if(p->fileName == file_name){string file_path = p->path;int tmpnum = head(file_path,num);flag = 2;break;}else{p=p->next;}} }}if(flag == 0){cout<<"Read file fail!"<<endl;}else if(flag == 1){cout<<"file hasNot been opend !"<<endl;}}
//__________________________________________________head命令 (读文件头几行)//__________________________________________________tail命令 (读文件尾部几行)else if(tmpOrder == "tail"){string Option;cin>>Option;string file_name;cin>>file_name;string subOption = Option.substr(1,Option.length());int tmp_num = stoi(subOption.c_str());//将string强制转为int int flag = 0;for(int i=0;i<12;i++){if(!tmpF->fcb[i]) continue;else if(file_name == tmpF->fcb[i]->fileName){flag=1;ASL *p = Shead->next;while(p){if(p->fileName == file_name){string file_path = p->path;int file_line_length = getlineNum(file_path);int num = file_line_length - tmp_num;int tmpnum = tail(file_path,num);flag = 2;break;}else{p=p->next;}} }}if(flag == 0){cout<<"Read file fail!"<<endl;}else if(flag == 1){cout<<"file hasNot been opend !"<<endl;}}
//__________________________________________________tail命令 (读文件尾部几行)//__________________________________________________cp命令 (复制文件)/*
cp命令格式: cp 当前目录下的文件 目标文件路径\\复制后的文件名 需要注意的点:
(1) 解析目标路径,找到目录结构树中的对应结点
(2)取dst和src的path,调用window.h实现实际结构的copy
(3)在目录结构树的目标路径下new出新的 FSct* 结点,根据源文件的信息填写新结点的信息
(4)需要根据其长度重新setBlock,注意是单独的setBlock
*/ else if(tmpOrder == "cp") {string source;string destination;string src_name;cin>>src_name;string dst_path;cin>>dst_path;for(int i=0;i<12;i++){if(!tmpF->fcb[i]) continue;else if(tmpF->child[i]->fileName == src_name and tmpF->fcb[i]->type == "—"){cout<<"source file found !"<<endl;source = tmpF->child[i]->filePath;//下面开始解析目标路径 string real_path = deal_path(dst_path,f->filePath);destination = real_path+"\\"+src_name;FSct *dst = search(f,real_path);if(real_path == f->filePath) dst = f;//至此: //source的路径: tmpF->child[i]->filePath//destination的路径: real_path //找到了目标路径的文件夹 dst,做数据分配 (其实在这里可以生成源文件的快捷方式!!直接改指针就行) for(int j =0;j<12;j++){if(!dst->fcb[j])//找到一个空的fcb块 {dst->child[j] = new FSct;dst->child[j]->fileName = src_name;//其实目标文件的名称可以自定义,将字符串处理函数写进来就行 dst->child[j]->filePath = real_path+"\\"+src_name; dst->child[j]->Owner[0] = new User;dst->child[j]->Owner[0] = f->Owner[0];dst->fcb[j] = new FCB;dst->fcb[j]->authority = 666;dst->fcb[j]->fileName = src_name;dst->fcb[j]->innerNum = j;dst->fcb[j]->Owner[0] = new User;dst->fcb[j]->Owner[0]->username = u.username;dst->fcb[j]->type = "—";dst->fcb[j]->length = tmpF->fcb[i]->length;//__________________________________ //物理块的分配for(long int num=0; num<1024*1024; num++){if(phBlock[num].state == 0){dst->fcb[j]->phNum = num;phBlock[num].state = 1;phBlock[num].content = ("complete file of "+ src_name);//开辟物理块 dst->fcb[j]->firstBlock = new PHB;//将该FCB指向其首物理块dst->fcb[j]->firstBlock->state = 1; //表示此块已被占用 dst->fcb[j]->firstBlock->phNum = num;//物理块内部标识的物理块号cout<<"文件"<<dst->child[j]->fileName<<"复制成功,(首)物理块号为:"<<dst->fcb[j]->phNum<<" "<<endl;break; //注意这个break要写在if语句的里面 }} if(dst->fcb[j]->length < 1){dst->fcb[j]->firstBlock->content = ("complete file of "+dst->fcb[j]->fileName);long int phNum = dst->fcb[j]->firstBlock->phNum;//注意一下动态分配数组已限定一个文件的最大大小string tmpContent = ("complete file of "+dst->fcb[j]->fileName);phBlock[phNum].content =tmpContent;}else if(dst->fcb[j]->length > 1){//先处理在初始化就分配好的块 dst->fcb[j]->firstBlock->content = ("IndexBlock of "+dst->fcb[j]->fileName);long int phNum = dst->fcb[j]->firstBlock->phNum;//注意一下动态分配数组已限定一个文件的最大大小phBlock[phNum].content = ("IndexBlock of "+dst->fcb[j]->fileName);int count = dst->fcb[j]->length/1.0;if(dst->fcb[j]->length > count+0.5) count++;//count为实际要为该文件分配的块数 int tmpNum = 0;for(long int num=0;num < 1024*1024; num++){if(phBlock[num].state==0 && tmpNum<=count){phBlock[num].state = 1;string tmpContent = ("Parts file of "+dst->fcb[j]->fileName);phBlock[num].content = tmpContent;int first = dst->fcb[j]->firstBlock->phNum;phBlock[first].indexList[tmpNum] = num; //还要处理动态分配数组 tmpNum++;}if(tmpNum == count) break;}}
//__________________________________ copy(source,destination);cout<<"文件复制成功!"<<endl; break;} }} }}//__________________________________________________cp命令 (复制文件)//__________________________________________________move命令 (移动文件)/*
move命令格式: move 当前目录下的文件 目标文件路径\\移动后的文件名 需要注意的点:
(1) 解析目标路径,找到目录结构树中的对应目标父结点
(2)取dst和src的path,调用window.h实现实际结构的move指令
(3)使得目标路劲结点父目录的child【j】指向源文件
(4)使得目标路劲结点父目录的fcb【j】指向源文件的fcb
(5)物理块无需变动
*/ else if(tmpOrder == "move") {string source;string destination;string src_name;cin>>src_name;string dst_path;cin>>dst_path;for(int i=0;i<12;i++){if(!tmpF->fcb[i]) continue;else if(tmpF->child[i]->fileName == src_name and tmpF->fcb[i]->type == "—"){cout<<"source file found !"<<endl;source = tmpF->child[i]->filePath;//下面开始解析目标路径 string real_path = deal_path(dst_path,f->filePath);destination = real_path+"\\"+src_name;FSct *dst = search(f,real_path);if(real_path == f->filePath) dst = f;//至此: //source的路径: tmpF->child[i]->filePath//destination的路径: real_path //找到了目标路径的文件夹 dst,做数据分配 (其实在这里可以生成源文件的快捷方式!!直接改指针就行) for(int j =0;j<12;j++){if(!dst->fcb[j])//找到一个空的fcb块 {dst->child[j] = new FSct;dst->child[j]->fileName = src_name;//其实目标文件的名称可以自定义,将字符串处理函数写进来就行 dst->child[j]->filePath = real_path+"\\"+src_name; dst->child[j]->Owner[0] = new User;dst->child[j]->Owner[0] = f->Owner[0];dst->fcb[j] = new FCB;dst->fcb[j]->authority = 666;dst->fcb[j]->fileName = src_name;dst->fcb[j]->innerNum = j;dst->fcb[j]->Owner[0] = new User;dst->fcb[j]->Owner[0]->username = u.username;dst->fcb[j]->type = "—";dst->fcb[j]->length = tmpF->fcb[i]->length;//更改物理块的内容和链接dst->fcb[j]->firstBlock = new PHB;dst->fcb[j]->firstBlock = tmpF->fcb[i]->firstBlock;dst->fcb[j]->phNum = dst->fcb[j]->firstBlock->phNum;copy(source,destination);//cout<<"文件复制成功!"<<endl; //释放源文件的所有链接和结点//(1)将其从文件目录(*fcb[12])中 删除free(tmpF->fcb[i] );tmpF->fcb[i] = NULL;//(2)释放其在文件结构中的child结点 free(tmpF->child[i]);tmpF->child[i] = NULL;char *savePath = &source[0];if(remove(savePath)==0){cout<<"文件移动成功"<<endl;}else {cout<<"文件移动失败"<<endl;}break;} }} }}
//__________________________________________________move命令 (移动文件)//__________________________________________________export命令 (将虚拟磁盘上的文件导出到 c 盘/任意本地文件夹)else if(tmpOrder == "export") {string src_file; //虚拟磁盘上的导出文件 cin>>src_file;string destination; //c 盘/任意本地文件夹cin>>destination;for(int i=0;i<12;i++) {if(!tmpF->fcb[i]) continue;else if(tmpF->child[i]->fileName == src_file){cout<<"Found source file !"<<endl; string source = tmpF->child[i]->filePath;copy(source,destination);cout<<"Export succeed !"<<endl; break;}}
}//__________________________________________________export命令 (将虚拟磁盘上的文件导出到 c 盘/任意本地文件夹)// __________________________________________________import命令 (将虚c 盘/任意本地文件夹导入到拟磁盘上的文件 )else if(tmpOrder == "import"){string destination;string source;cin>>source;string dst_fileName;cin>>dst_fileName;//先找到目标文件并计算其大小 double src_length = get_length(source); cout<<src_length<<endl;for(int i=0;i<12;i++){if(!tmpF->fcb[i]){//找到一个空的物理块 tmpF->child[i] = new FSct;tmpF->child[i]->fileName = dst_fileName;//其实目标文件的名称可以自定义,将字符串处理函数写进来就行 tmpF->child[i]->filePath = tmpF->filePath+"\\"+dst_fileName; destination = tmpF->child[i]->filePath;tmpF->child[i]->Owner[0] = new User;tmpF->child[i]->Owner[0] = f->Owner[0];tmpF->fcb[i] = new FCB;tmpF->fcb[i]->authority = 666;tmpF->fcb[i]->fileName = dst_fileName;tmpF->fcb[i]->innerNum = i;tmpF->fcb[i]->Owner[0] = new User;tmpF->fcb[i]->Owner[0]->username = u.username;tmpF->fcb[i]->type = "—";tmpF->fcb[i]->length = src_length;//__________________________________ //物理块的分配for(long int num=0; num<1024*1024; num++){if(phBlock[num].state == 0){tmpF->fcb[i]->phNum = num;phBlock[num].state = 1;phBlock[num].content = ("complete file of "+ dst_fileName);//开辟物理块 tmpF->fcb[i]->firstBlock = new PHB;//将该FCB指向其首物理块tmpF->fcb[i]->firstBlock->state = 1; //表示此块已被占用 tmpF->fcb[i]->firstBlock->phNum = num;//物理块内部标识的物理块号cout<<"文件"<<tmpF->child[i]->fileName<<"导入成功,(首)物理块号为:"<<tmpF->fcb[i]->phNum<<" "<<endl;break; //注意这个break要写在if语句的里面 }} if(tmpF->fcb[i]->length < 1){tmpF->fcb[i]->firstBlock->content = ("complete file of "+tmpF->fcb[i]->fileName);long int phNum = tmpF->fcb[i]->firstBlock->phNum;//注意一下动态分配数组已限定一个文件的最大大小string tmpContent = ("complete file of "+tmpF->fcb[i]->fileName);phBlock[phNum].content =tmpContent;}else if(tmpF->fcb[i]->length > 1){//先处理在初始化就分配好的块 tmpF->fcb[i]->firstBlock->content = ("IndexBlock of "+tmpF->fcb[i]->fileName);long int phNum = tmpF->fcb[i]->firstBlock->phNum;//注意一下动态分配数组已限定一个文件的最大大小phBlock[phNum].content = ("IndexBlock of "+tmpF->fcb[i]->fileName);int count = tmpF->fcb[i]->length/1.0;if(tmpF->fcb[i]->length > count+0.5) count++;//count为实际要为该文件分配的块数 int tmpNum = 0;for(long int num=0;num < 1024*1024; num++){if(phBlock[num].state==0 && tmpNum<=count){phBlock[num].state = 1;string tmpContent = ("Parts file of "+tmpF->fcb[i]->fileName);phBlock[num].content = tmpContent;int first = tmpF->fcb[i]->firstBlock->phNum;phBlock[first].indexList[tmpNum] = num; //还要处理动态分配数组 tmpNum++;}if(tmpNum == count) break;}}
//__________________________________ copy(source,destination);cout<<"Import succeed!"<<endl; break;}} }
// __________________________________________________import命令 (将虚c 盘/任意本地文件夹导入到拟磁盘上的文件 )else{cout<<"input error!"<<endl;}}
}// 线程的运行函数
void* operation(void* args)
{Initial(path);Initial_Sec_All();cout<<"——————————————————————————————————————————"<<endl;int key = -1;help(); while(key == -1){key = index();if(key != -1) break;}cd(uGroup[key],home->child[key]);return 0;
}int main()
{// 定义线程的 id 变量,多个变量使用数组pthread_t tids[NUM_THREADS];for(int i = 0; i < NUM_THREADS; ++i){//参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数int ret = pthread_create(&tids[i], NULL, operation, NULL);if (ret != 0){cout << "pthread_create error: error_code=" << ret << endl;}}//等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没反应过来;pthread_exit(NULL);
}
3.结语
这个是在大二刚学习完操作系统的时候根据所学到的知识去写的,有些指令Linux并不是这样的但是功能是类似的,另外算法能力还不足,还没充分去考虑性能的问题想到什么功能就花了一周去写了,但结果似乎看起来不差,当时课设95分,发出来看看以后有没有机会再拿出来改一下,也供有类似课设的同学参考,主要还是想涨点浏览量害哈哈哈…
















