OS-2019第五次实验

1概要设计

1.1 I/O系统

实际物理磁盘的结构是多维的:有柱面、磁头、扇区等概念。I/O系统的任务是隐藏磁盘的结构细节,把磁盘以逻辑块的面目呈现给文件系统。逻辑块顺序编号,编号取值范围为0至L−1,其中L表示磁盘的存储块总数。实验中,我们可以利用数组ldisk[C][H][B]构建磁盘模型,其中CHB 分别表示柱面号,磁头号和扇区号。每个扇区大小为512字节。I/O系统从文件系统接收命令,根据命令指定的逻辑块号把磁盘块的内容读入命令指定的内存区域,或者把命令指定的内存区域内容写入磁盘块。

I/O系统需要提供以下函数:read_block,write_block。
•read_block(int i,char *p):把逻辑块i的内容读入到指针p指向的内存位置,拷贝的字符个数为存储块的长度B。
•write_block(int i,char *p):该函数把指针p指向的内容写入逻辑块i,拷贝的字符个数为存储块的长度B。

1.2 文件系统

文件系统位于I/O系统之上。
磁盘的前k个块是保留区,其中包含如下信息:位图和文件描述符。位图用来描述磁盘块的分配情况。位图中的每一位对应一个逻辑块。创建或者删除文件,以及文件的长度发生变化时,文件系统都需要进行位图操作。前k个块的剩余部分包含一组文件描述符。每个文件描述符包含如下信息:
• 文件长度,单位字节
• 文件分配到的磁盘块号数组。该数组的长度是一个系统参数。在实验中我们可以把它设置为一个比较小的数,例如3。

文件系统需提供如下函数:create, destroy, open, close,read, write。
• create(filename): 根据指定的文件名创建新文件。
• destroy(filename): 删除指定文件。
• open(filename): 打开文件。该函数返回的索引号可用于后续的read, write, lseek,或close操作。
• close(index): 关闭制定文件。
• read(index, mem_area, count): 从指定文件顺序读入count个字节memarea指定的内存位置。读操作从文件的读写指针指示的位置开始。
• write(index, mem_area, count): 把memarea指定的内存位置开始的count个字节顺序写入指定文件。写操作从文件的读写指针指示的位置开始。
• lseek(index, pos): 把文件的读写指针移动到pos指定的位置。pos是一个整数,表示从文件开始位置的偏移量。文件打开时,读写指针自动设置为0。每次读写操作之后,它指向最后被访问的字节的下一个位置。lseek能够在不进行读写操作的情况下改变读写指针能位置。
• directory: 列表显示所有文件及其长度。

2详细设计

2.1 I/O系统

把逻辑块i的内容读入到指针p指向的内存位置,或把指针p指向的内容写入到逻辑块i,每次拷贝的字符个数为存储块的长度B。

2.2文件系统

2.2.1文件的创建与删除

创建文件时需要进行如下操作;
• 找一个空闲文件描述符(扫描ldisk [0]~ldisk [k - 1])
• 在文件目录里为新创建的文件分配一个目录项(可能需要为目录文件分配新的磁盘块)
• 在分配到的目录项里记录文件名及描述符编号.
• 返回状态信息(如有无错误发生等)

删除文件时需要进行如下操作(假设文件没有被打开):
• 在目录里搜索该文件的描述符编号
• 删除该文件对应的目录项并更新位图
• 释放文件描述符
• 返回状态信息

2.2.2文件的打开与关闭

文件系统维护一张打开文件表.打开文件表的长度固定,其表目包含如下信息:
• 读写缓冲区
• 读写指针
• 文件描述符号

文件被打开时,便在打开文件表中为其分配一个表目;
文件被关闭时,其对应的表目被释放。读写缓冲区的大小等于一个磁盘存储块。

打开文件时需要进行的操作如下:
• 搜索目录找到文件对应的描述符编号
• 在打开文件表中分配一个表目
• 在分配到的表目中把读写指针置为0,并记录描述符编号
• 读入文件的第一块到读写缓冲区中
• 返回分配到的表目在打开文件表中的索引号

关闭文件时需要进行的操作如下:
• 把缓冲区的内容写入磁盘
• 释放该文件在打开文件表中对应的表目
• 返回状态信息

2.2.3文件读写

文件打开之后才能进行读写操作.读操作需要完成的任务如下:

  1. 计算读写指针对应的位置在读写缓冲区中的偏移
  2. 把缓冲区中的内容拷贝到指定的内存位置,直到发生下列事件之一:
    • 到达文件尾或者已经拷贝了指定的字节数。这时,更新读写指针并返回相应信息
    • 到达缓冲区末尾。这时,把缓冲区内容写入磁盘,然后把文件下一块的内容读入磁盘。最后返回第2步。

