如何用C/C++写一个Linux文件系统模拟器

article/2025/11/8 13:34:09

用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分,发出来看看以后有没有机会再拿出来改一下,也供有类似课设的同学参考,主要还是想涨点浏览量害哈哈哈…


http://chatgpt.dhexx.cn/article/Pxs0M6xX.shtml

相关文章

Linux (Ubuntu) 下的Android模拟器:Genymotion

据说这是一款十分好用的Android模拟器&#xff0c;之前没玩过Android模拟器&#xff0c;这就是自己第一次使用。 Downloads&#xff1a;https://www.genymotion.com/ 麻烦的是需要现注册才能下载。有收费版&#xff0c;也有免费版&#xff0c;点击buy genymotion&#xff0c;…

kali linux 连接windows物理主机的安卓模拟器的方法

①不能直连&#xff0c;需要做个端口转发&#xff0c;具体如下: netsh interface portproxy add v4tov4 listenport18888 listenaddress0.0.0.0 connectport62026 connectaddress127.0.0.1 在windows cmd命令行输入这行代码&#xff0c;其中 listenport 18888 表示用来转发的…

安卓的完美Linux模拟器,推荐UserLAnd

UserLAnd 是一个开源应用程序&#xff0c;它允许您运行多个 Linux 发行版&#xff0c;例如 Ubuntu、Debian 和 Kali&#xff08;还是基于chroot的方式运行&#xff09;。 -无需root -使用内置终端访问您最喜欢的 shell。 -轻松连接 VNC 以获得图形体验。 -轻松设置几个常见…

在linux下安装android模拟器

genymotion https://www.genymotion.com/ 下载64位并安装&#xff0c;然而会出现 Unable to load VirtualBox engine. 这样的问题。解决方法也很简单&#xff0c;就是安装一个virtualBox就可以了 sudo apt-get install virtualbox 先安装virtualbox 然后在安装genymot…

linux系统模拟器网络配置步骤

1、打开linux虚拟器&#xff0c;在虚拟机左上角找到虚拟机 2、点击虚拟机&#xff0c;在下方找到设置后点开3、在点开的设置&#xff0c;在设备中找到网络适配器&#xff0c;适配网络选择自定义&#xff0c;并在自定义里选择VMnet0,选择后点击确定。 4、在编辑里打开虚拟网络编…

Linux终端在线模拟器和ps aux命令

进入此网址&#xff1b; https://bellard.org/jslinux/ 出来几个操作系统供选择&#xff0c;选择一个linux进入&#xff1b;这只是终端的模拟器&#xff1b; 等了很长很长时间&#xff0c;出来一个Linux的模拟桌面&#xff1b;然后进入此模拟器的Linux终端&#xff1b; 看一下…

Linux上有哪些好的终端模拟器?

注&#xff1a;本文转载自linux中国的文章&#xff1a;Linux上有哪些好的终端模拟器? &#xff0c;请支持原创&#xff01; 一个好的终端模拟器是一个选择Linux而不是Windows或Mac的充分理由&#xff0c;任何Linux的资深用户都会同意这点。通过使用shell&#xff0c;用户可以完…

ubuntu安装安卓模拟器

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装virtualbox二、安装genymotion1.下载2.安装3.登录4. 网络设置5. 安卓APP报错 参考链接 前言 最近由于工作原因笔记本安装成Ubuntu系统&#xff0c;而安…

linux-在线模拟器

jslinux:&#xff1a;http://bellard.org/jslinux/ 一个叫Fabrice Bellard的工程师使用 JavaScript 在浏览器上模拟出了一个 Linux 系统。没有图形化界面&#xff0c;完全使用命令行的方式与之互动。Linux操作系统内核版本为2.6.20。具体使用过程中可以参考jslinux:的FAQ&…

Linux下最强安卓模拟器,流畅又丝滑(附详细安装教程)此瓜保熟|Linux游戏党

我打算完全从头开始&#xff0c;写一个专门用于桌面办公的纯国产操作系统 &#xff0c;规避主流操作系统上影响用户体验的问题&#xff0c;系统力求简洁。有兴趣加QQ群&#xff1a;709652950 好东西让更多人发现&#xff01;我找了整整两年&#xff0c;什么Anbox&#xff0c;什…

2023年22个最佳Linux桌面终端模拟器

终端模拟器是Linux操作系统中常用的工具&#xff0c;它提供了一个图形界面来模拟命令行环境。终端模拟器不仅可以执行命令行操作&#xff0c;还具有许多功能和特性&#xff0c;如多标签页、自定义配置、分屏显示等&#xff0c;使得用户可以更加高效地使用命令行界面。在本文中&…

微信小程序 图片转换base64

js // pages/testA/testA.js Page({data: {url:,base64:,},upload: function(){var _this this;//调用上传_this.wx_chooseImage(1, "[compressed]"," [album, camera]",function(images){var url images.tempFilePaths[0];//图片转换 base64_this.wx_g…

微信小程序 背景图片base64_微信小程序图片转base64数据

小程序的开发在现阶段的应用越来越广泛&#xff0c;本文简要介绍如何实现在微信小程序端将获取的图片路径转换成base64数据格式&#xff01; 效果如图&#xff1a; 将图片转换成base64数据格式&#xff0c;目前本人所知的共三种方法&#xff0c;分别为&#xff1a; 1、通过canv…

微信小程序展示base64图片并保存

后台接口 /// <summary> /// 获取二维码 /// </summary> /// <returns></returns> [HttpPost] [Authorize] public async Task<MessageModel<string>> GetUserQRCode() {var result new MessageModel<string>();var url "pa…

uniapp微信小程序保存base64图片的方法

最近在开发点餐系统的找人付款的功能&#xff0c;生成付款二维码&#xff0c;生成后用户可以分享二维码发送给朋友替他付款&#xff0c;但是微信小程序是无法分享图片的&#xff0c;需要把图片保存到相册里面&#xff0c;然后在微信里面分享相册里面的图片就行了&#xff0c;但…

微信小程序选择图片并转base64

一般上传图片给后台更多情况是通过base64的形式&#xff0c;这样占存小&#xff0c;使用时也可以减少了服务器访问次数。微信官方提供的API又不支持上传多个文件&#xff0c;所以如果是上传图片的话&#xff0c;使用base64编码字符串是个不错的办法。 相关API wx.chooseImage…

微信小程序Base64图片不显示(Base64串存在换行问题)

背景 小程序内用wx.request来发请求&#xff0c;后台返回Base64流&#xff0c;前台用<image>标签显示。 简略代码如下&#xff1a; File tfile new File("/Users/sam/Downloads/test.jpg");FileInputStream fileInputStream new FileInputStream(tfile);byte…

微信公众号图片上传_base64图片上传处理

一、微信公众号图片上传_base64图片上传处理 使用到的接口拍照、选择相册接口&#xff1b; 读取本体图片接口 1.拍照或从手机相册中选图接口 wx.chooseImage({count: 1, // 默认9sizeType: [original, compressed], // 可以指定是原图还是压缩图&#xff0c;默认二者都有sou…

web 全栈

Web 开发技术结构

2019最新Web全栈架构师第九期视频教程全套

如需下载教程&#xff0c;请到原文链接下载 视频好不好&#xff0c;谁看谁知道&#xff0c;话不多说&#xff0c;先看目录&#xff1a; 课件代码软件资料 01课 vue核心API&&组件设计 &#xff08;2019.3.15&#xff09; 02课 Vue-router&Vuex &#xff08;2019.3.…