DOS下简单操作系统代码

////////////////////////////////////////////////////////////////////////////
//
// 本程序的文件名:OS实验参考程序.CPP
//
////////////////////////////////////////////////////////////////////////////
//
// 程序中假定:
// FAT[K]存储FAT表,本程序中K设为5000,其中FAT[0]存放空盘块数;
// Disk[K][R]用于存储对应磁盘块的内容(char型),每个盘块最多存R(=64)个字符;
// 文件目录项FCB中,文件属性fattrib=1表示“只读”,=2表示“隐藏”,=4表示“系统”;
// 文件属性fattrib=16表示“子目录”而非文件,各属性可以互相组合。
// 用户打开文件表UOF中,状态state=0表示空登记栏,=1表示“建立”,=2表示“打开”状态;
// UOF中“文件属性”即为被打开的文件的属性,对于“只读”文件,打开后只能读,不能写。
//
// 本系统对输入的命令,除文件名和目录名区分大小写外,其余部分字母都不区分大小写。
//
////////////////////////////////////////////////////////////////////////////
//
// 本模拟文件系统,包括如下操作命令:
// dir [<目录名>]——显示路径名指定的目录内容;
// cd [<目录名>]——指定当前目录。路径中“..”表示父目录;
// md <目录名>——创建子目录;
// rd <目录名>——删除子目录;
// create <文件名>[ <文件属性>]——创建文件;
// open <文件名>——打开文件;
// write <文件名> [<位置/app>[ insert]]——写文件;
// read <文件名> [<位置m> [<字节数n>]]——读文件;
// close <文件名>——关闭文件;
// ren <原文件名> <新文件名>——文件更名;
// copy <源文件名> [<目标文件名>]——复制文件;
// closeall——关闭当前用户的所有打开的文件
// del <文件名>——删除指定的文件
// type <文件名>——显示指定文件的内容;
// undel [<目录名>]——恢复指定目录中被删除的文件
// help——显示各命令的使用格式。
// attrib <文件名> [±<属性>]——显示[修改]文件/目录属性。
// rewind <文件名>——读、写指针移到文件开头(第一个字节处)
// fseek <文件名> <位置n>——将读、写指针都移到指定位置n处。
// block <文件名>——显示文件或目录占用的盘块号。
// uof——显示用户的UOF(文件打开表)。
// prompt——提示符中显示/不显示当前目录的切换。
// fat——显示模拟磁盘的空闲块数(FAT表中0的个数)。
// check——检查核对FAT表对应的空闲块数。
// exit——结束本程序的运行。
//
////////////////////////////////////////////////////////////////////////////

#include //cout,cin
#include //setw(),setiosflags()
#include //exit(),atoi()
#include //strcpy(),_stricmp()
#include //文件操作用

//定义若干符

号常量
#define S 32 //假设最多同时打开32个文件
#define K 5000 //假设磁盘共有5000个盘块
#define SIZE 64 //假设磁盘的大小是64字节
#define CK 8 //命令分解后的段数
#define INPUT_LEN 128 //输入缓冲区长度
#define COMMAND_LEN 11 //命令字符串长度
#define FILENAME_LEN 11 //文件名长度
#define PATH_LEN INPUT_LEN-COMMAND_LEN
#define DM 40 //恢复被删除文件表的表项数


struct FCB //定义文件目录项FCB的结构(共16个字节)
{
char FileName[FILENAME_LEN];//文件名(1~10字节)
char Fattrib; //文件属性
short int Addr; //文件首块号
short int Fsize; //文件长度
};

struct UOF //定义用户打开文件表的结构
{
char fname[PATH_LEN]; //文件全路径名
char attr; //文件属性,1=只可读;0=可读写
short int faddr; //文件的首块号
short int fsize; //文件大小(字节数)
FCB *fp; //该文件的目录项指针
short int state; //状态:0=空表项;1=新建;2=打开
short int readp; //读指针,指向某个要读的字符位置,0=空文件
short int writep; //写读指针,指向某个要写读的字符位置
};

struct CurPath //定义存储当前目录的数据结构
{
short int fblock; //当前目录的首块号
char cpath[PATH_LEN]; //当前目录绝对路径字符串(全路径名)
};

struct UnDel //恢复被删除文件表的数据结构
{
char gpath[PATH_LEN]; //被删除文件的全路径名(不含文件名)
char ufname[FILENAME_LEN]; //被删除文件名
short ufaddr; //被删除文件名的首块号
short fb; //存储被删除文件块号的第一个块号(链表头指针)
//首块号也存于fb所指的盘块中
};

//关于恢复被删除文件问题,还可以采用类似于Windows的回收站的方法。例如可以在根目录中
//建立一个特殊的文件夹recycled (其属性为:只读、隐藏、系统),其FCB记录结构中的成员
//Fsize,不用来存储文件长度,而用来存储一个盘块号,该盘块中存储文件长度和文件的全路
//径名(不含文件名),这里的“全路径名”就是文件的原位置,还原文件时该信息是不可或缺的。
//dir等命令处理recycled文件夹时,与普通文件夹略有不同(因其文件长度等信息要从Fsize号
//盘块中取出,不能直接获得)。rd命令应修改成不能删除文件夹recycled,copy,move,replace
//等命令也改成不能对文件夹recycled操作。

//当用del命令删除文件时,将该文件的有关信息保存到特殊的文件夹recycled中,亦即将文件“搬”
//到回收站,文件占用的磁盘空间并不释放;恢复时工作相反。清空回收站时才释放磁盘空间。
//此方案比前述UnDel结构的方案耗费更多的磁盘空间(删除的文件仍占用磁盘空间)

int FAT[K]; //FAT表,盘块数为K
//char (*Disk)[SIZE]=new char

[K][SIZE];//定义磁盘空间,每个盘块容量为SIZE个字节
char Disk[K][SIZE];
UOF uof[S]; //用户打开文件表UOF,最多同时打开S个文件
char comd[CK][PATH_LEN]; //分析命令时使用
char temppath[PATH_LEN]; //临时路径(全路径)
CurPath curpath;
UnDel udtab[DM]; //定义删除文件恢复表,退出系统时该表可存于文件UdTab.dat中
short Udelp=0; //udtab表的第一个空表项的下标,系统初始化时它为0。
//当Udelp=DM时,表示表已满,需清除最早的表项(后续表项依次前移)
short ffbp=1;
//0号盘快中存储如下内容:
// short ffbp; //从该位置开始查找空闲盘快(类似循环首次适应分配)
// short Udelp; //udtab表的第一个空表项的下标

int dspath=1; //dspath=1,提示符中显示当前目录

