1. 设计目的
通过实现文件系统的管理,操作虚拟磁盘中的文件存储空间、目录结构及文件操作,帮助理解文件系统的内部数据结构、功能以及实现过程。主要目标是通过实践掌握文件系统的设计与实现。
2. 系统功能要求
-
文件存储管理
在内存中创建一个虚拟磁盘空间作为文件存储分区,模拟文件系统的功能。通过文件系统,用户能够进行文件的创建、删除、读取、写入、目录操作等。退出时,应将虚拟文件系统保存到磁盘上,并在下次启动时恢复。 -
文件存储空间分配
1. 存储空间分配方式
文件存储空间的分配采用基于数组下标的方式,类似于链式分配,但通过下标查找磁盘块的位置。具体地,文件分配表(FAT)中的每一项记录一个磁盘块的下标,指示该块数据的下一个磁盘块的位置。如果该磁盘块为文件的最后一块,则在FAT表中该项的值为
END
,表示文件结束;如果该磁盘块为空,则该项的值为FREE
,表示该磁盘块为空闲状态。2. 存储结构与布局
-
虚拟磁盘:虚拟磁盘被模拟为一个包含多个磁盘块的数组。每个磁盘块大小为
1024
字节,磁盘总大小为1024000
字节,划分为多个磁盘块。 -
文件分配表(FAT):FAT表通过一个数组来管理磁盘块的分配情况。每个FAT表项包含一个下标,表示当前磁盘块的下一个簇的位置。
-
FAT项内容:
FREE
:表示该磁盘块为空闲状态。END
:表示该磁盘块为文件的最后一个簇。- 其他值:表示当前磁盘块的下一个簇的位置。
-
-
磁盘块分配:文件分配时,根据文件大小从FAT表中查找空闲的磁盘块,将文件的数据存储到这些磁盘块中,并通过FAT表项将它们链接起来。
3. 文件存储空间分配流程
- 文件分配:
- 系统会根据文件的大小和可用的空闲磁盘块,分配足够数量的磁盘块。
- 每个磁盘块通过FAT表项链接,形成一个链表。文件的每个块会指向下一个块,直到文件结束。
- 在分配磁盘块时,如果找到的磁盘块为
FREE
,则将该磁盘块分配给文件。 - 如果文件块已分配完,最后一个块将指向
END
,表示文件的结束。
- 文件释放:
- 文件释放时,通过FAT表遍历文件占用的磁盘块,将其对应的FAT项标记为
FREE
,表示该磁盘块空闲。 - 磁盘块的释放通过遍历链表方式完成,直到找到标记为
END
的块,表示文件释放完毕。
- 文件释放时,通过FAT表遍历文件占用的磁盘块,将其对应的FAT项标记为
- 查找空闲块:
- 在磁盘块分配时,系统会查找FAT表中状态为
FREE
的项,找到后分配该磁盘块并更新FAT表。
- 在磁盘块分配时,系统会查找FAT表中状态为
-
-
目录结构管理
在这个文件系统中,文件和目录之间的关系是通过 目录项(FCB) 来建立的。每个文件(包括文件和目录)都对应一个FCB
,而每个目录(包含文件或子目录)也是一个特殊的文件,其中的每个条目(目录项)表示一个文件或子目录。1.2 根目录和子目录的关系
根目录(
/
)是整个文件系统的顶级目录,它的作用类似于一个入口点。根目录本身也是一个目录文件,它包含指向其他子目录和文件的目录项。根目录的每个目录项可能是一个 文件,也可能是一个 子目录,从而形成了文件系统的层次结构。例如,根目录中的一个目录项可能指向一个子目录
/root/subdir1
,而另一个目录项可能指向一个普通文件/root/file1.txt
。1.3 目录项的查找
当需要访问某个目录或文件时,文件系统会通过路径逐级查找目录项。例如,在路径
/root/subdir1/file1.txt
中,系统首先查找根目录中的目录项,找到指向subdir1
的目录项,然后进入subdir1
子目录,再查找该子目录中指向file1.txt
的目录项。2. 目录和子目录之间的关系
每个 子目录 本质上也是一个目录,它的结构与根目录类似,只是它位于更深的层次中。子目录的创建和管理也采用类似的方式进行。
2.1 子目录的创建
- 每个目录都是一个文件,包含多个目录项。
- 创建子目录时,系统会在父目录中添加一个新的目录项,该目录项指向子目录的起始磁盘块,同时为该子目录分配一块新的磁盘空间。
- 子目录也是一个文件,它包含对该子目录下所有文件和子目录的管理。
例如,创建
/root/subdir1
子目录时,文件系统会在root
目录下添加一个目录项,指向subdir1
子目录的起始磁盘块。2.2 子目录的查找
当需要进入某个子目录时,系统会从父目录中查找该子目录的目录项。查找过程是逐级进行的。例如,从根目录进入
/root/subdir1
时,系统会首先在根目录中查找subdir1
目录项,然后进入该子目录,再查找该子目录中的文件或其他子目录。3. 目录结构的层次关系
3.1 多级目录的实现
文件系统采用多级目录结构,可以通过路径逐级访问到具体的文件或子目录。每个目录项包含对父目录的引用,因此系统能够在多级目录结构中进行有效的导航。
例如,
/root/subdir1/file1.txt
表示:root
是根目录,subdir1
是根目录下的一个子目录,file1.txt
是subdir1
子目录下的一个文件。- 系统在根目录中查找
subdir1
,进入subdir1
后,再查找file1.txt
文件。
3.2 目录项表(目录的文件)
每个目录本质上是一个文件,目录文件包含多个目录项。每个目录项表示一个文件或子目录。目录文件本身的 文件长度 表示目录项的数量。
每个目录文件(包括根目录和子目录)的格式相同,都是由多个目录项(FCB)组成的。系统通过目录项的 起始磁盘块号 来查找目录文件的内容。
4. 查找目录项的过程
系统如何查找目录项(文件或子目录)?
- 查找根目录:系统首先查找根目录(
/
)的目录项,获取根目录下的所有文件和子目录。 - 逐级查找子目录:当需要进入子目录时,系统从父目录中查找相应的目录项,找到该子目录的起始磁盘块,并进入该子目录。
- 查找文件:在子目录中查找文件时,系统会根据文件名和扩展名从该目录的目录项中查找,找到文件所在的磁盘块位置。
5. 目录操作
5.1 创建目录
my_mkdir
- 系统在父目录中分配一个新的目录项,并为该子目录分配磁盘块。
- 新创建的子目录会被初始化,并包含至少一个目录项(用于存储该子目录的目录项)。
5.2 删除目录
my_rmdir
- 删除子目录时,系统会检查该目录是否为空(即该目录项下没有其他文件或子目录)。
- 如果目录为空,系统会删除目录项,并释放与该目录相关的磁盘块。
- 如果目录不为空,删除操作会失败,必须先删除子目录中的文件或子目录。
5.3 改变当前目录
my_cd
- 当前目录由
currentdir
变量记录,改变当前目录时,系统根据路径更新当前目录。
-
提供文件操作命令
my_format
:格式化虚拟磁盘并创建根目录及管理数据结构。my_mkdir
:创建子目录。my_rmdir
:删除子目录。my_ls
:列出目录中的内容。my_cd
:更改当前目录。my_create
:创建文件。my_open
:打开文件。my_close
:关闭文件。my_write
:写文件。my_read
:读文件。my_rm
:删除文件。my_exitsys
:退出文件系统。
3. 开发平台
- 编程语言:C++
4. 数据结构设计
4.1 常量定义
BLOCKSIZE = 1024
:磁盘块大小。SIZE = 1024000
:虚拟磁盘空间总大小。END = 65535
:文件结束标志。FREE = 0
:磁盘块空闲标志。ROOTBLOCKNUM = 2
:根目录区所占盘块总数。MAXOPENFILE = 10
:最多同时打开的文件数。
4.2 数据结构
-
文件控制块 (FCB)
记录文件的控制信息,是文件目录项的内容。typedef struct FCB { char filename[8]; // 文件名 char exname[3]; // 文件扩展名 unsigned char attribute; // 文件属性:0 - 目录文件,1 - 数据文件 unsigned short time; // 文件创建时间 unsigned short data; // 文件创建日期 unsigned short first; // 文件起始盘块号 unsigned long length; // 文件长度(字节数) char free; // 目录项是否为空,0 - 空,1 - 已分配 } fcb;
-
文件分配表 (FAT)
记录磁盘块的分配情况,每个文件占据的磁盘块的块号及块的空闲状态。typedef struct FAT { unsigned short id; // 盘块号 } fat;
-
用户打开文件表 (USEROPEN)
记录用户打开的文件的相关信息。typedef struct USEROPEN { char filename[8]; // 文件名 char exname[3]; // 文件扩展名 unsigned char attribute; // 文件属性:0 - 目录,1 - 数据文件 unsigned short time; // 文件创建时间 unsigned short data; // 文件创建日期 unsigned short first; // 文件起始盘块号 unsigned long length; // 文件长度 char free; // 目录项是否为空,0 - 空,1 - 已分配 int dirno; // 目录项所在盘块号 int diroff; // 目录项在盘块中的位置 char dir[MAXOPENFILE][80]; // 文件所在目录路径 int count; // 读写指针的位置 char fcbstate; // 文件控制块状态:1 - 修改,0 - 未修改 char topenfile; // 打开文件表项是否被占用 } useropen;
-
引导块 (BLOCK0)
存放磁盘的描述信息,包括磁盘块大小、磁盘块数量、文件分配表等。typedef struct BLOCK0 { char information[200]; // 相关描述信息 unsigned short root; // 根目录起始盘块号 unsigned char *startblock; // 数据区开始位置 } block0;
5. 系统全局变量
unsigned char *myvhard
: 指向虚拟磁盘的起始地址。useropen openfilelist[MAXOPENFILE]
: 用户打开文件表数组。useropen *ptrcurdir
: 指向当前目录所在文件表项。char currentdir[80]
: 记录当前目录的路径。unsigned char *startp
: 数据区的起始位置。
6. 虚拟磁盘空间布局
虚拟磁盘总共被划分为1000个磁盘块,每个磁盘块的大小为1024字节。布局如下:
- 引导块:占1个磁盘块。
- 两张FAT表:各占2个磁盘块。
- 数据区:其余的空间分配给数据区,其中第6个磁盘块被分配为根目录区。