2.2.4文件目录

我们的文件系统中仅设置一个目录,该目录包含文件系统中的所有文件。除了不需要显示地创建和删除之外,目录在很多方面和普通文件相像。目录对应0号文件描述符。初始状态下,目录中没有文件,所有,目录对应的描述符中记录的长度应为0,而且也没有分配磁盘块。每创建一个文件,目录文件的长度便增加一分。目录文件的内容由一系列的目录项组成,其中每个目录项由如下内容组成:
• 文件名
• 文件描述符序号

3实验实现

3.1 I/O系统

3.1.1 read_block

void read_block(int i, char *p)//把逻辑块i的内容读入到指针P指向的内存位置,每次读入B块
{
	char *temp = (char *)malloc(sizeof(char));
	temp = p;
	for (int j = 0; j < B;j++)
	{
		*temp = ldisk[i][j];
		temp++;
	}
}

3.1.2 write_block

void write_block(int i, char *p)//把指针P的内容写入逻辑块i,每次写入B块
{
	char *temp = (char*)malloc(sizeof(char));
	temp = p;
	for (int j = 0; j < B; j++)
	{
		ldisk[i][j] =*temp;
		temp++;
	}
}

3.2 文件系统

3.2.1 文件的创建与删除

文件创建代码:

int create(char filename[])//创建文件
{
	int i, frees, freed, freed2;
	char temps[B], tempc[B], temp[B];
	for (i = K; i < K + FILE_NUM; i++)
	{
		read_block((i - K) / B, temp);
		if (temp[(i - K) % B] == BUSY)
		{
			read_block(i, temp);
			if (strncmp(temp + 1, filename, FILE_NAME_LENGTH) == 0)
			{
				printf("该目录已存在文件名为%s的文件\n", filename);
				return ERROR;
			}
		}
	}
	for (i = FILE_SIGN_AREA; i < K; i++)
	{
		read_block(i, temp);
		if (temp[0] == FREE)
		{
			frees = i;
			break;
		}
	}
	if (i == K)
	{
		printf("没有空闲的文件描述符\n");
		return ERROR;
	}
	for (i = K; i < K + FILE_NUM; i++)
	{
		read_block((i - K) / B, temp);
		if (temp[(i - K) % B] == FREE)
		{
			freed = i;
			break;
		}
	}
	if (i == K + FILE_NUM)
	{
		printf("文件数已达上限\n");
		return ERROR;
	}
	for (i = K + FILE_NUM; i < L; i++)
	{
		read_block((i - K) / B, temp);
		if (temp[(i - K) % B] == FREE)
		{
			freed2 = i;
			break;
		}
	}
	if (i == L)
	{
		printf("磁盘已满,分配失败\n");
		return ERROR;
	}
	filesign temp_filesign;
	contents temp_contents;
	temp_filesign.filesign_flags = 1;
	temp_filesign.file_length = 0;
	temp_filesign.file_block = 1;
	init_block(temps, B);
	temps[0] = temp_filesign.filesign_flags;
	temps[1] = temp_filesign.file_length;
	temps[2] = temp_filesign.file_block;
	temps[3] = freed2;
	for (i = 4; i < FILE_BLOCK_LENGTH; i++)
	{
		temps[i] = '\0';
	}
	write_block(frees, temps);
	temp_contents.filesignum = frees - FILE_SIGN_AREA;
	strncpy(temp_contents.filename, filename, FILE_NAME_LENGTH);
	init_block(tempc, B);
	tempc[0] = temp_contents.filesignum;
	tempc[1] = '\0';
	strcat(tempc, temp_contents.filename);
	write_block(freed, tempc);
	read_block((freed - K) / B, temp);
	temp[(freed - K) % B] = BUSY;
	write_block((freed - K) / B, temp);
	read_block((freed2 - K) / B, temp);
	temp[(freed2 - K) % B] = BUSY;
	write_block((freed2 - K) / B, temp);
	read_block(FILE_SIGN_AREA, temp);
	temp[1]++;
	write_block(FILE_SIGN_AREA, temp);
	return OK;
}

文件删除代码:

int destroy(char *filename)
{
	int i, dtys, dtyd, use_block, index;
	char temp[B];
	char tempd[B];
	for (i = K; i < K + FILE_NUM; i++)
	{
		read_block((i - K) / B, temp);
		if (temp[(i - K) % B] == BUSY)
		{
			read_block(i, temp);
			if (strncmp(temp + 1, filename, FILE_NAME_LENGTH) == 0)
			{
				dtyd = i;
				dtys = temp[0] + FILE_SIGN_AREA;
				index = temp[0];
				break;
			}
		}
	}
	if (i == K + FILE_NUM)
	{
		printf("没有找到该文件\n");
		return ERROR;
	}
	int list = -1;
	for (i = 0; i < FILE_NUM; i++)
	{
		if (open_list[i].filesigunm == index)
		{
			list = i;
			break;
		}
	}
	if (open_list[list].flag == BUSY && list != -1)
	{
		printf("该文件已经被打开,需要关闭才能删除\n");
		return ERROR;
	}
	read_block(dtys, temp);
	use_block = temp[2];
	for (i = 0; i < use_block; i++)
	{
		read_block((temp[i + 3] - K) / B, tempd);
		tempd[(temp[i + 3] - K) % B] = FREE;
		write_block((temp[i + 3] - K) / B, tempd);
	}
	init_block(temp, B);
	write_block(dtys, temp);
	init_block(temp, B);
	write_block(dtyd, temp);
	read_block((dtyd - K) / B, temp);
	temp[(dtyd - K) % B] = FREE;
	write_block((dtyd - K) / B, temp);
	read_block(FILE_SIGN_AREA, temp);
	temp[1]--;
	write_block(FILE_SIGN_AREA,temp);
	return OK;
}

3.2.2 文件的打开与关闭

打开文件的代码:

int open(char *filename)
{
	int i, opd, ops, list, index;
	char temp[B];
	for (i = K; i < K + FILE_NUM; i++)
	{
		read_block((i - K) / B, temp);
		if (temp[(i - K) % B] == BUSY)
		{
			read_block(i, temp);
			if (strncmp(temp + 1, filename, FILE_NAME_LENGTH) == 0)
			{
				opd = i;
				ops = temp[0];
				break;
			}
		}
	}
	if (i == K + FILE_NUM)
	{
		printf("没有找到该文件\n");
		return ERROR;
	}
	for (i = 0; i < FILE_NUM; i++)
	{
		if (open_list[i].filesigunm == ops && open_list[i].flag == BUSY)
		{
			printf("该文件已被打开\n");
			return ERROR;
		}
	}
	for (i = 0; i < FILE_NUM; i++)
	{
		if (open_list[i].flag != BUSY)
		{
			list = i;
			break;
		}
	}
	open_list[list].filesigunm = ops;
	open_list[list].flag = BUSY;
	index = open_list[list].filesigunm;
	lseek(index, 0);
	init_block(open_list[list].buffer, BUFFER_LENGTH);
	read_block(open_list[list].pointer[0], temp);
	strncpy(open_list[list].buffer, temp, BUFFER_LENGTH);
	return OK;
}

关闭文件的代码

int close(int index)
{
	int i;
	int list = -1;
	char temp[B];
	for (i = 0; i < FILE_NUM; i++)
	{
		if (open_list[i].filesigunm == index)
		{
			list = i;
			break;
		}
	}
	if (list == -1)
	{
		printf("没找到当前做引号文件,操作失败\n");
		return ERROR;
	}
	if (open_list[list].flag != BUSY)
	{
		printf("输入索引号有误,操作失败\n");
		return ERROR;
	}
	write_buffer(index, list);
	init_block(open_list[list].buffer, BUFFER_LENGTH);
	open_list[list].filesigunm = FREE;
	open_list[list].flag = FREE;
	open_list[list].pointer[0] = NULL;
	open_list[list].pointer[1] = NULL;
	return OK;
}

3.2.3 文件读写

读文件的代码:

int read(int index, int mem_area, int count)
{
	int i;
	int list = -1;
	char temp[B];
	for (i = 0; i < FILE_NUM; i++)
	{
		if (open_list[i].filesigunm == index)
		{
			list = i;
			break;
		}
	}
	if (list == -1)
	{
		printf("没找到当前索引号文件,操作失败\n");
		return ERROR;
	}
	if (open_list[list].flag != BUSY)
	{
		printf("输入的索引号有误,操作失败\n");
		return ERROR;
	}
	char temp_output[OUTPUY_LENGTH];
	init_block(temp_output, OUTPUY_LENGTH);
	char output[OUTPUY_LENGTH];
	init_block(output, OUTPUY_LENGTH);
	read_block(FILE_SIGN_AREA + index, temp);
	int file_length = temp[1];
	int file_block = temp[2];
	int file_area;
	for (i = 0; i < file_block - 1; i++)
	{
		read_block(FILE_SIGN_AREA + index, temp);
		read_block(temp[3 + i], temp);
		strncpy(temp_output + i * B, temp, B);
	}
	read_block(FILE_SIGN_AREA+index, temp);
	read_block(temp[3 + i], temp);
	strncpy(temp_output + i * B, temp, B);
	int x = open_list[list].pointer[0];
	int y = open_list[list].pointer[1];
	for (i = 0; i < file_block; i++)
	{
		read_block(FILE_SIGN_AREA + index, temp);
		if (temp[3 + i] == x)
		{
			break;
		}
	}
	file_area = i * B + y;
	for (i = 0; i < count; i++)
	{
		output[i + mem_area] = temp_output[i + file_area];
	}
	printf("%s\n", output + mem_area);
	return OK;
}