//函数原型说明
int CreateComd(int); //create命令处理函数
int OpenComd(int); //open命令处理函数
int ReadComd(int); //read命令处理函数
int WriteComd(int); //write命令处理函数
int CloseComd(int); //close命令处理函数
void CloseallComd(int); //closeaal命令处理函数, 关闭当前用户所有打开的文件
int DelComd(int); //del命令处理函数
int UndelComd(int); //undel命令处理函数,恢复被删除文件
int CopyComd(int); //copy命令处理函数
int DirComd(int); //dir命令处理函数,显示指定的文件目录——频繁使用
int CdComd(int); //cd命令处理函数
int MdComd(int); //md命令处理函数
int RdComd(int); //rd命令处理函数
int TypeComd(int); //type命令处理函数
int RenComd(int); //ren命令处理函数
int AttribComd(int); //attrib命令处理函数
void UofComd(void); //uof命令处理函数
void HelpComd(void); //help命令处理函数
int FindPath(char*,char,int,FCB* &); //找指定目录(的首块号)
int FindFCB(char*,int,char,FCB* &); //找指定的文件或目录
int FindBlankFCB(short s,FCB* &fcbp1); //寻找首块号为s的目录中的空目录项
int RewindComd(int); //rewind命令处理函数, 读、写指针移到文件开头(第一个字节处)
int FseekComd(int); //fseek命令处理函数, 读、写指针移到文件第n个字节处
int blockf(int); //block命令处理函数(显示文件占用的盘块号)
int delall(int); //delall命令处理函数, 删除指定目录中的所有文件
void save_FAT(void);
void save_Disk(void);
int getblock(void); //获得一个盘块
void FatComd(void);
void CheckComd(void);
int Check_UOF(char*);
void ExitComd(void);
bool IsName(char*); //判断名字是否符合规则
void PromptComd(void); //prompt命令,提示符是否显示当前目录的切换
void UdTabComd(void); //udtab命令,显示udtab表内容
void releaseblock(short s); //释放s开始的盘块链
int buffer_to_file(FCB* fcbp,char* Buffer); //Buffer写入文件
int file_to_buffer(FCB* fcbp,char* Buffer); //文件内容

读到Buffer,返回文件长度
int ParseCommand(char *); //将输入的命令行分解成命令和参数等
void ExecComd(int); //执行命令

//#define INIT //决定初始化还是从磁盘读入

