现在我们可以通过IDE磁盘操作来直接读写硬盘扇区,但是这样使用起来非常不方便。我们需要建立一个系统的,有序的文件系统来以“文件”的形式来读写硬盘数据。一个扇区的数据大小为0x200字节,这对于一个文件来说实在是太小了,于是人们采用了一种叫作三级指针的结构来存储文件。首先定义文件的数据结构:
//文件块数据结构
typedef struct fs_s
{
union
{
//文件信息块
struct
{
//模式
u32 mode;
//所属者
u32 owner;
//所属组
u32 group;
//大小
u32 size;
//./
u32 dot;
//../
u32 dotdot;
//root_no
u32 root;
//is root
u32 is_root;
//文件名
char name[476];
//文件地址项
u32 address;
};
//一级、二级、三级地址项
struct
{
u32 addr_no[FS_ADDR_COUNT];
};
//文件数据内容
struct
{
u8 data[FS_DATA_COUNT];
};
};
} s_fs;
一个文件的起始扇区中存放了文件头内容,包括文件名、文件类型、权限等内容,并在最后一个属性中定义了一个u32 address,用于存放一级地址号。这个一级地址号即为一个扇区号,这个扇区中存放了u32 addr_no[FS_ADDR_COUNT]一级地址,也就是一共有0x80个一级地址,每一个一级地址中都存放了一个二级地址号,每一个二级地址号中存放了0x80个三级地址,而每一个三级地址存放了一个真正的数据扇区号。如下图:

