C语言模拟UNIX文件系统实现
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
int physic[300]; // 文件地址缓冲区,用于存储文件的物理地址
int style = 1; // 文件的类型,1表示文本文件,2表示二进制文件
char cur_dir[10] = "c"; // 当前目录,初始值为'c'
struct command // 命令结构体
{
char com[10]; // 命令名称
} cmd[12];
struct block // 盘块结构体,用于模拟磁盘的存储空间
{
int n; // 空闲的盘块的个数
int free[50]; // 存放空闲盘块的地址
int a; // 模拟盘块是否被占用,0表示未被占用,1表示被占用
} memory[200];
struct block_super // 超级块结构体,用于存储空闲盘块的信息
{
int n; // 空闲的盘块的个数
int free[50]; // 存放进入栈中的空闲块
int stack[50]; // 存放下一组空闲盘块的地址
} super_block;
struct node // i结点结构体,用于存储文件的相关信息
{
int file_style; // i结点文件类型,1表示文本文件,2表示二进制文件
int file_length; // i结点文件长度,即文件占用的盘块数
int file_address[100]; // i结点文件的物理地址,即文件所占用的盘块的地址
} i_node[64];
struct dir // 目录项结构体,用于存储文件的目录信息
{
char file_name[10]; // 文件名
int i_num; // 文件的结点号
char dir_name[10]; // 文件所在的目录
} c[64];
void format() // 格式化函数,用于初始化文件系统
{
int i, j, k;
super_block.n = 50; // 超级块中空闲盘块的个数初始值为50
for (i = 0; i < 50; i++) // 初始化超级块
{
super_block.free[i] = i; // 存放进入栈中的空闲块
super_block.stack[i] = 50 + i; // 存放下一组的盘块
}
for (i = 0; i < 64; i++) // 初始化i结点信息
{
for (j = 0; j < 100; j++)
{
i_node[i].file_address[j] = -1; // 文件地址
}
i_node[i].file_length = -1; // 文件长度
i_node[i].file_style = -1; // 文件类型
}
for (i = 0; i < 64; i++) // 初始化根目录区信息
{
strcpy(c[i].file_name, ""); // 文件名
c[i].i_num = -1; // 文件的结点号
strcpy(c[i].dir_name, ""); // 文件所在的目录
}
for (i = 0; i < 200; i++) // 初始化存储空间
{
memory[i].n = 0; // 必须有这个
memory[i].a = 0;
for (j = 0; j < 50; j++)
{
memory[i].free[j] = -1; // 存放空闲盘块的地址
}
}
for (i = 0; i < 200; i++) // 将空闲块的信息用成组链接的方法写进每组的最后一个块中
{ // 存储空间初始化
if ((i + 1) % 50 == 0) // 每50个盘块为一组
{
k = i + 1;
for (j = 0; j < 50; j++)
{
if (k < 200)
{
memory[i].free[j] = k; // 下一组空闲地址
memory[i].n++; // 下一组空闲个数,注意在memory[i].n++之前要给其赋初值
k++;
}
else
{
memory[i].free[j] = -1;
}
}
memory[i].a = 0; // 标记为没有使用
continue; // 处理完用于存储下一组盘块信息的特殊盘块后,跳过本次循环
}
for (j = 0; j < 50; j++)
{
memory[i].free[j] = -1;
}
memory[i].n = 0;
}
printf("已经初始化完毕\n");
printf("欢迎进入UNIX文件模拟系统!!!\n\n");
}
void write_file(FILE *fp) /* 将信息读入系统文件中 */
{
int i;
fp = fopen("system", "wb"); // 打开名为system的二进制文件,以写入方式打开
for (i = 0; i < 200; i++) // 循环200次,将内存中的200个块写入文件
{
fwrite(&memory[i], sizeof(struct block), 1, fp); // 将内存中的一个块写入文件,每次写入一个块的大小
}
fwrite(&super_block, sizeof(struct block_super), 1, fp); // 将超级块写入文件
for (i = 0; i < 64; i++) // 循环64次,将i节点写入文件
{
fwrite(&i_node[i], sizeof(struct node), 1, fp); // 将一个i节点写入文件,每次写入一个i节点的大小
}
for (i = 0; i < 64; i++) // 循环64次,将目录项写入文件
{
fwrite(&c[i], sizeof(struct dir), 1, fp); // 将一个目录项写入文件,每次写入一个目录项的大小
}
fclose(fp); // 关闭文件
}
void read_file(FILE *fp) /* 读出系统文件的信息 */
{
int i;
fp = fopen("system", "rb"); // 打开名为system的二进制文件,以读取方式打开
for (i = 0; i < 200; i++) // 循环200次,将文件中的200个块读入内存
{
fread(&memory[i], sizeof(struct block), 1, fp); // 从文件中读取一个块,每次读取一个块的大小
}
fread(&super_block, sizeof(struct block_super), 1, fp); // 从文件中读取超级块
for (i = 0; i < 64; i++) // 循环64次,将i节点读入内存
{
fread(&i_node[i], sizeof(struct node), 1, fp); // 从文件中读取一个i节点,每次读取一个i节点的大小
}
for (i = 0; i < 64; i++) // 循环64次,将目录项读入内存
{
fread(&c[i], sizeof(struct dir), 1, fp); // 从文件中读取一个目录项,每次读取一个目录项的大小
}
fclose(fp); // 关闭文件
}
void callback(int length) /* 回收磁盘空间 */
{
int i, j, k, m, q = 0;
for (i = length - 1; i >= 0; i--) // 循环length次,回收length个盘块
{
k = physic[i]; /* 需要提供要回收的文件的地址 */
m = 49 - super_block.n; /* 回收到栈中的哪个位置 */
if (super_block.n == 50) /* 注意 当super_block.n==50时 m=-1;的值 */
{ /* super_block.n==50的时候栈满了,要将这个栈中的所有地址信息写进下一个地址中 */
for (j = 0; j < 50; j++) // 循环50次,将栈中的50个盘块号写入下一个文件地址中
{
memory[k].free[j] = super_block.free[j]; // 将栈中的盘块号写入下一个文件地址中
}
super_block.n = 0; // 栈中的盘块号已经全部写入下一个文件地址中,将栈中盘块数清零
memory[k].n = 50; // 将下一个文件地址中的盘块数设置为50
}
memory[k].a = 0; // 将要回收的盘块标记为未使用
if (m == -1)
{
m = 49; /* 将下一个文件地址中的盘块号回收到栈底中,这个地址中存放着刚才满栈的地址
的信息 */
}
super_block.free[m] = physic[i]; /* 将下一个文件地址中的盘块号回收到栈中 */
super_block.n++; // 栈中的盘块数加1
}
}
void allot(int length) /* 分配空间 */
{
int i, j, k, m, p;
for (i = 0; i < length; i++) // 循环length次,分配length个盘块
{
k = 50 - super_block.n; /* 超级块中表示空闲块的指针 */
m = super_block.free[k]; /* 栈中的相应盘块的地址 */
p = super_block.free[49]; /* 栈中的最后一个盘块指向的地址 */
if (m == -1 || memory[p].a == 1) /* 检测是否还有下一组盘块 */
{
printf("内存不足,不能够分配空间\n"); // 输出错误信息
callback(length); // 回收已经分配的盘块
break; // 跳出循环
}
if (super_block.n == 1)
{
memory[m].a = 1; /* 将最后一个盘块分配掉 */
physic[i] = m;
super_block.n = 0;
for (j = 0; j < memory[m].n; j++) /* 从最后一个盘块中取出下一组盘块号写入栈中 */
{
super_block.free[j] = memory[m].free[j]; // 将下一组盘块号写入栈中
super_block.n++; // 栈中的盘块数加1
}
continue; /* 要跳过这次循环,下面的语句在IF中已经执行过 */
}
physic[i] = m; /* 栈中的相应盘块的地址写进 文件地址缓冲区 */
memory[m].a = 1; // 将分配的盘块标记为已使用
super_block.n--; // 栈中的盘块数减1
}
}
void create_file(char filename[], int length) /* 创建文件 */
{
int i, j;
for (i = 0; i < 64; i++) // 循环64次,查找是否有同名文件
{
if (strcmp(filename, c[i].file_name) == 0) // 如果找到同名文件
{
printf("文件已经存在,不允许建立重名的文件\n"); // 输出错误信息
return; // 返回
}
}
for (i = 0; i < 64; i++) // 循环64次,查找空闲的目录项
{
if (c[i].i_num == -1) // 如果找到空闲的目录项
{
c[i].i_num = i; // 将目录项的i节点号设置为i
strcpy(c[i].file_name, filename); // 将文件名写入目录项
strcpy(c[i].dir_name, cur_dir); // 将当前目录名写入目录项
i_node[i].file_style = style; // 将文件类型写入i节点
i_node[i].file_length = length; // 将文件长度写入i节点
allot(length); // 分配盘块
for (j = 0; j < length; j++) // 循环length次,将盘块号写入i节点
{
i_node[i].file_address[j] = physic[j];
}
break; // 跳出循环
}
}
}
void create_dir(char filename[]) /* 创建目录 */
{
style = 0; /* 0代表文件类型是目录文件 */
create_file(filename, 4); // 创建文件,长度为4
style = 1; /* 用完恢复初值,因为全局变量,否则 */
}
上述代码可以创建多个目录,但代码中没有实现切换目录的功能。需要自行添加代码以实现切换目录功能。
原文地址: https://www.cveoy.top/t/topic/f2sc 著作权归作者所有。请勿转载和采集!