[山东大学操作系统课程设计]实验四+实验五

0.写在前面:

为什么这次把两个实验放在一起写了,因为实验五的要求就是在实验四的基础上完成实现的。但是我得实现说明,我的实验四虽然完成了要求,但是无法在我自己的实验四的基础上完成实验五,这是一个很大的问题,所以在这里将直接将实验四和实验五统一进行讲解和处理。

由于后续时间不足,因此实验四开始,全部的东西将完全使用报告的形式来进行演示。在一些我遇到坑的地方,我会告诉大家怎么样处理,当然仅此而已了。。。。。

对不起啦:D

小三爷,你大胆的往前走,莫回头

其实说真的,我的本职工作是写小说的,或许未来的某天我会试着重新开始写我想写的东西。

1.实验要求(四五)

1.实验四

实验四的要求,按照2021级的要求,大概就是这些了

1. 扩展nachos的文件大小

2. 增加文件的修改时间

其实对于这个实验来说,这个实验就是一个分水岭了,接下来该怎么做,就算是抄也要对源码部分有一定的理解才可以了。

2.实验五

实验五的要求,总结一下大致如下:

0.在实验四的基础上实现

1.实现二级索引

2.增加-DI指令,可以输出磁盘的占用状态

3.尝试并解释如何为nachos加上权限实现(不要求代码实现)

其实可以看出来,核心就在于两个实验各自的第一条,但是这个实验难搞的点就在于,我们需要百分百保证实验四的可行性,而实验手册对于这个的讲解其实非常混乱,因此我们在这里的实验步骤,是一次性完成实验四五的!大家可以按需所需,这个过程中需要什么可以直接选择,如果是全篇,可以拿去当实验五的完整步骤

ok,那么我们开始?

2.实验步骤

首先,将图中对应文件移动进入lab5文件夹

filehdr类

在h头文件中,加入以下声明:

并且在对应的类中,加入如下属性以及方法

(注意,这里给print加上了一个参数默认,这个参数我们会后续说明怎么修改,print下面的方法属于我们的添加)

在filehdr.cc文件中,实现对于这些功能的声明:

在这里直接写出对于对应方法的修改,自行取用

方法新增:

对于构造和解析方法:

FileHeader::FileHeader(){memset(dataSectors, 0, sizeof(dataSectors));bHdrChange=false;lastModTime=0;
}
FileHeader::~FileHeader(){if(bHdrChange){WriteBack(sectorNo);}
}

对于expendSize方法:

//申请新的扇区的方法
bool 
FileHeader::ExtendSpace(int newFileSize){  int i;if(newFileSize<=numBytes)return true;int numSectorsSet=divRoundUp(newFileSize,SectorSize); //计算新的扇区位置if(numSectorsSet==numSectors){numBytes = newFileSize;bHdrChange = true;return true;}BitMap * freeMap= new BitMap(NumSectors);OpenFile * bitMapFile=new OpenFile(0);freeMap->FetchFrom(bitMapFile);if(numSectorsSet>MaxFileSectors||freeMap->NumClear()<numSectorsSet-numSectors){ //超过最大限度或者是不合适//经过答案提示需要删除点东西==========维持系统的稳定性吧=============delete bitMapFile;delete freeMap;return false;}if(numSectorsSet<=NumDirect){                       //不需要二级索引的情况 for(int i=numSectors;i<=numSectorsSet;i++){     dataSectors[i] = freeMap->Find();     }}else{                                       //需要二级索引的情况if(numSectors<NumDirect){for(int i=numSectors;i<=NumDirect;i++){dataSectors[i] = freeMap->Find();    }numSectors=NumDirect;}int dataSectors2[NumDirect2];synchDisk->ReadSector(dataSectors[NumDirect],(char *)dataSectors2);for(i=0;i< numSectorsSet-numSectors;i++){dataSectors2[i+numSectors-NumDirect]=freeMap->Find();}synchDisk->WriteSector(dataSectors[NumDirect],(char *)dataSectors2);}freeMap->WriteBack(bitMapFile);numBytes=newFileSize;numSectors=numSectorsSet;bHdrChange=true;delete bitMapFile;delete freeMap;return true;
}

