diff --git a/kernel/Makefile b/kernel/Makefile index 117d5cbf..653e2e6d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -18,7 +18,7 @@ LD_LIST := head.o OBJ_LIST := head.o -kernel_subdirs := common driver process debug +kernel_subdirs := common driver process debug filesystem @@ -78,14 +78,6 @@ cpu.o: common/cpu.c softirq.o: exception/softirq.c gcc $(CFLAGS) -c exception/softirq.c -o exception/softirq.o -fat32.o: filesystem/fat32/fat32.c - gcc $(CFLAGS) -c filesystem/fat32/fat32.c -o filesystem/fat32/fat32.o - -MBR.o: filesystem/MBR.c - gcc $(CFLAGS) -c filesystem/MBR.c -o filesystem/MBR.o - -VFS.o: filesystem/VFS/VFS.c - gcc $(CFLAGS) -c filesystem/VFS/VFS.c -o filesystem/VFS/VFS.o # IPI的代码 ifeq ($(ARCH), __x86_64__) @@ -164,7 +156,7 @@ all: kernel echo "Done." -kernel: head.o entry.o main.o printk.o trap.o mm.o slab.o irq.o pic.o sched.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o HPET.o softirq.o timer.o fat32.o MBR.o VFS.o $(OBJ_LIST) +kernel: head.o entry.o main.o printk.o trap.o mm.o slab.o irq.o pic.o sched.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o HPET.o softirq.o timer.o $(OBJ_LIST) @list='$(kernel_subdirs)'; for subdir in $$list; do \ echo "make all in $$subdir";\ diff --git a/kernel/filesystem/Makefile b/kernel/filesystem/Makefile new file mode 100644 index 00000000..c3287936 --- /dev/null +++ b/kernel/filesystem/Makefile @@ -0,0 +1,20 @@ + +CFLAGS += -I . + +all: fat32.o MBR.o VFS.o fat_ent.o + + +fat32.o: fat32/fat32.c + gcc $(CFLAGS) -c fat32/fat32.c -o fat32/fat32.o + +MBR.o: MBR.c + gcc $(CFLAGS) -c MBR.c -o MBR.o + +VFS.o: VFS/VFS.c + gcc $(CFLAGS) -c VFS/VFS.c -o VFS/VFS.o + +fat_ent.o: fat32/fat_ent.c + gcc $(CFLAGS) -c fat32/fat_ent.c -o fat32/fat_ent.o + +clean: + echo "Done." \ No newline at end of file diff --git a/kernel/filesystem/VFS/VFS.h b/kernel/filesystem/VFS/VFS.h index a0746705..815d7e0f 100644 --- a/kernel/filesystem/VFS/VFS.h +++ b/kernel/filesystem/VFS/VFS.h @@ -107,7 +107,13 @@ struct vfs_super_block_operations_t */ struct vfs_inode_operations_t { - long (*create)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry, int mode); + /** + * @brief 创建新的文件 + * @param inode 要被创建的文件的inode结构体 + * @param parent_dEntry 父目录的dentry + * @param mode 创建模式 + */ + long (*create)(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *parent_dEntry, int mode); /** * @brief 在文件系统中查找指定的目录项 * @param parent_inode 父目录项(在这个目录下查找) diff --git a/kernel/filesystem/fat32/fat32.c b/kernel/filesystem/fat32/fat32.c index fe2ac27c..24390908 100644 --- a/kernel/filesystem/fat32/fat32.c +++ b/kernel/filesystem/fat32/fat32.c @@ -6,6 +6,7 @@ #include #include #include +#include "fat_ent.h" struct vfs_super_block_operations_t fat32_sb_ops; struct vfs_dir_entry_operations_t fat32_dEntry_ops; @@ -54,58 +55,6 @@ static uint8_t fat32_ChkSum(uint8_t *name) } return chksum; } -/** - * @brief 读取指定簇的FAT表项 - * - * @param fsbi fat32超级块私有信息结构体 - * @param cluster 指定簇 - * @return uint32_t 下一个簇的簇号 - */ -uint32_t fat32_read_FAT_entry(fat32_sb_info_t *fsbi, uint32_t cluster) -{ - // 计算每个扇区内含有的FAT表项数 - // FAT每项4bytes - uint32_t fat_ent_per_sec = (fsbi->bytes_per_sec >> 2); // 该值应为2的n次幂 - - uint32_t buf[256]; - memset(buf, 0, fsbi->bytes_per_sec); - - // 读取一个sector的数据, - ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, - (uint64_t)&buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); - - // 返回下一个fat表项的值(也就是下一个cluster) - return buf[cluster & (fat_ent_per_sec - 1)] & 0x0fffffff; -} - -/** - * @brief 写入指定簇的FAT表项 - * - * @param fsbi fat32超级块私有信息结构体 - * @param cluster 指定簇 - * @param value 要写入该fat表项的值 - * @return uint32_t errcode - */ -uint32_t fat32_write_FAT_entry(fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value) -{ - // 计算每个扇区内含有的FAT表项数 - // FAT每项4bytes - uint32_t fat_ent_per_sec = (fsbi->bytes_per_sec >> 2); // 该值应为2的n次幂 - uint32_t *buf = kmalloc(fsbi->bytes_per_sec, 0); - memset(buf, 0, fsbi->bytes_per_sec); - - ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, - (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); - - buf[cluster & (fat_ent_per_sec - 1)] = (buf[cluster & (fat_ent_per_sec - 1)] & 0xf0000000) | (value & 0x0fffffff); - // 向FAT1和FAT2写入数据 - ahci_operation.transfer(AHCI_CMD_WRITE_DMA_EXT, fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, - (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); - ahci_operation.transfer(AHCI_CMD_WRITE_DMA_EXT, fsbi->FAT2_base_sector + (cluster / fat_ent_per_sec), 1, - (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); - kfree(buf); - return 0; -} /** * @brief 在父目录中寻找指定的目录项 @@ -671,32 +620,32 @@ long fat32_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *pos * @param fsbi fat32超级块信息结构体 * @return uint64_t 空闲簇号(找不到则返回0) */ -uint64_t fat32_find_available_cluster(fat32_sb_info_t *fsbi) -{ - uint64_t sec_per_fat = fsbi->sec_per_FAT; +// uint64_t fat32_find_available_cluster(fat32_sb_info_t *fsbi) +// { +// uint64_t sec_per_fat = fsbi->sec_per_FAT; - // 申请1扇区的缓冲区 - uint32_t *buf = (uint32_t *)kmalloc(fsbi->bytes_per_sec, 0); - int ent_per_sec = (fsbi->bytes_per_sec >> 2); - for (int i = 0; i < sec_per_fat; ++i) - { - memset(buf, 0, fsbi->bytes_per_sec); +// // 申请1扇区的缓冲区 +// uint32_t *buf = (uint32_t *)kmalloc(fsbi->bytes_per_sec, 0); +// int ent_per_sec = (fsbi->bytes_per_sec >> 2); +// for (int i = 0; i < sec_per_fat; ++i) +// { +// memset(buf, 0, fsbi->bytes_per_sec); - ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + i, 1, (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); - // 依次检查簇是否空闲 - for (int j = 0; j < ent_per_sec; ++j) - { - // 找到空闲簇 - if ((buf[j] & 0x0fffffff) == 0) - { - kfree(buf); - return i * ent_per_sec + j; - } - } - } - kfree(buf); - return 0; -} +// ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + i, 1, (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); +// // 依次检查簇是否空闲 +// for (int j = 0; j < ent_per_sec; ++j) +// { +// // 找到空闲簇 +// if ((buf[j] & 0x0fffffff) == 0) +// { +// kfree(buf); +// return i * ent_per_sec + j; +// } +// } +// } +// kfree(buf); +// return 0; +// } /** * @brief 向fat32文件系统写入数据 @@ -712,7 +661,7 @@ long fat32_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *po fat32_sb_info_t *fsbi = (fat32_sb_info_t *)(file_ptr->dEntry->dir_inode->sb->private_sb_info); // First cluster num of the file - uint64_t cluster = finode->first_clus; + uint32_t cluster = finode->first_clus; int64_t flags = 0; // kdebug("fsbi->bytes_per_clus=%d fsbi->sec_per_clus=%d finode->first_clus=%d *position=%d", fsbi->bytes_per_clus, fsbi->sec_per_clus, finode->first_clus, *position); @@ -724,9 +673,13 @@ long fat32_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *po if (!cluster) // 起始簇号为0,说明是空文件 { - // 找一个可用的簇 - cluster = fat32_find_available_cluster(fsbi); - flags = 1; + // // 找一个可用的簇 + // cluster = fat32_find_available_cluster(fsbi); + // flags = 1; + + // 分配空闲簇 + if (fat32_alloc_clusters(file_ptr->dEntry->dir_inode, &cluster, 1) != 0) + return -ENOSPC; } else { @@ -739,14 +692,14 @@ long fat32_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *po if (!cluster) return -ENOSPC; - if (flags) // 空文件 - { - // kdebug("empty file"); - finode->first_clus = cluster; - // 写入目录项 - file_ptr->dEntry->dir_inode->sb->sb_ops->write_inode(file_ptr->dEntry->dir_inode); - fat32_write_FAT_entry(fsbi, cluster, 0x0ffffff8); // 写入fat表项 - } + // if (flags) // 空文件 + // { + // // kdebug("empty file"); + // finode->first_clus = cluster; + // // 写入目录项 + // file_ptr->dEntry->dir_inode->sb->sb_ops->write_inode(file_ptr->dEntry->dir_inode); + // fat32_write_FAT_entry(fsbi, cluster, 0x0ffffff8); // 写入fat表项 + // } int64_t bytes_remain = count; @@ -809,15 +762,13 @@ long fat32_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *po break; if (next_clus >= 0x0ffffff8) // 已经到达了最后一个簇,需要分配新簇 { - next_clus = fat32_find_available_cluster(fsbi); - if (!next_clus) // 没有空闲簇 + if(fat32_alloc_clusters(file_ptr->dEntry->dir_inode, &next_clus, 1) != 0) { + // 没有空闲簇 kfree(tmp_buffer); return -ENOSPC; } - // 将簇加入到文件末尾 - fat32_write_FAT_entry(fsbi, cluster, next_clus); - fat32_write_FAT_entry(fsbi, next_clus, 0x0ffffff8); + cluster = next_clus; // 切换当前簇 flags = 1; // 标记当前簇是新分配的簇 } @@ -896,99 +847,20 @@ struct vfs_file_operations_t fat32_file_ops = .readdir = fat32_readdir, }; -// todo: create -long fat32_create(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dentry, int mode) -{ -} - /** - * @brief 在父亲inode的目录项簇中,寻找连续num个空的目录项 - * - * @param parent_inode 父inode - * @param num 请求的目录项数量 - * @param mode 操作模式 - * @param res_sector 返回信息:缓冲区对应的扇区号 - * @param res_cluster 返回信息:缓冲区对应的簇号 - * @param res_data_buf_base 返回信息:缓冲区的内存基地址(记得要释放缓冲区内存) - * @return struct fat32_Directory_t* 符合要求的entry的指针(指向地址高处的空目录项,也就是说,有连续num个≤这个指针的空目录项) + * @brief 创建新的文件 + * @param inode 要被创建的文件的inode结构体 + * @param parent_dEntry 父目录的dentry + * @param mode 创建模式 */ -struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *parent_inode, uint32_t num, uint32_t mode, uint32_t *res_sector, uint64_t *res_cluster, uint64_t *res_data_buf_base) +long fat32_create(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *parent_dEntry, int mode) { - kdebug("find empty_dentry"); - struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)parent_inode->private_inode_info; - fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; - - uint8_t *buf = kmalloc(fsbi->bytes_per_clus, 0); - memset(buf, 0, fsbi->bytes_per_clus); - - // 计算父目录项的起始簇号 - uint32_t cluster = finode->first_clus; - - struct fat32_Directory_t *tmp_dEntry = NULL; - // 指向最终的有用的dentry的指针 - struct fat32_Directory_t *result_dEntry = NULL; - - while (true) - { - // 计算父目录项的起始LBA扇区号 - uint64_t sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; - - // 读取父目录项的起始簇数据 - ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); - tmp_dEntry = (struct fat32_Directory_t *)buf; - // 计数连续的空目录项 - uint32_t count_continuity = 0; - - // 查找连续num个空闲目录项 - for (int i = 0; (i < fsbi->bytes_per_clus) && count_continuity < num; i += 32, ++tmp_dEntry) - { - if (!(tmp_dEntry->DIR_Name[0] == 0xe5 || tmp_dEntry->DIR_Name[0] == 0x00)) - { - count_continuity = 0; - continue; - } - - if (count_continuity == 0) - result_dEntry = tmp_dEntry; - ++count_continuity; - } - - // 成功查找到符合要求的目录项 - if (count_continuity == num) - { - result_dEntry += (num - 1); - *res_sector = sector; - *res_data_buf_base = (uint64_t)buf; - *res_cluster = cluster; - return result_dEntry; - } - - // 当前簇没有发现符合条件的空闲目录项,寻找下一个簇 - uint old_cluster = cluster; - cluster = fat32_read_FAT_entry(fsbi, cluster); - if (cluster >= 0x0ffffff7) // 寻找完父目录的所有簇,都没有找到符合要求的空目录项 - { - // 新增一个簇 - cluster = fat32_find_available_cluster(fsbi); - kdebug("try to allocate a new cluster to parent dentry, cluster=%d, old_cluster=%d", cluster, old_cluster); - if (cluster == 0) - { - kerror("Cannot allocate a new cluster!"); - while (1) - pause(); - } - fat32_write_FAT_entry(fsbi, old_cluster, cluster); - fat32_write_FAT_entry(fsbi, cluster, 0x0ffffff8); - - // 将这个新的簇清空 - sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; - void *tmp_buf = kmalloc(fsbi->bytes_per_clus, 0); - memset(tmp_buf, 0, fsbi->bytes_per_clus); - ahci_operation.transfer(AHCI_CMD_WRITE_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)tmp_buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); - kfree(tmp_buf); - } - } + // 文件系统超级块信息 + fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_dEntry->dir_inode->sb->private_sb_info; + // 父目录项的inode的私有信息 + struct fat32_inode_info_t *parent_inode_info = (struct fat32_inode_info_t *)parent_dEntry->dir_inode->private_inode_info; } + /** * @brief 创建文件夹 * @param inode 父目录的inode @@ -997,8 +869,7 @@ struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *paren */ int64_t fat32_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dEntry, int mode) { - - // 先检查是否有重名的目录项,然后分配一个簇 + int64_t retval = 0; // 文件系统超级块信息 fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; @@ -1010,6 +881,7 @@ int64_t fat32_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_ // 计算总共需要多少个目录项 uint32_t cnt_longname = (dEntry->name_length + 25) / 26; + // 默认都是创建长目录项来存储 if (cnt_longname == 0) cnt_longname = 1; @@ -1022,9 +894,17 @@ int64_t fat32_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_ struct fat32_Directory_t *empty_fat32_dentry = fat32_find_empty_dentry(parent_inode, cnt_longname + 1, 0, &tmp_dentry_sector, &tmp_parent_dentry_clus, &tmp_dentry_clus_buf_addr); kdebug("found empty dentry"); // ====== 为新的文件夹分配一个簇 ======= - uint32_t new_dir_clus = fat32_find_available_cluster(fsbi); - kdebug("new_dir_clus=%d", new_dir_clus); - fat32_write_FAT_entry(fsbi, new_dir_clus, 0x0ffffff8); + // uint32_t new_dir_clus = fat32_find_available_cluster(fsbi); + // kdebug("new_dir_clus=%d", new_dir_clus); + // fat32_write_FAT_entry(fsbi, new_dir_clus, 0x0ffffff8); + + // ====== 为新的文件夹分配一个簇 ======= + uint32_t new_dir_clus; + if (fat32_alloc_clusters(parent_inode, &new_dir_clus, 1) != 0) + { + retval = -ENOSPC; + goto fail; + } // ====== 填写短目录项 memset(empty_fat32_dentry, 0, sizeof(struct fat32_Directory_t)); @@ -1106,7 +986,7 @@ int64_t fat32_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_ new_dir_dentries->DIR_Name[0] = '.'; for (int i = 1; i < 11; ++i) new_dir_dentries->DIR_Name[i] = 0x20; - + new_dir_dentries->DIR_FstClusHI = empty_fat32_dentry->DIR_FstClusHI; new_dir_dentries->DIR_FstClusLO = empty_fat32_dentry->DIR_FstClusLO; @@ -1157,6 +1037,10 @@ int64_t fat32_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_ kfree((void *)tmp_dentry_clus_buf_addr); return 0; +fail:; + // 释放在find empty dentry中动态申请的缓冲区 + kfree((void *)tmp_dentry_clus_buf_addr); + return retval; } // todo: rmdir diff --git a/kernel/filesystem/fat32/fat32.h b/kernel/filesystem/fat32/fat32.h index f73fffde..326c183c 100644 --- a/kernel/filesystem/fat32/fat32.h +++ b/kernel/filesystem/fat32/fat32.h @@ -155,7 +155,7 @@ typedef struct fat32_partition_info_t fat32_sb_info_t; struct fat32_inode_info_t { - uint64_t first_clus; // 文件的起始簇号 + uint32_t first_clus; // 文件的起始簇号 uint64_t dEntry_location_clus; // fat entry的起始簇号 dEntry struct in cluster (0 is root, 1 is invalid) uint64_t dEntry_location_clus_offset; // fat entry在起始簇中的偏移量(是第几个entry) dEntry struct offset in cluster diff --git a/kernel/filesystem/fat32/fat_ent.c b/kernel/filesystem/fat32/fat_ent.c new file mode 100644 index 00000000..a0e85200 --- /dev/null +++ b/kernel/filesystem/fat32/fat_ent.c @@ -0,0 +1,253 @@ +#include "fat_ent.h" +#include +#include +#include + +/** + * @brief 请求分配指定数量的簇 + * + * @param inode 要分配簇的inode + * @param clusters 返回的被分配的簇的簇号结构体 + * @param num_clusters 要分配的簇的数量 + * @return int 错误码 + */ +int fat32_alloc_clusters(struct vfs_index_node_t *inode, uint32_t *clusters, int32_t num_clusters) +{ + int retval = 0; + + fat32_sb_info_t *fsbi = (fat32_sb_info_t *)inode->sb->private_sb_info; + struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)inode->private_inode_info; + + uint64_t sec_per_fat = fsbi->sec_per_FAT; + + // todo: 对alloc的过程加锁 + + // 申请1扇区的缓冲区 + uint32_t *buf = (uint32_t *)kmalloc(fsbi->bytes_per_sec, 0); + int ent_per_sec = (fsbi->bytes_per_sec >> 2); + int clus_idx = 0; + for (int i = 0; i < sec_per_fat; ++i) + { + if (clus_idx >= num_clusters) + goto done; + memset(buf, 0, fsbi->bytes_per_sec); + + ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + i, 1, (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); + // 依次检查簇是否空闲 + for (int j = 0; j < ent_per_sec; ++j) + { + if (clus_idx >= num_clusters) + goto done; + // 找到空闲簇 + if ((buf[j] & 0x0fffffff) == 0) + { + clusters[clus_idx] = i * ent_per_sec + j; + ++clus_idx; + } + } + } + // 空间不足 + retval = -ENOSPC; + +done:; + kfree(buf); + if (retval == 0) // 成功 + { + int cluster, idx; + if (finode->first_clus == 0) + { + // 空文件 + finode->first_clus = clusters[0]; + cluster = finode->first_clus; + // 写入inode到磁盘 + inode->sb->sb_ops->write_inode(inode); + idx = 1; + } + else + { + // todo: 跳转到文件当前的最后一个簇 + idx = 0; + int tmp_clus = finode->first_clus; + while (true) + { + tmp_clus = fat32_read_FAT_entry(fsbi, cluster); + if (tmp_clus < 0x0ffffff7) + cluster = tmp_clus; + else + break; + } + } + + // 写入fat表 + for (int i = idx; i < num_clusters; ++i) + { + fat32_write_FAT_entry(fsbi, cluster, clusters[i]); + cluster = clusters[i]; + } + fat32_write_FAT_entry(fsbi, cluster, 0x0ffffff8); + + return 0; + } + else // 出现错误 + { + if (clus_idx < num_clusters) + fat32_free_clusters(inode, clusters[0]); + return retval; + } + + return 0; +} + +/** + * @brief 释放从属于inode的,从cluster开始的所有簇 + * + * @param inode 指定的文件的inode + * @param cluster 指定簇 + * @return int 错误码 + */ +int fat32_free_clusters(struct vfs_index_node_t *inode, int32_t cluster) +{ + // todo: 释放簇 + return 0; +} + +/** + * @brief 读取指定簇的FAT表项 + * + * @param fsbi fat32超级块私有信息结构体 + * @param cluster 指定簇 + * @return uint32_t 下一个簇的簇号 + */ +uint32_t fat32_read_FAT_entry(fat32_sb_info_t *fsbi, uint32_t cluster) +{ + // 计算每个扇区内含有的FAT表项数 + // FAT每项4bytes + uint32_t fat_ent_per_sec = (fsbi->bytes_per_sec >> 2); // 该值应为2的n次幂 + + uint32_t buf[256]; + memset(buf, 0, fsbi->bytes_per_sec); + + // 读取一个sector的数据, + ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, + (uint64_t)&buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); + + // 返回下一个fat表项的值(也就是下一个cluster) + return buf[cluster & (fat_ent_per_sec - 1)] & 0x0fffffff; +} + +/** + * @brief 写入指定簇的FAT表项 + * + * @param fsbi fat32超级块私有信息结构体 + * @param cluster 指定簇 + * @param value 要写入该fat表项的值 + * @return uint32_t errcode + */ +uint32_t fat32_write_FAT_entry(fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value) +{ + // 计算每个扇区内含有的FAT表项数 + // FAT每项4bytes + uint32_t fat_ent_per_sec = (fsbi->bytes_per_sec >> 2); // 该值应为2的n次幂 + uint32_t *buf = kmalloc(fsbi->bytes_per_sec, 0); + memset(buf, 0, fsbi->bytes_per_sec); + + ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, + (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); + + buf[cluster & (fat_ent_per_sec - 1)] = (buf[cluster & (fat_ent_per_sec - 1)] & 0xf0000000) | (value & 0x0fffffff); + // 向FAT1和FAT2写入数据 + ahci_operation.transfer(AHCI_CMD_WRITE_DMA_EXT, fsbi->FAT1_base_sector + (cluster / fat_ent_per_sec), 1, + (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); + ahci_operation.transfer(AHCI_CMD_WRITE_DMA_EXT, fsbi->FAT2_base_sector + (cluster / fat_ent_per_sec), 1, + (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); + kfree(buf); + return 0; +} + + +/** + * @brief 在父亲inode的目录项簇中,寻找连续num个空的目录项 + * + * @param parent_inode 父inode + * @param num 请求的目录项数量 + * @param mode 操作模式 + * @param res_sector 返回信息:缓冲区对应的扇区号 + * @param res_cluster 返回信息:缓冲区对应的簇号 + * @param res_data_buf_base 返回信息:缓冲区的内存基地址(记得要释放缓冲区内存!!!!) + * @return struct fat32_Directory_t* 符合要求的entry的指针(指向地址高处的空目录项,也就是说,有连续num个≤这个指针的空目录项) + */ +struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *parent_inode, uint32_t num, uint32_t mode, uint32_t *res_sector, uint64_t *res_cluster, uint64_t *res_data_buf_base) +{ + kdebug("find empty_dentry"); + struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)parent_inode->private_inode_info; + fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; + + uint8_t *buf = kmalloc(fsbi->bytes_per_clus, 0); + memset(buf, 0, fsbi->bytes_per_clus); + + // 计算父目录项的起始簇号 + uint32_t cluster = finode->first_clus; + + struct fat32_Directory_t *tmp_dEntry = NULL; + // 指向最终的有用的dentry的指针 + struct fat32_Directory_t *result_dEntry = NULL; + + while (true) + { + // 计算父目录项的起始LBA扇区号 + uint64_t sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; + + // 读取父目录项的起始簇数据 + ahci_operation.transfer(AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); + tmp_dEntry = (struct fat32_Directory_t *)buf; + // 计数连续的空目录项 + uint32_t count_continuity = 0; + + // 查找连续num个空闲目录项 + for (int i = 0; (i < fsbi->bytes_per_clus) && count_continuity < num; i += 32, ++tmp_dEntry) + { + if (!(tmp_dEntry->DIR_Name[0] == 0xe5 || tmp_dEntry->DIR_Name[0] == 0x00)) + { + count_continuity = 0; + continue; + } + + if (count_continuity == 0) + result_dEntry = tmp_dEntry; + ++count_continuity; + } + + // 成功查找到符合要求的目录项 + if (count_continuity == num) + { + result_dEntry += (num - 1); + *res_sector = sector; + *res_data_buf_base = (uint64_t)buf; + *res_cluster = cluster; + return result_dEntry; + } + + // 当前簇没有发现符合条件的空闲目录项,寻找下一个簇 + uint64_t old_cluster = cluster; + cluster = fat32_read_FAT_entry(fsbi, cluster); + if (cluster >= 0x0ffffff7) // 寻找完父目录的所有簇,都没有找到符合要求的空目录项 + { + + // 新增一个簇 + + if (fat32_alloc_clusters(parent_inode, &cluster, 1) != 0) + { + kerror("Cannot allocate a new cluster!"); + while (1) + pause(); + } + + // 将这个新的簇清空 + sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; + void *tmp_buf = kmalloc(fsbi->bytes_per_clus, 0); + memset(tmp_buf, 0, fsbi->bytes_per_clus); + ahci_operation.transfer(AHCI_CMD_WRITE_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)tmp_buf, fsbi->ahci_ctrl_num, fsbi->ahci_port_num); + kfree(tmp_buf); + } + } +} \ No newline at end of file diff --git a/kernel/filesystem/fat32/fat_ent.h b/kernel/filesystem/fat32/fat_ent.h new file mode 100644 index 00000000..092460d8 --- /dev/null +++ b/kernel/filesystem/fat32/fat_ent.h @@ -0,0 +1,55 @@ +#pragma once + +#include "fat32.h" +#include + +/** + * @brief 请求分配指定数量的簇 + * + * @param inode 要分配簇的inode + * @param clusters 返回的被分配的簇的簇号结构体 + * @param num_clusters 要分配的簇的数量 + * @return int 错误码 + */ +int fat32_alloc_clusters(struct vfs_index_node_t *inode, uint32_t *clusters, int32_t num_clusters); + +/** + * @brief 释放从属于inode的,从cluster开始的所有簇 + * + * @param inode 指定的文件的inode + * @param cluster 指定簇 + * @return int 错误码 + */ +int fat32_free_clusters(struct vfs_index_node_t * inode, int32_t cluster); + +/** + * @brief 读取指定簇的FAT表项 + * + * @param fsbi fat32超级块私有信息结构体 + * @param cluster 指定簇 + * @return uint32_t 下一个簇的簇号 + */ +uint32_t fat32_read_FAT_entry(fat32_sb_info_t *fsbi, uint32_t cluster); + +/** + * @brief 写入指定簇的FAT表项 + * + * @param fsbi fat32超级块私有信息结构体 + * @param cluster 指定簇 + * @param value 要写入该fat表项的值 + * @return uint32_t errcode + */ +uint32_t fat32_write_FAT_entry(fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value); + +/** + * @brief 在父亲inode的目录项簇中,寻找连续num个空的目录项 + * + * @param parent_inode 父inode + * @param num 请求的目录项数量 + * @param mode 操作模式 + * @param res_sector 返回信息:缓冲区对应的扇区号 + * @param res_cluster 返回信息:缓冲区对应的簇号 + * @param res_data_buf_base 返回信息:缓冲区的内存基地址(记得要释放缓冲区内存!!!!) + * @return struct fat32_Directory_t* 符合要求的entry的指针(指向地址高处的空目录项,也就是说,有连续num个≤这个指针的空目录项) + */ +struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *parent_inode, uint32_t num, uint32_t mode, uint32_t *res_sector, uint64_t *res_cluster, uint64_t *res_data_buf_base);