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

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.rhkb.cn/news/214337.html

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

相关文章

免费的SEO外链发布工具,提升排名的利器

互联网已经成为信息传播和商业发展的重要平台。而对于拥有网站的个人、企业来说&#xff0c;如何让自己的网站在搜索引擎中脱颖而出&#xff1f;SEO&#xff08;Search Engine Optimization&#xff09;作为提高网站在搜索引擎中排名的关键手段. 什么是SEO外链&#xff1f; S…

class064 Dijkstra算法、分层图最短路【算法】

class064 Dijkstra算法、分层图最短路【算法】 算法讲解064【必备】Dijkstra算法、分层图最短路 code1 743. 网络延迟时间 // Dijkstra算法模版&#xff08;Leetcode&#xff09; // 网络延迟时间 // 有 n 个网络节点&#xff0c;标记为 1 到 n // 给你一个列表 times&…

Linux(centos)学习笔记(初学)

[rootlocalhost~]#:[用户名主机名 当前所在目录]#超级管理员标识 $普通用户的标识 Ctrlshift放大终端字体 Ctrl缩小终端字体 Tab可以补全命令 Ctrlshiftc/V复制粘贴 / &#xff1a;根目录&#xff0c;Linux系统起点 ls&#xff1a; #list列出目录的内容&#xff0c;通常用户查看…

Word插件-好用的插件-一键设置字体--大珩助手

常用字体 整理了论文、公文常用字体 整理了常用的论文字体&#xff0c;可一键设置当前节或选择的文字的字体 字体设置 包含字体选择、字体颜色 特殊格式 包含首字下沉、段落分栏、统一宽度、双行合一、上标切换、下标切换、转为全角、转为半角、挖词填空、当前日期、大写金…

思科最新版Cisco Packet Tracer 8.2.1安装

思科最新版Cisco Packet Tracer 8.2.1安装 一. 注册并登录CISCO账号二. 下载 Cisco Packet Tracer 8.2.1三. 安装四. 汉化五. cisco packet tracer教学文档六. 正常使用图 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新…

uniApp项目的创建,运行到小程序

一、项目创建 1. 打开 HBuilder X 2. 右击侧边栏点击新建&#xff0c;选择项目 3. 填写项目名&#xff0c;点击创建即可 注&#xff1a;uniapp中如果使用生命周期钩子函数&#xff0c;建议使用哪种 ?(建议使用Vue的) 二、运行 1. 运行前先登录 2. 登录后点击 manifest.js…

YOLOv8 目标过线计数

使用 Ultralytics YOLOv8 进行目标计数 🚀 实际应用场景 物流水产养殖使用 Ultralytics YOLOv8 进行传送带包裹计数使用 Ultralytics YOLOv8 在海中进行鱼类计数请使用最新代码(2023年12月8日后),旧版本不支持! 示例 “目标计数示例” 目标计数 from ultralytics

公有云迁移研究——AWS Route53

大纲 1 什么是Route 532 Route 53能做些什么# 3 通过DNS托管来实现分流3.1 创建DNS托管3.2 对托管创建记录对流量进行分配 4 通过流量策略来对流量进行分流4.1 创建流量策略 5 对比两者的区别6 推荐 在给客户从本地机房往AWS迁移的过程中&#xff0c;我们接到如下需求&#xff…

SpringBoot 项目 Jar 包加密,防止反编译

1场景 最近项目要求部署到其他公司的服务器上&#xff0c;但是又不想将源码泄露出去。要求对正式环境的启动包进行安全性处理&#xff0c;防止客户直接通过反编译工具将代码反编译出来。 2方案 第一种方案使用代码混淆 采用proguard-maven-plugin插件 在单模块中此方案还算简…

[香橙派]orange pi zero 3 烧录Ubuntu系统镜像——无需HDMI数据线安装

一、前言 本文我们将介绍如何使用orange pi zero 3 安装Ubuntu系统&#xff0c;本文相关步骤均参考自开发手册。 二、实施准备 根据开发手册中所提到的&#xff0c;我们应该拥有如下配件: 1.orange pi zero 3 开发板 2.TF 卡——最小 8GB 容量的 class10 级或以上的高速闪迪卡。…

错题总结(四)

1.【一维数组】输入10个整数&#xff0c;求平均值 编写一个程序&#xff0c;从用户输入中读取10个整数并存储在一个数组中。然后&#xff0c;计算并输出这些整数的平均值。 int main() {int arr[10];int sum 0;for (int n 0; n < 10; n){scanf("%d", &arr…

58.Nacos源码分析2

三、服务心跳。 3.服务心跳 Nacos的实例分为临时实例和永久实例两种&#xff0c;可以通过在yaml 文件配置&#xff1a; spring:application:name: order-servicecloud:nacos:discovery:ephemeral: false # 设置实例为永久实例。true&#xff1a;临时; false&#xff1a;永久ser…

Nginx负载均衡实战

&#x1f3b5;负载均衡组件 ngx_http_upstream_module https://nginx.org/en/docs/http/ngx_http_upstream_module.html upstream模块允许Nginx定义一组或多组节点服务器组&#xff0c;使用时可以通过多种方式去定义服务器组 样例&#xff1a; upstream backend {server back…

Python开源项目周排行 2023年 第39周

Python 趋势周报&#xff0c;按周浏览往期 GitHub,Gitee 等最热门的Python开源项目&#xff0c;入选的项目主要参考GitHub Trending,部分参考了Gitee和其他。排名不分先后&#xff0c;都是当周相对热门的项目。 入选公式&#xff1d;70%GitHub Trending20%Gitee10%其他 关注微…

C# WPF上位机开发(动态库dll的开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多时候&#xff0c;我们并不希望所有的程序都放到一个exe里面。因为这样相当于把所有的风险都放在了一个文件里里面&#xff0c;既不利于程序的升…

[CTFshow 红包挑战] 刷题记录

文章目录 红包挑战7红包挑战8红包挑战9 红包挑战7 考点&#xff1a;xdebug拓展 源码 <?php highlight_file(__FILE__); error_reporting(2);extract($_GET); ini_set($name,$value);system("ls ".filter($_GET[1])."" );function filter($cmd){$cmd s…

P2 Qt Creator创建第一个Qt程序

前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《LLinux C应用编程&#xff08;概念类&#xff09;_ChenPi的博客-CSDN博客》✨✨✨ &#x1f33a;本篇简介 &#xff1a;这一章我们学…

简易加减运算器的制作----数字电路设计(含proteus仿真)

简易加减运算器的制作 一、功能要求—基本功能 1、自制0-9按键&#xff0c;在一个LED数码管上稳定地显示当前按下的值。&#xff08;基本功能&#xff09; 2、增加、两个按键&#xff0c;实现0-9两个一位数的加法运算&#xff0c;同时在两位LED上稳定地显示运算结果。&#…

C#大型LIS检验信息系统项目源码

LIS系统&#xff0c;一套医院检验科信息系统。它是以数据库为核心&#xff0c;将实验仪器与电脑连接成网&#xff0c;基础功能包括病人样本登录、实验数据存取、报告审核、打印分发等。除基础功能外&#xff0c;实验数据统计分析、质量控制管理、人员权限管理、试剂出入库等功能…

Java UDP 多人聊天室简易版

服务端 import java.io.*; import java.net.*; import java.util.ArrayList; public class Server{public static ServerSocket server_socket;public static ArrayList<Socket> socketListnew ArrayList<Socket>(); public static void main(String []args){try{…