关于修改时间的参数

//关于时间新增的方法如下
//这两个方法为文件头这个对象加上了些许时间属性。
time_t FileHeader::GetModTime(){return (time_t)lastModTime;
}
void FileHeader::SetModTime(time_t modTime){lastModTime=(unsigned)modTime;
}

关于代码的重写

首先是空间分配的方法

bool  
FileHeader::Allocate(BitMap *freeMap, int fileSize)        //这个方法可能只是用于最开始分配空间而已了。。。。
{ printf("\n=========分配空间================\n");int i;numBytes = fileSize;                                                          //确定文件的大小numSectors  = divRoundUp(fileSize, SectorSize);                              //根据文件大小和每个盘的尺寸确定要分几个盘if (freeMap->NumClear() < numSectors)return FALSE;		    // not enough space  空间不足else if(NumDirect2+NumDirect<numSectors)return FALSE;           // 超过了二级索引所能容纳的最大部//然后接下来分成两种情况,也就是看看是否超过了最后一层的索引,根据这种情况来完成需要的分配        //应该就是这里设置了-1这个东西if(numSectors<=NumDirect){for (int i = 0; i < numSectors; i++)dataSectors[i] = freeMap->Find();//这个时候,按照要求,因为没有用上二级的索引,因此最后一个指向二级索引的块应该为-1dataSectors[NumDirect]=-1;//打印当前信息printf("numSector:%d . numBytes:%d . lastIndex:%d\n",numSectors,numBytes,NumDirect);}else{for (int i = 0; i <=NumDirect; i++)                //更改2,这个位置写错了dataSectors[i] = freeMap->Find();int dataSectors2[NumDirect2];for (int i = 0; i < numSectors - NumDirect; i++)dataSectors2[i] = freeMap->Find();//将结果写回,就算成功了synchDisk->WriteSector(dataSectors[NumDirect],(char *)dataSectors2);}//=================================================================================return true;
}

撤销空间分配的方法

