內存中開闢一塊虛擬磁盤空間
做爲文件存儲分區,在其上實現一個簡單的基於多級目錄的單用戶單任務系統
中的文件系統。ios
在退出該文件系統的使用時,虛擬文件系統以一個文件的方式保存到磁盤中,以便下次能夠把它恢復到內存的虛擬存儲空間git
cd /home/zy/Desktop/
這樣的絕對路徑cd ../hah/1/2
這樣的相對路徑mkdir
,rmdir
,cd
,creat
,rm
均支持open_path
是open
的升級版,也是支持上述函數實現的主要函數。open
,read
,close
實現了一個cat
直接打印文件內容。
read
出全部內容創建目錄樹,/home
是用戶的根目錄github
/home
下有/zy
函數
/zy
下有 /Documents
,/Desktop
,/Viedeos
,Music
等測試
/home/zy/Documents
目錄下創建一個文件Hello.txt
Hello World!Fisrt
,能正確顯示長度和文件內容。creat
,open
,close
,read
,write
等基本用法creat /home/zy/hellozy.txt
在/home/zy
下創建了一個hellozy.txt
creat
在路徑下的用法測試了mkdir
,cd
,rmdir
在路徑下也能正常工做。其他幾個相似的同理,OVERspa
#include <cstdio> #include <memory.h> #include <string> #include <iostream> #include <malloc.h> #include <time.h> using namespace std; /*常量定義*/ #define Path "/home" //根目錄 #define BLOCKSIZE 1024 //磁盤塊大小 #define BLOCKCOUNT 1000 //盤塊大小 #define MAXOPENFILE 10 //能打開最多的文件數 #define DISKSIZE (BLOCKSIZE*BLOCKCOUNT)//磁盤大小 #define END -1 const int FCBCOUNT = BLOCKSIZE/sizeof(FCB);//一個塊的最多FCB數量
FAT1
:4個FAT2
:4個根目錄
1個其他數據
991個代碼:命令行
/*------------------磁盤------------------------*/ struct DISK { int FAT1[BLOCKCOUNT];//磁盤塊0-3表明FAT int FAT2[BLOCKCOUNT];//磁盤塊4-7表明FAT2 DirFile RootDir; //根目錄 磁盤塊8 char Data[BLOCKCOUNT-9][BLOCKSIZE];//目錄和其餘文件 磁盤塊9~1000 };
代碼:指針
/*-----------------目錄文件---------------------*/ struct DirFile{ FCB fcb[FCBCOUNT]; //文件控制塊 void init(int father,int self) { //給根目錄建立.. 和 . 序號0放".", 序號1放".." memset(fcb,0,sizeof(fcb)); fcb[1].free=fcb[0].free=1; fcb[1].attribute=fcb[0].attribute=1; fcb[1].first=father; fcb[0].first=self; memcpy(fcb[0].filename,".",sizeof(".")); memcpy(fcb[1].filename,"..",sizeof("..")); } };
struct FCB { char filename[12]; //文件名 char attribute;//0表示目錄,1表示數據文件 int time;//建立時間 int data;//建立日期 int first;//起始盤號 int length;//長度 char free;//表示目錄項是否爲空 };
struct USEROPEN { FCB fcb; char dir[80];//相應打開文件所在的目錄名 int count;//讀寫指針在文件的位置 char fcbstate;//是否修改了文件的FCB內容,修改了置爲1,不然置爲0 char topenfile;//表示該用戶表項是否被佔用,1就是被佔用,0就是沒有被佔用 char fatherfilename[12];//上一層目錄的名字 int pos; };
ls
函數#include "OS.h" using namespace std; /*-------------函數聲明------------------------*/ void help(); int cd(char *dirname); int startsys(); int format(); int mkdir(char *dirname); int rmdir(char *dirname); int close(int fd); int open(char *filename); int creat(char *filename); int rm(char *filename); int filewrite(int fd); int dowrite(int fd,char *text,int len, char wstyle); int fileread(int fd,int len); int doread(int fd,int len,char *text); void exitsys(); /*--------------全局變量-------------------------*/ char* myvhard;//虛擬磁盤起始地址 string currentdir="/home";//當前目錄 string cmd; //讀取指令 USEROPEN openfilelist[MAXOPENFILE];//文件打開表 USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 DISK* disk;//將內容結構化 char command[50];//文件名標示符 /*--------------------- 顯示目錄函數 ---------------*/ void ls() { int BlockDirNum = (ptrcuridr->fcb).first; DirFile *dir = (DirFile *) disk->Data[BlockDirNum - 8]; for (int i = 0; i < FCBCOUNT; i++) { if (dir->fcb[i].free == 1) { if (dir->fcb[i].attribute == 0) printf("%10s---length:%5d----File\n",dir->fcb[i].filename,dir->fcb[i].length); else printf("%10s---length:%5d----Directory\n",dir->fcb[i].filename,dir->fcb[i].length); } } } int main() { printf("Welcome the OS FileSystem\n"); printf("input 'help' get more information\n\n\n"); // freopen("E:\\OSFileSystem\\a.in","r",stdin); startsys(); //Init the System int len; while(1) { cout<<currentdir+">"; cin>>cmd; if(cmd=="help"){ //幫助 help(); } else if(cmd=="mkdir"){ cin>>command; mkdir(command); } else if(cmd=="cd"){ cin>>command; cd(command); } else if(cmd=="exit") { break; } else if(cmd=="rmdir"){ cin>>command; rmdir(command); } else if(cmd=="ls"){ ls(); } else if(cmd=="open"){ cin>>command; open(command); } else if(cmd=="close"){ cin>>command; close(atoi(command)); } else if(cmd=="creat"){ cin>>command; creat(command); } else if(cmd=="rm"){ cin>>command; rm(command); } // else if(cmd=="write"){ cin>>command; filewrite(atoi(command)); } else if(cmd=="read") { cin >> command >> len; fileread(atoi(command),len); } else if(cmd=="exitsys"){ exitsys(); }else { printf("The cmd is not exits\n"); } } }
int format()
.
和..
兩個子目錄int startsys()
把根目錄加載進文件打開表。code
#include "OS.h"
/--------------全局變量-------------------------/
extern char* myvhard;//虛擬磁盤起始地址
extern string currentdir;//當前目錄
extern string cmd; //讀取指令
extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表
extern USEROPEN ptrcuridr;//當前目錄在文件打開表的位置
extern DISK disk;//將內容結構化
extern char command[50];//文件名標示符
/--------------------------------磁盤格式化函數-------------------/
int format() {
memset(myvhard,0,DISKSIZE);
//建立根目錄,在磁盤塊8orm
//前九個被FAT1+FAT2+root佔用 for(int i=0;i<9;i++){ disk->FAT1[i]=disk->FAT2[i]=-2;//-2表明被佔用 } DirFile *dir=(DirFile *)disk->Data[8-8];//注意Data和FAT的區別 //初始化根目錄. dir->init(8,8); return 1;
}
/--------------------------------進入文件系統函數--------------------/
int startsys() {
myvhard=(char )malloc(DISKSIZE); //申請10241000磁盤空間
disk=(DISK )myvhard;
FILE fp=fopen("myfsys","r");
if(fp!=NULL)
{
printf("|-------------------------------------------|\n");
printf("|-----------myfsys is loading---------------|\n");
printf("|-------------------------------------------|\n\n");
fread(myvhard,sizeof(char),DISKSIZE,fp);
fclose(fp);
}
else{
printf("|-------------------------------------------|\n");
printf("|-----------myfsys is not exit--------------|\n");
printf("|--File system is being created now --------|\n");
printf("|-------------------------------------------|\n\n");
format();
}
//初始化用戶打開表
memset(openfilelist,0,sizeof(openfilelist));
//將根目錄打開,首先修改fcb裏的內容
openfilelist->fcb.first=8;
//文件打開表項的內容
openfilelist[0].topenfile=1;
strcpy(openfilelist->dir,"");
strcpy(openfilelist->fcb.filename,"home");
strcpy(openfilelist->fatherfilename,"");
ptrcuridr=&openfilelist[0];
openfilelist[0].pos=0;
//當前目錄設置爲根目錄
currentdir=Path;
return 1;
}
處理好.
和..
兩個子目錄
維護好openfilelist
裏的每一個值
#include "OS.h"
/--------------全局變量-------------------------/
extern char* myvhard;//虛擬磁盤起始地址
extern string currentdir;//當前目錄
extern string cmd; //讀取指令
extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表
extern USEROPEN ptrcuridr;//當前目錄在文件打開表的位置
extern DISK disk;//將內容結構化
extern char command[50];//文件名標示符
/-----------------------------打開文件函數--------------------/
int open(char *filename){
//檢查要被打開文件是否存在 int BlockDirNum = (ptrcuridr->fcb).first; DirFile *dir = (DirFile *) disk->Data[BlockDirNum - 8]; int Fileaddr = -1; for (int i = 0; i < FCBCOUNT; i++) { if (dir->fcb[i].free == 1 && strcmp(dir->fcb[i].filename, filename) == 0)//表項被使用,且是目錄,且文件名相等 { Fileaddr = i;//文件存在 break; } } //文件不存在 輸出-1 if(Fileaddr==-1){ printf("file does not exist\n"); return -1; } //檢查打開文件表是否還有空表項,沒有報錯,有則記錄 int OpenFileaddr=-1; for(int i=0;i<MAXOPENFILE;i++) { if (openfilelist[i].topenfile == 0) { OpenFileaddr=i; } } //沒有空表了 if(OpenFileaddr==-1) { printf("File open table is full \n"); return -1; } //若是又要打開一個根目錄,那麼直接返回0 if(dir->fcb[Fileaddr].first==8) { OpenFileaddr=0; if(ptrcuridr->fcb.first==8) return 0; } //爲該文件填寫文件打開表項 //檢查是否已經打開 //須要一個temp來表示實際的dir值 char temp[300]; if(strcmp(filename,"..")==0) { strcpy(temp,ptrcuridr->dir); int len1=strlen(ptrcuridr->dir); int len2=strlen(ptrcuridr->fatherfilename); temp[len1-len2-1]=0; } else { char buffer[80]; memset(buffer,0,sizeof(buffer)); strcat(strcat(strcat(buffer,ptrcuridr->dir),"/"),ptrcuridr->fcb.filename); strcpy(temp,buffer); } for(int i=1;i<MAXOPENFILE;i++) { //"."必定是被打開了 if ((openfilelist[i].topenfile == 1 && strcmp(openfilelist[i].fcb.filename, filename) == 0 && strcmp(openfilelist[i].dir,temp) ==0 )||(strcmp(filename,".")==0)) { printf(" The file has been opened !\n"); return -1;//無效返回-1 } } if(strcmp(filename,"..")==0) { openfilelist[OpenFileaddr].fcb=dir->fcb[Fileaddr]; //名字是錯的,會是"..";正確的名字在工做塊的父親名字 strcpy(openfilelist[OpenFileaddr].fcb.filename,ptrcuridr->fatherfilename); //曾經的路徑減去名字減去'/' 就是新的 strcpy(openfilelist[OpenFileaddr].dir,ptrcuridr->dir); int len1=strlen(openfilelist[OpenFileaddr].dir); int len2=strlen(ptrcuridr->fatherfilename); openfilelist[OpenFileaddr].dir[len1-len2-1]=0; //找新的fathername,經過分析dir來獲得 char test[20]; strcpy(test,openfilelist[OpenFileaddr].dir); char *q; int len=strlen(test); for(int i=0;i<len;i++) { if(test[i]=='/'&&i!=len-1) q=test+i+1; } strcpy(openfilelist[OpenFileaddr].fatherfilename,q); } else { openfilelist[OpenFileaddr].fcb=dir->fcb[Fileaddr]; char buffer[80]; memset(buffer,0,sizeof(buffer)); strcat(strcat(strcat(buffer,ptrcuridr->dir),"/"),ptrcuridr->fcb.filename); strcpy(openfilelist[OpenFileaddr].dir,buffer); strcpy(openfilelist[OpenFileaddr].fatherfilename,ptrcuridr->fcb.filename); } openfilelist[OpenFileaddr].pos=OpenFileaddr; openfilelist[OpenFileaddr].count=0; openfilelist[OpenFileaddr].fcbstate=0; openfilelist[OpenFileaddr].topenfile=1; //返回文件描述符fd,此時的fd跟下標相同,通常不一樣. if(openfilelist[OpenFileaddr].fcb.attribute==0)//若是是文件,輸出文件打開符號 printf("File Open Success,The fd is %d\n",OpenFileaddr); return OpenFileaddr;
}
cd
,mkdir
,creaet
,rm
,rmdir
使用的方式是拆分路徑的元素,而後分析元素
不斷的調用open
和close
來實現。
#include "OS.h" int open(char *filename); int close(int fd); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[50];//文件名標示符 /*----------------------更改當前目錄函數--------------------- 讀入一條文件路徑,返回一個打開的fd 支持絕對路徑和相對路徑. 輸出,若是路徑正確,返回文件打開後的fd. ------------------------------------------------------*/ int open_path(char *dirname) { //若是dirname是絕對路徑 int fd=0, ok = 1, fdtemp = -1;//ok表明是否找到dirname所指的文件,fdtemp存臨時的,用來關閉 USEROPEN *temp = ptrcuridr;//暫時保管一下ptrcuridr原始值,可能要回溯 if (dirname[0] == '/') { ptrcuridr = openfilelist;//咱們的openfilelist[0]永遠是根目錄 //使工做目錄暫時指向根目錄 char *p = strtok(dirname + 1, "/");//用「/」分割 dirname[1]開始的字符串 if (p != NULL) p = strtok(NULL, "/");//跳過/home while (p) { fd = open(p); if (fd == -1) { ok = 0; if (fdtemp != -1) //離開前記得關文件 close(fdtemp);//把上個打開的文件關掉 break; } ptrcuridr = openfilelist + fd; if (fdtemp != -1) close(fdtemp);//把上個打開的文件關掉 fdtemp = fd; p = strtok(NULL, "/"); } } //若是是相對路徑 else { int len=strlen(dirname); dirname[len]='/'; dirname[len+1]=0; char *p = strtok(dirname, "/");//用「/」分割 dirname[1]開始的字符串 while (p) { fd = open(p); if (fd == -1) { ok = 0; if (fdtemp != -1) //離開前記得關文件 close(fdtemp);//把上個打開的文件關掉 break; } ptrcuridr = openfilelist + fd; if (fdtemp != -1) close(fdtemp);//把上個打開的文件關掉 fdtemp = fd; p = strtok(NULL, "/"); } } ptrcuridr = temp; //輸出數據 if (ok == 1) return fd; else return -1; }
#include "OS.h" int open_path(char* dirname); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[16];//文件名標示符 /*---------------關閉文件函數-----------------*/ int close(int fd){ //檢查fd的合法性 if(fd>=MAXOPENFILE||fd<=0){ printf(" Is not a legitimate fd \n"); return -1; }else if(openfilelist[fd].topenfile==0){ printf("filewrite ERROR:The File Don't Open\n"); return -1; } //檢查用戶打開文件表表項的`fcbstate`字段,若是是1,則須要將該文件的FCB的內容保存的虛擬磁盤上該文件的目錄項 //方法是:打開該文件的父目錄文件,已覆蓋寫方式調用do_wirte()將欲關閉的FCB寫入父目錄文件的相應盤塊. if(openfilelist[fd].fcbstate==1){ char buffer[30]=".."; int fatherfd=open_path(buffer); if(fatherfd!=-1) { //找到相應的盤號 int pan1 = openfilelist[fatherfd].fcb.first; int area1 = -1; //盤號上相應的位置 DirFile *dirson = (DirFile *) (disk->Data[pan1 - 8]); for (int i = 0; i < FCBCOUNT; i++) { if (dirson->fcb[i].free == 1 && strcmp(dirson->fcb[i].filename, openfilelist[fd].fcb.filename) == 0) { //找到了該文件,覆蓋fcb dirson->fcb[i] = openfilelist[fd].fcb; break; } } //關文件 if(fatherfd!=0) close(fatherfd); } } //回收該文件佔據的用戶打開表表項(clear),topenfile字段置0 memset(openfilelist+fd,0,sizeof(openfilelist[0])); openfilelist[fd].topenfile=0; //返回 return 0; }
open_path
來返打開一個父級目錄,並返回fd
ptrcuridr
的原始值保存下來,而後將其賦值給那個父級目錄。ptrcuridr
#include "OS.h" int close(int fd); int open_path(char *dirname); int FileSubstr(char *str); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[50];//文件名標示符 int mkdir(char *dirname) { char newdir[20]; char dirpath[60]; USEROPEN *tempp = ptrcuridr;//暫時保管一下ptrcuridr原始值,可能要回溯 int k=FileSubstr(dirname),fd=-1; if(k!=-1) { dirname[k] = 0; memset(newdir, 0, sizeof(newdir)); memset(dirpath, 0, sizeof(dirpath)); strcpy(newdir, dirname + k + 1); strcpy(dirpath, dirname); fd = open_path(dirpath); if(fd!=-1) { ptrcuridr = openfilelist + fd; dirname = newdir; } else { printf("error\n"); return -1; } } //-------------如下爲一天前的代碼-----------------------// //讀取當前目錄的地址 int BlockDirNum=(ptrcuridr->fcb).first; DirFile *dir=(DirFile *)disk->Data[BlockDirNum-8]; //遍歷文件目錄,檢查是否有文件名相同的文件或目錄,並找一個沒有被使用的目錄空閒表項 int temp=-1, DirFreeItems =-1; for(int i=0;i<FCBCOUNT;i++) { if (dir->fcb[i].free == 1 && strcmp(dir->fcb[i].filename, dirname) == 0)//表項被使用,且是目錄,且文件名相等 { temp = i;//重名的表項 break; } else if (dir->fcb[i].free == 0) { DirFreeItems = i;//目錄空閒表項 } } //若是文件名已存在,報錯並退出 if(temp!=-1) { printf("mkdir: cannot create directory '%s': Directory exists\n",dirname); if(fd!=-1) close(fd); ptrcuridr=tempp; return 0; } //若是沒有空閒位置,報錯退出 if(DirFreeItems==-1) { printf("mkdir: cannot create directory '%s': Directory is full \n",dirname); if(fd!=-1) close(fd); ptrcuridr=tempp; return 0; } //檢查FAT中是否有空閒的盤塊 int FATFreeItems=-1; for(int i = 0;i < BLOCKCOUNT;i++) { if(disk->FAT1[i] == 0) {//沒被使用的塊標記爲0 FATFreeItems=i;//找到了一個空閒塊 break; } } //若是FAT沒有空閒塊,報錯退出 if(FATFreeItems==-1) { printf("mkdir: cannot create directory '%s': Disk is full \n",dirname); if(fd!=-1) close(fd); ptrcuridr=tempp; return 0; } /*----------------開始新建目錄-------------------*/ //修改長度,fcbstate置爲1 ptrcuridr->fcbstate=1; ptrcuridr->fcb.length++;//不包括.和..的 //分配FAT的空閒塊,2表示被目錄使用 disk->FAT1[FATFreeItems]=disk->FAT2[FATFreeItems]=2; //將改塊分配到 當前目錄的空閒項目下 strcpy(dir->fcb[DirFreeItems].filename,dirname); dir->fcb[DirFreeItems].free=1;//被使用 dir->fcb[DirFreeItems].attribute=1;//是目錄 dir->fcb[DirFreeItems].first=FATFreeItems;//分配FAT空閒塊 dir->fcb[DirFreeItems].length=0; dir->fcb[DirFreeItems].data=0;//時間以後弄 dir->fcb[DirFreeItems].time=0;//時間以後弄 //進入下一次目錄,初始化新得到的塊(重置給予"."和"..") dir=(DirFile*)(disk->Data[FATFreeItems-8]); dir->init(BlockDirNum,FATFreeItems); /*----------------恢復現場------------------------*/ if(fd!=-1) close(fd); ptrcuridr=tempp; return 1; }
mkdir
相似#include "OS.h" int close(int fd); int open_path(char *dirname); int FileSubstr(char *str); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[50];//文件名標示符 /*-------------------------------刪除子目錄函數---------------------*/ int rmdir(char *dirname) { char newdir[20]; char dirpath[60]; USEROPEN *tempp = ptrcuridr;//暫時保管一下ptrcuridr原始值,可能要回溯 int k=FileSubstr(dirname),fd=-1; if(k!=-1) { dirname[k] = 0; memset(newdir, 0, sizeof(newdir)); memset(dirpath, 0, sizeof(dirpath)); strcpy(newdir, dirname + k + 1); strcpy(dirpath, dirname); fd = open_path(dirpath); if(fd!=-1) { ptrcuridr = openfilelist + fd; dirname = newdir; } else { printf("error\n"); return -1; } } /*---------使用open_path更新----------------------*/ //檢查文件是否存在 int BlockDirNum = (ptrcuridr->fcb).first; DirFile *dir = (DirFile *) disk->Data[BlockDirNum - 8]; int temp = -1; for (int i = 0; i < FCBCOUNT; i++) { if (dir->fcb[i].free == 1 && dir->fcb[i].attribute == 1 && strcmp(dir->fcb[i].filename, dirname) == 0)//表項被使用,且是目錄,且文件名相等 { temp = i;//文件存在 break; } } //要刪除的目錄不存在 if(temp == -1) { printf("rmdir: failed to remove '%s': No such file or directory\n",dirname); if(fd!=-1) close(fd); ptrcuridr=tempp; return 0; } //判斷子目錄是否爲空,不包括0和1,也能夠用length,懶得用 DirFile *dirson=(DirFile*)(disk->Data[dir->fcb[temp].first-8]); int flag=-1; for(int i=2; i < FCBCOUNT; i++ ) { if (dir->fcb[i].free == 1){ flag=1; break; } } //要刪除的目錄不爲空 if(flag==-1) { printf("rmdir: failed to remove '%s': Directory not empty\n",dirname); if(fd!=-1) close(fd); ptrcuridr=tempp; return 0; } //檢查目錄是否已打開,打開就關閉 //回收該目錄文件所佔據的磁盤塊,修改FAT disk->FAT1[dir->fcb[temp].first]=disk->FAT1[dir->fcb[temp].first]=0; //當前目錄文件中清空該目錄文件的目錄項,memset清理乾淨 memset(&(dir->fcb[temp]),0,sizeof(dir->fcb[temp])); //修改長度,表項的fcbstate置爲1 ptrcuridr->fcbstate=1; ptrcuridr->fcb.length--;//不包括.和..的 /*-----------------恢復現場-------------*/ if(fd!=-1) close(fd); ptrcuridr=tempp; return 1; }
open_path
十分簡單的實現一個跳轉到任意路徑的函數#include "OS.h" int open(char *filename); int close(int fd); int open_path(char *dirname); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[50];//文件名標示符 /*----------------------更改當前目錄函數---------------------*/ int cd(char *dirname) { USEROPEN *temp = ptrcuridr;//暫時保管一下ptrcuridr原始值,可能要回溯 int fd=open_path(dirname); if (fd != -1) { //關掉舊的描述符 int old=temp->pos; //獲取舊的描述符 if (old != 0) //根目錄描述符不關 close(old); //工做目錄指向它 ptrcuridr = openfilelist + fd; //當前目錄賦值 currentdir= ptrcuridr->dir ; currentdir+= '/'; currentdir+= ptrcuridr->fcb.filename; return 0; } else { ptrcuridr = temp; printf("No such file or directory\n"); return 0; } }
有了open_path
so easy
#include "OS.h"
int close(int fd);
int open_path(char dirname);
int FileSubstr(char str);
/--------------全局變量-------------------------/
extern char* myvhard;//虛擬磁盤起始地址
extern string currentdir;//當前目錄
extern string cmd; //讀取指令
extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表
extern USEROPEN ptrcuridr;//當前目錄在文件打開表的位置
extern DISK disk;//將內容結構化
extern char command[50];//文件名標示符
int creat(char filename){
//爲新文件分配一個空閒打開文件表項,若是沒有空閒表項就返回 -1
//檢查打開文件表是否還有空表項,沒有報錯,有則記錄
int OpenFileaddr=-1;
for(int i=0;i<MAXOPENFILE;i++) {
if (openfilelist[i].topenfile == 0) {
OpenFileaddr=i;
}
}
//沒有空表了
if(OpenFileaddr==-1) {
printf("File open table is full \n");
return -1;
}
/-----------打開路徑所指的父目錄---------/
char newdir[20];
char dirpath[60];
USEROPEN tempp = ptrcuridr;//暫時保管一下ptrcuridr原始值,可能要回溯
int k=FileSubstr(filename),fd=-1;
if(k!=-1) {
filename[k] = 0;
memset(newdir, 0, sizeof(newdir));
memset(dirpath, 0, sizeof(dirpath));
strcpy(newdir, filename + k + 1);
strcpy(dirpath, filename);
fd = open_path(dirpath);
if(fd!=-1) {
ptrcuridr = openfilelist + fd;
filename = newdir;
}
else {
printf("error\n");
return -1;
}
}
//檢查重名
int BlockDirNum = (ptrcuridr->fcb).first;
DirFile dir = (DirFile ) disk->Data[BlockDirNum - 8];
int temp = -1,DirFreeItems =-1;
for (int i = 0; i < FCBCOUNT; i++) {
if (dir->fcb[i].free == 1 &&
strcmp(dir->fcb[i].filename, filename) == 0)//表項被使用,且是目錄,且文件名相等
{
temp = i;//有重名,可能文件,可能文件夾
break;
}
else if (dir->fcb[i].free == 0) {
DirFreeItems = i;//目錄空閒表項
}
}
//若是文件名已存在,報錯並退出
if(temp!=-1)
{
if(fd!=-1)
close(fd);
ptrcuridr=tempp;
printf("creat: cannot create file '%s': File exists\n",filename);
return 0;
}
//若是沒有空閒位置,報錯退出
if(DirFreeItems==-1)
{
printf("creat: cannot create file '%s': Directory is full \n",filename);
if(fd!=-1)
close(fd);
ptrcuridr=tempp;
return 0;
}
//檢查FAT中是否有空閒的盤塊
int FATFreeItems=-1;
for(int i = 0;i < BLOCKCOUNT;i++)
{
if(disk->FAT1[i] == 0) {//沒被使用的塊標記爲0
FATFreeItems=i;//找到了一個空閒塊
break;
}
}
//若是FAT沒有空閒塊,報錯退出
if(FATFreeItems==-1)
{
printf("mkdir: cannot create directory '%s': Disk is full \n",filename);
if(fd!=-1)
close(fd);
ptrcuridr=tempp;
return 0;
}
/----------------開始新建文件-------------------/
//修改長度,fcbstate置爲1
ptrcuridr->fcbstate=1;
ptrcuridr->fcb.length++;//不包括.和..的
//準備好新文件的FCB的內容,文件屬性爲數據文件,長度0.
//分配FAT的空閒塊,-3表示被文件使用,-1表示文件結尾
disk->FAT1[FATFreeItems]=disk->FAT2[FATFreeItems]=-1;
//將改塊分配到 當前目錄的空閒項目下
strcpy(dir->fcb[DirFreeItems].filename,filename);
dir->fcb[DirFreeItems].free=1;//被使用
dir->fcb[DirFreeItems].attribute=0;//是文件
dir->fcb[DirFreeItems].first=FATFreeItems;//分配FAT空閒塊
dir->fcb[DirFreeItems].length=0;
dir->fcb[DirFreeItems].data=0;//時間以後弄
dir->fcb[DirFreeItems].time=0;//時間以後弄
//文件新建完畢
//填寫文件打開表項
openfilelist[OpenFileaddr].fcb=dir->fcb[DirFreeItems];
char buffer[80];
memset(buffer,0,sizeof(buffer));
strcat(strcat(strcat(buffer,ptrcuridr->dir),"/"),ptrcuridr->fcb.filename);
strcpy(openfilelist[OpenFileaddr].dir,buffer);
strcpy(openfilelist[OpenFileaddr].fatherfilename,ptrcuridr->fcb.filename);
openfilelist[OpenFileaddr].pos=OpenFileaddr;
openfilelist[OpenFileaddr].count=0;
openfilelist[OpenFileaddr].fcbstate=0;
openfilelist[OpenFileaddr].topenfile=1;
//關閉文件走人
if(fd!=-1)
close(fd);
ptrcuridr=tempp;
//返回文件描述符fd,此時的fd跟下標相同,通常不一樣.
printf("File Creat Success,The fd is %d\n",OpenFileaddr);
return OpenFileaddr;
}
-1
#include "OS.h" int close(int fd); int open_path(char *dirname); int FileSubstr(char *str); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[50];//文件名標示符 /*--------------------------刪除文件函數---------------------*/ int rm(char *filename){ /*--------------------------打開上級目錄---------------------*/ char newdir[20]; char dirpath[60]; USEROPEN *tempp = ptrcuridr;//暫時保管一下ptrcuridr原始值,可能要回溯 int k=FileSubstr(filename),fd=-1; if(k!=-1) { filename[k] = 0; memset(newdir, 0, sizeof(newdir)); memset(dirpath, 0, sizeof(dirpath)); strcpy(newdir, filename + k + 1); strcpy(dirpath, filename); fd = open_path(dirpath); if(fd!=-1) { ptrcuridr = openfilelist + fd; filename = newdir; } else { printf("error\n"); return -1; } } //調用read,判斷目錄下文件是否存在 int BlockDirNum = (ptrcuridr->fcb).first; DirFile *dir = (DirFile *) disk->Data[BlockDirNum - 8]; int temp = -1; for (int i = 0; i < FCBCOUNT; i++) { if (dir->fcb[i].free == 1 && dir->fcb[i].attribute == 0 && strcmp(dir->fcb[i].filename, filename) == 0)//表項被使用,且是文件,且文件名相等 { temp = i;//文件存在 break; } } //要刪除的目錄不存在 if(temp == -1) { printf("rm: failed to remove '%s': No such file or directory\n",filename); if(fd!=-1) close(fd); ptrcuridr=tempp; return 0; } //檢查該文件是否打開,若打開則關閉 char buffer[80]; memset(buffer,0,sizeof(buffer)); strcat(strcat(strcat(buffer,ptrcuridr->dir),"/"),ptrcuridr->fcb.filename); for(int i=1;i<MAXOPENFILE;i++) { //"."必定是被打開了 if ((openfilelist[i].topenfile == 1 && strcmp(openfilelist[i].fcb.filename, filename) == 0 && strcmp(openfilelist[i].dir,buffer) ==0 )) { printf(" The file been opened,Now Close it !\n"); close(i); break; } } //回收磁盤,一個鏈表 int TEMP=0; for(int p=dir->fcb[temp].first;p!=-1;p=TEMP) { TEMP=disk->FAT1[p]; disk->FAT1[p]=disk->FAT2[p]=0; } //清空該目錄項,free字段爲0, memset(&(dir->fcb[temp]),0,sizeof(dir->fcb[temp])); //修改長度,表項的fcbstate置爲1 ptrcuridr->fcbstate=1; ptrcuridr->fcb.length--;//不包括.和..的 /*-----------------恢復現場-------------*/ if(fd!=-1) close(fd); ptrcuridr=tempp; return 1; }
blockno
和 塊內偏移blockoff;
#include "OS.h" int open_path(char* dirname); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[16];//文件名標示符 /*---------------實際寫文件函數----------------*/ int dowrite(int fd,char *text,int len, char wstyle) { //申請1024字節的緩衝區buf char *buf = (char *) malloc(1024); if (buf == NULL) { printf("MALLOC ERROR b\n"); return -1; } int tmplen = 0; int textpos = 0; int textlen = strlen(text); //將文件指針轉換爲邏輯塊塊號blockno 和 塊內偏移blockoff; /*--------------------分配-----------------*/ while(tmplen<len) { int blockno = (openfilelist[fd].count) / 1024; int blockoff = (openfilelist[fd].count) % 1024; //尋找磁盤塊blockno int currentblock = 0; int cnt = 0; for (int p = openfilelist[fd].fcb.first; p != -1; p = disk->FAT1[p]) { cnt++; currentblock = p; if (cnt == blockno + 1) break; } int pre = currentblock; if (cnt != blockno + 1)//若是找不到這樣的一塊,那麼還須要給它分配blockno+1-cnt塊 { //從currentblock開始分配 for (int i = 1; i <= blockno + 1 - cnt; i++) { //檢查FAT中是否有空閒的盤塊 int FATFreeItems = -1; for (int i = 0; i < BLOCKCOUNT; i++) { if (disk->FAT1[i] == 0) {//沒被使用的塊標記爲0 FATFreeItems = i;//找到了一個空閒塊 break; } } //若是FAT沒有空閒塊,報錯退出 if (FATFreeItems == -1) { printf("FAT IS FULL\n"); return -1; } disk->FAT1[pre] = FATFreeItems; pre = FATFreeItems; } } //若是是覆蓋寫,或者塊內偏移off不等於0,則將blkno的虛擬磁盤塊所有寫入buff中,不然memset if (wstyle == 2 || blockoff != 0) { memcpy(buf, disk->Data[currentblock - 8], 1024); } //將text中的內容暫存到緩衝區buff的第off字節開始的位置,直到緩衝區滿 for (int i = blockoff; i < 1024 && textpos < textlen && tmplen<len; i++) { buf[i] = text[textpos]; textpos++; tmplen++; //讀入長度 } memcpy(disk->Data[currentblock - 8], buf, 1024); openfilelist[fd].count += tmplen; } free(buf); return tmplen; }
#include "OS.h" int open_path(char* dirname); int dowrite(int fd,char *text,int len, char wstyle); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[16];//文件名標示符 /*---------------寫文件函數----------------*/ int filewrite(int fd) { int way = 0; //檢查fd的有效性 if (fd >= MAXOPENFILE || fd <= 0) { printf("filewirt ERROR:Is not a legitimate fd \n"); return -1; }else if(openfilelist[fd].topenfile==0){ printf("filewrite ERROR:該文件沒有被打開\n"); return -1; } while (1) { //提示等待用戶輸入寫方式 printf(" ------Please enter the way to write---------\n "); //1 : 截斷寫 2: 覆蓋寫 3: 追加寫 printf(" ------1:TRUNC 2:OVER 3:APPEND---------\n "); scanf("%d", &way); if (1 <= way && way <= 3) break; else printf("Input Error,Please Try Again\n"); } // 若是是截斷寫,釋放文件除第一塊外的磁盤空間內容 //內存用戶打開表中文件長度爲0,,讀寫指針置爲0 if (way == 1) { //釋放文件除第一塊外的磁盤空間內容 int TEMP = 0; int ok = 1; for (int p = openfilelist[fd].fcb.first; p != -1; p = TEMP) { TEMP = disk->FAT1[p]; if (ok != 1) { disk->FAT1[p] = disk->FAT2[p] = 0; } else { ok = 0; } } //長度置爲0 openfilelist[fd].fcb.length = 0; //讀寫指針置爲0 openfilelist[fd].count = 0; } //若是是追加寫,修改文件的當前讀寫指針到文件的末尾 else if (way == 3) { openfilelist[fd].count = openfilelist[fd].fcb.length; } //提示用戶,輸入內容經過CTRL+Z結束,用戶可分屢次輸入寫入內容,每次用回車結束 printf(" Input CTRL+D end the input\n "); int temp=0; char buffer[3000]; while(gets(buffer)!=0){ int len=strlen(buffer); buffer[len]='\n'; buffer[len+1]='\0'; int ret=dowrite(fd,buffer,strlen(buffer),way); if(ret==-1) { return -1; } else temp+=ret; } //若是當前讀寫指針位置大於長度,則更新長度,並置fcbstate置1 if(openfilelist[fd].count>openfilelist[fd].fcb.length) { openfilelist[fd].fcb.length = openfilelist[fd].count; openfilelist[fd].fcbstate=1; } //返回實際寫入的字節 return temp; }
每次讀一片磁盤
#include "OS.h"
int open_path(char* dirname);
int dowrite(int fd,char text,int len, char wstyle);
/--------------全局變量-------------------------/
extern char myvhard;//虛擬磁盤起始地址
extern string currentdir;//當前目錄
extern string cmd; //讀取指令
extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表
extern USEROPEN ptrcuridr;//當前目錄在文件打開表的位置
extern DISK disk;//將內容結構化
extern char command[16];//文件名標示符
/------------------實際讀文件函數--------------------------/
//text的指向那個讀出數據的用戶地址
int doread(int fd,int len,char text){
//申請1024字節的緩衝區buf
char buf = (char *) malloc(1024);
if (buf == NULL) {
printf("MALLOC ERROR b\n");
return -1;
}
int tmplen = 0;
int textpos = 0;
//將最終指針轉換爲邏輯塊塊號blockno 和 塊內偏移blockoff;
while(tmplen<len) {
int blockno = (openfilelist[fd].count) / 1024;
int blockoff = (openfilelist[fd].count) % 1024;
//尋找磁盤塊blockno
int currentblock = 0;
int cnt = 0;
for (int p = openfilelist[fd].fcb.first; p != -1; p = disk->FAT1[p]) {
cnt++;
currentblock = p;
if (cnt == blockno + 1)
break;
}
memcpy(buf, disk->Data[currentblock - 8], 1024); // for (int i = blockoff; i < 1024 && tmplen<len && openfilelist[i].count<openfilelist[i].fcb.length; i++) { text[textpos] = buf[i]; textpos++; tmplen++; //讀入長度 openfilelist[fd].count; } memcpy(disk->Data[currentblock - 8], buf, 1024); } free(buf); return tmplen;
}
#include "OS.h" int open_path(char* dirname); int dowrite(int fd,char *text,int len, char wstyle); int doread(int fd,int len,char *text); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[16];//文件名標示符 /*---------------讀文件函數----------------*/ const int MAXSIZE=1024*50; int fileread(int fd,int len){ char text[MAXSIZE]; memset(text,0,sizeof(text)); //檢查fd的有效性 if (fd >= MAXOPENFILE || fd <= 0) { printf("filewirt:Is not a legitimate fd \n"); return -1; }else if(openfilelist[fd].topenfile==0){ printf("filewrite ERROR:The File Don't Open\n"); return -1; } //調用do_read()讀取指定文件的len字節內容到text[]中. int rt=doread(fd,len,text); //若是do_read()返回值爲負,則顯示出錯信息,不然將text[]中的內容顯示到屏幕上; if(rt==-1){ printf("READ FAIL"); return -1; }else{ //輸出text的內容 for(int i=0;i<len;i++){ printf("%c",text[i]); } printf("\n"); } }
#include "OS.h" int open_path(char* dirname); int close(int fd); /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[16];//文件名標示符 /*--------------退出文件系統函數------------------*/ void exitsys(){ FILE * fd=fopen("myfsys","w"); //關閉全部打開的文件 for(int i=0;i<MAXOPENFILE;i++){ if(openfilelist[i].topenfile==1) close(i); } fwrite(myvhard,sizeof(char),DISKSIZE,fd); fclose(fd); free(myvhard); exit(0); }
幾個可有可無的函數
#include "stdio.h" void help() { printf("\n"); printf("-----------------------help------------\n"); printf("format :-------Format The Disk.\n"); printf("exit :-------Exit OS File System AND **NOT SAVE**\n"); printf("exitsys :-------Exit OS File System AND SAVE") printf("cd dirname :-------Change Directory\n"); printf("mkdir dirname :-------Make Directory.\n"); printf("rmdir dirname :-------Delete Directory.\n"); printf("ls dirname :-------List Directory .\n"); printf("creat filename:-------Creat File\n"); printf("write fd :-------Wirte File\n"); printf("read fd :-------Read File\n"); printf("rm filename:-------Remove File\n"); printf("open filename:-------Open File\n"); printf("close fd :-------Close File\n"); printf("open_path\n"); printf("--------------------------------------\n\n"); }
和本身實現的分割字符串
// // 切割字符串,例如/A/B/C/D 切割成 /A/B/C 和 D // #include "OS.h" /*--------------全局變量-------------------------*/ extern char* myvhard;//虛擬磁盤起始地址 extern string currentdir;//當前目錄 extern string cmd; //讀取指令 extern USEROPEN openfilelist[MAXOPENFILE];//文件打開表 extern USEROPEN *ptrcuridr;//當前目錄在文件打開表的位置 extern DISK* disk;//將內容結構化 extern char command[50];//文件名標示符 /*-----------------------------------------------*/ int FileSubstr(char *str){ int len=strlen(str); int cnt=0,flag=0; for(int i=1;i<len-1;i++) { if(str[i]=='/') { cnt++; flag=i; } } if(cnt==0) return -1; else return flag; }