操作系統課程設計
一、實驗內容
1、 題目:模擬UNIX(linux)文件系統
[問題描述]
在任一OS下,建立一個大文件,把它假象成一張盤,在其中實現一個簡單的 模擬UNIX文件系統 。
二、概要設計
在現有機器硬盤上開辟20M的硬盤空間(利用一個循環操作,在Disk中寫入20M的零,創建一個20M的文件即是),作為設定的硬盤空間。
磁盤塊物理模型如下
文件則是指具有文件名的若干相關元素的集合。
文件屬性主要如下
文件名:實現了按名存取,文件名和目錄文件允許重名。
文件類型:可以從不同的角度來規定文件的類型。普通文件、管道文件、塊文件。
文件長度:指文件的當前長度,長度的單位可以是KB。
文件的物理位置:文件在磁盤中物理的存儲,並打印出來。
此次UNIX文件系統最簡單的目錄結構。整個文件系統中只建立一張目錄表,每個文件一個目錄項,目錄項含有文件相關信息。每建立一個新文件要先檢索所有的目錄項保證文件名唯一。然后找出一空白目錄項填入相關信息,並修改狀態位。刪除文件是找到對應目錄項,回收所占用空間,清除該目錄。
邏輯結構如下
文件名 |
索引節點編號 |
文件名1 |
INode |
文件名2 |
INode |
文件名3 |
INode |
…. |
…. |
Unix文件系統當文件很多時,文件目錄要占用大量的盤塊。在查找目錄的過程中,可能需要多次啟動磁盤讀入目錄文件的盤塊。在檢索目錄文件中只用到了文件名,顯然,文件的物理地址等文件的描述信息在檢索目錄時不需調入內存。為此,可以把文件名與文件描述信息分開。使文件描述信息單獨形成一個索引結點。
把文件描述信息單獨形成一個稱為索引結點的數據結構,簡稱為inode;文件目錄中的每個目錄項,則僅由文件名及指向該文件所對應的inode的指針所構成。這樣,為找到一個文件的平均啟動磁盤的次數減少很多
模型如下:
Root |
Fan.txt |
A |
B |
|
|
存儲空間的分配與回收
成組鏈接法
首先,建立操作系統課程的設計模型。這個系統將利用一個20M的文件作為自己的磁盤空間,設計時由於一個盤塊占用1KB,所以20M空間可以產生20480個盤塊系統本身將0# - 30#塊作為系統區,所以用戶區便剩下20450個盤塊,每50個盤塊為一組,一共可以分為409個組。
將每一組含有的盤塊總數N和該組的盤塊號,記入其前一組的第一個盤塊的S.free(1)~S.free(50)。這樣由各組的第一個盤塊形成了一條鏈。
將第一組的盤塊總數和所有的盤塊號,記入空閑盤塊號棧中,作為當前可供分配的空閑盤塊號。最末一組只有49個盤塊,其盤塊號分別記入其前一組的S.free(1)~S.free(99)中,而在S.free(0)中則存放0,作為空閑盤塊鏈的結束標志。
基本功能
1、初始化
2、建立文件
3、建立子目錄
4、打開文件
5、刪除文件
6、刪除目錄
7、顯示目錄
三、詳細設計和編碼
正規文件
i 結點文件類型 目錄文件
(共1byte) 塊設備
管道文件
。物理地址(索引表)
共有13個表項,每表項2byte
。文件長度 4byte
。聯結計數 1byte
struct INode{
FileSpec fileSpec;
short iaddr[13];
int fileLength;
int linkCount;
};
文件名 14byte
(5)目錄項信息
i 結點號 2byte
struct DirChild
{
char filename[14];
short i_BNum ;
};
struct DirNode{
DirChild childItem[64];
short DirCount;
};
定義磁盤文件名
const char FileName[]="os.txt";
默認為空的文件名
const char NullName[]="0000000000000";
默認目錄文件的長度
const int DirLen=1;
默認超級塊的快號
const short SSNum=-1; //super block num
定義枚舉類型,普通,目錄,塊文件,管道文件
enum FileSpec{NORMAL,DIR,BLOCK,PIP};//0,1,2,3
short SS[51]; //超級棧,指針為SS[0],保存當前可用盤快
short freeBlockNum=0; //當前可用盤快所在組記錄的盤快號
short freeTotalB=20450; 文件總長度
short freeDirNode[29]; //可用索引節點棧
short freeDirCount=30; //索引節點棧指針
short currDirNum; //當前目錄所在的磁盤號
short currINum;
DirNode *currDir; //當前目錄節點
INode *iNode; //當前iNode 節點
系統調用函數列表
系統調用原型 |
功能 |
入口、出口參數說明 |
Void ArrarEqual(short arr[51],short begin,short end) |
arr[51]數組賦值,在成組鏈接初始化時使用 |
|
void BWrite(short arr[51],short diskNum) |
往磁盤中寫入短數組 |
|
void BWriteArr(short arr[512],short diskNum ) |
重構BWrite,實現一個數組的寫入,數組長度不確定
|
|
void BRead(INode *iNode,short diskNum) |
從磁盤中讀出iNode節點 |
|
void BRead(short arr[51],short diskNum) |
從磁盤中讀出數組
|
|
void BReadArr(short arr[512],short diskNum) |
從磁盤中讀出數組,成組鏈接多級索引使用 |
|
BWrite(DirNode *currDir,short diskNum) |
寫入一個目錄項 |
|
Void BWrite(INode *iNode,short diskNum) |
寫入一個iNode |
|
Void AssAnEmpty() |
分配一個空閑的普通快 |
|
short AssAnDir() |
分配一個空閑的目錄快 |
|
short IsFileExist(DirNode *currDir,char fileName[14]) |
判斷一個文件是否存在 |
-1不存在,否則返回文件所在磁盤號 |
bool IsFile(INode *iNode,short diskNum) |
判斷一個文件是一個普通文件 |
|
bool IsDir(INode *iNode,short diskNum) |
判斷一個文件是一個索引文件 |
|
void CreateINode(INode *iNode,FileSpec fileSpec,short linkCount,short length) |
創建一個iNode,並分配磁盤空間 |
|
void CleanINode(INode *iNode) |
清空iNode信息,並分配磁盤空間 |
|
void InsertDir(DirNode *currDir,char fileName[14],short blockNum) |
將當前目錄項插入到內存中目錄項中 |
|
void ShowFileInfo(INode *iNode,char fileName[14]) |
打開一個文件,顯示文件信息 |
|
void ShowBlockInfo(INode *iNode) |
打開一個文件,顯示文件占用磁盤空間信息 |
|
void DelDirItem(DirNode *currDir,char fileName[14]) |
刪除索引中一項 |
|
void CallBackOne(short diskNum) |
回收一塊空余磁盤片 |
|
void CallBackINode(short diskNum) |
回收文件的iNOde節點 |
|
主要函數列表
函數原型 |
功能 |
入口、出口參數說明 |
Format |
創建20M磁盤 |
|
void Init(DirNode *currDir,FileSpec fielSpec,char filename[14],INode *iNode,short diskNum) |
初始化,創建個目錄節點並初始化超級棧
|
|
Init() |
初始化索引棧 |
|
void Linkdisk() |
成組鏈接初始化 |
|
void InitCreate(DirNode *currDir,FileSpec fielSpec,char filename[14],INode *iNode,short diskNum)
|
創建一個文件節點,並分配INOde和磁盤空間
|
|
void Create(DirNode *currDir,char fileName[14],INode *iNode,short length,FileSpec fileSpec) |
存在文件,並分配iNOde節點和磁盤空間 |
|
|
|
|
void Mf(DirNode *currDir,char fileName[14],INode *iNode,short length) |
創建一個文件 |
|
void Md(DirNode *currDir,char fileName[14],INode *iNode,short length) |
在當前目錄創建一個子目錄 |
|
void Open(DirNode *currDir,char fileName[14],INode *iNode) |
打開文件,顯示文件信息 |
|
void Del(DirNode *currDir,char fileName[14],INode *iNode) |
刪除一個文件 |
|
void Rd(DirNode *currDir,char fileName[14],INode *iNode) |
刪除一個目錄 |
|
void Dir(DirNode *currDir,INode *iNode) |
顯示目錄項的內容 |
|
void exit(DirNode *currDir,INode *iNode) |
退出,並銷毀資源 |
|
void AuthorMessage() |
打印版權信息 |
|
void help() |
提示信息 |
|
主框架
初始化命令——format
利用文件創建命令可在硬盤上創建一個名為Disk的20M的空間,並將該磁盤空間整體假想成一個獨立硬盤,我們將在這張封閉的磁盤上進行各種關於文件的操作。Format 具體操作如下:
(1) 利用一個循環操作,在Disk中寫入20M的零。
(2) 然后將0#塊,即超級塊中寫入31# - 80#的盤塊號,並將全部可用剩余盤塊數FreeBlock=20450記錄在0#塊中。
(3) 同時將80#,130#,180#(間距50)等408個(第409個組頭不存在下一組)盤組的組頭中寫入成組連接好的下一組盤塊號。
2、系統初始化——自動完成
假如Disk已被格式化完畢,那么系統便將進行下一步,那就是初始化。初
始化主要完成將根目錄項讀入內存,便於文件操作,並將0#超級塊中保存的當前可用盤塊號寫入內存中的超級棧中,具體操作如下:
(1) 初始化一個超級棧,將超級塊中保存的當前可分配盤塊號讀入棧中。
(2) 定義一個全局變量FreeBlock,用來記錄當前全部可用的盤塊總數。
3、建立文件——mf filename
如果終端發來的命令格式為mf filename,則可以判斷出這是建立文件的命
令。要想成功建立一個文件,首先需要判斷在同級目錄下是否有重名的文件,並且需要判斷是否有足夠的空間允許建立一個指定長度的文件。mf(代表make file)具體操作如下:
(1) 判斷所要建立的文件是否重名。首先將終端輸入的文件名filename在RootDir[640]進行檢索,看是否可以找到相同的名字,假如找到了相同的名字還不能立刻判斷是重名了,因為同級目錄下允許文件夾與文件重名,然后利用DirItem結構中的最后2個Byte要找到暫時重名文件的i結點,從i結點中讀出該文件的屬性,看是為正規文件還是文件夾。如果重名了,系統會提示,否則進行下一步。
(2) 如果不重名,則要根據用戶輸入的文件長度來判斷當前的剩余盤塊總數是否足夠分配,這項工作不僅僅是用終端輸入來的length與剩余盤塊總數FreeBlock比較,因為Unix本身采取混合索引方式,所以根據文件的長度會分配不同的索引盤塊數。所以判斷盤塊數是否足夠同時要計算出相應的索引盤塊數。如果文件數據本身盤塊數加上相應的索引盤塊數不會超過總剩余盤塊數,則可進行分配。
4、建立子目錄——md filename
建立子目錄,即建立一個文件夾。其可以看作是建立文件的一個特殊情況,
建立一個文件夾的過程和上述的建立文件非常相似,也要判斷重名,也要判斷是否盤塊數足夠分配,以及分配時所要考慮到的全部情況(文件夾利用0級索引)。
5、 打開文件——open filename(顯示文件所占的盤塊)
(a) 這個命令就是所謂的讀文件命令,在這個模擬Unix的系統中,我們將顯示文件所占的盤塊以及文件的相關信息。要打開文件,當然首先要判斷是否有這樣一個文件名,然后才是讀出全部的盤塊數
6、 刪除文件——del filename
刪除文件同創建文件都是非常復雜的操作,要有多種情況需要考慮。要想成功刪除一個文件,首先需要判斷在同級目錄下是否有該文件名,然后在根據該文件為幾級索引文件進行相應的回收
7、 刪除目錄——rd filename
就如同建立目錄好似建立文件的一種特殊情況,刪除目錄也和刪除文件差不多,但是有一點是絕對不同的,要特別注意。當子目錄下建立了文件或者文件夾時,即表示子目錄不為空,那么系統本身為了保持數據的完整性,是不對該目錄進行刪除操作的,而提示用戶該目錄不為空。除非用戶刪除了該目錄下的全部文件后,返回到根目錄,此時子目錄為空,才允許系統刪除該文件夾。刪除時的具體過程同刪除0級索引文件極為相似,這里就不作過多說明。文件流程如刪除文件,此處不再贅述。
8、 顯示目錄——dir(即顯示目錄下的信息,包括文件、子目錄等)
Dir是一個很容易實現的命令,在目錄下輸入此命令,即可以獲得目錄下的信息,包括文件、子目錄等。
11、正常退出指令exit
不要小看了這條指令,它可以幫你完成許多被你遺忘的操作,由於此次代碼編寫超過了3000行,而且涉及到大量的文件操作函數,所以難免會對文件的關閉,棧的釋放等結束工作考慮不周全,為了提高數據的可靠性與完整性,建議退出系統時用此命令,它可以自動完成文件的關閉。
程序源代碼
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
const char FileName[]="os.txt";
const char NullName[]="0000000000000";
const int DirLen=1;
const short SSNum=-1; //super block num
enum FileSpec{NORMAL,DIR,BLOCK,PIP};//0,1,2,3
//i節點結構信息
struct INode{
FileSpec fileSpec;
short iaddr[13];
int fileLength;
int linkCount;
};
struct DirChild
{
char filename[14];
short i_BNum ;
};
struct DirNode{
DirChild childItem[64];
short DirCount;
};
short SS[51]; //超級棧,指針為SS[0]
short freeBlockNum=0; //當前可用盤快所在組記錄的盤快號
short freeTotalB=20450;
short freeDirNode[29]; //可用索引節點棧
short freeDirCount=30; //索引節點棧指針
short currDirNum; //當前目錄所在的磁盤號
short currINum;
DirNode *currDir;
INode *iNode;
//================================================================
//函數描述:創建20M磁盤
//入口參數:無
//返回值: 無
//===============================================================
void Format()
{
cout<<"系統正在初始化......"<<endl;
// 打開文件
FILE *f = fopen(FileName,"w+");
if (f == NULL)
{
cout<<"程序創建錯誤,請重新輸入"<<endl;
return ;
}
for(int i=0;i<20971520;i++)//20971520=20Mb,暫時2mb
fprintf(f,"%c",'0');
// 關閉文件
fclose(f);
}
//================================================================
//函數描述:數組賦值
//入口參數:無
//返回值: 無
//===============================================================
void ArrarEqual(short arr[51],short begin,short end)
{
for(short i=0;i<end-begin+1;i++)
arr[50-i]=begin+i;
}
//================================================================
//函數描述:數組賦值
//入口參數:無
//返回值: 無
//===============================================================
/*
void BWrite(short arr[51],short diskNum){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"寫文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
fwrite(arr,sizeof(short),51,f);
fclose(f);
}
*/
//================================================================
//函數描述:重構BWrite,實現一個數組的寫入
//入口參數:無
//返回值: 無
//===============================================================
void BWrite(short arr[51],short diskNum ){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"寫文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
fwrite(arr,sizeof(short),51,f);
fclose(f);
}
//================================================================
//函數描述:重構BWrite,實現一個數組的寫入,數組長度不確定
//入口參數:無
//返回值: 無
//===============================================================
void BWriteArr(short arr[512],short diskNum ){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"寫文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
fwrite(arr,sizeof(short),512,f);
fclose(f);
}
//================================================================
//函數描述:重構BWrite,實現一個數組的寫入
//入口參數:無
//返回值: 無
//===============================================================
void MyBWrite(short arr[51],short diskNum ){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"寫文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
for(short i=0;i<51;i++)
fprintf(f,"%d",arr[i]);
fclose(f);
}
//================================================================
//函數描述:從磁盤中讀出數組
//入口參數:無
//返回值: 無
//===============================================================
void MyBRead(short arr[51],short diskNum){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"讀文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
for(short i=0;i<51;i++)
fscanf(f,"%d",&arr[i]);
fclose(f);
}
//================================================================
//函數描述:從磁盤中讀出iNode節點
//入口參數:無
//返回值: 無
//===============================================================
void BRead(INode *iNode,short diskNum){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"寫文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
fscanf(f,"%d",&iNode->fileLength);
int temp=int(fgetc(f));
switch(temp){
case 0:
iNode->fileSpec=NORMAL;
break;
case 1:
iNode->fileSpec=DIR;
break;
case 2:
iNode->fileSpec=BLOCK;
break;
case 3:
iNode->fileSpec=PIP;
break;
}
fread(iNode->iaddr,2,13,f);
fscanf(f,"%d",&iNode->linkCount);
fclose(f);
}
//================================================================
//函數描述:從磁盤中讀出數組
//入口參數:無
//返回值: 無
//===============================================================
void BRead(short arr[51],short diskNum){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"讀文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
fread(arr,sizeof(short),51,f);
fclose(f);
}
//================================================================
//函數描述:從磁盤中讀出數組, 放入到iNOde中
//入口參數:無
//返回值: 無
//===============================================================
void BReadArr(short arr[512],short diskNum){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"讀文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
fread(arr,sizeof(short),512,f);
fclose(f);
}
//================================================================
//函數描述:寫入一個目錄項
//入口參數:無
//返回值: 無
//===============================================================
void BWrite(DirNode *currDir,short diskNum){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"寫文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,long(1024*diskNum),0))
cout<<"文件指針錯誤"<<endl;
for(int i=0;i<64;i++)
{
fprintf(f,"%hd",currDir->childItem[i].i_BNum);
fputs(currDir->childItem[i].filename,f);
}
fclose(f);
}
//================================================================
//函數描述:寫入一個iNode
//入口參數:無
//返回值: 無
//===============================================================
void BWrite(INode *iNode,short diskNum){
FILE *f = fopen(FileName, "r+");
if (f == NULL)
{
cout<<"寫文件處錯誤,請重新輸入"<<endl;
return ;
}
//設置文件指針
if(fseek(f,1024*diskNum,0))
cout<<"文件指針錯誤"<<endl;
fprintf(f,"%d",iNode->fileLength);
fputc(iNode->fileSpec,f);
fwrite(iNode->iaddr,2,13,f);
fprintf(f,"%d",iNode->linkCount);
fclose(f);
}
//================================================================
//函數描述:分配一個空閑的普通快
//入口參數:無
//返回值: 無
//===============================================================
short AssAnEmpty(){
short temp;
if(SS[0]>1){
SS[0]--;
temp=SS[SS[0]+1];
// SS[SS[0]+1]=-1;
freeTotalB--;//總剩余數-1
return temp;
}else{
if(SS[1]==0){
cout<<"盤片用盡"<<endl;
return -1;
}
temp=freeBlockNum;
freeBlockNum=SS[1];
BRead(SS,SS[1]);
if(temp==0){
SS[0]--;
temp=SS[SS[0]+1];
// SS[SS[0]+1]=-1;
}
freeTotalB--;
return temp;
}
}
//================================================================
//函數描述:分配一個空閑的目錄快
//入口參數:無
//返回值: 無
//===============================================================
short AssAnDir(){
if(freeDirCount==0){
cout<<"無空余目錄節點"<<endl;
return -1;
}
else{
freeDirCount--;
short s=freeDirNode[freeDirCount];
freeDirNode[freeDirCount]=-1;
return s; //可用索引節點棧
}
}
//================================================================
//函數描述:創建一個文件節點,並分配INOde和磁盤空間
//入口參數:無
//返回值: 無
//===============================================================
void InitCreate(DirNode *currDir,FileSpec fielSpec,char filename[14],INode *iNode,short diskNum){
// int blockNum=AssertAnEmpty();
if(fielSpec==DIR){
//init dirNode and write
int blockNum=AssAnDir();
currDirNum=blockNum;
for(int i=0;i<64;i++){
strcpy(currDir->childItem[i].filename,"0000000000000");
currDir->childItem[i].i_BNum=-1;
}
BWrite(currDir,blockNum);
/*
//init INode and write
blockNum=AssertAnEmpty();
iNode->fileLength=DirLen;
iNode->fileSpec=DIR;
iNode->iaddr[0]=blockNum;
iNode->linkCount=1;
BWrite(iNode,distNum);
//為文件分配磁盤空間
*/
}//end if(fileSpec==DIR)
}
//================================================================
//函數描述:初始化
//入口參數:無
//返回值: 無
//===============================================================
void Init(DirNode *currDir,FileSpec fielSpec,char filename[14],INode *iNode,short diskNum){
InitCreate(currDir,fielSpec,filename,iNode,diskNum);
BRead(SS,0);
}
//================================================================
//函數描述:初始化索引棧
//入口參數:無
//返回值: 無
//===============================================================
void Init(){
for(int i=0;i<30;i++)
freeDirNode[i]=30-i; //可用索引節點棧
freeDirCount=30; //索引節點棧指針
}
//================================================================
//函數描述:成組鏈接初始化
//入口參數:無
//返回值: 無
//===============================================================
void Linkdisk(){
//臨時空閑棧
SS[0]=50;
ArrarEqual(SS,31,80);
BWrite(SS,0);
for(short i=1;i<408;i++){
SS[0]=50;
ArrarEqual(SS,i*50+31,i*50+80);
BWrite(SS,i*50+30);
BRead(SS,0);
}
ArrarEqual(SS,408*50+31,408*50+79);
SS[1]=0;//49
BWrite(SS,408*50+30);
cout<<"磁盤disk.txt完成創建,大小20MB"<<endl;
}
//================================================================
//函數描述:判斷一個文件是否存在
//入口參數:無
//返回值: -1,不存在,文件號
//===============================================================
short IsFileExist(DirNode *currDir,char fileName[14]){
for(int i=0;i<64;i++){
if(strcmp(fileName,currDir->childItem[i].filename)==0)
return currDir->childItem[i].i_BNum;
}
return -1;
}
//================================================================
//函數描述:判斷一個文件是一個普通文件
//入口參數:無
//返回值: -1,不存在,文件號
//===============================================================
bool IsFile(INode *iNode,short diskNum){
BRead(iNode,diskNum);
if(iNode->fileSpec==NORMAL)
return true;
else
return false;
}
//================================================================
//函數描述:判斷一個文件是一個普通文件
//入口參數:無
//返回值: -1,不存在,文件號
//===============================================================
bool IsDir(INode *iNode,short diskNum){
BRead(iNode,diskNum);
if(iNode->fileSpec==DIR)
return true;
else
return false;
}
//================================================================
//函數描述:創建一個iNode,並分配磁盤空間
//入口參數:無
//返回值: 無 AssAnEmpty(),BWrite(dirChild,dir[512-i])未實現
//===============================================================
void CreateINode(INode *iNode,FileSpec fileSpec,short linkCount,short length){
iNode->fileSpec=fileSpec;
iNode->linkCount=linkCount;
iNode->fileLength=length;
//為目錄磁盤,分配目錄節點
if(fileSpec==DIR){
iNode->iaddr[0]=AssAnDir();
return;
}
//根據文件長度分配文件磁盤節點
//直接尋址
short i;
i=10;
short left=length;
while(left&&i){
iNode->iaddr[10-i]=AssAnEmpty();
left--;
i--;
}
if(left>0){ //一級索引
i=512;
short dir[512];
iNode->iaddr[10]=AssAnEmpty();
while(left&&i){
dir[512-i]=AssAnEmpty();
i--;
left--;
}
if(i!=0)
dir[512-i+1]=-1;//標志文件結束
BWriteArr(dir,iNode->iaddr[10]);
if(left>0){ //二級索引
short k=512;
short j=512;
short dirChild[512];
iNode->iaddr[11]=AssAnEmpty();
while(left&&k){ //二級索引1次尋址
dir[512-k]=AssAnEmpty();
while(left&&j){ //二級索引二次尋址
dirChild[512-j]=AssAnEmpty();
left--;
j--;
}
if(j!=0)
dir[512-j+1]=-1; //標志二級索引二次尋址結束
BWriteArr(dirChild,dir[512-k]);
BWriteArr(dir,iNode->iaddr[11]);//寫二級索引一次尋址中盤快記錄的一次尋的盤快號
k--;
}
if(k!=0)
dir[512-k+1]=-1;//標志文件結束
}
}
}
//================================================================
//函數描述:清空iNode信息,並分配磁盤空間
//入口參數:無
//返回值: 無 AssAnEmpty(),BWrite(dirChild,dir[512-i])未實現
//===============================================================
void CleanINode(INode *iNode){
iNode->fileSpec=PIP;
iNode->linkCount=-1;
iNode->fileLength=-1;
//根據文件長度非配文件磁盤節點
//直接尋址
for(short i=0;i<13;i++)
iNode->iaddr[i]=-1;
}
//================================================================
//函數描述:創建一個iNode,並分配磁盤空間
//入口參數:無
//返回值: 無
//===============================================================
void InsertDir(DirNode *currDir,char fileName[14],short blockNum){
strcpy(currDir->childItem[currDir->DirCount].filename,fileName);
currDir->childItem[currDir->DirCount].i_BNum=blockNum;
currDir->DirCount++;
return;
}
//================================================================
//函數描述:存在文件,並分配iNOde節點和磁盤空間
//入口參數:無
//返回值: 無
//===============================================================
void Create(DirNode *currDir,char fileName[14],INode *iNode,short length,FileSpec fileSpec){
int blockNum;
if(length>freeTotalB){
cout<<"當前文件超出長度"<<endl;
return;
}
CreateINode(iNode,fileSpec,0,length);
blockNum=AssAnEmpty();//分配一個空余磁盤存儲iNOde
InsertDir(currDir,fileName,blockNum);
BWrite(iNode,blockNum);
CleanINode(iNode);
BWrite(currDir,currDirNum);//此處
}
//================================================================
//函數描述:創建一個文件,
//入口參數:無
//返回值: 無
//===============================================================
void Mf(DirNode *currDir,char fileName[14],INode *iNode,short length){
int blockNum=IsFileExist(currDir,fileName);
if(blockNum!=-1){//有重名名,進一步判斷
if(IsFile(iNode,blockNum))
cout<<"當前文件已經存在,請重新輸入文件名"<<endl;
} else{//存在文件,為索引文件,或者無重名現象,創建文件,並分配iNOde節點和磁盤空間
// BRead(iNode,1059);//此處出錯
Create(currDir,fileName,iNode,length,NORMAL);
}
}
//================================================================
//函數描述:在當前目錄創建一個子目錄
//入口參數:無
//返回值: 無
//===============================================================
void Md(DirNode *currDir,char fileName[14],INode *iNode,short length){
int blockNum=IsFileExist(currDir,fileName);
if(blockNum!=-1){//有重名名,進一步判斷
if(IsDir(iNode,blockNum))
cout<<"當前目錄已經存在,請重新輸入目錄名"<<endl;
} else{//存在文件但為普通文件,或者無重名現象。創建文件,並分配iNOde節點和磁盤空間
Create(currDir,fileName,iNode,length,DIR);
CleanINode(iNode);
}
}//================================================================
//函數描述:打開一個文件,
//入口參數:無
//返回值: 無
//===============================================================
void ShowBlockInfo(INode *iNode){
short dir[512];
short i;
i=10;
short left=iNode->fileLength;
while(left&&i){
cout<<(iNode->fileLength-left)<<":"<<iNode->iaddr[10-i]<<" ";
left--;
i--;
}
if(left>0){
i=512;
short dir1[512];
BReadArr(dir1,iNode->iaddr[10]);
while(left&&i){
cout<<(iNode->fileLength-left)<<":"<<dir1[512-i]<<" ";
i--;
left--;
}
}
if(left>0){ //二級索引
short k=512;
short j=512;
short dirChild[512];
BReadArr(dir,iNode->iaddr[11]);
while(left&&k){ //二級索引1次尋址
BReadArr(dirChild,dir[512-k]);
while(left&&j){ //二級索引二次尋址
cout<<(iNode->fileLength-left)<<":"<<dirChild[512-j]<<" ";
left--;
j--;
}
k--;
}
}
}
//================================================================
//函數描述:打開一個文件,
//入口參數:無
//返回值: 無
//===============================================================
void ShowFileInfo(INode *iNode,char fileName[14]){
cout<<"文件名 "<<fileName;
cout<<" 文件類型 ";
switch(iNode->fileSpec){
case NORMAL:
cout<<"< 文件 > ";
break;
case DIR:
cout<<"< 目錄 > ";break;
case BLOCK:
cout<<"< INode節點 > ";break;
case PIP:
cout<<"管道 ";break;
}
cout<<" "<<iNode->fileLength<<"KB"<<endl;
}
//================================================================
//函數描述:打開一個文件,
//入口參數:無
//返回值: 無
//===============================================================
void Open(DirNode *currDir,char fileName[14],INode *iNode){
int blockNum=IsFileExist(currDir,fileName);
if(blockNum==-1){//不存在該文件,退出
cout<<"該文件按不存在"<<endl;
return;
}
else{
if(IsFile(iNode,blockNum)){
ShowFileInfo(iNode,fileName);
ShowBlockInfo(iNode);
}
}
}
//================================================================
//函數描述:回收一塊空余磁盤片
//入口參數:無
//返回值: 無
//===============================================================
void CallBackOne(short diskNum){
freeTotalB++;
if(SS[0]<=49){
SS[0]++;
SS[SS[0]]=diskNum;
}else{//SS[0]==50
BWrite(SS,freeBlockNum); //將空白的一組回寫到上一組記錄空閑盤快號的磁盤
freeBlockNum=SS[1]; //將當前空白的一組第一個盤快作為下一個盤組的記錄盤
//修改超級棧
SS[1]=diskNum;
SS[0]=1;
}
}
//================================================================
//函數描述:回收文件占用的磁盤
//入口參數:無
//返回值: 無
//===============================================================
void CallBackDisk(INode *iNode){
short i;
i=10;
short left=iNode->fileLength;
while(left&&i){//直接索引回收
CallBackOne(iNode->iaddr[10-i]);
left--;
i--;
}
if(left>0){ //一級索引回收
i=512;
short dir1[512];
BReadArr(dir1,iNode->iaddr[10]);
while(left&&i){
CallBackOne(dir1[512-i]);
i--;
left--;
}
CallBackOne(iNode->iaddr[10]);
}
if(left>0){ //二級索引
short k=512;
short j=512;
short dir[512];
short dirChild[512];
BReadArr(dir,iNode->iaddr[11]);//二級索引1次尋址
while(left&&k){ //二級索引1次尋址
BReadArr(dirChild,dir[512-k]);
while(left&&j){ //二級索引二次回收
CallBackOne(dirChild[512-j]);
left--;
j--;
}
CallBackOne(dir[512-k]);//二級索引一次尋址
k--;
}
CallBackOne(iNode->iaddr[11]);
}
}
//================================================================
//函數描述:回收文件的iNOde節點
//入口參數:無
//返回值: 無
//===============================================================
void CallBackINode(short diskNum){
CallBackOne(diskNum);
}
//================================================================
//函數描述:刪除索引中一項
//入口參數:無
//返回值: -1,不存在,文件號
//===============================================================
void DelDirItem(DirNode *currDir,char fileName[14]){
for(int i=0;i<64;i++){
if(strcmp(fileName,currDir->childItem[i].filename)==0){
// currDir->DirCount--;
strcpy(currDir->childItem[i].filename,NullName);
currDir->childItem[i].i_BNum=-1;
return;
}
}
cout<<"刪除失敗"<<endl;
}
//================================================================
//函數描述:刪除一個文件
//入口參數:無
//返回值: 無
//===============================================================
void Del(DirNode *currDir,char fileName[14],INode *iNode){
short blockNum=IsFileExist(currDir,fileName);
if(blockNum==-1){//不存在該文件,退出
cout<<"文件不存在,刪除失敗"<<endl;
}else{
if(IsFile(iNode,blockNum)){
CallBackDisk(iNode);
DelDirItem(currDir,fileName);
CleanINode(iNode);
}else{
cout<<"文件不存在,刪除失敗"<<endl;
}
}
}
//================================================================
//函數描述:刪除一個目錄
//入口參數:無
//返回值: 無
//===============================================================
void Rd(DirNode *currDir,char fileName[14],INode *iNode){
short blockNum=IsFileExist(currDir,fileName);
if(blockNum==-1){//不存在該文件,退出
cout<<"目錄不存在,刪除失敗"<<endl;
}else{
if(IsDir(iNode,blockNum)){
CallBackDisk(iNode);
DelDirItem(currDir,fileName);
CleanINode(iNode);
}else{
cout<<"目錄不存在,刪除失敗"<<endl;
}
}
}
//================================================================
//函數描述:顯示目錄項的內容
//入口參數:無
//返回值: 無
//===============================================================
void Dir(DirNode *currDir,INode *iNode){
for(int i=0;i<currDir->DirCount;i++){
if(currDir->childItem[i].i_BNum!=-1){
BRead(iNode,currDir->childItem[i].i_BNum);
ShowFileInfo(iNode,currDir->childItem[i].filename);
}
CleanINode(iNode);
}
}
//================================================================
//函數描述:銷毀資源
//入口參數:無
//返回值: 無
//===============================================================
void exit(DirNode *currDir,INode *iNode){
delete iNode;
delete currDir;
}
//================================================================
//函數描述:打印版權信息
//入口參數:無
//返回值: 無
//===============================================================
void AuthorMessage(){
cout<<"=============================================================================="<<endl;
cout<<" 操作系統課程設計"<<endl;
cout<<"=============================================================================="<<endl;
printf("單位: 濟南大學信息學院計本0601班\n");
printf("作者: 范海青\n");
printf("學號: 20061204013\n");
printf("時間: 2009.4 \n");
printf(" 版權所有 翻版必究\n");
cout<<"=============================================================================="<<endl;
}
//================================================================
//函數描述:打印版權信息
//入口參數:無
//返回值: 無
//===============================================================
void help() //打印命令及解釋
{
cout<<"==============================================================================\n"<<endl;
printf(" 命令使用指南\n");
printf(" 1: mf 新建文件\n");
printf(" 2: md 建立子目錄\n");
printf(" 3: open 打開文件\n");
printf(" 4: del 刪除文件\n");
printf(" 5: rd 刪除目錄\n");
printf(" 6: dir 顯示目錄\n");
printf(" 7: exit 退出系統\n");
printf(" 8: cls 清屏\n");
cout<<"==============================================================================\n"<<endl;
cout<<"\n請輸入命令,回車確認"<<endl;
}
void main(){
bool run=true;
int length=1024;
char fileName[14];
char dirName[14];
int command;
DirNode *rootNode; //根節點
currDir=new DirNode;
currDir->DirCount=0;
rootNode=currDir;
iNode =new INode;
AuthorMessage();
Format(); //初始化
Linkdisk(); //成組連接
Init();
Init(currDir,DIR,"root\\a:\\",iNode,0);
while(run){
help();
while(true){
scanf("%d",&command);
fflush(stdin);
if(command>0&&command<9)
break;
cout<<"\n命令錯誤,請重新輸入"<<endl;
command=-1;
}
switch(command)
{
case 1:
cout<<"\n請輸入文件名"<<endl; //新建問件
cin>>fileName;
fflush(stdin);
cout<<"\n請輸入文件長度,單位KB"<<endl;
cin>>length;
fflush(stdin);
if(length<0||length>freeTotalB){
cout<<"文件長度不合法\n"<<endl;
break;
}
Mf(currDir,fileName,iNode,length);
break;
case 2:
cout<<"\n請輸入目錄名"<<endl;
cin>>dirName;
Md(currDir,dirName,iNode,1);
break;
case 3:
cout<<"\n請輸入打開文件名"<<endl; //打開文件
cin>>fileName;
Open(currDir,fileName,iNode);
break;
case 4:
cout<<"\n請輸入刪除文件名"<<endl; //刪除文件
cin>>fileName;
Del(currDir,fileName,iNode);
break;
case 5: //建立子目錄
cout<<"\n請輸入目錄名"<<endl;
cin>>dirName;
Rd(currDir,dirName,iNode);
break;
case 6:
Dir(currDir,iNode); //顯示當前目錄下的信息
break;
case 7:
exit(currDir,iNode); //退出系統
run=false;
break;
case 8:
system("cls"); //清屏
break;
default:
break;
}
}
}
四、測試數據及程序運行情況
程序啟動界面
打印作者信息程序初始化並打印提示信息
五、實驗過程中出現的問題及解決方法
試驗過程中主要問題
對unix文件系統理解認識不到位
l 成組鏈接法
l 多級索引機制
l 文件的邏輯結構向物理存儲結構的映射
l 空閑盤快的存儲和回收
對文件存儲不熟悉
l 由於txt文件中是以字符型存儲且此次設計到的文件比較大,存儲頻繁,任何一個不注意都會影響試驗幾過,主要如下
l 文件讀寫模式模糊
l 文件讀寫過程中內存和文件保存信息的類型的相互轉化
l 如字符,變長數組的存儲和轉化結構體
l 詳細調試過程在此不再贅述
六、實驗體會
這次的操作系統大作業的工作量比較大,我投入了很多的時間和精力才完成了系統的設計。不過這些付出都是值得的,因為我收獲了更多。首先,在開發系統的過程中,我對操作系統的功能實現,特別是文件管理這一塊的內容有了較深的理解,加深了對Unix文件系統中目錄管理和檢索快的使用、文件存儲空間和成組鏈接法的使用、混合索引機制。這個理解程度是看書所無法達到的,唯有親身實踐才能深刻理解Unix文件系統。另外,這次開發要使用到文件存取的操作來實現數據塊資料的存取,從而使我對文件存取的操作更熟悉了。同時,操作系統大作業的經歷在很大程度上磨練了我的意志,同時鍛煉了我個人的編程思維。而最重要的,此次操作系統課程設計讓我認識到了我自身的不足,激勵我加強對計算機理論的學習,讓我認識到在計算機科學這個龐大的學科我還只是初學者,有永葆進取心,路漫漫其修遠兮,吾將上下而求索。