void 
FileHeader::Deallocate(BitMap *freeMap)                     //在释放空间这一步需要回收二级列表
{int lastIndex=NumDirect;if(dataSectors[lastIndex]==-1){                         //for (int i = 0; i < numSectors; i++) {ASSERT(freeMap->Test((int) dataSectors[i]));  // ought to be marked!freeMap->Clear((int) dataSectors[i]);}}else{for (int i = 0; i < lastIndex; i++) {ASSERT(freeMap->Test((int) dataSectors[i]));  // ought to be marked!freeMap->Clear((int) dataSectors[i]);}int dataSectors2[NumDirect2];synchDisk->ReadSector(dataSectors[lastIndex],(char *)dataSectors2);freeMap->Clear(dataSectors[lastIndex]);for (int i = lastIndex; i < numSectors; i++) {ASSERT(freeMap->Test((int) dataSectors2[i-lastIndex]));  // ought to be marked!freeMap->Clear((int) dataSectors2[i-lastIndex]);}}}

根据扇区号码,拉取和写回的方法

void
FileHeader::FetchFrom(int sector)
{synchDisk->ReadSector(sector, (char *)this);numSectors=divRoundUp(numBytes,SectorSize);sectorNo=sector;bHdrChange=false;
}//----------------------------------------------------------------------
// FileHeader::WriteBack
// 	Write the modified contents of the file header back to disk. 
//
//	"sector" is the disk sector to contain the file header
//----------------------------------------------------------------------void
FileHeader::WriteBack(int sector)
{//在这里修改时间即可synchDisk->WriteSector(sector, (char *)this); sectorNo=sector;bHdrChange=false;
}

print方法

void                                            //这个是打印具体文件信息的方法
FileHeader::Print(bool bPrintTime)
{int i, j, k;char *data = new char[SectorSize];//临时测试//lastTime=(unsigned)std::time(nullptr);  //段错误就这段代码引起的if(bPrintTime){printf("FileHeader contents==========\n.  File size: %d. lastModTime: %u .  File blocks:\n",numBytes,lastModTime);}else{printf("FileHeader contents==========\n.  File size: %d.  File blocks:\n", numBytes);}  //这里加上两种情况,来输出所占的块的数目=========================================================int lastIndex=NumDirect;if(dataSectors[lastIndex]==-1){  //仅仅占用了一个索引for (i = 0; i < numSectors; i++)printf("%d ", dataSectors[i]);printf("\n没有使用二级索引\n");}else{                           //占用了所有的索引        printf("一级索引内容\n");for (i = 0; i < lastIndex; i++)printf("%d ", dataSectors[i]);printf("\n二级索引内容\n");int dataSectors2[NumDirect2];synchDisk->ReadSector(dataSectors[lastIndex],(char*)dataSectors2);for (; i < numSectors; i++)printf("%d ", dataSectors2[i-lastIndex]);  //为什么这里会一直认为是-1呢printf("\n确定使用二级索引,索引地址为:%d\n",dataSectors[lastIndex]);}//==========================================================================================printf("\nFile contents:\n");for (i = k = 0; i < numSectors; i++) {synchDisk->ReadSector(dataSectors[i], data);for (j = 0; (j < SectorSize) && (k < numBytes); j++, k++) {if ('\040' <= data[j] && data[j] <= '\176')   // isprint(data[j])printf("%c", data[j]);elseprintf("\\%x", (unsigned char)data[j]);}printf("\n"); }delete [] data;
}

然后是对于openfile类的修改:

openfile:

首先是对于头文件中的声明

新增一个写回方法

属性增加这些:

接下来是对实现的一个修改

首先是对于构造方法的修改,如下

OpenFile::OpenFile(int sector)             //文件读取器的创建
{ hdr = new FileHeader;hdr->FetchFrom(sector);seekPosition = 0;// 修改时间=======================================================================================================hdr->SetModTime((unsigned)std::time(nullptr));hdrSector=sector;
}

读和写的方法,大概是这些,我在这里主要添加了关于时间修改的函数

int
OpenFile::Read(char *into, int numBytes)            //读写文件
{int result = ReadAt(into, numBytes, seekPosition);seekPosition += result;// 修改时间=======================================================================================================hdr->SetModTime((unsigned)std::time(nullptr));return result;
}int
OpenFile::Write(char *into, int numBytes)
{int result = WriteAt(into, numBytes, seekPosition);seekPosition += result;// 修改时间=======================================================================================================hdr->SetModTime((unsigned)std::time(nullptr));return result;}

在writeAt方法上作出改进

int
OpenFile::WriteAt(char *from, int numBytes, int position)   //最后是在这个方法上进行一些小小的改进
{int fileLength = hdr->FileLength();int i, firstSector, lastSector, numSectors;bool firstAligned, lastAligned;char *buf;//if ((numBytes <= 0) || (position >= fileLength))  // For original Nachos file system// For lab4 ...if ((numBytes <= 0)|| position > fileLength)    return 0;	if ((position+numBytes) >= fileLength)if(!(hdr->ExtendSpace(position+numBytes)))numBytes=fileLength-position;if(fileLength==0)       return 0;DEBUG('f', "Writing %d bytes at %d, from file of length %d.\n", 	numBytes, position, fileLength);firstSector = divRoundDown(position, SectorSize);lastSector = divRoundDown(position + numBytes - 1, SectorSize);numSectors = 1 + lastSector - firstSector;buf = new char[numSectors * SectorSize];firstAligned = (bool)(position == (firstSector * SectorSize));lastAligned = (bool)((position + numBytes) == ((lastSector + 1) * SectorSize));// read in first and last sector, if they are to be partially modifiedif (!firstAligned)ReadAt(buf, SectorSize, firstSector * SectorSize);	if (!lastAligned && ((firstSector != lastSector) || firstAligned))ReadAt(&buf[(lastSector - firstSector) * SectorSize], SectorSize, lastSector * SectorSize);	// copy in the bytes we want to change bcopy(from, &buf[position - (firstSector * SectorSize)], numBytes);// write modified sectors backfor (i = firstSector; i <= lastSector; i++)	synchDisk->WriteSector(hdr->ByteToSector(i * SectorSize), &buf[(i - firstSector) * SectorSize]);delete [] buf;hdr->SetModTime((unsigned)std::time(nullptr));   // 修改时间==============return numBytes;
}

最后实现写回方法

void 
OpenFile::WriteBack(void){     //给文件头部设置扇区号hdr->WriteBack(hdrSector);
}

directory:

我好像是直接加入了这个方法

int Directory::GetHdrSecByIndex(int index){if(table[index].inUse){return table[index].sector;}else{return -1;}
}

filesys:

在这个类中,我们只需要实现一个打印的方法,来帮助我们实现需要的-DI指令获取文件信息的操作

首先在头文件的声明中,加入

然后直接实现这个方法即可

void FileSystem::PrintInfo(){BitMap *freeMap=new BitMap(NumSectors);Directory *directory=new Directory(NumDirEntries);FileHeader *fileHdr= new FileHeader();int i, nBytes;int fileHdrSector;int nUsedSector, nFiles =0, nBytesInFiles=0,nSectorsOfFiles=0,nFragSectors=0;printf("\n磁盘尺寸:%d个扇区,字节数目:%d\n",NumSectors,NumSectors*SectorSize);freeMap->FetchFrom(freeMapFile);nUsedSector = NumSectors - freeMap->NumClear();printf("\n(已经使用):%d个扇区,字节数目:%d\n",nUsedSector,nUsedSector*SectorSize);printf("\n(未使用):%d个扇区,字节数目:%d\n",freeMap->NumClear(),freeMap->NumClear()*SectorSize);directory->FetchFrom(directoryFile);for(i = 0; i < NumDirEntries; i++) {fileHdrSector = directory->GetHdrSecByIndex(i);if(fileHdrSector != -1) {nFiles++;fileHdr->FetchFrom(fileHdrSector);nBytes = fileHdr->FileLength();nBytesInFiles += nBytes;nSectorsOfFiles += divRoundUp(nBytes, SectorSize);if(nBytes % SectorSize)nFragSectors++;}}printf("%d bytes in %d files, occupy %d bytes(%d sectors).\n", \nBytesInFiles, nFiles, nSectorsOfFiles * SectorSize, nSectorsOfFiles);printf("%d bytes of internal fragmentation in %d sectors.\n", \nSectorsOfFiles * SectorSize - nBytesInFiles, nFragSectors);delete freeMap;delete directory;delete fileHdr;
}

main:

最后在这个入口文件中,新增这样一个分支

到此为止,所有的代码全部修改完毕:

3.实验汇总

关于代码的执行:

首先使用如下指令,初始化并且复制一个big文件

make
rm -f DISK//初始化磁盘
./nachos -f

然后使用cp指令创建big文件

./nachos -cp test/big big

使用./nachos -D查询当前文件的状态

可以看到已经创建了big文件

此时使用指令

./nachos -ap test/big big

执行多次以后,可以检查到最后的修改时间被更新,并且已经实现了二级索引

最后使用指令

./nachos -D

查看占用情况:

最后是关于为nachos添加wxz等权限:

  • 在Nachos的文件系统中,每个文件都有一个相应的文件描述符(File Descriptor),用于标识和操作该文件。

  • 使用文件描述符打开文件,并获取文件的当前权限。在Nachos中,可以使用 OpenFile::Open 函数打开文件,并使用 OpenFile::GetFileHeader 函数获取文件的文件头(File Header)信息。

  • 在文件头中,找到与权限相关的位(比如读、写、执行位),并根据需要修改这些位。可以使用位操作来设置或清除相应的权限位。

  • 将修改后的文件头写回到文件系统中,以保存更改后的权限。可以使用 OpenFile::WriteAt 函数将文件头写回磁盘中的相应位置。

  • 关闭文件并释放相关资源。使用 OpenFile::Close 函数关闭文件

4.可能会踩坑的问题

我这里只说一个,我在实验四里面遇到的一个大问题,就是这个3到底含义是什么

答案就是,nachos的文件头需要存储在一个sector的内部,但是一个磁盘内的容量仅仅为128字节,而我们需要存入的是这些东西

这些东西是按照顺序存储的,如果这些东西超过了128字节,那就没救了

因此我们需要适当修改数组的大小,因此在定义NumDirect的时候,是根据我们需要存储的其他变量的大小,修改数组的长度

5.补充,我自己的实验四实现(等待补充)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/212439.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软考考前背过-软件设计师

今年5月份开始准备考&#xff0c;没想到会突然改革&#xff0c;还好刷题刷的多&#xff0c;也过了。 跟着B站up主的视频学的&#xff0c;都学了一遍之后才开始刷题&#xff0c;平时要上班&#xff0c;也就下班和周末能学&#xff0c;时间可能拉的比较长&#xff0c;学完前面的内…

使用linux CentOS本地部署SQL Server数据库

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 安装sql server二. 局域网测试连接三. 安装cpolar内网穿透四. 将sqlserver映射…

【Vulnhub 靶场】【Funbox: GaoKao】【简单】【20210606】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/funbox-gaokao,707/ 靶场下载&#xff1a;https://download.vulnhub.com/funbox/FunboxGaoKao.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年06月06日 文件大小&#xff1a;1.3 GB 靶场作者&#…

[BJDCTF2020]EzPHP 许多的特性

这道题可以学到很多东西 静下心来慢慢通过本地知道是干嘛用的就可以学会了 BJDctf2020 Ezphp_[bjdctf2020]ezphp-CSDN博客 这里开始 一部分一部分看 $_SERVER[QUERY_SRING]的漏洞 if($_SERVER) { if (preg_match(/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|…

Windows 上安装nvm node版本管理工具 windows安装nvm 管理工具

Windows 上安装nvm node版本管理工具 windows安装nvm 管理工具 1、nvm2、安装2.1、下载 NVM 安装程序进行安装2.2、打开nvm的安装路径&#xff0c;运行终端测试是否安装成功2.3、配置环境变量&#xff0c;让nvm能在电脑全局使用2.3.1、nvm配置淘宝镜像2.3.2、nvm环境变量设置 1…

低代码还是好用的,我持有这个观念

低代码开发是近年来迅速崛起的软件开发方法&#xff0c;让编写应用程序变得更快、更简单。 有人说它是美味的膳食&#xff0c;让开发过程高效而满足&#xff0c;但也有人质疑它是垃圾食品&#xff0c;缺乏定制性与深度。 你认为低代码到底是美味的膳食还是垃圾食品呢&#xff0…

C++ 模拟实现vector

目录 一、定义 二、模拟实现 1、无参初始化 2、size&capacity 3、reserve 4、push_back 5、迭代器 6、empty 7、pop_back 8、operator[ ] 9、resize 10、insert 迭代器失效问题 11、erase 12、带参初始化 13、迭代器初始化 14、析构函数 完整版代码 一、…

一款基于ESP32的迷你四足机器人

一、软件介绍 增加自定义动作模式&#xff0c;可以在小程序中自定义一个最多10个步骤的动作。 附件中&#xff1a;带自定模式固件bin.zip esp32c3固件文件 烧录下图设置 无串口版本esp32c3开发板烧录前先按住BOOT键再插线进入烧录模式&#xff0c;LoadMode选择USB。 二、AP…

2023团体程序设计天梯赛——模拟赛和总决赛题

M-L1-1 嫑废话上代码 Linux 之父 Linus Torvalds 的名言是&#xff1a;“Talk is cheap. Show me the code.”&#xff08;嫑废话&#xff0c;上代码&#xff09;。本题就请你直接在屏幕上输出这句话。 输入格式&#xff1a; 本题没有输入。 输出格式&#xff1a; 在一行中输出…

java resource ‘process/qingjia.png‘ not found

resource中的资源在target中没有&#xff0c;导致报错&#xff0c;如下图所示&#xff1a; 解决办法&#xff1a;在pom文件中添加如下代码&#xff1a; 重新执行代码&#xff0c;就能在target中看到png文件了。 类似的错误参考链接&#xff1a;mybatis-plus框架报错&#x…

Java 手写设计HashMap源码,让面试官膜拜

Java 手写HashMap源码&#xff0c;让面试官膜拜 一&#xff0c;手写源码 这是一个模仿HashMap的put&#xff0c;get功能的自定义的MyHashMap package cn.wxs.demo;import java.io.Serializable; import java.util.*; import java.util.function.BiConsumer;class MyHashMap&…

面向对象三大特征——封装

目录 1. 封装概述&#xff08;封装与隐藏&#xff09; 2. private关键字 3. Getter & Setter方法 4. 变量访问原则和this关键字 5. 构造方法 5.1 构造方法概述 5.2 构造方法和set方法的比较 6. 静态 6.1 静态概述 6.2 静态效果 6.3 静态变量和非静态变量的区别 …

win11 CUDA(12.3) + cuDNN(12.x) 卸载

win11 CUDA&#xff08;12.3&#xff09; cuDNN&#xff08;12.x&#xff09;卸载 信息介绍卸载 信息介绍 本文是对应 win11RTX4070Ti 安装 CUDA cuDNN&#xff08;图文教程&#xff09; 的卸载 卸载 控制面板 --> 程序 --> 卸载程序 卸载掉图中红框内的&#xff0c…

reinforce 跑 CartPole-v1

gym版本是0.26.1 CartPole-v1的详细信息&#xff0c;点链接里看就行了。 修改了下动手深度强化学习对应的代码。 然后这里 J ( θ ) J(\theta) J(θ)梯度上升更新的公式是用的不严谨的&#xff0c;这个和王树森书里讲的严谨公式有点区别。 代码 import gym import torch from …

Android 11 适配——整理总结篇

背景 > 经过检测&#xff0c;我们识别到您的应用&#xff0c;目前未适配安卓11&#xff08;API30&#xff09;&#xff0c;请您关注适配截止时间&#xff0c;尽快开展适配工作&#xff0c;避免影响应用正常发布和经营。 > targetSdkVersion30 升级适配工作参考文档&am…

从零开发短视频电商 Jmeter压测示例模板详解(无认证场景)

文章目录 添加线程组添加定时器添加HTTP请求默认值添加HTTP头管理添加HTTP请求添加结果断言响应断言 Response AssertionJSON断言 JSON Assertion持续时间断言 Duration Assertion 添加察看结果树添加聚合报告添加表格察看结果参考 以压测百度搜索为例 https://www.baidu.com/s…

class066 一维动态规划【算法】

class066 一维动态规划 算法讲解066【必备】从递归入手一维动态规划 code1 509斐波那契数列 // 斐波那契数 // 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 // 该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。…

kotlin - ViewBinding

前言 为什么用ViewBinding&#xff0c;而不用findViewById()&#xff0c;这个有很多优秀的博主都做了讲解&#xff0c;就不再列出了。 可参考下列博主的文章&#xff1a; kotlin ViewBinding的使用 文章里也给出了如何在gradle中做出相应的配置。 &#xff08;我建议先看这位博…

【LeetCode热题100】【滑动窗口】无重复字符的最长子串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为无…

Redis,什么是缓存穿透?怎么解决?

Redis&#xff0c;什么是缓存穿透&#xff1f;怎么解决&#xff1f; 1、缓存穿透 一般的缓存系统&#xff0c;都是按照key去缓存查询&#xff0c;如果不存在对用的value&#xff0c;就应该去后端系统查找&#xff08;比如DB数据库&#xff09;。一些恶意的请求会故意查询不存在…