void main()
{

char cmd[INPUT_LEN]; //命令行缓冲区
int i,k;
// 进入系统时,当前目录是根目录
curpath.fblock=1; //当前目录(根目录)的首块号
strcpy(curpath.cpath,"/"); //根目录的路径字符串

#ifdef INIT

int j;
FCB *fcbp;
// *********** 初始化FAT和Disk ************
for (i=0;iFAT[i]=0; //空闲盘块标记
FAT[0]=K-1; //FAT[0]中保存空闲盘块数
for (i=1;i<30;i++) //构造根目录盘块链
{
FAT[i]=i+1; //初始化根目录的FAT表
FAT[0]--; //空盘块数减1
}
FAT[i]=-1; //根目录尾标记
FAT[0]--; //空盘块数减1
for (i++;i<40;i++)
{
FAT[i]=-1; //各子目录尾标记
FAT[0]--;
}
// *********** 初始化Disk ************
fcbp=(FCB*) Disk[1];
j=40*SIZE/sizeof(FCB);
for (i=1;i<=j;i++)
{
fcbp->FileName[0]='\0'; //初始目录树各目录中初始化为空目录项
fcbp++;
}
//以下建立初始目录树中各个子目录
fcbp=(FCB*) Disk[1];
strcpy(fcbp->FileName,"bin"); //子目录bin
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=31; //该子目录的首盘块号是31
fcbp->Fsize=0; //约定子目录的长度为0
fcbp++; //指向下一个目录项
strcpy(fcbp->FileName,"usr"); //子目录usr
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=32; //该子目录的首盘块号是32
fcbp->Fsize=0; //约定子目录的长度为0
fcbp++;
strcpy(fcbp->FileName,"auto"); //文件unix的目录项
fcbp->Fattrib=0; //表示是普通文件
fcbp->Addr=0; //该子目录的首盘块号是0,表示是空文件
fcbp->Fsize=0; //该文件的长度为0
fcbp++;
strcpy(fcbp->FileName,"dev"); //子目录etc
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=33; //该子目录的首盘块号是33
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[31];
strcpy(fcbp->FileName,".."); //bin的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=1; //父目录(此处是根目录)的首盘块号是1
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[32];
strcpy(fcbp->FileName,".."); //usr的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=1; //父目录(此处是根目录)的首盘块号是1
fcbp->Fsize=0; //约定子目录的长度为0
fcbp++;
strcpy(fcbp->FileName,"user"); //子目录lib
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=34; //该子目录的首盘块号是34
fcbp->Fsize=0; //约定子目录的长度为0
fcbp++;
strcpy(fcbp->FileName,"lib"); //子目录user
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=3

5; //该子目录的首盘块号是35
fcbp->Fsize=0; //约定子目录的长度为0
fcbp++;
strcpy(fcbp->FileName,"bin"); //子目录bin
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=36; //该子目录的首盘块号是36
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[33];
strcpy(fcbp->FileName,".."); //etc的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=1; //父目录(此处是根目录)的首盘块号是1
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[34];
strcpy(fcbp->FileName,".."); //lib的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=32; //父目录(此处是usr目录)的首盘块号是32
fcbp->Fsize=0; //约定子目录的长度为0
fcbp++;
strcpy(fcbp->FileName,"lin"); //子目录liu
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=37; //该子目录的首盘块号是37
fcbp->Fsize=0; //约定子目录的长度为0
fcbp++;
strcpy(fcbp->FileName,"sun"); //子目录sun
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=38; //该子目录的首盘块号是38
fcbp->Fsize=0; //约定子目录的长度为0
fcbp++;
strcpy(fcbp->FileName,"ma"); //子目录fti
fcbp->Fattrib=16; //表示是子目录
fcbp->Addr=39; //该子目录的首盘块号是39
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[35];
strcpy(fcbp->FileName,".."); //user的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=32; //父目录(此处是usr目录)的首盘块号是32
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[36];
strcpy(fcbp->FileName,".."); //usr/bin的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=32; //父目录(此处是usr目录)的首盘块号是32
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[37];
strcpy(fcbp->FileName,".."); //usr/lib/liu的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=34; //父目录(此处是usr/lib目录)的首盘块号是34
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[38];
strcpy(fcbp->FileName,".."); //usr/lib/sun的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=34; //父目录(此处是usr/lib目录)的首盘块号是34
fcbp->Fsize=0; //约定子目录的长度为0
fcbp=(FCB*) Disk[39];
strcpy(fcbp->FileName,".."); //usr/lib/fti的父目录对应的目录项
fcbp->Fattrib=16; //表示是目录而不是文件
fcbp->Addr=34; //父目录(此处是usr/lib目录)的首盘块号是34
fcbp->Fsize=0; //约定子目录的长度为0

// *********** 初始化UnDel表 ************
Udelp=0;

ffbp=1; //从FAT表开头查找空闲盘快

#else

//

读入文件分配表FAT
char yn;
ifstream ffi("FAT2008.txt",ios::nocreate);//打开文件FAT2008.txt
if (!ffi)
{
cout<<"Can't open FAT2008.txt!\n";
cin>>yn;
exit(0);
}
for (i=0;iif(ffi)
ffi>>FAT[i];
else
break;
ffi.close();

//读入磁盘块Disk[ ]信息
ffi.open("Disk2008.dat",ios::binary|ios::nocreate);
if (!ffi)
{
cout<<"Can't open Disk2008.dat!\n";
cin>>yn;
exit(0);
}
for (i=0;iif(ffi)
ffi.read((char*)&Disk[i],SIZE);
else
break;
ffi.close();

//读入恢复删除文件表UdTab.dat信息
ffi.open("UdTab2008.dat",ios::binary|ios::nocreate);
if (!ffi)
{
cout<<"Can't open UdTab2008.dat!\n";
cin>>yn;
exit(0);
}
for (i=0;iif(ffi)
ffi.read((char*)&udtab[i],sizeof(udtab[0]));
else
break;
ffi.close();

short *pp=(short*) Disk[0];
ffbp=pp[0];
Udelp=pp[1];

#endif

for (i=0;iuof[i].state=0; //初始化为空表项

cout<<"\n现在你可以输入各种操作命令.\n"
<<"Help —— 简易帮助信息.\n"
<<"exit —— 退出本程序.\n";
while (1) //循环,等待用户输入命令,直到输入“exit”结束循环,程序结束
{ //输入命令,分析并执行命令

while (1)
{
cout<<"\nC:"; //显示提示符(本系统总假定是C盘)
if (dspath)
cout<cout<<">";
cin.getline(cmd,INPUT_LEN); //输入命令
if (strlen(cmd)>0)
break;
}
k=ParseCommand(cmd); //分解命令及其参数
//comd[0]中是命令,comd[1],comd[2]...是参数
ExecComd(k); //执行命令
}
}

/////////////////////////////////////////////////////////////////

void ExecComd(int k) //执行命令
{
int cid; //命令标识

//操作命令表
char CmdTab[][COMMAND_LEN]={"create","open","write","read","close",
"del","dir","cd","md","rd","ren","copy","type","help","attrib",
"uof","closeall","block","rewind","fseek","fat","check","exit",
"undel","Prompt","udtab"};
int M=sizeof(CmdTab)/COMMAND_LEN; //统计命令个数
for (cid=0;cidif (_stricmp(CmdTab[cid],comd[0])==0)//命令不区分大小写
break;
//以下命令函数中,命令参数通过全局变量comd[][]传递,故未出现在函数参数表中
switch(cid)
{
case 0:CreateComd(k); //create命令,建立文件
break;
case 1:OpenComd(k); //open命令,打开文件
break;
case 2:WriteComd(k); //write命令,k为命令中的参数个数(命令本身除外)
break;
case 3:ReadComd(k); //read命令,读文件
break;
case 4:CloseComd(k); //close命令,关闭文件
break;
case 5:DelComd(k); //del命令,删

除文件
break;
case 6:DirComd(k); //dir命令
break;
case 7:CdComd(k); //cd命令
break;
case 8:MdComd(k); //md命令
break;
case 9:RdComd(k); //rd命令
break;
case 10:RenComd(k); //ren命令,文件更名
break;
case 11:CopyComd(k); //copy命令,复制文件
break;
case 12:TypeComd(k); //type命令,显示文件内容(块号)
break;
case 13:HelpComd(); //help命令,帮助信息
break;
case 14:AttribComd(k); //attrib命令,修改文件属性
break;
case 15:UofComd(); //uof命令,显示用户的UOF(文件打开表)
break;
case 16:CloseallComd(1); //closeall命令,关闭所有文件
break;
case 17:blockf(k); //block命令,显示文件的盘块号
break;
case 18:RewindComd(k); //rewind命令,将读指针移到文件开头
break;
case 19:FseekComd(k); //fseek命令:将读、写指针都移到指定记录号
break;
case 20:FatComd(); //fat命令
break;
case 21:CheckComd(); //check命令
break;
case 22:ExitComd(); //exit命令
break;
case 23:UndelComd(k); //undel命令
break;
case 24:PromptComd(); //prompt命令
break;
case 25:UdTabComd(); //udtab命令
break;
default:cout<<"\n命令错:"<}
}

//////////////////////////////////////////////////////////////////////////////////////

void HelpComd() //help命令,帮助信息(显示各命令格式)
{
cout<<"\n* * * * * * * * * 本系统主要的文件操作命令简述如下 * * * * * * * * * *\n\n";
cout<<"create <文件名>[ <文件属性>] ——创建新文件,文件属性是r、h或s。\n";
cout<<"open <文件名> ——打开文件,操作类型可为r、h或(与)s。\n";
cout<<"write <文件名> [<位置/app>[ insert]] ——在指定位置写文件(有插入功能)。\n";
cout<<"read <文件名> [<位置m> [<字节数n>]] ——读文件,从第m字节处读n个字节。\n";
cout<<"close <文件名> ——关闭文件。\n";
cout<<"del <文件名> ——撤消(删除)文件。\n";
cout<<"dir [<路径名>] [|<属性>] ——显示当前目录。\n";
cout<<"cd [<路径名>] ——改变当前目录。\n";
cout<<"md <路径名> [<属性>] ——创建指定目录。\n";
cout<<"rd [<路径名>] ——删除指定目录。\n";
cout<<"ren <旧文件名> <新文件名> ——文件更名。\n";
cout<<"attrib <文件名> [±<属性>] ——修改文件属性(r、h、s)。\n";
cout<<"copy <源文件名> [<目标文件名>] ——复制文件。\n";
cout<<"type <文件名> ——显示文件内容。\n";
cout

<<"rewind <文件名> ——将读、写指针移到文件第一个字符处。\n";
cout<<"fseek <文件名> <位置> ——将读、写指针都移到指定位置。\n";
cout<<"block <文件名> ——显示文件占用的盘块号。\n";
cout<<"closeall ——关闭当前打开的所有文件。\n";
cout<<"uof ——显示UOF(用户打开文件表)。\n";
cout<<"undel [<路径名>] ——恢复指定目录中被删除的文件。\n";
cout<<"exit ——退出本程序。\n";
cout<<"prompt ——提示符是否显示当前目录(切换)。\n";
cout<<"fat ——显示FAT表中空闲盘块数(0的个数)。\n";
cout<<"check ——核对后显示FAT表中空闲盘块数。\n";
}

/////////////////////////////////////////////////////////////////

int GetAttrib(char* str,char& attrib)
{
int i,len;
char ar='\01',ah='\02',as='\04';
if (str[0]!='|')
{
cout<<"\n命令中属性参数错误。\n";
return -1;
}
len=strlen(str);
_strlwr(str); //转换成小写字母
for (i=1;i{
switch(str[i])
{
case 'r': attrib=attrib|ar;
break;
case 'h': attrib=attrib|ah;
break;
case 's': attrib=attrib|as;
break;
default: cout<<"\n命令中属性参数错误。\n";
return -1;
}
}
return 1;
}

/////////////////////////////////////////////////////////////////

int DirComd(int k) //dir命令,显示指定目录的内容(文件名或目录名等)
{
// 命令形式:dir[ <目录名>[ <属性>]]
// 命令功能:显示"目录名"指定的目录中文件名和第一级子目录名。若指
// 定目录不存在,则给出错误信息。如果命令中没有指定目录名,则显示
// 当前目录下的相应内容。若命令中无"属性"参数,则显示指定目录中"非
// 隐藏"属性的全部文件名和第一级子目录名;若命令中有"属性"参数,则
// 仅显示指定属性的文件名和目录名。h、r或s或两者都有,则显示隐藏属
// 性或只读属性或既是隐藏又是只读属性的文件。属性参数的形式是"|<属
// 性符号>",其中属性符号有r、h和s三种(不区分大小写),分别表示"只
// 读"、"隐藏"和"系统"三种属性,它们可以组合使用且次序不限。例如"|rh"
// 和"|hr"都表示要求显示同时具有"只读"和"隐藏"属性的文件和目录名。显
// 示文件名时,显示该文件长度;显示目录名时,同时显示"

"的字样。

// 举例:
// dir /usr |h
// 上述命令显示根目录下usr子目录中全部"隐藏"属性的文件名和子目录名
// dir ..
// 上述命令显示当前目录的父目录中

全部"非隐藏"属性的文件和子目录名(包
// 括"只读"属性的也显示,但一般不显示"系统"属性的,因为"系统"属性的对
// 象一般也是"隐藏"属性的)。
//
// 学生可考虑将此函数修改成命令中的路径的最后允许是文件名的情况。
// 另外还可以考虑含通配符的问题。

short i,s;
short filecount,dircount,fsizecount; //文件数、目录数、文件长度累计
char ch,attrib='\0',attr,cc;
FCB *fcbp,*p;

filecount=dircount=fsizecount=0;
if (k>1) //命令中多于1个参数,错误(较复杂的处理应当允许有多个参数)
{
cout<<"\n命令错误:参数太多。\n";
return -1;
}
if (k<1) //命令无参数,显示当前目录
{
strcpy(temppath,curpath.cpath);
s=curpath.fblock; //当前目录的首块号保存于s
}
else if (k==1) //命令有1个参数(k=1)
{
if (comd[1][0]=='|')
{
i=GetAttrib(comd[1],attrib);
if (i<0) return i;
strcpy(temppath,curpath.cpath);
s=curpath.fblock; //当前目录的首块号保存于s
}
else
{
s=FindPath(comd[1],'\020',1,fcbp); //找指定目录(的首块号)
if (s<1)
{
cout<<"\n输入的路径错误!"<return -1;
}
}
}
else //命令有2个参数(k=2)
{
s=FindPath(comd[1],'\020',1,fcbp); //找指定目录(的首块号)
if (s<1)
{
cout<<"\n输入的路径错误!"<return -1;
}
i=GetAttrib(comd[2],attrib);
if (i<0) return i;
}
cout<<"\nThe Directory of C:"<while (s>0)
{
p=(FCB*) Disk[s]; //p指向该目录的第一个盘块
for (i=0;i<4;i++,p++)
{
ch=p->FileName[0]; //取文件(目录)名的第一个字符
if (ch==(char)0xe5) //空目录项
continue;
if (ch=='\0') //已至目录尾部
break;
attr=p->Fattrib&'\07'; //不考虑文件还是目录,只考虑属性
if (attrib==0) //命令中没有指定属性
{
if (attr&'\02') //不显示“隐藏”属性文件
continue;
}
else
{
cc=attr & attrib;
if (attrib!=cc) //只显示指定属性的文件
continue;
}
cout<FileName;
if (p->Fattrib>='\20') //是子目录
{
cout<<"

\n";
dircount++;
}
else
{
cout<cout<Fsize<filecount++;
fsizecount+=p->Fsize;
}
}
if (ch=='\0') break;
s=FAT[s]; //指向该目录的下一个盘块
}
cout<cout<cout<cout<cout<<" free"<return 1;
}

/////////////////////////////////////////////////////////////////

int CdComd(int k)
{
// 当前目录(工作目录)转移到指定目录下。指定目录不存在时,

给出错误信息。
// 若命令中无目录名,则显示当前目录路径。

short i,s;
char attrib=(char)16;
FCB* fcbp;
if (k>1) //命令中多于1个参数,错误
{
cout<<"\n命令错误:参数太多。\n";
return -1;
}
if (k<1) //命令无参数,显示当前目录
{
cout<<"\nThe Current Directory is C:"<return 1;
}
else //命令有一个参数,将指定目录作为当前目录
{
i=strlen(comd[1]);
if (i>1 && comd[1][i-1]=='/') //路径以"/"结尾,错误
{
cout<<"\n路径名错误!\n";
return -1;
}
s=FindPath(comd[1],attrib,1,fcbp); //找指定目录(的首块号)
if (s<1)
{
cout<<"\n路径名错误!"<return -1;
}
curpath.fblock=s;
strcpy(curpath.cpath,temppath);
if (!dspath)
cout<<"\n当前目录变为 C:"<return 1;
}
}

/////////////////////////////////////////////////////////////////

int M_NewDir(char *Name,FCB* p,short fs,char attrib) //在p位置创建一新子目录
{
//成功返回新子目录的首块号

short i,b,kk;
FCB *q;
kk=SIZE/sizeof(FCB);
b=getblock(); //新目录须分配一磁盘块用于存储目录项“..”
if (b<0)
return b;
strcpy(p->FileName,Name); //目录名
p->Fattrib=attrib; //目录项属性为目录而非文件
p->Addr=b; //该新目录的首块号
p->Fsize=0; //子目录的长度约定为0
q=(FCB*) Disk[b];
for (i=0;iq->FileName[0]='\0'; //置空目录项标志*/
q=(FCB*) Disk[b];
strcpy(q->FileName,".."); //新目录中的第一个目录项名是“..”
q->Fattrib=(char)16; //目录项属性为目录而非文件
q->Addr=fs; //该目录的首块号是父目录的首块号
q->Fsize=0; //子目录的长度约定为0
return b; //成功创建,返回
}

/////////////////////////////////////////////////////////////////

int ProcessPath(char* path,char* &Name,int k,int n,char attrib)
{
// 将path中最后一个名字分离出来,并由引用参数Name带回;
// 返回path中除掉Name后,最后一个目录的地址(首块号);
// 必要时调用函数FindPath(),并通过全局变量temppath返
// 回path(去掉Name后)的全路径名(绝对路径名)

short i,len,s;
FCB* fcbp;

if (n && k!=n) //n=0,参数个数k任意,n>0,必须k=n
{
cout<<"\n命令参数个数错误!\n";
return -1;
}
len=strlen(path);
for (i=len-1;i>=0;i--)
if (path[i]=='/')
break;
Name=&path[i+1]; //取路径中最后一个名字
if (i==-1)
{
s=curpath.fblock;
strcpy(temppath,curpath.cpath);
}
else
{
if (i==0)
{
s=1;
strcpy(temppath,"/");
}
else
{
path[i]='\0';
s=FindPath(path,attrib,1,fcbp);
if (s<1)
{
cout<<"\n路径名错误!\n";
return -3;
}
}
}
return s;
}

/////////////////////////////////////////////////////////////////

int MdComd(int k) //md命令

处理函数
{
// 命令形式:md <目录名>
// 功能:在指定路径下创建指定目录,若没有指定路径,则在当前目录下创建指定目录。
// 对于重名目录给出错误信息。目录与文件也不能重名。

// 学生可以考虑命令中加“属性”参数,用于创建指定属性的子目录。命令形式如下:
// md <目录名>[ <属性>]
// 属性包括R、H、S以及它们的组合(不区分大小写,顺序也不限)。例如:
// md user rh
// 其功能是在当前目录中创建具有“只读”和“隐藏”属性的子目录user。

short i,s,s0,kk;
char attrib=(char)16,*DirName;
FCB *p;

kk=SIZE/sizeof(FCB);

if (k<1)
{
cout<<"\n错误:命令中没有目录名。\n";
return -1;
}
if (k>2)
{
cout<<"\n错误:命令参数太多。\n";
return -1;
}
s=ProcessPath(comd[1],DirName,k,0,attrib);
if (s<0)
return s; //失败,返回
if (!IsName(DirName)) //若名字不符合规则
{
cout<<"\n命令中的新目录名错误。\n";
return -1;
}
i=FindFCB(DirName,s,attrib,p);
if (i>0)
{
cout<<"\n错误:目录重名!\n";
return -1;
}
if (k==2) //命令形式:md <目录名> |<属性符>
{
i=GetAttrib(comd[2],attrib);
if (i<0)
return i;
}
s0=FindBlankFCB(s,p);//找空白目录项
if (s0<0) //磁盘满
return s0;
s0=M_NewDir(DirName,p,s,attrib); //在p所指位置创建一新子目录项
if (s0<0) //创建失败
{
cout<<"\n磁盘空间已满,创建目录失败。\n";
return -1;
}
return 1; //新目录创建成功,返回
}

/////////////////////////////////////////////////////////////////

int RdComd(int k)
{
// 若指定目录为空,则删除之,否则,给出"非空目录不能删除"的提示。
// 不能删除当前目录。

short i,j,count=0,fs,s0,s;
char attrib=(char)16,*DirName;
FCB *p,*fcbp;
fs=ProcessPath(comd[1],DirName,k,1,attrib); //返回DirName的父目录的首块号
if (fs<0)
return fs; //失败,返回
s0=s=FindFCB(DirName,fs,attrib,fcbp);//取DirName的首块号
if (s<1)
{
cout<<"\n要删除的目录不存在。\n";
return -1;
}
if (s==curpath.fblock)
{
cout<<"\n不能删除当前目录。\n";
return 0;
}
while (s>0) //循环查找,直到目录尾部
{
p=(FCB*) Disk[s];
for (i=0;i<4;i++,p++)
{
if (p->FileName[0]!=(char)0xe5 && p->FileName[0]!='\0')//累计非空目录项
count++;
}
//s0=s; //记下上一个盘块号
s=FAT[s]; //取下一个盘块号
}
if (count>1)
{
cout<<"\n目录"<return -1;
}
//s0=fcbp->Addr; //取DirName的首块号
while (s0>0) //归还目录DirName所占的磁盘空间
{
s=FAT[s0]; //记下第s0块的后续块号
FAT[s0]=0; //回收第s0块
FAT[0]++; //空闲盘块数增1
s0=s; //后续块号赋予s0
}
fcbp->FileName[0]=(char)0xe5; //删除D

irName的目录项
if (strcmp(temppath,"/")==0) //所删除的子目录在根目录
return 1;
//所删除的子目录DirName不在根目录时,对其父目录作以下处理
s0=s=fs; //取DirName父目录的首块号
while (s>0) //整理DirName的父目录空间(回收无目录项的盘块)
{
p=(FCB*) Disk[s];
for (j=i=0;i<4;i++,p++)
if (p->FileName[0]!=(char)0xe5 && p->FileName[0]!='\0')//累计非空目录项
j++;
if (j==0)
{
FAT[s0]=FAT[s]; //调整指针
FAT[s]=0; //回收s号盘块
FAT[0]++; //空闲盘块数增1
s=FAT[s0];
}
else
{
s0=s; //记下上一个盘块号
s=FAT[s]; //s指向下一个盘块
}
}
return 1;
}

/////////////////////////////////////////////////////////////////

int TypeComd(int k) //type命令处理函数(显示文件内容)
{
// 显示文件内容:type <文件名>,显示指定文件的内容。
// 若指定文件不存在,则给出错误信息。

short i,s,size,jj=0;
char attrib='\0',*FileName;
char *Buffer;
char gFileName[PATH_LEN]; //存放文件全路径名
FCB* fcbp;

if(k<1)
{
cout<<"\n命令中无文件名。\n";
return -1;
}
s=ProcessPath(comd[1],FileName,k,0,'\020');//取FileName所在目录的首块号
if (s<1) //路径错误
return s; //失败,返回
s=FindFCB(FileName,s,attrib,fcbp); //取FileName的首块号(查其存在性)
strcpy(gFileName,temppath);
i=strlen(temppath);
if (temppath[i-1]!='/')
strcat(gFileName,"/");
strcat(gFileName,FileName); //构造文件的全路径名
if (s<0)
{
cout<<"\n文件"<return -3;
}
if (s==0)
cout<<"\n文件"<else
{
size=fcbp->Fsize;
Buffer=new char[size+1]; //分配动态内存空间
while (s>0)
{
for (i=0;i{
if (jj==size)
break;
Buffer[jj]=Disk[s][i];
}
if (ibreak;
s=FAT[s];
}
Buffer[jj]='\0';
cout<delete [] Buffer; //释放分配的动态内存空间
}
return 1;
}

/////////////////////////////////////////////////////////////////

int blockf(int k) //block命令处理函数(显示文件或目录占用的盘块号)
{
short s;
char attrib='\040'; //32表示任意(文件或子目录)目录项都可以
FCB* fcbp;

if(k!=1)
{
cout<<"\n命令中参数个数错误。\n";
return -1;
}
s=FindPath(comd[1],attrib,1,fcbp); //找指定目录(的首块号)
if (s<1)
{
cout<<"\n路径名错误!"<return -2;
}
cout<<"\n"<while (s>0)
{
cout<s=FAT[s];
}
cout<return 1;
}

/////////////////////////////////////////////////////////////////

void Put_UOF(char *gFileName,int i,short status,FCB* fcbp)
{
strcpy(uof[i].fname,gFileName); //复制文件全路径名
uof[i].attr=fcbp->Fattrib; //复制文件属性
uof[i].faddr=f

cbp->Addr; //文件的首块号(0代表空文件)
uof[i].fsize=fcbp->Fsize;
uof[i].fp=fcbp;
uof[i].state=status; //打开状态
if (fcbp->Fsize>0) //若文件非空
uof[i].readp=1; //读指针指向文件开头
else
uof[i].readp=0; //读指针指向空位置
uof[i].writep=fcbp->Fsize+1; //写指针指向文件末尾
}

/////////////////////////////////////////////////////////////////

int FindBlankFCB(short s,FCB* &fcbp1) //寻找首块号为s的目录中的空目录项
{
short i,s0;
while (s>0) //在首块号为s的目录找空登记栏,直到目录尾部
{
fcbp1=(FCB*) Disk[s];
for (i=0;i<4;i++,fcbp1++)
if (fcbp1->FileName[0]==(char)0xe5 || fcbp1->FileName[0]=='\0')
{
fcbp1->Addr=fcbp1->Fsize=0; //假设为空目录项
return 1; //找到空目录项,成功返回
}
s0=s; //记下上一个盘块号
s=FAT[s]; //取下一个盘块号
}
if (strcmp(temppath,"/")==0) //若是根目录
{
cout<<"\n根目录已满,不能再创建目录项。\n";
return -1;
}
s=getblock(); //取一空闲盘快
if (s<0) //无空闲盘快
{
cout<<"\n磁盘空间已满,创建目录失败。\n";
return -1;
}
FAT[s0]=s; //构成FAT链
fcbp1=(FCB*) Disk[s];
for (i=0;i<4;i++,fcbp1++)
fcbp1->FileName[0]='\0'; //置空目录标志
fcbp1=(FCB*) Disk[s];
fcbp1->Addr=fcbp1->Fsize=0; //假设为空目录项
return 1;
}

/////////////////////////////////////////////////////////////////

int CreateComd(int k) //create命令处理函数:建立新文件
{
// 创建文件:create <文件名> [<文件属性>],创建一个指定名字的新文件,
// 即在目录中增加一目录项,不考虑文件的内容。对于重名文件给出错误信息。

short i,i_uof,s0,s;
char attrib='\0',*FileName;
char gFileName[PATH_LEN]; //存放文件全路径名
char ch,*p;
FCB* fcbp1;
if(k>2 || k<1)
{
cout<<"\n命令中参数个数不对。\n";
return -1;
}
s=ProcessPath(comd[1],FileName,k,0,'\020');//取FileName所在目录的首块号
if (s<1) //路径错误
return s; //失败,返回
if (!IsName(FileName)) //若名字不符合规则
{
cout<<"\n命令中的新文件名错误。\n";
return -2;
}
s0=FindFCB(FileName,s,attrib,fcbp1); //取FileName的首块号(查其存在性)
if (s0>0)
{
cout<<"\n有同名文件,不能建立。\n";
return -2;
}
strcpy(gFileName,temppath);
i=strlen(temppath);
if (temppath[i-1]!='/')
strcat(gFileName,"/");
strcat(gFileName,FileName); //构造文件的全路径名
if (k==2)
{
p=comd[2];
while (*p!='\0') //处理文件属性
{
ch=*p;
ch=tolower(ch);
switch(ch)
{
case 'r' : attrib=attrib | (char) 1;
break;
case 'h' : attrib=attrib | (char) 2;
break;
case 's' : attrib=attrib | (char) 4;
break;
default : cout<<"\n输入的文件属性错误。\n";
return -3;
}
p++;

}
}
for (i_uof=0;i_uofif (uof[i_uof].state==0)
break;
if (i_uof==S)
{
cout<<"\nUOF已满,不能创建文件。\n";
return -4;
}
i=FindBlankFCB(s,fcbp1); //寻找首块号为s的目录中的空目录项
if (i<0)
{
cout<<"\n创建文件失败。\n";
return i;
}
strcpy(fcbp1->FileName,FileName); //目录项中保存文件名
fcbp1->Fattrib=attrib; //复制文件属性
fcbp1->Addr=0; //空文件首块号设为0
fcbp1->Fsize=0; //空文件长度为0
Put_UOF(gFileName,i_uof,1,fcbp1); //建立UOF登记项
cout<<"\n文件"<return 1; //文件创建成功,返回
}

/////////////////////////////////////////////////////////////////

int Check_UOF(char *Name) //检查UOF中有无命令中指定的文件
{
int i;
for (i=0;i{
if (uof[i].state==0) //空表项
continue;
if (strcmp(Name,uof[i].fname)==0) //找到
break;
}
return i;
}

/////////////////////////////////////////////////////////////////

int OpenComd(int k) //open命令处理函数:打开文件
{
// 命令形式:open <文件名>
// 若指定文件存在且尚未打开,则打开之,并在用户打开文件表(UOF)中登
// 记该文件的有关信息。若指定文件已经打开,则显示"文件已打开"的信息;
// 若指定文件不存在,则给出错误信息。只读文件打开后只能读不能写。

short i,s0,s;
char attrib='\0',*FileName;
char gFileName[PATH_LEN]; //存放文件全路径名
FCB* fcbp;

s0=ProcessPath(comd[1],FileName,k,1,'\20');//取FileName所在目录的首块号
if (s0<1) //路径错误
return s0; //失败,返回
s=FindFCB(FileName,s0,attrib,fcbp); //取FileName的首块号(查其存在性)
if (s<0)
{
cout<<"\n要打开的文件不存在。\n";
return -2;
}
strcpy(gFileName,temppath);
i=strlen(temppath);
if (temppath[i-1]!='/')
strcat(gFileName,"/");
strcat(gFileName,FileName); //构造文件的全路径名
i=Check_UOF(gFileName); //查UOF
if (i{
cout<<"\n文件"<return -3;
}
for (i=0;iif (uof[i].state==0)
break;
if (i==S)
{
cout<<"\nUOF已满,不能打开文件。\n";
return -4;
}
Put_UOF(gFileName,i,2,fcbp);
cout<<"\n文件"<return 1;
}

/////////////////////////////////////////////////////////////////

int getblock() //获得一个空闲盘块,供fappend()函数调用
{
short b;
if (FAT[0]==0) //FAT[0]中是磁盘空闲块数
return -1; //磁盘已满(已无空闲盘块)
for(b=ffbp;bif (!FAT[b])
break;
if (b==K)
{
for (b=1;bif (!FAT[b]) break;
}
ffbp=b+1;
if (ffbp==K) ffbp=1;
FAT[0]--; //盘块数减1
FAT[b]=-1; //置盘块已分配

标志(此处不妨假设其为文件尾)
return b; //返回取得的空闲盘块号
}

////////////////////////////////////////////////////////////////

int WriteComd(int k) //write命令的处理函数
{
// 写文件:write <文件名> [<位置>[ insert]],命令中若无"位置"参数,则在写指
// 针所指位置写入文件内容;若提供"位置"参数,则在对应位置写入内容。位置可以
// 是整数n,是指在文件的第n个字节处开始写入(位置从1开始编号)。"位置" 还可以
// 是 "append"(前3个字符有效,不区分大小写),表示在文件尾部写入信息;若有
// 参数 "insert"(前3个字符有效,不区分大小写),则新写入的内容插入到对应位
// 置,对应位置开始的原内容后移。若无参数 "insert" ,写入的内容代替文件原先
// 的内容(对应位置的内容)。写入完毕调整文件长度和写指针值。
// 若文件未打开或文件不存在,分别给出错误信息。

// 可以有如下几种命令形式:
// write <文件名> ——在写指针当前所指位置写,写入内容代替原内容(代替方式或改写方式)
// write <文件名> ——在文件开头第n个字节处写,改写方式
// write <文件名> insert——在写指针所指位置写,写入处开始的原内容后移(插入方式)
// write <文件名> insert——在文件开头第n个字节处写,插入方式
// write <文件名> append——在文件尾部写(添加方式)

//【思考】如何使参数“insert”、“append”只要前3个字符对就可以,但多于3个字符也行。例如:
// 对于“insert”,输入ins、inse、inser、insert(不区分大小写)都可以,输入其它不行。

#define BSIZE 40*SIZE+1
short int ii,ii_uof,len0,len,len1,pos,ins=0;
short int bn0,bn1,jj,count=0;
char attrib='\0',Buffer[BSIZE]; //为方便计,假设一次最多写入2560字节
char *buf;
FCB *fcbp;

if (k<1)
{
cout<<"\n命令中没有文件名。\n";
return -1;
}
FindPath(comd[1],attrib,0,fcbp); //构成全路径且去掉“..”存于temppath中
ii_uof=Check_UOF(temppath); //查UOF
if (ii_uof==S)
{
cout<<"\n文件"<return -2;
}
if (uof[ii_uof].attr&'\01' && uof[ii_uof].state!=1)
{ //只读文件不是创建状态不能写
cout<<"\n"<return -3;
}
if (k==1)
pos=uof[ii_uof].writep; //从写指针所指位置开始写(write <文件名>)
else //k=2或3
{
if (_strnicmp(comd[2],"app",3)==0)
pos=uof[ii_uof].fsize+1; //文件尾部添加模式(write <文件名> append)
else if (_strnicmp(comd[2],"ins",3)==0)
{
pos=uof[ii_uof].writep; //从当前写指针位置开始写
ins=1; //插入模式(write <文件名> insert)
}
else
{
pos=atoi(comd[2]); //从命令中指定位置写(write <

文件名> )
if (pos<=0)
{
cout<<"\n命令中提供的写入位置错误。\n";
return -4;
}
if (k==3)
{
if (_strnicmp(comd[3],"ins",3)==0)
ins=1; //插入模式(write <文件名> insert)
else
{
cout<<"\n命令参数"<return -5;
}
}
}
}
if (pos<=0)
{
cout<<"\n命令中提供的写入位置错误。\n";
return -1;
}
if (pos>=uof[ii_uof].fsize+1)
{
pos=uof[ii_uof].fsize+1;
ins=0; //这种情况不会是插入方式
}

pos--; //使pos从0开始

cout<<"\n请输入写入文件的内容(最多允许输入"<cin.getline(Buffer,BSIZE);
len1=strlen(Buffer);
if (len1==0) //输入长度为0,不改变文件
return 0;
fcbp=uof[ii_uof].fp;
len0=uof[ii_uof].fsize; //取文件原来的长度值
if (len0==0) //若是空文件
{
ii=buffer_to_file(fcbp,Buffer);
if(ii==0) //写文件失败
return ii;
uof[ii_uof].fsize=uof[ii_uof].fp->Fsize;
uof[ii_uof].faddr=uof[ii_uof].fp->Addr;
uof[ii_uof].readp=1;
uof[ii_uof].writep=uof[ii_uof].fsize+1;
return 1;
}
//以下处理文件非空的情况
len=len1+pos+ins*(len0-pos); //计算写入完成后文件的长度
bn0=len0/SIZE+(short)(len0%SIZE>0); //文件原来占用的盘块数
bn1=len/SIZE+(short)(len%SIZE>0); //写入后文件将占用的盘块数
if (FAT[0]{
cout<<"\n磁盘空间不足,不能写入文件.\n";
return -1;
}
buf=new char[len+1];
if (buf==0)
{
cout<<"\n分配内存失败。\n";
return -1;
}
file_to_buffer(fcbp,buf); //文件读到buf
if (ins) //若是插入方式
{
for (ii=len0;ii>=pos;ii--)
buf[ii+len1]=buf[ii]; //后移,空出后插入Buffer
jj=pos;
ii=0;
while (Buffer[ii]!='\0') //Buffer插入到buf
buf[jj++]=Buffer[ii++];
}
else //若是改写方式
strcpy(&buf[pos],Buffer);
buffer_to_file(fcbp,buf);
delete [] buf;
uof[ii_uof].fsize=uof[ii_uof].fp->Fsize;
uof[ii_uof].writep=uof[ii_uof].fsize+1;
cout<<"\n写文件"<return 1;
}

////////////////////////////////////////////////////////////////

int CloseComd(int k) //close命令的处理函数:关闭文件
{
// close <文件名>,若指定文件已打开,则关闭之,即从UOF中删除该文件
// 对应的表项。若文件未打开或文件不存在,分别给出有关信息。

int i_uof;
char attrib='\0';
FCB *p;
if (k<1)
{
cout<<"\n命令中缺少文件名。\n";
return -1;
}
FindPath(comd[1],attrib,0,p); //构成全路径且去掉“..”存于temppath中
i_uof=Check_UOF(temppath); //查UOF
if (i_uof==S)
cout<<"\n文件"<else
{
uof[i_uof].state=0; //在UOF中清除该文件登记栏
p=uof[i_uof].fp; //取该文件的目录项位置指针
p->Addr=uof[i_uof]

.faddr; //保存文件的首块号
p->Fsize=uof[i_uof].fsize; //保存文件的大小
cout<<"\n关闭文件"<}
return 1;
}

/////////////////////////////////////////////////////////////////

void CloseallComd(int disp) //closeall命令,关闭当前用户的所有文件
{
int i_uof,j,k;
FCB *p;
for (k=i_uof=0;i_uof{
j=uof[i_uof].state; //UOF中状态>0为有效登记项
if (j>0)
{
k++; //已打开文件计数
uof[i_uof].state=0; //在UOF中清除该文件登记栏
p=uof[i_uof].fp; //取该文件的目录项位置指针
p->Addr=uof[i_uof].faddr; //保存文件的首块号
p->Fsize=uof[i_uof].fsize; //保存文件的大小
cout<<"\n文件"<}
}
if (!disp)
return;
if (k==0)
cout<<"\n你没有打开文件,故无文件可关闭。\n\n";
else
cout<<"\n共关闭 "<}

/////////////////////////////////////////////////////////////////

short int SAVE_bn(short bb)
{
// 在udtab中存储被删除文件的块号

short i=0,b0,b,bs;
if (bb==0) //被删除文件是空文件
return bb;
bs=getblock();
short *pb=(short*) Disk[bs];
while (bb>0)
{
pb[i]=bb;
bb=FAT[bb];
i++;
if (i==SIZE/2)
{
i=0;
b0=b;
b=getblock();
FAT[b0]=b;
pb=(short*) Disk[b];
}
}
pb[i]=-1;
return bs;
}

/////////////////////////////////////////////////////////////////

void Del1Ud(short a)
{
// 在udtab表中删除一项,并前移后续表项

short i,b,b0;
b=udtab[a].fb;
while (b>0)
{ //回收存储文件块号的磁盘空间
b0=b;
b=FAT[b];
FAT[b0]=0;
FAT[0]++;
}
for (i=a;iudtab[i]=udtab[i+1];
Udelp--;
}

/////////////////////////////////////////////////////////////////

int PutUdtab(FCB *fp)
{
//在udtab中加入一表项

short bb,bn,n,m,size;
size=fp->Fsize;
bn=size/SIZE+(size%SIZE>0)+1; //文件的盘块号个数(含-1)
n=SIZE/sizeof(short); //每个盘块可存储的盘块号数
m=bn/n+(short)(bn%n>0); //共需m个盘块存储文件的块号
if (Udelp==DM)
Del1Ud(0);
if (m>FAT[0])
{
cout<<"\n磁盘空间不足,不能保存删除恢复信息,该文件删除后将不能恢复.\n";
return -1;
}
strcpy(udtab[Udelp].gpath,temppath);
strcpy(udtab[Udelp].ufname,fp->FileName);
bb=udtab[Udelp].ufaddr=fp->Addr;
udtab[Udelp].fb=SAVE_bn(bb); //保存被删除文件的盘块号
Udelp++; //调整指针位置
return 1;
}

/////////////////////////////////////////////////////////////////

int DelComd(int k) //del(删除文件)命令处理函数
{
// 删除文件:del <文件名>,删除指定的文件,即清除其目录项和回收
// 其所占用磁盘空间。对于只读文件,删除前应询问用户,得到同意后
// 方能删除。当指定文件正在使用时,显示"文件正

在使用,不能删除"
// 的信息,当指定文件不存在时给出错误信息。
// 删除文件时,将该文件的有关信息记录到删除文件恢复信息表udtab中,
// 以备将来恢复时使用。

short i,s0,s;
char yn,attr;
char attrib='\0',*FileName;
char gFileName[PATH_LEN]; //存放文件全路径名
FCB* fcbp;

s0=ProcessPath(comd[1],FileName,k,1,'\20');//取FileName所在目录的首块号
if (s0<1) //路径错误
return s0; //失败,返回
s=FindFCB(FileName,s0,attrib,fcbp); //取FileName的首块号(查其存在性)
if (s<0)
{
cout<<"\n要删除的文件不存在。\n";
return -2;
}
strcpy(gFileName,temppath);
i=strlen(temppath);
if (temppath[i-1]!='/')
strcat(gFileName,"/");
strcat(gFileName,FileName); //构造文件的全路径名
i=Check_UOF(gFileName); //查UOF
if (i{
cout<<"\n文件"<return -3;
}
attr=fcbp->Fattrib & '\01';
if (attr=='\01')
{
cout<<"\n文件"<cin>>yn;
if (yn!='Y' && yn!='y')
return 0; //不删除,返回
}
i=PutUdtab(fcbp); //被删除文件的有关信息保存到udtab表中
if (i<0) //因磁盘空间不足,不能保存被删除文件的信息
{
cout<<"\n你是否仍要删除文件 "<cin>>yn;
if (yn=='N' || yn=='n')
return 0; //不删除返回
}
fcbp->FileName[0]=(char) 0xe5; //删除目录项
while (s>0) //回收磁盘空间
{
s0=s;
s=FAT[s];
FAT[s0]=0;
FAT[0]++;
}
return 1;
}

/////////////////////////////////////////////////////////////////

int Udfile(FCB *fdp,short s0,char *fn,short &cc)
{
// 在目录中找到被删除文件(文件名首字符为'\0xe5')的目录项后调用此函数
// 本函数在udtab表中逐个查找,当找到与被删除文件的路径相同、名字(首字
// 符除外)相同、首块号相同的表项时,显示“可能可以恢复字样”,询问用
// 户得到肯定答复后,即开始恢复工作。恢复中若发现发生重名冲突时,由用
// 户输入新文件名解决。恢复中若发现文件原先占用的盘块已作它用,则恢复
// 失败。无论恢复成功与否,都将删除udtab中对应的表项。

int i,j;
char yn[11],Fname[INPUT_LEN];
short *stp,b,b0,b1,s;
FCB* fcbp;

for (i=0;i{
if (strcmp(udtab[i].gpath,temppath)==0 && strcmp(&udtab[i].ufname[1],fn)==0
&& udtab[i].ufaddr==fdp->Addr)
{
cout<<"\n文件"<cin.getline(yn,10);
if (yn[0]=='y' || yn[0]=='Y')
{
if (udtab[i].ufaddr>0)
{
b=udtab[i].fb; //取存储被删文件盘块号的第一个块号
stp=(short*) Disk[b]; //stp指向该盘块
b0=stp[0]; //取被删除文件的第一个块号到b0


j=1;
while (b0>0)
{
if (FAT[b0]!=0) //若被删除文件的盘块已经不空闲
{
cout<<"\n文件"<Del1Ud(i); //删除udtab表中第i项(该表项已无用)
return -1;
}
b0=stp[j++]; //取被删除文件的下一个块号到b0
if (j==SIZE/2 && b0!=-1)
{
b=FAT[b];
j=0;
stp=(short*) Disk[b];
}
}
b=udtab[i].fb;
stp=(short*) Disk[b];
b0=b1=stp[0];
j=1;
while (b1>0)
{
b1=stp[j];
FAT[b0]=b1;
FAT[0]--;
b0=b1;
j++;
if (j==SIZE/2 && b1!=-1)
{
b=FAT[b];
j=0;
stp=(short*) Disk[b];
}
}
}
s=FindFCB(udtab[i].ufname,s0,'\0',fcbp);
fdp->FileName[0]=udtab[i].ufname[0]; //恢复文件名
if (s>=0) //有重名文件
{
cout<<"\n该目录中已经存在名为"<<<"请为被恢复文件输入一个新的名字:";
while (1)
{
cin.getline(Fname,INPUT_LEN);
if (IsName(Fname)) //若输入的名字符合规则
{
s=FindFCB(Fname,s0,'\0',fcbp); //查输入名字有否重名
if (s>=0)
cout<<"\n输入的文件名发生重名冲突。\n请重新输入文件名:";
else
break; //输入名字合法且无重名文件存在。退出循环
}
else //输入名字不符合命名规则
cout<<"\n输入的文件名不合法。\n请重新输入文件名:";
}
strcpy(fdp->FileName,Fname);
}
cc++; //被恢复文件数增1
Del1Ud(i); //删除udtab表中第i项
}
}
}
return 0;
}

/////////////////////////////////////////////////////////////////

int UndelComd(int k) //undel命令
{
// 命令形式:undel [<目录名>]
// 命令功能:恢复指定目录中被删除的文件
// 具体有如下2种命令形式:
// undel——恢复当前目录中被删除的文件
// undel <目录名>——恢复指定目录中被删除的文件

short i,s,s0,cc=0; //cc是恢复文件计数变量
char *fn;
FCB *fcbp1;
if (k>1)
{
cout<<"\n命令不能有参数。\n";
return -1;
}
if (k<1) //若命令中无参数
{
strcpy(temppath,curpath.cpath);
s0=s=curpath.fblock;
}
else
{
s0=s=FindPath(comd[1],'\020',1,fcbp1);
if (s<0)
{
cout<<"\n命令中所给的路径错误。\n";
return -2;
}
}
while (s>0) //在首块号为s的目录找被删除文件的表项,直到目录尾部
{
fcbp1=(FCB*) Disk[s];
for (i=0;i<4;i++,fcbp1++)
{
if (fcbp1->FileName[0]==(char)0xe5) //找到可能进行删除恢复的目录项
{
fn=&(fcbp1->FileName[1]);
Udfile(fcbp1,s0,fn,cc);
}
}
s=FAT[s]; //取下一个盘块号
}
cout<<"\n共恢复了 "<return 1;
}

/////////////////////

////////////////////////////////////////////

int ReadComd(int k) //read命令的处理函数:读文件
{
// 读文件:read <文件名> [<位置m> [<字节数n>],从已打开的文件读文件内容并显示。若无
// “位置”参数,则从读指针所指位置开始读。若有"位置"参数,则从指定位置处开始读。位
// 置m是指从文件开头第m个字节处读(m从1开始编号)。若无"字节数"参数,则从指定位置读
// 到文件末尾;若有"字节数n"参数,则从指定位置开始读n个字节。每读一个字节,读指针后
// 移一个字节。若文件未打开或文件不存在,分别给出错误信息。
// read命令有如下几种形式:
// read <文件名>——从读指针开始读文件,一直读到文件末尾为止。
// read <文件名> <位置m>——从文件第m个字节开始,一直读到文件末尾为止。
// read <文件名> <位置m> <字节数n>>——从文件第m个字节开始,共读n个字节。
// 说明:刚打开的文件,其读指针指向文件开头(即读指针等于1),约定空文件的读指针等于0。

short i,j,ii,i_uof,pos,offset;
short b,b0,bnum,count=0,readc;
char attrib='\0';
char Buffer[SIZE+1];
FCB* fcbp;

if (k<1 || k>3)
{
cout<<"\n命令中参数个数太多或太少。\n";
return -1;
}
FindPath(comd[1],attrib,0,fcbp); //构成全路径且去掉“..”存于temppath中
i_uof=Check_UOF(temppath); //查UOF
if (i_uof==S)
{
cout<<"\n文件"<return -2;
}
if (uof[i_uof].readp==0)
{
cout<<"\n文件"<return 1;
}
if (k==1) //参数个数k=1的情况(无参数m和n)
{
pos=uof[i_uof].readp;//从读指针所指位置开始读
if (pos>uof[i_uof].fsize)
{
cout<<"\n读指针已指向文件尾部,无可读信息。\n";
return 1;
}
readc=uof[i_uof].fsize-pos+1; //读到文件尾部共需读readc个字节
}
else //k=2或k=3的情况
{
pos=atoi(comd[2]); //从命令中指定位置写
if (pos<=0 || pos>uof[i_uof].fsize)
{
cout<<"\n命令中提供的读位置错误。\n";
return -3;
}
readc=uof[i_uof].fsize-pos+1; //读到文件尾部共需读readc个字节
if (k==3)
{
readc=atoi(comd[3]);
if (readc<1)
{
cout<<"\n命令中提供的读字节数错误。\n";
return -4;
}
if (readc>uof[i_uof].fsize-pos+1)
readc=uof[i_uof].fsize-pos+1;
}
}
bnum=(pos-1)/SIZE; //从文件的第bnum块读(bnum从0开始编号)
offset=(pos-1)%SIZE; //在第bnum块的偏移位置offset处开始读(offset从0开始)
b=uof[i_uof].faddr; //取文件首块号
for (i=0;i{
b0=b;
b=FAT[b];
}
ii=offset;
while (count{
for (i=ii,j=0;i{
Buffer[j]=Disk[b][i];
coun

相关文档
最新文档