其中每个地址都是一个箭头指向另一个地址扇区或数据扇区。可以计算出一个文件的最大占用大小为:0x80 * 0x80 * 0x80 * 0x200 = 0x40000000字节 = 1024MB = 1GB。
下面来实现创建文件的具体代码:
/*
* fs_create_fs : 根据父级文件编号创建子文件(夹)
* - u32 parent_no : 低级文件块编号
* - char *fs_name : 待创建的文件(夹)名称
* - u32 fs_mode : FS_FOLDER_MODE为文件夹,FS_FILE_MODE为文件
* return : u32 返回新创建的子文件(夹—)编号,0代表创建失败
*/
u32 fs_create_fs_path(char *path, char *fs_name, u32 uid, u32 gid, u32 mode)
{
//根据父级编号读入文件块
s_fs *fs_parent = alloc_mm(sizeof(s_fs));
u32 dev_id = 0;
fs_find_path(path, &dev_id, &fs_parent);
//root
if (uid != 0)
{
if (fs_parent->owner != uid && fs_parent->group != gid)
{
if (((fs_parent->mode >> 1) & 0x1) == 0)
{
free_mm(fs_parent, sizeof(sizeof(s_fs)));
return 0;
}
}
else if (fs_parent->owner != uid && fs_parent->group == gid)
{
if (((fs_parent->mode >> 4) & 0x1) == 0)
{
free_mm(fs_parent, sizeof(sizeof(s_fs)));
return 0;
}
}
else if (fs_parent->owner == uid)
{
if (((fs_parent->mode >> 7) & 0x1) == 0)
{
free_mm(fs_parent, sizeof(sizeof(s_fs)));
return 0;
}
}
}
s_fs *fs = alloc_mm(sizeof(s_fs));
//清空文件块内容
fs_empty_data(fs);
fs->owner = uid;
fs->group = gid;
//文件模式
fs->mode = mode;
//申请一块未使用的文件块,给本文件块
fs->dot = alloc_sec(dev_id);
if (fs->dot == 0)
{
free_mm(fs, sizeof(s_fs));
free_mm(fs_parent, sizeof(s_fs));
return 0;
}
//设定父级文件块编号
fs->dotdot = fs_parent->dot;
//root
if (fs_parent->is_root)
{
fs->root = fs_parent->dot;
}
else
{
fs->root = fs_parent->root;
}
//文件大小
fs->size = 0;
//设定文件名称
str_copy(fs_name, fs->name);
//定入此新的文件块
write_block(dev_id, fs->dot, fs);
/*
* 以下是将此文件块挂入其父级文件块中
*/
//父级子项地址
s_fs *fst_addrs = alloc_mm(sizeof(s_fs));
if (fs_parent->address == 0)
{
//创建一级磁盘指针
fs_parent->address = alloc_sec(dev_id);
fs_empty_data(fst_addrs);
//保存地址项
write_block(dev_id, fs_parent->address, fst_addrs);
//保存父级文件块
write_block(dev_id, fs_parent->dot, fs_parent);
}
//一级地址列表
read_block(dev_id, fs_parent->address, fst_addrs);
for (int i = 0; i < FS_ADDR_COUNT; ++i)
{
s_fs *sec_addrs = alloc_mm(sizeof(s_fs));
if (fst_addrs->addr_no[i] == 0)
{
//创建二级磁盘指针
fst_addrs->addr_no[i] = alloc_sec(dev_id);
fs_empty_data(sec_addrs);
//保存地址项
write_block(dev_id, fst_addrs->addr_no[i], sec_addrs);
//保存父级文件块
write_block(dev_id, fs_parent->address, fst_addrs);
}
//二级地址列表
read_block(dev_id, fst_addrs->addr_no[i], sec_addrs);
for (int j = 0; j < FS_ADDR_COUNT; ++j)
{
s_fs *thrid_addrs = alloc_mm(sizeof(s_fs));
if (sec_addrs->addr_no[j] == 0)
{
//创建三级磁盘指针
sec_addrs->addr_no[j] = alloc_sec(dev_id);
fs_empty_data(thrid_addrs);
//保存地址项
write_block(dev_id, sec_addrs->addr_no[j], thrid_addrs);
//保存父级文件块
write_block(dev_id, fst_addrs->addr_no[i], sec_addrs);
}
//三级地址列表
read_block(dev_id, sec_addrs->addr_no[j], thrid_addrs);
for (int k = 0; k < FS_ADDR_COUNT; ++k)
{
if (thrid_addrs->addr_no[k] == 0)
{
//挂入文件块
thrid_addrs->addr_no[k] = fs->dot;
//保存三级文件块内容
write_block(dev_id, sec_addrs->addr_no[j], thrid_addrs);
//返回新的文件块编号
u32 sno = fs->dot;
free_mm(thrid_addrs, sizeof(s_fs));
free_mm(sec_addrs, sizeof(s_fs));
free_mm(fst_addrs, sizeof(s_fs));
free_mm(fs, sizeof(s_fs));
free_mm(fs_parent, sizeof(s_fs));
return sno;
}
}
free_mm(thrid_addrs, sizeof(s_fs));
}
free_mm(sec_addrs, sizeof(s_fs));
}
free_mm(fst_addrs, sizeof(s_fs));
free_mm(fs, sizeof(s_fs));
free_mm(fs_parent, sizeof(s_fs));
//创建失败,返回0
return 0;
}
打开一个文件:
/*
* f_open : 打开文件
* - char *file_name : 完整路径文件名
* - int fs_mode : FS_MODE_WRITE为写模式,FS_MODE_READ为读模式
* return : s_file*文件结构指针
*/
s_file* f_open(char *file_name, int fs_mode, u32 uid, u32 gid)
{
if (str_len(file_name) == 0)
{
return NULL;
}
char dev_path[FS_NAME_LENGTH];
u32 dev_id = find_dev_id_fullpath(file_name, dev_path);
//文件名称,临时变量
char *fs_name = alloc_mm(FS_NAME_LENGTH);
u32 parent_no = 0;
int child_no = 0;
for (int i = 0, j = 0; dev_path[i] != '\0'; ++i)
{
//取得文件目录名称
if (dev_path[i] != '/')
{
fs_name[j++] = dev_path[i];
}
else
{
//根据目录名称查找子目录
fs_name[j++] = '/';
fs_name[j++] = '\0';
j = 0;
child_no = fs_find_sub_fs(dev_id, parent_no, fs_name);
if (child_no == 0)
{
free_mm(fs_name, FS_NAME_LENGTH);
return NULL;
}
parent_no = child_no;
}
if (dev_path[i + 1] == '\0')
{
fs_name[j++] = '\0';
//查找文件
child_no = fs_find_sub_fs(dev_id, parent_no, fs_name);
//没找到
if (child_no == 0)
{
free_mm(fs_name, FS_NAME_LENGTH);
//返回空
return NULL;
}
}
}
//申请文件内存
s_file *fp = alloc_mm(sizeof(s_file));
//读入文件内容
read_block(dev_id, child_no, &fp->fs);
//root
if (uid != 0)
{
if (fp->fs.owner != uid && fp->fs.group != gid)
{
if (fs_mode == FS_MODE_READ && ((fp->fs.mode >> 2) & 0x1) == 0)
{
free_mm(fs_name, FS_NAME_LENGTH);
free_mm(fp, sizeof(s_file));
return NULL;
}
else if (fs_mode == FS_MODE_WRITE && ((fp->fs.mode >> 1) & 0x1) == 0)
{
free_mm(fs_name, FS_NAME_LENGTH);
free_mm(fp, sizeof(s_file));
return NULL;
}
}
else if (fp->fs.owner != uid && fp->fs.group == gid)
{
if (fs_mode == FS_MODE_READ && ((fp->fs.mode >> 5) & 0x1) == 0)
{
free_mm(fs_name, FS_NAME_LENGTH);
free_mm(fp, sizeof(s_file));
return NULL;
}
else if (fs_mode == FS_MODE_WRITE && ((fp->fs.mode >> 4) & 0x1) == 0)
{
free_mm(fs_name, FS_NAME_LENGTH);
free_mm(fp, sizeof(s_file));
return NULL;
}
}
else if (fp->fs.owner == uid)
{
if (fs_mode == FS_MODE_READ && ((fp->fs.mode >> 8) & 0x1) == 0)
{
free_mm(fs_name, FS_NAME_LENGTH);
free_mm(fp, sizeof(s_file));
return NULL;
}
else if (fs_mode == FS_MODE_WRITE && ((fp->fs.mode >> 7) & 0x1) == 0)
{
free_mm(fs_name, FS_NAME_LENGTH);
free_mm(fp, sizeof(s_file));
return NULL;
}
}
}
fp->dev_id = dev_id;
fp->fs_mode = fs_mode;
fp->offset = 0;
fp->offset_buff = 0;
fp->offset_read_buff = FS_READ_BUFF;
fp->block_offset = 0;
fp->addr_index = 0;
fp->first_index = 0;
fp->sec_index = 0;
fp->third_index = 0;
if (fs_mode == FS_MODE_WRITE)
{
fp->fs.size = 0;
fp->buff = alloc_mm(FS_DATA_COUNT);
}
else if (fs_mode == FS_MODE_READ)
{
fp->buff = alloc_mm(FS_READ_BUFF);
}
fs_empty_data(fp->buff);
fp->next = NULL;
free_mm(fs_name, FS_NAME_LENGTH);
//返回文件指针
return fp;
}
读取文件内容:
/*
* f_read : 读取文件内容
* - s_file *fp : 文件指针
* - int size : 读入字节数
* - char *data : 等待读入的数据地址
* return : int读入字节数
*/
int f_read(s_file *fp, int size, char *data)
{
//文件为空,出错
if (fp == NULL)
{
return 0;
}
//文件不是读模式,出错
if (fp->fs_mode != FS_MODE_READ)
{
return 0;
}
if (fp->offset + size >= fp->fs.size)
{
size = fp->fs.size - fp->offset;
}
int read_size = 0;
int offset_read = 0;
while (size >= FS_READ_BUFF)
{
if (fp->offset_read_buff >= FS_READ_BUFF)
{
f_read_buff(fp);
fp->offset_read_buff = 0;
}
mmcopy_with(fp->buff, data + offset_read, fp->offset_read_buff, FS_READ_BUFF);
fp->offset += FS_READ_BUFF;
fp->offset_read_buff += FS_READ_BUFF;
offset_read += FS_READ_BUFF;
size -= FS_READ_BUFF;
read_size += FS_READ_BUFF;
}
if (size > 0 && size < FS_READ_BUFF)
{
if (fp->offset_read_buff >= FS_READ_BUFF)
{
f_read_buff(fp);
fp->offset_read_buff = 0;
}
mmcopy_with(fp->buff, data + offset_read, fp->offset_read_buff, size);
fp->offset += size;
fp->offset_read_buff += size;
offset_read += size;
read_size += size;
size = 0;
}
return read_size;
}
写入文件内容:
/*
* f_write : 写入数据到文件
* - s_file *fp : 文件指针
* - int size : 写入字节数
* - char *data : 写入数据
* return : int文件当前偏移
*/
int f_write(s_file *fp, int size, char *data)
{
//文件为空,出错
if (fp == NULL)
{
return -1;
}
//读模式不能写入文件
if (fp->fs_mode != FS_MODE_WRITE)
{
return -1;
}
//循环写文件
for (int i = 0; i < size; ++i)
{
//拷贝数据到缓冲区
fp->buff[fp->block_offset] = data[i];
fp->block_offset++;
fp->fs.size++;
//buff写满0x200之后写入磁盘块
if (fp->block_offset >= FS_DATA_COUNT)
{
//一次写入0x200字节
f_write_block(fp);
fp->block_offset = 0;
fp->offset += FS_DATA_COUNT;
}
}
//返回文件当前偏移
return fp->offset;
}
关闭文件:
/*
* f_close : 关闭文件
* - s_file *fp : 文件指针
* return : -1为失败, 0 为成功
*/
int f_close(s_file *fp)
{
//文件指针为空,出错
if (fp == NULL)
{
return -1;
}
//如果是写模式,要将最后一次没写入完成的内容写入文件
if (fp->fs_mode == FS_MODE_WRITE)
{
//如果有块内偏移
if (fp->block_offset > 0)
{
//写入剩余内容
for (int i = fp->block_offset; i < FS_DATA_COUNT; ++i)
{
fp->buff[i] = 0;
}
f_write_block(fp);
}
//写入文件,主要更新文件大小属性
write_block(fp->dev_id, fp->fs.dot, &fp->fs);
}
//释放文件指针内存
if (fp->fs_mode == FS_MODE_WRITE)
{
free_mm(fp->buff, FS_DATA_COUNT);
}
else if (fp->fs_mode == FS_MODE_READ)
{
free_mm(fp->buff, FS_READ_BUFF);
}
free_mm(fp, sizeof(s_file));
//返回成功
return 0;
}
查找文件:
/*
* 查找文件,根据文件路径名查找文件,并取得文件内容
*/
int fs_find_path(char *path_name, u32 *ret_dev_id, s_fs **fs)
{
char dev_path[FS_NAME_LENGTH];
u32 dev_id = find_dev_id_fullpath(path_name, dev_path);
//临时保存文件夹名称
char folder_name[FS_NAME_LENGTH];
//父级文件块编号
u32 parent_no = 0;
for (int i = 0, j = 0; dev_path[i] != '\0'; ++i)
{
//以'/'为分割符取得文件夹名称
if (dev_path[i] != '/')
{
folder_name[j++] = dev_path[i];
}
else
{
//取得文件夹名称
folder_name[j++] = '/';
folder_name[j++] = '\0';
j = 0;
//根据父级文件块编号查找其下的直属子文件
int child_no = fs_find_sub_fs(dev_id, parent_no, folder_name);
//没有找到此文件
if (child_no == 0)
{
//返回空
fs_empty_data(*fs);
return FS_STATUS_NO_FILE_DIR;
}
//找到子文件块,将其设定为下一级父文件块编号
parent_no = child_no;
}
}
//根据文件块编号读取文件块内容,并写入文件块指针所指向的地址
read_block(dev_id, parent_no, *fs);
*ret_dev_id = dev_id;
return FS_STATUS_OK;
}
Copyright © 2015-2023 问渠网 辽ICP备15013245号