写文件的代码:

int write(int index, int mem_area, int count)
{
	int i;
	int list = -1;
	int input_length;
	char temp[B];
	for (i = 0; i < FILE_NUM; i++)
	{
		if (open_list[i].filesigunm == index)
		{
			list = i;
			break;
		}
	}
	if (list == -1)
	{
		printf("没找到当前索引号文件,操作失败\n");
		return ERROR;
	}
	if (open_list[list].flag != BUSY)
	{
		printf("输入索引号错误,操作失败\n");
		return ERROR;
	}
	char input[INPUT_LENGTH];
	init_block(input, INPUT_LENGTH);
	fflush(stdin);
	for(i=0;;i++)
	{
		scanf("%c", &input[i]);
		if (input[i] == '\n')
		{
			input[i] = '\0';
			break;
		}
	}
	while (scanf("%c", &input[i]))
	{
		if (input[i] == '\n')
		{
			input[i] = '\0';
			break;
		}
		i++;
	}
	input_length = i;
	if (count <= BUFFER_LENGTH)
	{
		strncat(open_list[list].buffer, input + mem_area, count);
	}
	else
	{
		int rest;
		for (i = 0; i < BUFFER_LENGTH; i++)
		{
			if (open_list[list].buffer[i] == FREE)
			{
				rest = BUFFER_LENGTH - i;
				break;
			}
		}
		strncat(open_list[list].buffer + BUFFER_LENGTH - rest, input + mem_area, rest);
		write_buffer(index, list);
		init_block(open_list[list].buffer, BUFFER_LENGTH);
		for (i = 0; i < (count / BUFFER_LENGTH) - 1; i++)
		{
			strncpy(open_list[list].buffer, (input + mem_area) + rest + i * BUFFER_LENGTH, BUFFER_LENGTH);
			write_buffer(index, list);
			init_block(open_list[list].buffer, BUFFER_LENGTH);
		}
		init_block(open_list[list].buffer, BUFFER_LENGTH);
		strncpy(open_list[list].buffer, (input + mem_area) + rest + i*BUFFER_LENGTH, count%BUFFER_LENGTH);
		int buffer_start;
	}
	return OK;
}

3.2.4 文件目录

void directory()
{
	int i, filenum, filelength;
	char filename[FILE_NAME_LENGTH], temp[B], tempd[B], temps[B];
	read_block(FILE_SIGN_AREA, temp);
	filenum = temp[1];
	printf("\n");
	if (filenum == 0)
	{
		printf("该目录下没有文件\n");
	}
	for (i = 0; i < FILE_NUM; i++)
	{
		read_block(temp[3 + i], tempd);
		if (tempd[0] != 0)
		{
			read_block(tempd[0] + FILE_SIGN_AREA, temps);
			if (temps[0] == BUSY && tempd[0] != 0)
			{
				filelength = temps[1];
				strcpy(filename, tempd + 1);
				printf("%s\t\t%d字节\n", filename, filelength);
			}
		}
	}
	if (filenum != 0)
	{
		printf("\t\t\t\t共%d个文件\n", filenum);
	}
}

3.3实验结果

菜单目录
在这里插入图片描述
创建文件
在这里插入图片描述
查看文件目录
在这里插入图片描述
打开文件
在这里插入图片描述
查看已打开文件
在这里插入图片描述
关闭文件
        首先我们输入关闭文件命令,将我们刚刚打开的文件“yuan”关闭,在输入命令查看一下已打开文件列表,可以看到,无文件打开,操作成功。
在这里插入图片描述
删除文件
        首先我们输入删除文件命令,将我们刚刚创建的文件“yuan”关闭,在输入命令查看一下文件列表,可以看到,仅剩一个文件,我们刚刚创建的文件“yuan”已被删除。
在这里插入图片描述
读取文件内容
        读取文件内容时,我们通过文件的索引号来确定文件,同时也需要读取文件内容的长度。
ps:由于这里之前未写入文件,所以读取内容为空。
在这里插入图片描述
修改文件内容
        修改文件内容前,我们首先需要打开一个文件,可以看到,我们第一次操作时,由于未打开文件,所以操作失败。修改文件时,我们需要通过文件的索引号定位文件。
在这里插入图片描述
查看磁盘信息
在这里插入图片描述



本实验完整源码已完全上传至github
如若上述超链接无法打开,可直接复制如下地址访问: https://github.com/16281307/OS/tree/master/lab5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值