模拟的多级文件系统,先申请一个100M的大文件作为模拟磁盘,然后在这个模拟磁盘上来实现文件系统的各类功能。
编译环境:ubuntu6.06+gcc
放在VC下编译则需要自己写getpass函数即可。
#include<iostream>
#include<stdio.h>
#include<string>
#include<stdlib.h>
#include<bitset>
#include<time.h>
#define DEV_SIZE (1024*1024*100)
#define BLOCK_SIZE 1024 //一个块的大小定义为1k
#define DIR_NUM 5120
#define BLOCK_NUM (5120*16)
#define INODE_NUM 5120
#define USER_NUM 16 //MAX NUMber of users
#define NAME_LEN 16 //文件名/用户名的长度
#define PSD_LEN 16 //密码长度
#define FILE_BLOCKS 16 //每个文件最多占用16个磁盘块
#define MIX_UNIT 8 //最小单元以字节计
#define DIR 1 //表示要创建的是目录
#define FE 0 //表示要创建的是文件
#define ROOT 1 //表示创建位置为根目录下
#define CURENT 0 //表示创建位置为当前目录下
using namespace std;
struct time_info{ //时间结构
short year;
short month;
short day;
short hour;
short min;
};
struct dirItem{ //目录项结构
int number;
int inode_num; //所对应的的I结点号
bool dir_or_file; //true 表示目录,false表示文件
char name[NAME_LEN]; //目录名称或文件名
int parent,son,brother; //用于在磁盘中保存目录的层次结构
struct dirItem *p_parent,*p_son,*p_brother; //同样是表示目录间的层次结构,主要用于在内存中的操作
};
struct inode{ //I结点结构
int number; //I节点号
short mode; //文件的rwx权限
char user_name[NAME_LEN]; //文件所属用户
char user_group; //用户所在组
int file_length; //文件长度,以字节计
time_info file_creat; //文件创建时间
time_info file_edit; //文件最后编辑时间
short blocks; //记录文件存储占用的存储块
int block[FILE_BLOCKS]; //文件存储用到的块,目前还不支持间接块的使用
};
struct user_info{ //用户信息
bool flag; //用户的有效性标识,可用于遍历用户
char name[NAME_LEN];
char group; //用户所在组,分两个组,root和user
int my_dir; //表示用户目录
char password[PSD_LEN]; //用户密码
};
struct sup_blk{ //super block
int num_of_users; //记录用户的数目
user_info users[USER_NUM]; //所有用户的信息
int num_of_files; //记录文件系统中文件的总数
bool dirs[DIR_NUM]; //true 表示该目录项可用,false表示不可用
bool blocks[BLOCK_NUM]; //TRUE 表示该块可用,false表示该块不可用
bool inodes[INODE_NUM]; //TRUE 表示该I结点可用,false表示该结点不可用
dirItem dir_items[BLOCK_NUM]; //把目录项的所有内容放到超级块中,以便到时将目录项读入内存建立目录层次
int first_inode; //表示第一个inode结点的相对地址
int first_block; //第一个用于存储文件的磁盘块的相对地址
};
static sup_blk *super_block; //全局变量,指向超级块
static FILE *fp; //文件指针
static dirItem *head_dir,*dir_active; //head_dir指向根目录的指针,根目录固定放在dir_items[0]处,dir_active指向当前工作目录
static user_info *user_active; //当前活跃的用户
class BlockControl
{
public:
BlockControl(void);
~BlockControl(void);
void Bread(int num); //读磁盘块,直接输出,参数为磁盘块号
void Brelse(int num); //释放磁盘块,注意还要改写bitmap,最好格式化一下
void Bwrite(char *buf,int num); //写第num块,同时记得设置位示图
int Bwrite(char *buf); //写块,返回块号同时记得设置位示图
int is_free(bool *bitmap,int num); //查找各类位图中的空闲区域,参数num为最大偏移量若没找到,则返回-1
void set_busy(bool *bitmap,int num); //将对应的区域标志为被占用
void set_free(bool *bitmap,int num); //设置为空闲
private:
int fb; //super_block->first_block
char *samp;
};
class FileControl
{
public:
FileControl(void);
~FileControl(void);
/*建目录或文件,第一个参数为名称,第二个表示创建的是目录1/文件0,*
*第三个表示位置(根1/当前目录0下),同时还得加入到目录项树中去*/
int creat_df(char *name,bool dir,bool root);
void add_user(user_info *user_new); //将新建的用户复制到超级块中去
int find(string name,bool dir); //查找文件/目录,dir为true时表示目录,为false是表示文件,返回文件或目录所在的目录项编号
void del(int num); //删除文件/或目录,参数为对应的目录项编号
void read_file(int num); //读文件,参数为对应的目录项编号
void write_file(string &str,int num); //向磁盘块里写入添加的信息,从最后一块开始写,参数为目录项编号
private:
BlockControl bc; //磁盘块控制
void ins_dir(dirItem *posi,dirItem *dir_for_ins);
//将dir_for_ins插入到where的同一级目录中,要进行适当的排序,目录放在前面,文件放在后面
void gettime(time_info *time); //获取时间函数
void cleartime(time_info *time);
};
enum ORDER{CREAT=0,READ,WRITE,DEL,MKDIR,RMDIR,CD,LS,PWD,NEW,SHOW,HELP,LOGOUT,EXIT};
class ICmd {
public:
ICmd(void);
~ICmd(void);
void show_menu(void);
void get_order(void); //接收命令
void Creat(string filename); //创建文件
void Read(string filename);
void Write(string filename);
void Del(string filename);
//void Save(void); //保存当前编辑的文件,其实可以放到下一层
void CreatDir(string name); //创建目录
void DelDir(string name); //删除目录
void Cd(string name); //参数分几种:..上一级目录,~用户目录,/绝对路径目录,不带/表示直接下一级目录
void Ls(void); //列出目录和文件
void Pwd(void); //列出用户当前所在的路径
void NewUser(void); //增加新用户
void Show(void); //列出所有的用户信息
void Help(void); //列出帮助信息
void Logout(void); //登出,准备换用户名登录
void Exit(void); //退出文件系统
private:
FileControl fc;
char order[10],param[NAME_LEN]; //命令和参数
bool logout_flag; //true 表示登出
bool exit_flag; //表示退出文件系统
void pwd(dirItem *p); //递归显示路径
void init_fs(void); //初始化文件系统
void init_fs_first(void); //第一次使用文件系统
void end_fs(void); //结束文件系统时的一些收尾工作
int check_user(char *name,char *password); //检查用户是否合法,合法返回用户编号,否则返回-1
int check_order(void);//检查命令,以整数形式返回命令
void cr_dir_tree(dirItem *head); //建目录树
};
BlockControl::BlockControl(void)
{
char *samp=new char[BLOCK_SIZE];
for(int i=0;i<BLOCK_SIZE;i++)
*(samp+i)='/0';
}
BlockControl::~BlockControl(void)
{
delete [] samp;
}
void BlockControl::Bread(int num) //读磁盘块,直接输出里面的内容
{
char buf2[BLOCK_SIZE];
fseek(fp,(super_block->first_block)+num*sizeof(char)*BLOCK_SIZE,SEEK_SET);
fread(buf2,sizeof(char)*BLOCK_SIZE,1,fp);
cout<<buf2;
}
void BlockControl::Brelse(int num) //释放块
{
fseek(fp,(super_block->first_block)+num*sizeof(char)*BLOCK_SIZE,SEEK_SET);
fwrite(samp,sizeof(char)*BLOCK_SIZE,1,fp);
set_free(super_block->blocks,num);
}
void BlockControl::Bwrite(char *buf,int num)
{
fseek(fp,(super_block->first_block)+num*sizeof(char)*BLOCK_SIZE,SEEK_SET);
fwrite(buf,sizeof(char)*BLOCK_SIZE,1,fp);
set_busy(super_block->blocks,num);
}
int BlockControl::Bwrite(char *buf)
{
int num=is_free(super_block->blocks,BLOCK_NUM);
fseek(fp,(super_block->first_block)+num*sizeof(char)*BLOCK_SIZE,SEEK_SET);
fwrite(buf,sizeof(char)*BLOCK_SIZE,1,fp);
set_busy(super_block->blocks,num);
return num;
}
int BlockControl::is_free(bool *bitmap,int num)
{
int no;
for(no=0;no<num;no++)
if(*(bitmap+no)) return no;
return -1;
}
void BlockControl::set_busy(bool *bitmap,int num)
{
*(bitmap+num)=false;
}
void BlockControl::set_free(bool *bitmap,int num)
{
*(bitmap+num)=true;
}
FileControl::FileControl(void)
{
}
FileControl::~FileControl(void)
{
}
void FileControl::gettime(time_info *stime){ //获取时间函数
tm *tim; //定义tm结构的变量tim
time_t end;//=time_info();
end=time((time_t *)NULL);
tim=localtime(&end);
stime->year=1900+tim->tm_year;
stime->month=1+tim->tm_mon;
stime->day=tim->tm_mday;
stime->hour=tim->tm_hour;
stime->min=tim->tm_min;
return;
}
void FileControl::read_file(int num)
{
dirItem *tmp;
tmp=&((super_block->dir_items)[num]);
inode *tmp_inode=new inode;
fseek(fp,super_block->first_inode+sizeof(inode)*(tmp->inode_num),SEEK_SET);
fread(tmp_inode,sizeof(inode),1,fp);
for(int i=0;i<tmp_inode->blocks;i++)
bc.Bread((tmp_inode->block)[i]); //读磁盘块函数,直接输出
cout<<endl;
delete tmp_inode;
}
void FileControl::add_user(user_info *user_new) //将新建的用户复制到超级块中去
{
int i;
for(i=0;i<super_block->num_of_users&&(super_block->users)[i].flag;i++);
(super_block->users)[i].flag=true;
(super_block->users)[i].group=user_new->group;
(super_block->users)[i].my_dir=user_new->my_dir;
strcpy((super_block->users)[i].name,user_new->name);
strcpy((super_block->users)[i].password,user_new->password);
}
int FileControl::creat_df(char *name,bool dir,bool root)
/*建目录或文件,第一个参数为名称,第二个表示创建的是目录1/文件0,*
*第三个表示位置(根1/当前目录0下),同时还得加入到目录项树中去*/
{
int num_dir=bc.is_free(super_block->dirs,DIR_NUM);
if(num_dir==-1){
cout<<"找不到空闲的目录项,退出"<<endl;
return -1;
}
bc.set_busy(super_block->dirs,num_dir); //设置该目录项已经被占用
dirItem *tmp_dir=&((super_block->dir_items)[num_dir]);
int num_inode=bc.is_free(super_block->inodes,INODE_NUM); //寻找空闲的I节点
if(num_inode==-1){
cout<<"找不到空闲的I节点,退出"<<endl;
return -1;
}
bc.set_busy(super_block->inodes,num_inode); //设置该I节点被占用
tmp_dir->inode_num=num_inode; //设置为该目录项对应的I节点
if(dir) tmp_dir->dir_or_file=true; //表示目录
else {
tmp_dir->dir_or_file=false; //表示文件,初步设置i节点
inode *tmp_inode=new inode;
//tmp_dir->dir_or_file=false;
fseek(fp,super_block->first_inode+num_inode*(sizeof(inode)),SEEK_SET);
fread(tmp_inode,sizeof(inode),1,fp);
tmp_inode->mode=0755;
strcpy(tmp_inode->user_name,user_active->name);
tmp_inode->user_group=user_active->group;
gettime(&(tmp_inode->file_creat));
fseek(fp,super_block->first_inode+num_inode*(sizeof(inode)),SEEK_SET);
fwrite(tmp_inode,sizeof(inode),1,fp);
delete tmp_inode;
}
strcpy(tmp_dir->name,name);
if(root) ins_dir(head_dir,tmp_dir); //若该文件/目录建在根目录下
else ins_dir(dir_active,tmp_dir); //若该文件/目录建在当前目录下
return num_dir;
}
void FileControl::cleartime(time_info *st)
{
st->year=0;
st->month=0;
st->day=0;
st->hour=0;
st->min=0;
}
void FileControl::del(int num) //删除目录或文件,参数为目录项的编号
{
dirItem *tmp_dir=&((super_block->dir_items)[num]);
if(tmp_dir->inode_num!=-1){
inode *tmp_node=new inode;
fseek(fp,super_block->first_inode+tmp_dir->inode_num*sizeof(inode),SEEK_SET);
fread(tmp_node,sizeof(inode),1,fp);
for(short int i=0;i<tmp_node->blocks;i++){
bc.Brelse((tmp_node->block)[i]);
(tmp_node->block)[i]=-1;
}
tmp_node->blocks=0;
tmp_node->file_length=0;
tmp_node->mode=0777;
strcpy(tmp_node->user_name,"");
tmp_node->user_group='/0';
cleartime(&(tmp_node->file_creat));//将时间清为零
cleartime(&(tmp_node->file_edit));
fseek(fp,super_block->first_inode+tmp_dir->inode_num*sizeof(inode),SEEK_SET);
fwrite(tmp_node,sizeof(inode),1,fp);
delete tmp_node;
bc.set_free(super_block->inodes,tmp_dir->inode_num);
tmp_dir->inode_num=-1;
}
//下面开始将该目录项从链表中删除
dirItem *father,*son;
if(tmp_dir==dir_active->p_son){ //当tmp_dir 是其第一个子结点时
son=tmp_dir->p_brother;
dir_active->p_son=son;
if(son!=NULL) dir_active->son=son->number;
else dir_active->son=-1;
}
else {
for(father=dir_active->p_son;father;father=father->p_brother){
if(father->p_brother==tmp_dir) break;
}
son=tmp_dir->p_brother;
father->p_brother=son;
if(son!=NULL) father->brother=son->number;
else father->brother=-1;
}
//删除完毕,下面进行必要的清尾工作
strcpy(tmp_dir->name,"");
tmp_dir->p_parent=NULL; tmp_dir->parent=-1;
tmp_dir->p_brother=NULL; tmp_dir->brother=-1;
tmp_dir->p_son=NULL; tmp_dir->son=-1;
bc.set_free(super_block->dirs,tmp_dir->number);
}
int FileControl::find(string name, bool dir)
//在当前目录下查找文件/目录,dir为true时表示目录,为false是表示文件,返回文件或目录所在的目录项编号
{
dirItem *tmp_dir=dir_active->p_son;
for(;tmp_dir!=NULL;tmp_dir=tmp_dir->p_brother)
if(tmp_dir->dir_or_file==dir&&string(tmp_dir->name)==name)
return tmp_dir->number;
return -1; //当当前目录下面为空时
}
void FileControl::ins_dir(dirItem *posi,dirItem *dir_for_ins)
//将dir_for_ins插入到where的同一级目录中,要进行适当的排序,目录放在前面,文件放在后面
{
dirItem *tmp_dir1,*tmp_dir2;
tmp_dir1=posi->p_son;
dir_for_ins->p_parent=posi; dir_for_ins->parent=posi->number;
if(tmp_dir1==NULL){
posi->p_son=dir_for_ins; posi->son=dir_for_ins->number;
//dir_for_ins->p_parent=posi; dir_for_ins->parent=posi->number;
dir_for_ins->p_brother=NULL; dir_for_ins->brother=-1;
dir_for_ins->p_son=NULL; dir_for_ins->son=-1;
return;
}
else if(tmp_dir1->p_brother==NULL){
if(tmp_dir1->dir_or_file){
tmp_dir1->p_brother=dir_for_ins; tmp_dir1->brother=dir_for_ins->number;
//dir_for_ins->p_parent=tmp_dir1; dir_for_ins->parent=tmp_dir1->number;
dir_for_ins->p_brother=NULL; dir_for_ins->brother=-1;
dir_for_ins->p_son=NULL; dir_for_ins->son=-1;
return;
}
else {
posi->p_son=dir_for_ins; posi->son=dir_for_ins->number;
//dir_for_ins->p_parent=posi; dir_for_ins->parent=posi->number;
dir_for_ins->p_brother=tmp_dir1; dir_for_ins->brother=tmp_dir1->number;
dir_for_ins->p_son=NULL; dir_for_ins->son=-1;
}
}
else{
for(tmp_dir2=tmp_dir1->p_brother;tmp_dir2->dir_or_file&&tmp_dir2->p_brother;tmp_dir1=tmp_dir2,tmp_dir2=tmp_dir2->p_brother);
tmp_dir1->p_brother=dir_for_ins; tmp_dir1->brother=dir_for_ins->number;
dir_for_ins->p_brother=tmp_dir2; dir_for_ins->brother=tmp_dir2->number;
//tmp_dir2->p_parent=dir_for_ins; tmp_dir2->parent=dir_for_ins->number;
//dir_for_ins->p_parent=tmp_dir1; dir_for_ins->parent=tmp_dir1->number;
dir_for_ins->p_son=NULL; dir_for_ins->son=-1;
}
return;
}
void FileControl::write_file(string &str, int num)
//向磁盘块里写入添加的信息,从最后一块开始写,参数为目录项编号
{
dirItem *tmp_dir;
inode *tmp_inode;
tmp_dir=&((super_block->dir_items)[num]);
tmp_inode=new inode;
fseek(fp,super_block->first_inode+sizeof(inode)*(tmp_dir->inode_num),SEEK_SET);
fread(tmp_inode,sizeof(inode),1,fp);
char *stch=new char[BLOCK_SIZE];
bool first=true; //判断写最后一个块
int i=0,j=0;
for(;j<str.length();){
stch[i++]=str[j++];
if(i!=BLOCK_SIZE&&j<str.length()) continue;
stch[i]='/0';
i=0;
if(first&&tmp_inode->blocks!=0){
bc.Bwrite(stch,(stch,tmp_inode->block)[tmp_inode->blocks-1]);
tmp_inode->file_length=tmp_inode->file_length/BLOCK_SIZE+strlen(stch);
first=false;
//fseek(fp,super_block->first_inode+sizeof(inode)*(tmp_dir->inode_num),SEEK_SET);
//fwrite(tmp_inode,sizeof(inode),1,fp);
//continue;
}
else{
int num=bc.Bwrite(stch); //自动申请一个块写,返回块号
tmp_inode->block[tmp_inode->blocks]=num;
tmp_inode->blocks++;
tmp_inode->file_length+=strlen(stch);
}
}
gettime(&(tmp_inode->file_edit));
fseek(fp,super_block->first_inode+sizeof(inode)*(tmp_dir->inode_num),SEEK_SET);
fwrite(tmp_inode,sizeof(inode),1,fp);
delete tmp_inode;
delete [] stch;
return;
}
ICmd::ICmd(void)
{
show_menu();
}
ICmd::~ICmd(void)
{
end_fs();
}
void ICmd::show_menu(void)
{
char name[NAME_LEN];
char *password;
int user_num;
cout<<"########################################################################"<<endl;
cout<<"######################### Welcome to my filesystem #####################"<<endl;
cout<<"######################## designed by luju ##############"<<endl;
cout<<"#######################################################################"<<endl;
init_fs();
exit_flag=false; //表示进入文件系统
logout_flag=false; //表示换身份进入文件系统
while(!exit_flag){
logout_flag=false; //表示换身份进入文件系统
for(int i=0;i<3;i++){
cout<<"login:";
cin>>name;
password=getpass("password:");
user_num=check_user(name,password); //检查用户是否合法,合法返回用户所在编号,否则返回-1
if(user_num!=-1) break;
cout<<"The user doesn't exist or bad password!"<<endl;
if(i>=2) {
cout<<"You have tried too many times,you are forbiden to try again."<<endl;
exit(-1);
}
}
user_active=&(super_block->users[user_num]);
dir_active=&((super_block->dir_items)[user_active->my_dir]);
cout<<"Welcome!"<<user_active->name<<endl;
cout<<"You can type help for help"<<endl;
while(!logout_flag){
cout<<user_active->name<<"@";
if(user_active->group=='r') cout<<"root:";
else cout<<"user:";
get_order(); //接收命令
switch(check_order()){
case CREAT:
Creat(string(param)); break;
case READ:
Read(string(param)); break;
case WRITE:
Write(string(param)); break;
case DEL:
Del(string(param)); break;
case MKDIR:
CreatDir(string(param)); break;
case RMDIR:
DelDir(string(param)); break;
case CD:
Cd(string(param)); break;
case LS:
Ls(); break;
case PWD:
Pwd();break;
case NEW:
NewUser(); break;
case SHOW:
Show(); break;
case HELP:
Help(); break;
case LOGOUT:
Logout();break; //在这个函数里改变logout_flag即可
case EXIT:
Exit(); break;
default:
cout<<"The order is wrong!You can type help for help"<<endl;
}
}
}
}
void ICmd::get_order(void)
{
string tmp;
char buffer[20];
cin>>buffer;
for(int i=0;i<20&&buffer[i]!='/0';i++){
if(buffer[i]>='a'&&buffer[i]<='z') buffer[i]=buffer[i]-32;
}
tmp=buffer;
strcpy(order,tmp.c_str());
if(tmp=="CREAT"||tmp=="WRITE"||tmp=="CD"||tmp=="DEL"||tmp=="READ"||tmp=="MKDIR"||tmp=="RMDIR"){
cin>>tmp;
strcpy(param,tmp.c_str());
}
}
//检查用户
int ICmd::check_user(char *name,char *password)
{
int i,is_find=-1;
string name1=string(name);
string name2;
for(i=0;i<super_block->num_of_users;i++){
name2=string((super_block->users[i]).name);
if(name1==name2){
if(string(password)==string((super_block->users[i]).password)){
is_find=i;
break;
}
}
}
return is_find;
}
int ICmd::check_order(void)
{
string tmp=string(order);
if(tmp=="CREAT") return CREAT;
if(tmp=="READ") return READ;
if(tmp=="WRITE") return WRITE;
if(tmp=="DEL") return DEL;
if(tmp=="MKDIR") return MKDIR;
if(tmp=="RMDIR") return RMDIR;
if(tmp=="CD") return CD;
if(tmp=="LS") return LS;
if(tmp=="PWD") return PWD;
if(tmp=="NEW") return NEW;
if(tmp=="SHOW") return SHOW;
if(tmp=="HELP") return HELP;
if(tmp=="LOGOUT") return LOGOUT;
if(tmp=="EXIT") return EXIT;
return -1;
}
void ICmd::init_fs(void){
super_block=NULL;
dir_active=NULL;
head_dir=NULL;
user_active=NULL;
if((fp=fopen("storage","r+"))==NULL){
init_fs_first();
fp=fopen("storage","r+");
}
super_block=new sup_blk;
fread(super_block,sizeof(sup_blk),1,fp);
head_dir=&(super_block->dir_items[0]);
cr_dir_tree(head_dir); //建目录树
}
void ICmd::cr_dir_tree(dirItem *head)
{
if(head==NULL) return;
if(head->parent!=-1)
head->p_parent=&(super_block->dir_items[head->parent]);
else head->p_parent=NULL;
if(head->brother!=-1)
head->p_brother=&(super_block->dir_items[head->brother]);
else head->p_brother=NULL;
if(head->son!=-1)
head->p_son=&(super_block->dir_items[head->son]);
else head->p_son=NULL;
cr_dir_tree(head->p_brother);
cr_dir_tree(head->p_son);
return;
}
void ICmd::end_fs(void)
{
rewind(fp);
fwrite(super_block,sizeof(sup_blk),1,fp);
//delete super_block;
}
void ICmd::init_fs_first(void)
{
if((fp=fopen("storage","w+"))==0)
{
cout<<"ERROR!Cannot creat a file for the vitual fs.exit"<<endl;
exit(-1);
}
fseek(fp,DEV_SIZE,SEEK_SET);
fputc('#',fp); //写入磁盘文件结束标志
//开始初始化超级块
super_block=new sup_blk;
//初始化目录项的位示图和各个目录项
for(int i=0;i<DIR_NUM;i++) {
super_block->dirs[i]=true;
(super_block->dir_items[i]).number=i;
(super_block->dir_items[i]).inode_num=-1;
(super_block->dir_items[i]).name[0]='/0';
(super_block->dir_items[i]).parent=-1;
(super_block->dir_items[i]).son=-1;
(super_block->dir_items[i]).brother=-1;
(super_block->dir_items[i]).p_parent=NULL;
(super_block->dir_items[i]).p_son=NULL;
(super_block->dir_items[i]).p_brother=NULL;
}
for(int i=0;i<BLOCK_NUM;i++) super_block->blocks[i]=true;
for(int i=0;i<INODE_NUM;i++) super_block->inodes[i]=true;
super_block->num_of_users=0;
super_block->num_of_files=0;
super_block->dirs[0]=false; //做根目录项
(super_block->dir_items[0]).inode_num=0;
(super_block->dir_items[0]).dir_or_file=true; //表示目录
strcpy((super_block->dir_items[0]).name,""); //此目录不属于任何用户
(super_block->dir_items[0]).parent=-1;
(super_block->dir_items[0]).brother=-1;
(super_block->dir_items[0]).son=-1;
//还要初始化各个目录项和i节点!!!!
for(int i=0;i<USER_NUM;i++)
(super_block->users[i]).flag=false;
super_block->inodes[0]=false; //根的i节点
super_block->first_inode=sizeof(sup_blk);
super_block->first_block=super_block->first_inode+INODE_NUM*(sizeof(inode));
inode *tmp=new inode;
tmp->number=0;
tmp->mode=(short)0755;//初始化权限
strcpy(tmp->user_name,"");
tmp->user_group='/0';
tmp->file_length=0;
tmp->blocks=0;
for(int i=0;i<FILE_BLOCKS;i++)
tmp->block[i]=-1;
fseek(fp,super_block->first_inode,SEEK_SET);
fwrite(tmp,sizeof(inode),1,fp);
for(int i=1;i<INODE_NUM;i++){
tmp->number=i;
fwrite(tmp,sizeof(inode),1,fp);
}
char tmpch[BLOCK_SIZE];
for(int i=0;i<BLOCK_SIZE;i++) tmpch[i]='/0';
fseek(fp,super_block->first_block,SEEK_SET);
for(int i=0;i<BLOCK_NUM;i++)
fwrite(tmpch,sizeof(char)*BLOCK_SIZE,1,fp);
cout<<"这是你第一次使用该文件系统,你必须首先创建一个用户,且第一个用户默认为管理员"<<endl;
head_dir=&(super_block->dir_items[0]);
NewUser(); //创建第一个用户,还须为其创建一个目录
user_active=NULL;
fseek(fp,0,SEEK_SET);
fwrite(super_block,sizeof(sup_blk),1,fp);
delete tmp;
delete super_block;
fclose(fp);
}
void ICmd::NewUser(void)
//需要考虑是否是第一个用户
{
user_info *newone=new user_info;
string pass1,pass2;
cout<<"creat name:";
cin>>(newone->name);
while(1){
pass1=getpass("please input your password:");
pass2=getpass("please input your password again:");
if(pass1==pass2) break;
}
strcpy(newone->password,pass1.c_str());
if(super_block->num_of_users==0) //创建第一个用户,默认为管理员
newone->group='r';
else if(user_active->group=='r'){ //只有root组的用户才有选择创建何类型用户的权利,非root组用户只能创建user组用户
cout<<"please input its group(r/u):";
cin>>newone->group;
}
else newone->group='u';
newone->flag=true;
newone->my_dir=fc.creat_df(newone->name,DIR,ROOT); //建目录或文件,第一个参数为名称,第二个表示创建的是目录/文件,第三个表示位置(根/当前目录下)
fc.add_user(newone); //加到超级块中去
super_block->num_of_users++;
}
void ICmd::Logout(void)
{
logout_flag=true;
dir_active=head_dir;
user_active=NULL;
}
void ICmd::Exit(void){
logout_flag=true;
exit_flag=true;
}
void ICmd::Show(void){
user_info *tmp_user;
cout<<"/t用户名/t所属组/t用户目录"<<endl;
for(int i=0;i<USER_NUM;i++){
tmp_user=&(super_block->users[i]);
if(tmp_user->flag){
cout<<"/t"<<tmp_user->name<<"/t"<<tmp_user->group<<"/t/"<<tmp_user->name<<"/"<<endl;
}
}
return;
}
void ICmd::Cd(string name) //目录转移函数
{
if(name=="..") {
if(dir_active->number) dir_active=dir_active->p_parent; //若当前目录不是根目录时执行
}
else if(name=="~") dir_active=&(super_block->dir_items[user_active->my_dir]);
else if(name=="/") dir_active=&(super_block->dir_items[0]); //返回根目录
else {
int num=fc.find(name,DIR); //在当前目录下寻找该目录,返回它的目录项号,否则返回-1
if(num==-1) cout<<"ERROR:Cannot find the directory: "<<name<<endl;
else dir_active=&(super_block->dir_items[num]);
}
}
void ICmd::Creat(string filename)
{
char name[20];
strcpy(name,filename.c_str());
fc.creat_df(name,FE,CURENT);
}
void ICmd::CreatDir(string name)
{
char str[20];
strcpy(str,name.c_str());
fc.creat_df(str,DIR,CURENT);
}
void ICmd::Del(string filename)
{
int num=fc.find(filename,FE);
if(num==-1) cout<<"ERROR:Cannot find the file: "<<filename<<endl;
else fc.del(num); //删除,参数为目录项编号
}
void ICmd::DelDir(string name)
{
int num=fc.find(name,DIR);
if(num==-1) cout<<"ERROR:Cannot find the directory: "<<name<<endl;
else fc.del(num);
}
void ICmd::Help(void)
{
cout<<"/t"<<"命 令"<<"/t"<<"参 数"<<"/t/t"<<"功能说明"<<endl
<<"/t"<<"CREAT"<<"/t"<<"文件名"<<"/t/t"<<"创建文件"<<endl
<<"/t"<<"READ"<<"/t"<<"文件名"<<"/t/t"<<"读文件"<<endl
<<"/t"<<"WRITE"<<"/t"<<"文件名"<<"/t/t"<<"在文件尾编辑"<<endl
<<"/t"<<"DEL"<<"/t"<<"文件名"<<"/t/t"<<"删除文件"<<endl
<<"/t"<<"MKDIR"<<"/t"<<"路径名"<<"/t/t"<<"创建目录"<<endl
<<"/t"<<"RMDIR"<<"/t"<<"路径名"<<"/t/t"<<"删除目录"<<endl
<<"/t"<<"CD"<<"/t"<<"路径名"<<"/t/t"<<"转移工作目录"<<endl
<<"/t"<<"LS"<<"/t"<<"无"<<"/t/t"<<"列出目录"<<endl
<<"/t"<<"PWD"<<"/t"<<"无"<<"/t/t"<<"列出用户当前所在目录"<<endl
<<"/t"<<"NEW"<<"/t"<<"无"<<"/t/t"<<"创建新用户"<<endl
<<"/t"<<"SHOW"<<"/t"<<"无"<<"/t/t"<<"列出所有用户"<<endl
<<"/t"<<"HELP"<<"/t"<<"无"<<"/t/t"<<"列出帮助"<<endl
<<"/t"<<"LOGOUT"<<"/t"<<"无"<<"/t/t"<<"用户登出"<<endl
<<"/t"<<"EXIT"<<"/t"<<"无"<<"/t/t"<<"退出文件系统"<<endl;
}
void ICmd::Pwd()
{
pwd(dir_active);
cout<<endl;
}
void ICmd::pwd(dirItem *p) //列出工作目录
{
if(p->number==0){
cout<<"/";
return;
}
pwd(p->p_parent);
cout<<p->name<<"/";
}
void ICmd::Ls()
{
dirItem *tmp;
inode *tmp_inode=new inode;
pwd(dir_active);
cout<<": 的目录为:"<<endl;
int dir=0,file=0;
for(tmp=dir_active->p_son;tmp!=NULL;tmp=tmp->p_brother){
cout<<tmp->name;
if(tmp->dir_or_file) {
cout<<"/t"<<"< DIR >"<<endl;
dir++;
}
else {
file++;
fseek(fp,super_block->first_inode+(sizeof(inode)*tmp->inode_num),SEEK_SET);
fread(tmp_inode,sizeof(inode),1,fp);
cout<<"/t"<<tmp_inode->file_length<<" Byte "<<"created:"<<tmp_inode->file_creat.year<<"-"<<tmp_inode->file_creat.month<<"-"<<tmp_inode->file_creat.day<<" "<<tmp_inode->file_creat.hour<<":"<<tmp_inode->file_creat.min<<" latest edited:"<<tmp_inode->file_edit.year<<"-"<<tmp_inode->file_edit.month<<"-"<<tmp_inode->file_edit.day<<" "<<tmp_inode->file_edit.hour<<":"<<tmp_inode->file_edit.min<<endl;
}
}
cout<<"总共有"<<dir<<"个目录和"<<file<<"个文件"<<endl;
delete tmp_inode;
}
void ICmd::Read(string filename)
{
int num=fc.find(filename,FE);
if(num==-1) cout<<"ERROR:Cannot find the file; "<<filename<<endl;
else fc.read_file(num);
}
void ICmd::Write(string filename)
{
int num=fc.find(filename,FE);
char tmp_block[BLOCK_SIZE];
char buf[100];
bool flag=false;
if(num==-1) {
cout<<"ERROR:Cannot find the file: "<<filename<<endl;
return;
}
fc.read_file(num);
inode *tmp_node=new inode;
fseek(fp,super_block->first_inode+((super_block->dir_items)[num].inode_num)*sizeof(inode),SEEK_SET);
fread(tmp_node,sizeof(inode),1,fp); //将文件的I节点读入
string str;
if(tmp_node->blocks!=0){
fseek(fp,super_block->first_block+sizeof(char)*BLOCK_SIZE*(tmp_node->block[tmp_node->blocks-1]),SEEK_SET);
fread(tmp_block,sizeof(char)*BLOCK_SIZE,1,fp);//读最后一块
str=tmp_block;
}
cout<<endl<<"请输入要添加的内容,以#结束:"<<endl;
int len;
for(;;){
gets(buf);
len=strlen(buf);
if(len!=0&&buf[len-1]!='#') {
buf[len+1]='/0';
buf[len]='/n';
}
else if(len!=0&&buf[len-1]=='#'){
buf[len]='/0';
buf[len-1]='/n';
flag=true; //表示到了文件输入结束,跳出循环标志
}
str=str+buf;
if(str.length()>=BLOCK_SIZE) break;
if(flag) break;
}
fc.write_file(str,num); //将文件写入磁盘,从原来的最后一块开始写,参数为目录项编号
}
int main(void)
{
ICmd ch;
return 0;
}
编译环境:ubuntu6.06+gcc
放在VC下编译则需要自己写getpass函数即可。
#include<iostream>
#include<stdio.h>
#include<string>
#include<stdlib.h>
#include<bitset>
#include<time.h>
#define DEV_SIZE (1024*1024*100)
#define BLOCK_SIZE 1024 //一个块的大小定义为1k
#define DIR_NUM 5120
#define BLOCK_NUM (5120*16)
#define INODE_NUM 5120
#define USER_NUM 16 //MAX NUMber of users
#define NAME_LEN 16 //文件名/用户名的长度
#define PSD_LEN 16 //密码长度
#define FILE_BLOCKS 16 //每个文件最多占用16个磁盘块
#define MIX_UNIT 8 //最小单元以字节计
#define DIR 1 //表示要创建的是目录
#define FE 0 //表示要创建的是文件
#define ROOT 1 //表示创建位置为根目录下
#define CURENT 0 //表示创建位置为当前目录下
using namespace std;
struct time_info{ //时间结构
short year;
short month;
short day;
short hour;
short min;
};
struct dirItem{ //目录项结构
int number;
int inode_num; //所对应的的I结点号
bool dir_or_file; //true 表示目录,false表示文件
char name[NAME_LEN]; //目录名称或文件名
int parent,son,brother; //用于在磁盘中保存目录的层次结构
struct dirItem *p_parent,*p_son,*p_brother; //同样是表示目录间的层次结构,主要用于在内存中的操作
};
struct inode{ //I结点结构
int number; //I节点号
short mode; //文件的rwx权限
char user_name[NAME_LEN]; //文件所属用户
char user_group; //用户所在组
int file_length; //文件长度,以字节计
time_info file_creat; //文件创建时间
time_info file_edit; //文件最后编辑时间
short blocks; //记录文件存储占用的存储块
int block[FILE_BLOCKS]; //文件存储用到的块,目前还不支持间接块的使用
};
struct user_info{ //用户信息
bool flag; //用户的有效性标识,可用于遍历用户
char name[NAME_LEN];
char group; //用户所在组,分两个组,root和user
int my_dir; //表示用户目录
char password[PSD_LEN]; //用户密码
};
struct sup_blk{ //super block
int num_of_users; //记录用户的数目
user_info users[USER_NUM]; //所有用户的信息
int num_of_files; //记录文件系统中文件的总数
bool dirs[DIR_NUM]; //true 表示该目录项可用,false表示不可用
bool blocks[BLOCK_NUM]; //TRUE 表示该块可用,false表示该块不可用
bool inodes[INODE_NUM]; //TRUE 表示该I结点可用,false表示该结点不可用
dirItem dir_items[BLOCK_NUM]; //把目录项的所有内容放到超级块中,以便到时将目录项读入内存建立目录层次
int first_inode; //表示第一个inode结点的相对地址
int first_block; //第一个用于存储文件的磁盘块的相对地址
};
static sup_blk *super_block; //全局变量,指向超级块
static FILE *fp; //文件指针
static dirItem *head_dir,*dir_active; //head_dir指向根目录的指针,根目录固定放在dir_items[0]处,dir_active指向当前工作目录
static user_info *user_active; //当前活跃的用户
class BlockControl
{
public:
BlockControl(void);
~BlockControl(void);
void Bread(int num); //读磁盘块,直接输出,参数为磁盘块号
void Brelse(int num); //释放磁盘块,注意还要改写bitmap,最好格式化一下
void Bwrite(char *buf,int num); //写第num块,同时记得设置位示图
int Bwrite(char *buf); //写块,返回块号同时记得设置位示图
int is_free(bool *bitmap,int num); //查找各类位图中的空闲区域,参数num为最大偏移量若没找到,则返回-1
void set_busy(bool *bitmap,int num); //将对应的区域标志为被占用
void set_free(bool *bitmap,int num); //设置为空闲
private:
int fb; //super_block->first_block
char *samp;
};
class FileControl
{
public:
FileControl(void);
~FileControl(void);
/*建目录或文件,第一个参数为名称,第二个表示创建的是目录1/文件0,*
*第三个表示位置(根1/当前目录0下),同时还得加入到目录项树中去*/
int creat_df(char *name,bool dir,bool root);
void add_user(user_info *user_new); //将新建的用户复制到超级块中去
int find(string name,bool dir); //查找文件/目录,dir为true时表示目录,为false是表示文件,返回文件或目录所在的目录项编号
void del(int num); //删除文件/或目录,参数为对应的目录项编号
void read_file(int num); //读文件,参数为对应的目录项编号
void write_file(string &str,int num); //向磁盘块里写入添加的信息,从最后一块开始写,参数为目录项编号
private:
BlockControl bc; //磁盘块控制
void ins_dir(dirItem *posi,dirItem *dir_for_ins);
//将dir_for_ins插入到where的同一级目录中,要进行适当的排序,目录放在前面,文件放在后面
void gettime(time_info *time); //获取时间函数
void cleartime(time_info *time);
};
enum ORDER{CREAT=0,READ,WRITE,DEL,MKDIR,RMDIR,CD,LS,PWD,NEW,SHOW,HELP,LOGOUT,EXIT};
class ICmd {
public:
ICmd(void);
~ICmd(void);
void show_menu(void);
void get_order(void); //接收命令
void Creat(string filename); //创建文件
void Read(string filename);
void Write(string filename);
void Del(string filename);
//void Save(void); //保存当前编辑的文件,其实可以放到下一层
void CreatDir(string name); //创建目录
void DelDir(string name); //删除目录
void Cd(string name); //参数分几种:..上一级目录,~用户目录,/绝对路径目录,不带/表示直接下一级目录
void Ls(void); //列出目录和文件
void Pwd(void); //列出用户当前所在的路径
void NewUser(void); //增加新用户
void Show(void); //列出所有的用户信息
void Help(void); //列出帮助信息
void Logout(void); //登出,准备换用户名登录
void Exit(void); //退出文件系统
private:
FileControl fc;
char order[10],param[NAME_LEN]; //命令和参数
bool logout_flag; //true 表示登出
bool exit_flag; //表示退出文件系统
void pwd(dirItem *p); //递归显示路径
void init_fs(void); //初始化文件系统
void init_fs_first(void); //第一次使用文件系统
void end_fs(void); //结束文件系统时的一些收尾工作
int check_user(char *name,char *password); //检查用户是否合法,合法返回用户编号,否则返回-1
int check_order(void);//检查命令,以整数形式返回命令
void cr_dir_tree(dirItem *head); //建目录树
};
BlockControl::BlockControl(void)
{
char *samp=new char[BLOCK_SIZE];
for(int i=0;i<BLOCK_SIZE;i++)
*(samp+i)='/0';
}
BlockControl::~BlockControl(void)
{
delete [] samp;
}
void BlockControl::Bread(int num) //读磁盘块,直接输出里面的内容
{
char buf2[BLOCK_SIZE];
fseek(fp,(super_block->first_block)+num*sizeof(char)*BLOCK_SIZE,SEEK_SET);
fread(buf2,sizeof(char)*BLOCK_SIZE,1,fp);
cout<<buf2;
}
void BlockControl::Brelse(int num) //释放块
{
fseek(fp,(super_block->first_block)+num*sizeof(char)*BLOCK_SIZE,SEEK_SET);
fwrite(samp,sizeof(char)*BLOCK_SIZE,1,fp);
set_free(super_block->blocks,num);
}
void BlockControl::Bwrite(char *buf,int num)
{
fseek(fp,(super_block->first_block)+num*sizeof(char)*BLOCK_SIZE,SEEK_SET);
fwrite(buf,sizeof(char)*BLOCK_SIZE,1,fp);
set_busy(super_block->blocks,num);
}
int BlockControl::Bwrite(char *buf)
{
int num=is_free(super_block->blocks,BLOCK_NUM);
fseek(fp,(super_block->first_block)+num*sizeof(char)*BLOCK_SIZE,SEEK_SET);
fwrite(buf,sizeof(char)*BLOCK_SIZE,1,fp);
set_busy(super_block->blocks,num);
return num;
}
int BlockControl::is_free(bool *bitmap,int num)
{
int no;
for(no=0;no<num;no++)
if(*(bitmap+no)) return no;
return -1;
}
void BlockControl::set_busy(bool *bitmap,int num)
{
*(bitmap+num)=false;
}
void BlockControl::set_free(bool *bitmap,int num)
{
*(bitmap+num)=true;
}
FileControl::FileControl(void)
{
}
FileControl::~FileControl(void)
{
}
void FileControl::gettime(time_info *stime){ //获取时间函数
tm *tim; //定义tm结构的变量tim
time_t end;//=time_info();
end=time((time_t *)NULL);
tim=localtime(&end);
stime->year=1900+tim->tm_year;
stime->month=1+tim->tm_mon;
stime->day=tim->tm_mday;
stime->hour=tim->tm_hour;
stime->min=tim->tm_min;
return;
}
void FileControl::read_file(int num)
{
dirItem *tmp;
tmp=&((super_block->dir_items)[num]);
inode *tmp_inode=new inode;
fseek(fp,super_block->first_inode+sizeof(inode)*(tmp->inode_num),SEEK_SET);
fread(tmp_inode,sizeof(inode),1,fp);
for(int i=0;i<tmp_inode->blocks;i++)
bc.Bread((tmp_inode->block)[i]); //读磁盘块函数,直接输出
cout<<endl;
delete tmp_inode;
}
void FileControl::add_user(user_info *user_new) //将新建的用户复制到超级块中去
{
int i;
for(i=0;i<super_block->num_of_users&&(super_block->users)[i].flag;i++);
(super_block->users)[i].flag=true;
(super_block->users)[i].group=user_new->group;
(super_block->users)[i].my_dir=user_new->my_dir;
strcpy((super_block->users)[i].name,user_new->name);
strcpy((super_block->users)[i].password,user_new->password);
}
int FileControl::creat_df(char *name,bool dir,bool root)
/*建目录或文件,第一个参数为名称,第二个表示创建的是目录1/文件0,*
*第三个表示位置(根1/当前目录0下),同时还得加入到目录项树中去*/
{
int num_dir=bc.is_free(super_block->dirs,DIR_NUM);
if(num_dir==-1){
cout<<"找不到空闲的目录项,退出"<<endl;
return -1;
}
bc.set_busy(super_block->dirs,num_dir); //设置该目录项已经被占用
dirItem *tmp_dir=&((super_block->dir_items)[num_dir]);
int num_inode=bc.is_free(super_block->inodes,INODE_NUM); //寻找空闲的I节点
if(num_inode==-1){
cout<<"找不到空闲的I节点,退出"<<endl;
return -1;
}
bc.set_busy(super_block->inodes,num_inode); //设置该I节点被占用
tmp_dir->inode_num=num_inode; //设置为该目录项对应的I节点
if(dir) tmp_dir->dir_or_file=true; //表示目录
else {
tmp_dir->dir_or_file=false; //表示文件,初步设置i节点
inode *tmp_inode=new inode;
//tmp_dir->dir_or_file=false;
fseek(fp,super_block->first_inode+num_inode*(sizeof(inode)),SEEK_SET);
fread(tmp_inode,sizeof(inode),1,fp);
tmp_inode->mode=0755;
strcpy(tmp_inode->user_name,user_active->name);
tmp_inode->user_group=user_active->group;
gettime(&(tmp_inode->file_creat));
fseek(fp,super_block->first_inode+num_inode*(sizeof(inode)),SEEK_SET);
fwrite(tmp_inode,sizeof(inode),1,fp);
delete tmp_inode;
}
strcpy(tmp_dir->name,name);
if(root) ins_dir(head_dir,tmp_dir); //若该文件/目录建在根目录下
else ins_dir(dir_active,tmp_dir); //若该文件/目录建在当前目录下
return num_dir;
}
void FileControl::cleartime(time_info *st)
{
st->year=0;
st->month=0;
st->day=0;
st->hour=0;
st->min=0;
}
void FileControl::del(int num) //删除目录或文件,参数为目录项的编号
{
dirItem *tmp_dir=&((super_block->dir_items)[num]);
if(tmp_dir->inode_num!=-1){
inode *tmp_node=new inode;
fseek(fp,super_block->first_inode+tmp_dir->inode_num*sizeof(inode),SEEK_SET);
fread(tmp_node,sizeof(inode),1,fp);
for(short int i=0;i<tmp_node->blocks;i++){
bc.Brelse((tmp_node->block)[i]);
(tmp_node->block)[i]=-1;
}
tmp_node->blocks=0;
tmp_node->file_length=0;
tmp_node->mode=0777;
strcpy(tmp_node->user_name,"");
tmp_node->user_group='/0';
cleartime(&(tmp_node->file_creat));//将时间清为零
cleartime(&(tmp_node->file_edit));
fseek(fp,super_block->first_inode+tmp_dir->inode_num*sizeof(inode),SEEK_SET);
fwrite(tmp_node,sizeof(inode),1,fp);
delete tmp_node;
bc.set_free(super_block->inodes,tmp_dir->inode_num);
tmp_dir->inode_num=-1;
}
//下面开始将该目录项从链表中删除
dirItem *father,*son;
if(tmp_dir==dir_active->p_son){ //当tmp_dir 是其第一个子结点时
son=tmp_dir->p_brother;
dir_active->p_son=son;
if(son!=NULL) dir_active->son=son->number;
else dir_active->son=-1;
}
else {
for(father=dir_active->p_son;father;father=father->p_brother){
if(father->p_brother==tmp_dir) break;
}
son=tmp_dir->p_brother;
father->p_brother=son;
if(son!=NULL) father->brother=son->number;
else father->brother=-1;
}
//删除完毕,下面进行必要的清尾工作
strcpy(tmp_dir->name,"");
tmp_dir->p_parent=NULL; tmp_dir->parent=-1;
tmp_dir->p_brother=NULL; tmp_dir->brother=-1;
tmp_dir->p_son=NULL; tmp_dir->son=-1;
bc.set_free(super_block->dirs,tmp_dir->number);
}
int FileControl::find(string name, bool dir)
//在当前目录下查找文件/目录,dir为true时表示目录,为false是表示文件,返回文件或目录所在的目录项编号
{
dirItem *tmp_dir=dir_active->p_son;
for(;tmp_dir!=NULL;tmp_dir=tmp_dir->p_brother)
if(tmp_dir->dir_or_file==dir&&string(tmp_dir->name)==name)
return tmp_dir->number;
return -1; //当当前目录下面为空时
}
void FileControl::ins_dir(dirItem *posi,dirItem *dir_for_ins)
//将dir_for_ins插入到where的同一级目录中,要进行适当的排序,目录放在前面,文件放在后面
{
dirItem *tmp_dir1,*tmp_dir2;
tmp_dir1=posi->p_son;
dir_for_ins->p_parent=posi; dir_for_ins->parent=posi->number;
if(tmp_dir1==NULL){
posi->p_son=dir_for_ins; posi->son=dir_for_ins->number;
//dir_for_ins->p_parent=posi; dir_for_ins->parent=posi->number;
dir_for_ins->p_brother=NULL; dir_for_ins->brother=-1;
dir_for_ins->p_son=NULL; dir_for_ins->son=-1;
return;
}
else if(tmp_dir1->p_brother==NULL){
if(tmp_dir1->dir_or_file){
tmp_dir1->p_brother=dir_for_ins; tmp_dir1->brother=dir_for_ins->number;
//dir_for_ins->p_parent=tmp_dir1; dir_for_ins->parent=tmp_dir1->number;
dir_for_ins->p_brother=NULL; dir_for_ins->brother=-1;
dir_for_ins->p_son=NULL; dir_for_ins->son=-1;
return;
}
else {
posi->p_son=dir_for_ins; posi->son=dir_for_ins->number;
//dir_for_ins->p_parent=posi; dir_for_ins->parent=posi->number;
dir_for_ins->p_brother=tmp_dir1; dir_for_ins->brother=tmp_dir1->number;
dir_for_ins->p_son=NULL; dir_for_ins->son=-1;
}
}
else{
for(tmp_dir2=tmp_dir1->p_brother;tmp_dir2->dir_or_file&&tmp_dir2->p_brother;tmp_dir1=tmp_dir2,tmp_dir2=tmp_dir2->p_brother);
tmp_dir1->p_brother=dir_for_ins; tmp_dir1->brother=dir_for_ins->number;
dir_for_ins->p_brother=tmp_dir2; dir_for_ins->brother=tmp_dir2->number;
//tmp_dir2->p_parent=dir_for_ins; tmp_dir2->parent=dir_for_ins->number;
//dir_for_ins->p_parent=tmp_dir1; dir_for_ins->parent=tmp_dir1->number;
dir_for_ins->p_son=NULL; dir_for_ins->son=-1;
}
return;
}
void FileControl::write_file(string &str, int num)
//向磁盘块里写入添加的信息,从最后一块开始写,参数为目录项编号
{
dirItem *tmp_dir;
inode *tmp_inode;
tmp_dir=&((super_block->dir_items)[num]);
tmp_inode=new inode;
fseek(fp,super_block->first_inode+sizeof(inode)*(tmp_dir->inode_num),SEEK_SET);
fread(tmp_inode,sizeof(inode),1,fp);
char *stch=new char[BLOCK_SIZE];
bool first=true; //判断写最后一个块
int i=0,j=0;
for(;j<str.length();){
stch[i++]=str[j++];
if(i!=BLOCK_SIZE&&j<str.length()) continue;
stch[i]='/0';
i=0;
if(first&&tmp_inode->blocks!=0){
bc.Bwrite(stch,(stch,tmp_inode->block)[tmp_inode->blocks-1]);
tmp_inode->file_length=tmp_inode->file_length/BLOCK_SIZE+strlen(stch);
first=false;
//fseek(fp,super_block->first_inode+sizeof(inode)*(tmp_dir->inode_num),SEEK_SET);
//fwrite(tmp_inode,sizeof(inode),1,fp);
//continue;
}
else{
int num=bc.Bwrite(stch); //自动申请一个块写,返回块号
tmp_inode->block[tmp_inode->blocks]=num;
tmp_inode->blocks++;
tmp_inode->file_length+=strlen(stch);
}
}
gettime(&(tmp_inode->file_edit));
fseek(fp,super_block->first_inode+sizeof(inode)*(tmp_dir->inode_num),SEEK_SET);
fwrite(tmp_inode,sizeof(inode),1,fp);
delete tmp_inode;
delete [] stch;
return;
}
ICmd::ICmd(void)
{
show_menu();
}
ICmd::~ICmd(void)
{
end_fs();
}
void ICmd::show_menu(void)
{
char name[NAME_LEN];
char *password;
int user_num;
cout<<"########################################################################"<<endl;
cout<<"######################### Welcome to my filesystem #####################"<<endl;
cout<<"######################## designed by luju ##############"<<endl;
cout<<"#######################################################################"<<endl;
init_fs();
exit_flag=false; //表示进入文件系统
logout_flag=false; //表示换身份进入文件系统
while(!exit_flag){
logout_flag=false; //表示换身份进入文件系统
for(int i=0;i<3;i++){
cout<<"login:";
cin>>name;
password=getpass("password:");
user_num=check_user(name,password); //检查用户是否合法,合法返回用户所在编号,否则返回-1
if(user_num!=-1) break;
cout<<"The user doesn't exist or bad password!"<<endl;
if(i>=2) {
cout<<"You have tried too many times,you are forbiden to try again."<<endl;
exit(-1);
}
}
user_active=&(super_block->users[user_num]);
dir_active=&((super_block->dir_items)[user_active->my_dir]);
cout<<"Welcome!"<<user_active->name<<endl;
cout<<"You can type help for help"<<endl;
while(!logout_flag){
cout<<user_active->name<<"@";
if(user_active->group=='r') cout<<"root:";
else cout<<"user:";
get_order(); //接收命令
switch(check_order()){
case CREAT:
Creat(string(param)); break;
case READ:
Read(string(param)); break;
case WRITE:
Write(string(param)); break;
case DEL:
Del(string(param)); break;
case MKDIR:
CreatDir(string(param)); break;
case RMDIR:
DelDir(string(param)); break;
case CD:
Cd(string(param)); break;
case LS:
Ls(); break;
case PWD:
Pwd();break;
case NEW:
NewUser(); break;
case SHOW:
Show(); break;
case HELP:
Help(); break;
case LOGOUT:
Logout();break; //在这个函数里改变logout_flag即可
case EXIT:
Exit(); break;
default:
cout<<"The order is wrong!You can type help for help"<<endl;
}
}
}
}
void ICmd::get_order(void)
{
string tmp;
char buffer[20];
cin>>buffer;
for(int i=0;i<20&&buffer[i]!='/0';i++){
if(buffer[i]>='a'&&buffer[i]<='z') buffer[i]=buffer[i]-32;
}
tmp=buffer;
strcpy(order,tmp.c_str());
if(tmp=="CREAT"||tmp=="WRITE"||tmp=="CD"||tmp=="DEL"||tmp=="READ"||tmp=="MKDIR"||tmp=="RMDIR"){
cin>>tmp;
strcpy(param,tmp.c_str());
}
}
//检查用户
int ICmd::check_user(char *name,char *password)
{
int i,is_find=-1;
string name1=string(name);
string name2;
for(i=0;i<super_block->num_of_users;i++){
name2=string((super_block->users[i]).name);
if(name1==name2){
if(string(password)==string((super_block->users[i]).password)){
is_find=i;
break;
}
}
}
return is_find;
}
int ICmd::check_order(void)
{
string tmp=string(order);
if(tmp=="CREAT") return CREAT;
if(tmp=="READ") return READ;
if(tmp=="WRITE") return WRITE;
if(tmp=="DEL") return DEL;
if(tmp=="MKDIR") return MKDIR;
if(tmp=="RMDIR") return RMDIR;
if(tmp=="CD") return CD;
if(tmp=="LS") return LS;
if(tmp=="PWD") return PWD;
if(tmp=="NEW") return NEW;
if(tmp=="SHOW") return SHOW;
if(tmp=="HELP") return HELP;
if(tmp=="LOGOUT") return LOGOUT;
if(tmp=="EXIT") return EXIT;
return -1;
}
void ICmd::init_fs(void){
super_block=NULL;
dir_active=NULL;
head_dir=NULL;
user_active=NULL;
if((fp=fopen("storage","r+"))==NULL){
init_fs_first();
fp=fopen("storage","r+");
}
super_block=new sup_blk;
fread(super_block,sizeof(sup_blk),1,fp);
head_dir=&(super_block->dir_items[0]);
cr_dir_tree(head_dir); //建目录树
}
void ICmd::cr_dir_tree(dirItem *head)
{
if(head==NULL) return;
if(head->parent!=-1)
head->p_parent=&(super_block->dir_items[head->parent]);
else head->p_parent=NULL;
if(head->brother!=-1)
head->p_brother=&(super_block->dir_items[head->brother]);
else head->p_brother=NULL;
if(head->son!=-1)
head->p_son=&(super_block->dir_items[head->son]);
else head->p_son=NULL;
cr_dir_tree(head->p_brother);
cr_dir_tree(head->p_son);
return;
}
void ICmd::end_fs(void)
{
rewind(fp);
fwrite(super_block,sizeof(sup_blk),1,fp);
//delete super_block;
}
void ICmd::init_fs_first(void)
{
if((fp=fopen("storage","w+"))==0)
{
cout<<"ERROR!Cannot creat a file for the vitual fs.exit"<<endl;
exit(-1);
}
fseek(fp,DEV_SIZE,SEEK_SET);
fputc('#',fp); //写入磁盘文件结束标志
//开始初始化超级块
super_block=new sup_blk;
//初始化目录项的位示图和各个目录项
for(int i=0;i<DIR_NUM;i++) {
super_block->dirs[i]=true;
(super_block->dir_items[i]).number=i;
(super_block->dir_items[i]).inode_num=-1;
(super_block->dir_items[i]).name[0]='/0';
(super_block->dir_items[i]).parent=-1;
(super_block->dir_items[i]).son=-1;
(super_block->dir_items[i]).brother=-1;
(super_block->dir_items[i]).p_parent=NULL;
(super_block->dir_items[i]).p_son=NULL;
(super_block->dir_items[i]).p_brother=NULL;
}
for(int i=0;i<BLOCK_NUM;i++) super_block->blocks[i]=true;
for(int i=0;i<INODE_NUM;i++) super_block->inodes[i]=true;
super_block->num_of_users=0;
super_block->num_of_files=0;
super_block->dirs[0]=false; //做根目录项
(super_block->dir_items[0]).inode_num=0;
(super_block->dir_items[0]).dir_or_file=true; //表示目录
strcpy((super_block->dir_items[0]).name,""); //此目录不属于任何用户
(super_block->dir_items[0]).parent=-1;
(super_block->dir_items[0]).brother=-1;
(super_block->dir_items[0]).son=-1;
//还要初始化各个目录项和i节点!!!!
for(int i=0;i<USER_NUM;i++)
(super_block->users[i]).flag=false;
super_block->inodes[0]=false; //根的i节点
super_block->first_inode=sizeof(sup_blk);
super_block->first_block=super_block->first_inode+INODE_NUM*(sizeof(inode));
inode *tmp=new inode;
tmp->number=0;
tmp->mode=(short)0755;//初始化权限
strcpy(tmp->user_name,"");
tmp->user_group='/0';
tmp->file_length=0;
tmp->blocks=0;
for(int i=0;i<FILE_BLOCKS;i++)
tmp->block[i]=-1;
fseek(fp,super_block->first_inode,SEEK_SET);
fwrite(tmp,sizeof(inode),1,fp);
for(int i=1;i<INODE_NUM;i++){
tmp->number=i;
fwrite(tmp,sizeof(inode),1,fp);
}
char tmpch[BLOCK_SIZE];
for(int i=0;i<BLOCK_SIZE;i++) tmpch[i]='/0';
fseek(fp,super_block->first_block,SEEK_SET);
for(int i=0;i<BLOCK_NUM;i++)
fwrite(tmpch,sizeof(char)*BLOCK_SIZE,1,fp);
cout<<"这是你第一次使用该文件系统,你必须首先创建一个用户,且第一个用户默认为管理员"<<endl;
head_dir=&(super_block->dir_items[0]);
NewUser(); //创建第一个用户,还须为其创建一个目录
user_active=NULL;
fseek(fp,0,SEEK_SET);
fwrite(super_block,sizeof(sup_blk),1,fp);
delete tmp;
delete super_block;
fclose(fp);
}
void ICmd::NewUser(void)
//需要考虑是否是第一个用户
{
user_info *newone=new user_info;
string pass1,pass2;
cout<<"creat name:";
cin>>(newone->name);
while(1){
pass1=getpass("please input your password:");
pass2=getpass("please input your password again:");
if(pass1==pass2) break;
}
strcpy(newone->password,pass1.c_str());
if(super_block->num_of_users==0) //创建第一个用户,默认为管理员
newone->group='r';
else if(user_active->group=='r'){ //只有root组的用户才有选择创建何类型用户的权利,非root组用户只能创建user组用户
cout<<"please input its group(r/u):";
cin>>newone->group;
}
else newone->group='u';
newone->flag=true;
newone->my_dir=fc.creat_df(newone->name,DIR,ROOT); //建目录或文件,第一个参数为名称,第二个表示创建的是目录/文件,第三个表示位置(根/当前目录下)
fc.add_user(newone); //加到超级块中去
super_block->num_of_users++;
}
void ICmd::Logout(void)
{
logout_flag=true;
dir_active=head_dir;
user_active=NULL;
}
void ICmd::Exit(void){
logout_flag=true;
exit_flag=true;
}
void ICmd::Show(void){
user_info *tmp_user;
cout<<"/t用户名/t所属组/t用户目录"<<endl;
for(int i=0;i<USER_NUM;i++){
tmp_user=&(super_block->users[i]);
if(tmp_user->flag){
cout<<"/t"<<tmp_user->name<<"/t"<<tmp_user->group<<"/t/"<<tmp_user->name<<"/"<<endl;
}
}
return;
}
void ICmd::Cd(string name) //目录转移函数
{
if(name=="..") {
if(dir_active->number) dir_active=dir_active->p_parent; //若当前目录不是根目录时执行
}
else if(name=="~") dir_active=&(super_block->dir_items[user_active->my_dir]);
else if(name=="/") dir_active=&(super_block->dir_items[0]); //返回根目录
else {
int num=fc.find(name,DIR); //在当前目录下寻找该目录,返回它的目录项号,否则返回-1
if(num==-1) cout<<"ERROR:Cannot find the directory: "<<name<<endl;
else dir_active=&(super_block->dir_items[num]);
}
}
void ICmd::Creat(string filename)
{
char name[20];
strcpy(name,filename.c_str());
fc.creat_df(name,FE,CURENT);
}
void ICmd::CreatDir(string name)
{
char str[20];
strcpy(str,name.c_str());
fc.creat_df(str,DIR,CURENT);
}
void ICmd::Del(string filename)
{
int num=fc.find(filename,FE);
if(num==-1) cout<<"ERROR:Cannot find the file: "<<filename<<endl;
else fc.del(num); //删除,参数为目录项编号
}
void ICmd::DelDir(string name)
{
int num=fc.find(name,DIR);
if(num==-1) cout<<"ERROR:Cannot find the directory: "<<name<<endl;
else fc.del(num);
}
void ICmd::Help(void)
{
cout<<"/t"<<"命 令"<<"/t"<<"参 数"<<"/t/t"<<"功能说明"<<endl
<<"/t"<<"CREAT"<<"/t"<<"文件名"<<"/t/t"<<"创建文件"<<endl
<<"/t"<<"READ"<<"/t"<<"文件名"<<"/t/t"<<"读文件"<<endl
<<"/t"<<"WRITE"<<"/t"<<"文件名"<<"/t/t"<<"在文件尾编辑"<<endl
<<"/t"<<"DEL"<<"/t"<<"文件名"<<"/t/t"<<"删除文件"<<endl
<<"/t"<<"MKDIR"<<"/t"<<"路径名"<<"/t/t"<<"创建目录"<<endl
<<"/t"<<"RMDIR"<<"/t"<<"路径名"<<"/t/t"<<"删除目录"<<endl
<<"/t"<<"CD"<<"/t"<<"路径名"<<"/t/t"<<"转移工作目录"<<endl
<<"/t"<<"LS"<<"/t"<<"无"<<"/t/t"<<"列出目录"<<endl
<<"/t"<<"PWD"<<"/t"<<"无"<<"/t/t"<<"列出用户当前所在目录"<<endl
<<"/t"<<"NEW"<<"/t"<<"无"<<"/t/t"<<"创建新用户"<<endl
<<"/t"<<"SHOW"<<"/t"<<"无"<<"/t/t"<<"列出所有用户"<<endl
<<"/t"<<"HELP"<<"/t"<<"无"<<"/t/t"<<"列出帮助"<<endl
<<"/t"<<"LOGOUT"<<"/t"<<"无"<<"/t/t"<<"用户登出"<<endl
<<"/t"<<"EXIT"<<"/t"<<"无"<<"/t/t"<<"退出文件系统"<<endl;
}
void ICmd::Pwd()
{
pwd(dir_active);
cout<<endl;
}
void ICmd::pwd(dirItem *p) //列出工作目录
{
if(p->number==0){
cout<<"/";
return;
}
pwd(p->p_parent);
cout<<p->name<<"/";
}
void ICmd::Ls()
{
dirItem *tmp;
inode *tmp_inode=new inode;
pwd(dir_active);
cout<<": 的目录为:"<<endl;
int dir=0,file=0;
for(tmp=dir_active->p_son;tmp!=NULL;tmp=tmp->p_brother){
cout<<tmp->name;
if(tmp->dir_or_file) {
cout<<"/t"<<"< DIR >"<<endl;
dir++;
}
else {
file++;
fseek(fp,super_block->first_inode+(sizeof(inode)*tmp->inode_num),SEEK_SET);
fread(tmp_inode,sizeof(inode),1,fp);
cout<<"/t"<<tmp_inode->file_length<<" Byte "<<"created:"<<tmp_inode->file_creat.year<<"-"<<tmp_inode->file_creat.month<<"-"<<tmp_inode->file_creat.day<<" "<<tmp_inode->file_creat.hour<<":"<<tmp_inode->file_creat.min<<" latest edited:"<<tmp_inode->file_edit.year<<"-"<<tmp_inode->file_edit.month<<"-"<<tmp_inode->file_edit.day<<" "<<tmp_inode->file_edit.hour<<":"<<tmp_inode->file_edit.min<<endl;
}
}
cout<<"总共有"<<dir<<"个目录和"<<file<<"个文件"<<endl;
delete tmp_inode;
}
void ICmd::Read(string filename)
{
int num=fc.find(filename,FE);
if(num==-1) cout<<"ERROR:Cannot find the file; "<<filename<<endl;
else fc.read_file(num);
}
void ICmd::Write(string filename)
{
int num=fc.find(filename,FE);
char tmp_block[BLOCK_SIZE];
char buf[100];
bool flag=false;
if(num==-1) {
cout<<"ERROR:Cannot find the file: "<<filename<<endl;
return;
}
fc.read_file(num);
inode *tmp_node=new inode;
fseek(fp,super_block->first_inode+((super_block->dir_items)[num].inode_num)*sizeof(inode),SEEK_SET);
fread(tmp_node,sizeof(inode),1,fp); //将文件的I节点读入
string str;
if(tmp_node->blocks!=0){
fseek(fp,super_block->first_block+sizeof(char)*BLOCK_SIZE*(tmp_node->block[tmp_node->blocks-1]),SEEK_SET);
fread(tmp_block,sizeof(char)*BLOCK_SIZE,1,fp);//读最后一块
str=tmp_block;
}
cout<<endl<<"请输入要添加的内容,以#结束:"<<endl;
int len;
for(;;){
gets(buf);
len=strlen(buf);
if(len!=0&&buf[len-1]!='#') {
buf[len+1]='/0';
buf[len]='/n';
}
else if(len!=0&&buf[len-1]=='#'){
buf[len]='/0';
buf[len-1]='/n';
flag=true; //表示到了文件输入结束,跳出循环标志
}
str=str+buf;
if(str.length()>=BLOCK_SIZE) break;
if(flag) break;
}
fc.write_file(str,num); //将文件写入磁盘,从原来的最后一块开始写,参数为目录项编号
}
int main(void)
{
ICmd ch;
return 0;
}