说明:blog 中写到的这几个实验,不全面而且也不是上交实验报告的最终版本(是自己实验过程中用typora简单记录的笔记),完整内容(含代码+实验报告)可以通过(山东大学软件学院操作系统课设)下载,或者关注“陌兮blog”免费获取
一、文件系统分析
查看 /filesys/ 中文件系统的构造函数,可以发现以下信息
#define FreeMapSector 0#define DirectorySector 1#define FreeMapFileSize (NumSectors / BitsInByte)#define NumDirEntries 10#define DirectoryFileSize (sizeof(DirectoryEntry) * NumDirEntries)FileSystem::FileSystem(bool format){if (format) {// 是否应该初始化磁盘BitMap *freeMap = new BitMap(NumSectors); // 创建文件位图Directory *directory = new Directory(NumDirEntries); // 创建包含10个文件目录项的文件目录表FileHeader *mapHdr = new FileHeader; // 创建文件位图的文件头FileHeader *dirHdr = new FileHeader; // 创建文件目录表的文件头// 第一步:文件位图中标记0、1号扇区被占用freeMap->Mark(FreeMapSector);// 0号扇区为文件位图文件头freeMap->Mark(DirectorySector); // 1号扇区为文件目录表文件头// 第二步:在文件系统中分配位图文件与文件目录表的空间(传入文件位图与空间大小)ASSERT(mapHdr->Allocate(freeMap, FreeMapFileSize)); // 位图文件大小为128字节,1个扇区ASSERT(dirHdr->Allocate(freeMap, DirectoryFileSize)); // 十个文件目录项大小// 第三步:将更新后的位图文件头、文件目录表文件头写入磁盘mapHdr->WriteBack(FreeMapSector); // 传入对应文件头所在扇区号dirHdr->WriteBack(DirectorySector);// 第四步:创建位图文件、文件目录表的Openfile, Openfile中存储文件头与文件读写位置freeMapFile = new OpenFile(FreeMapSector);// 传入文件头所在扇区, 用于创建Openfile文件头directoryFile = new OpenFile(DirectorySector);// 文件读写位置初始为0// 第五步:将位图文件信息、文件目录项信息传入对应Openfile中freeMap->WriteBack(freeMapFile); // 确定Openfile的起始扇区与结束扇区,开辟文件缓冲区directory->WriteBack(directoryFile); // 初始化整个文件} else {// 非初始化操作,则根据原有位图文件头、文件目录表文件头信息初始化OpenfilefreeMapFile = new OpenFile(FreeMapSector);directoryFile = new OpenFile(DirectorySector);}}
其中主要包含了位图文件、文件目录表的文件头、Openfile的创建,并将初始化信息写入磁盘。其中位图文件用每位的0、1来表示磁盘该位置是否空闲,分配时从前开始找,一旦有空位则直接分配。另外,从上面文件系统创建的部分可以发现,当文件创建后其大小则无法改变。
我们接下来需要自行实现的两个文件命令,-ap、-hap
nachos [-d f] -ap UNIX_filename nachos_filename:表示将一个 UNIX 文件内容添加到 nachos 文件的末尾。
nachos [-d f] -hap UNIX_filename nachos_filename:表示将一个 UNIX 文件内容从 nachos 文件的中间部分开始向后添加并覆盖 nachos 文件的后半部分。
二、文件系统扩展
1、老版本
nachos -ap 与 -hap 命令的实现
首先观察一下 中是如何实现 nachos -ap 命令的
else if (!strcmp(*argv, "-ap")) {// append from UNIX to NachosASSERT(argc > 2);Append(*(argv + 1), *(argv + 2), 0);argCount = 3;}
可以发现 “-ap” 的命令调用了函数 Append(),而该函数主要调用的是 OpenFile::Write()
OpenFile::Write(char *into, int numBytes){int result = WriteAt(into, numBytes, seekPosition);seekPosition += result;return result;}
OpenFile::Write() 调用的是 OpenFile::WriteAt(),因此我们接下来考虑如何修改 OpenFile::WriteAt() 函数来实现该功能。
对原有 WriteAt 函数的分析可以看到,原有函数并不支持写入的数据超过其文件原有大小,因此我们现在需要修改该函数。
// 检查输入是否合法以及避免输入数据超过文件大小if ((numBytes <= 0) || (position >= fileLength)) // For original Nachos file system//if ((numBytes <= 0) || (position > fileLength)) // For lab4 ...return 0;// check requestif ((position + numBytes) > fileLength)numBytes = fileLength - position;
接下来实现这两个命令
大概的思路就是要修改 WriteAt 方法,如果说写入的数据超出了文件的大小,那么进行扩展,再申请新的内存空间。然后调用 OpenFile 的 WriteBack 函数写回磁盘,这个函数通过调用 filehdr 的 WriteBack 方法实现数据的写回操作,我们需要将修改后的文件头写回硬盘时,需要获取该文件头所在扇区号,因此我们在 OpenFile 类中增加一个 sector 变量用于记录该文件头所在扇区号。
首先来实现 ExtendSpace 函数,修改文件大小的方法,完成对文件的扩展,并能够根据文件大小为其分配足够大的扇区。
首先在文件 fileheader.h 中类定义中添加了方法 bool ExtendSpace(int newSize); 然后在文件 中实现 FileHeader::ExtendSpace 方法
实现思路:首先根据数据大小判断是否需要扩展数据扇区,这里有两种情况,若不需要,就简单地修改文件大小,若需要,就分配扇区,然后再修改大小。
boolFileHeader::Extend(int newSize){if(newSize<numBytes)return FALSE; //if not a extend operationif(newSize==numBytes)return TRUE; //if size not change//计算所需的空间int newNumSectors = divRoundUp(newSize, SectorSize); //the number of sectors the new size need to be allocated.//如果所需空间等于numSectors(原有的空间)if(newNumSectors == numSectors){//设置一下大小numBytes = newSize; return TRUE; }//否则计算一下还需要申请的空间int diffSector = newNumSectors - numSectors; OpenFile *bitmapfile = new OpenFile(0);BitMap *freeMap;//新建一个位图freeMap = new BitMap(NumSectors);freeMap->FetchFrom(bitmapfile);//从磁盘中取出位图printf("debug in fhdr extend where new Sector=%d \n",freeMap->NumClear());//if disk is full or file size is too big.if(newNumSectors>NumDirect||freeMap->NumClear()< diffSector)return FALSE; //申请新的空间,并且存储到文件头int i;//i从numSectors到newNumSectors,即循环diffSector次for(i = numSectors; i<newNumSectors; i++){dataSectors[i] = freeMap->Find();}numBytes = newSize;numSectors = newNumSectors;return TRUE;}
接下来实现 WriteBack() 方法:
在文件 openfile.h 类定义中添加方法声明 void WriteBack(); ,然后添加属性 int sector; ,用于记录该文件头所在扇区号
class OpenFile {public://.11.21add+++++++++++++++++++++++++++++++++++void WriteBack();//.11.21add+++++++++++++++++++++++++++++++++++
private://.11.21add++++++++++++++++++++++++++++++++int sector;//.11.21add++++++++++++++++++++++++++++++++
在文件 构造方法中添加 this->ector = sector; 。
OpenFile::OpenFile(int sector){//.11.21add++++++++++++++++++++++++++++++++++++++++this->sector = sector;//.11.21add++++++++++++++++++++++++++++++++++++++++
WriteAt 方法中修改对于 (position + numBytes) > fileLength 的处理
//.11.21add++++++++++++++++++++++++++++++++++++++++// if ((numBytes <= 0) || (position >= fileLength)) // For original Nachos file systemif ((numBytes <= 0) || (position > fileLength)) // For lab4 ...return 0;// check requestif ((position + numBytes) > fileLength)//numBytes = fileLength - position;hdr->ExtendSpace(position+numBytes);//.11.21add++++++++++++++++++++++++++++++++++++++++
实现方法 OpenFile::WriteBack ,通过调用 filehdr 的 WriteBack 方法实现数据的写回操作
voidOpenFile::WriteBack(){hdr->WriteBack(sector);}
最后一步就是按照实验指导书上所提及的,去除掉 中 Append 方法的 openfile->WriteBack() 前面的注释。
//.11.21add++++++++++++++++++++++++++++++++++++++++// Write the inode back to the disk, because we have changed itopenFile->WriteBack();printf("inodes have been written back\n");//.11.21add++++++++++++++++++++++++++++++++++++++++
2、验收版本
首先需要实现openFile类的WriteBack方法,添加成员变量hdrSector用于记录该文件头所在扇区号,并按照实验指导书上所提及的,去除掉 中 Append 方法的 openfile->WriteBack() 前面的注释。
在openfile.h文件中的openFile类里面添加WriteBack方法
//lab4 add++++++++++++++++++++++++++++void WriteBack();
添加私有成员变量hdrSector
private://lab4 add+++++++++++++++++++++++++++++int hdrSector;
然后在 中实现WriteBack方法
//lab4 add++++++++++++++++++++++++++++voidOpenFile::WriteBack(){hdr->WriteBack(hdrSector);}
在文件中的openFile类构造方法中初始化成员变量hdrSector
去除掉 中 Append 方法的 openfile->WriteBack() 前面的注释。
//lab4 add++++++++++++++++++++++++++++// Write the inode back to the disk, because we have changed itopenFile->WriteBack();printf("inodes have been written back\n");
接下来实现文件扩展方法ExtendSpace
在filehdr.h文件中的FileHeader类里面添加ExtendSpace方法
//lab4 add++++++++++++++++++++++++++++ bool ExtendSpace(OpenFile *bitmapfile,int newSize);
然后在文件实现ExtendSpace方法
//lab4 add++++++++++++++++++++++++++++boolFileHeader::ExtendSpace(OpenFile *bitmapfile,int newSize){//计算所需扇区int newNumSectors = divRoundUp(newSize, SectorSize);//不需扩展,直接更新文件头信息if(newNumSectors == numSectors){numBytes = newSize; return true; }//需要扩充的扇区数量int diffSector = newNumSectors - numSectors; BitMap *freeMap = new BitMap(NumSectors);freeMap->FetchFrom(bitmapfile);//超出一级索引||空间不足if(newNumSectors>NumDirect||freeMap->NumClear()< diffSector){return false; }//分配新扇区,并更改文件头信息for(int i = numSectors; i<newNumSectors; i++){dataSectors[i] = freeMap->Find();}numBytes = newSize;numSectors = newNumSectors;return true;}//lab4 add+++++++++++++++++++++++++++++++++++++++++
最后修改文件中的openFile类的WriteAt函数,判断文件是否需要扩展,如果需要扩展则调用ExtendSpace方法进行文件扩展