diff --git a/.vscode/settings.json b/.vscode/settings.json index 96619eba..f64251f4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -147,7 +147,8 @@ "compiler_attributes.h": "c", "timer.h": "c", "hid.h": "c", - "cfs.h": "c" + "cfs.h": "c", + "fat32.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", "esbonio.sphinx.confDir": "" diff --git a/kernel/filesystem/VFS/VFS.c b/kernel/filesystem/VFS/VFS.c index d79651d8..5874fcfe 100644 --- a/kernel/filesystem/VFS/VFS.c +++ b/kernel/filesystem/VFS/VFS.c @@ -160,7 +160,7 @@ struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags) char *tmpname = kzalloc(tmp_path_len + 1, 0); strncpy(tmpname, tmp_path, tmp_path_len); tmpname[tmp_path_len] = '\0'; - + // kdebug("tmpname=%s", tmpname); dentry = vfs_search_dentry_list(parent, tmpname); kfree(tmpname); @@ -179,7 +179,7 @@ struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags) if (parent->dir_inode->inode_ops->lookup(parent->dir_inode, dentry) == NULL) { // 搜索失败 - // kerror("cannot find the file/dir : %s", dentry->name); + // kwarn("cannot find the file/dir : %s", dentry->name); kfree(dentry->name); kfree(dentry); return NULL; @@ -429,9 +429,10 @@ uint64_t do_open(const char *filename, int flags) // 创建新的文件 dentry = vfs_alloc_dentry(path_len - tmp_index); - dentry->name_length = path_len - tmp_index - 1; + dentry->name_length = path_len - tmp_index - 2; + + // kdebug("to create new file:%s namelen=%d", dentry->name, dentry->name_length); strncpy(dentry->name, path + tmp_index + 1, dentry->name_length); - // kdebug("to create new file:%s namelen=%d", dentry->name, dentry->name_length) dentry->parent = parent_dentry; // 对父目录项加锁 @@ -639,7 +640,6 @@ int64_t vfs_rmdir(const char *path, bool from_userland) if (dentry == NULL) { retval = -ENOENT; - kdebug("noent"); goto out0; } @@ -776,14 +776,14 @@ int do_unlink_at(int dfd, const char *pathname, bool from_userland) else if (pathname[0] != '/') return -EINVAL; - char *buf = (char *)kzalloc(last_slash + 2, 0); + char *buf = (char *)kzalloc(last_slash + 1, 0); - // 拷贝字符串(不包含要被创建的部分) + // 拷贝字符串 if (from_userland) strncpy_from_user(buf, pathname, last_slash); else strncpy(buf, pathname, last_slash); - buf[last_slash + 1] = '\0'; + buf[last_slash] = '\0'; struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0); kfree(buf); @@ -797,13 +797,20 @@ int do_unlink_at(int dfd, const char *pathname, bool from_userland) struct vfs_index_node_t *p_inode = dentry->parent->dir_inode; // 对父inode加锁 spin_lock(&p_inode->lockref.lock); - retval = vfs_unlink(NULL, dentry->parent->dir_inode, dentry, NULL); - spin_lock(&dentry->lockref.lock); - retval = vfs_dentry_put(dentry); + retval = vfs_unlink(NULL, dentry->parent->dir_inode, dentry, NULL); + if (unlikely(retval != 0)) + { + // kdebug("retval=%d", retval); + spin_unlock(&dentry->lockref.lock); + spin_unlock(&p_inode->lockref.lock); + goto out; + } + // kdebug("vfs_dentry_put=%d", retval); + spin_unlock(&dentry->lockref.lock); spin_unlock(&p_inode->lockref.lock); - if (IS_ERR(retval)) + if (IS_ERR_VALUE(retval)) kwarn("In do_unlink_at: dentry put failed; retval=%d", retval); else retval = 0; @@ -822,14 +829,14 @@ out:; uint64_t sys_unlink_at(struct pt_regs *regs) { int dfd = regs->r8; - const char *pathname = regs->r9; + const char *pathname = (const char *)regs->r9; int flag = regs->r10; bool from_user = SYSCALL_FROM_USER(regs) ? true : false; if ((flag & (~AT_REMOVEDIR)) != 0) return -EINVAL; if (flag & AT_REMOVEDIR) return vfs_rmdir(pathname, from_user); - + // kdebug("to do_unlink_at, path=%s", pathname); return do_unlink_at(dfd, pathname, from_user); } diff --git a/kernel/filesystem/VFS/dcache.c b/kernel/filesystem/VFS/dcache.c index 609851c5..d146b25f 100644 --- a/kernel/filesystem/VFS/dcache.c +++ b/kernel/filesystem/VFS/dcache.c @@ -89,9 +89,12 @@ int vfs_dentry_put(struct vfs_dir_entry_t *dentry) } else // 是文件或设备 { + kdebug("to put dentry: file: %s", dentry->name); + list_del(&dentry->child_node_list); // 从父dentry中删除 // 释放inode spin_lock(&dentry->dir_inode->lockref.lock); retval = vfs_free_inode(dentry->dir_inode); + kdebug("retval=%d", retval); if (retval > 0) // 还有其他的dentry引用着这个inode spin_unlock(&dentry->dir_inode->lockref.lock); diff --git a/kernel/filesystem/fat32/fat32.c b/kernel/filesystem/fat32/fat32.c index e5d47715..6db79515 100644 --- a/kernel/filesystem/fat32/fat32.c +++ b/kernel/filesystem/fat32/fat32.c @@ -1,9 +1,11 @@ #include "fat32.h" #include "fat_ent.h" +#include "internal.h" #include #include #include #include +#include #include #include #include @@ -12,9 +14,14 @@ struct vfs_super_block_operations_t fat32_sb_ops; struct vfs_dir_entry_operations_t fat32_dEntry_ops; struct vfs_file_operations_t fat32_file_ops; struct vfs_inode_operations_t fat32_inode_ops; - extern struct blk_gendisk ahci_gendisk0; +static unsigned int vfat_striptail_len(unsigned int len, const char *name); +static int vfat_find(struct vfs_index_node_t *dir, const char *name, struct fat32_slot_info *slot_info); +static int __fat32_search_long_short(struct vfs_index_node_t *parent_inode, const char *name, int name_len, + struct fat32_slot_info *sinfo); +static int fat32_detach_inode(struct vfs_index_node_t *inode); + /** * @brief 注册指定磁盘上的指定分区的fat32文件系统 * @@ -46,17 +53,9 @@ static uint8_t fat32_ChkSum(uint8_t *name) return chksum; } -/** - * @brief 在父目录中寻找指定的目录项 - * - * @param parent_inode 父目录项的inode - * @param dest_dentry 搜索目标目录项 - * @return struct vfs_dir_entry_t* 目标目录项 - */ -struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dentry) +static int __fat32_search_long_short(struct vfs_index_node_t *parent_inode, const char *name, int name_len, + struct fat32_slot_info *sinfo) { - int errcode = 0; - 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; struct block_device *blk = parent_inode->sb->blk_device; @@ -67,12 +66,13 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru uint32_t cluster = finode->first_clus; struct fat32_Directory_t *tmp_dEntry = NULL; + int cnt_long_dir = 0; // 最终结果中,长目录项的数量 while (true) { // 计算父目录项的起始LBA扇区号 - uint64_t sector = fsbi->first_data_sector + (cluster - 2) * fsbi->sec_per_clus; + uint64_t sector = __fat32_calculate_LBA(fsbi->first_data_sector, fsbi->sec_per_clus, cluster); // kdebug("fat32_part_info[part_id].bootsector.BPB_SecPerClus=%d",fat32_part_info[part_id].bootsector.BPB_SecPerClus); // kdebug("sector=%d",sector); @@ -81,7 +81,7 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru tmp_dEntry = (struct fat32_Directory_t *)buf; - // 查找短目录项 + // 查找每个文件的短目录项 for (int i = 0; i < fsbi->bytes_per_clus; i += 32, ++tmp_dEntry) { // 跳过长目录项 @@ -94,7 +94,7 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru // kdebug("short name [%d] %s\n 33333==[%#02x]", i / 32, tmp_dEntry->DIR_Name, tmp_dEntry->DIR_Name[3]); // 找到长目录项,位于短目录项之前 struct fat32_LongDirectory_t *tmp_ldEntry = (struct fat32_LongDirectory_t *)tmp_dEntry - 1; - + cnt_long_dir = 0; int js = 0; // 遍历每个长目录项 while (tmp_ldEntry->LDIR_Attr == ATTR_LONG_NAME && tmp_ldEntry->LDIR_Ord != 0xe5) @@ -102,41 +102,38 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru // 比较name1 for (int x = 0; x < 5; ++x) { - if (js > dest_dentry->name_length && tmp_ldEntry->LDIR_Name1[x] == 0xffff) + if (js >= name_len && (tmp_ldEntry->LDIR_Name1[x] == 0xffff)) continue; - else if (js > dest_dentry->name_length || - tmp_ldEntry->LDIR_Name1[x] != - (uint16_t)(dest_dentry->name[js++])) // 文件名不匹配,检索下一个短目录项 + else if (js > name_len || + tmp_ldEntry->LDIR_Name1[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 goto continue_cmp_fail; } // 比较name2 for (int x = 0; x < 6; ++x) { - if (js > dest_dentry->name_length && tmp_ldEntry->LDIR_Name2[x] == 0xffff) + if (js >= name_len && (tmp_ldEntry->LDIR_Name2[x] == 0xffff)) continue; - else if (js > dest_dentry->name_length || - tmp_ldEntry->LDIR_Name2[x] != - (uint16_t)(dest_dentry->name[js++])) // 文件名不匹配,检索下一个短目录项 + else if (js > name_len || + tmp_ldEntry->LDIR_Name2[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 goto continue_cmp_fail; } // 比较name3 for (int x = 0; x < 2; ++x) { - if (js > dest_dentry->name_length && tmp_ldEntry->LDIR_Name3[x] == 0xffff) + if (js >= name_len && (tmp_ldEntry->LDIR_Name3[x] == 0xffff)) continue; - else if (js > dest_dentry->name_length || - tmp_ldEntry->LDIR_Name3[x] != - (uint16_t)(dest_dentry->name[js++])) // 文件名不匹配,检索下一个短目录项 + else if (js > name_len || + tmp_ldEntry->LDIR_Name3[x] != (uint16_t)(name[js++])) // 文件名不匹配,检索下一个短目录项 goto continue_cmp_fail; } - if (js >= dest_dentry->name_length) // 找到需要的目录项,返回 + if (js >= name_len) // 找到需要的目录项,返回 { // kdebug("found target long name."); - - goto find_lookup_success; + cnt_long_dir = tmp_dEntry - (struct fat32_Directory_t *)tmp_ldEntry; + goto success; } --tmp_ldEntry; // 检索下一个长目录项 @@ -153,9 +150,9 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru case ' ': if (!(tmp_dEntry->DIR_Attr & ATTR_DIRECTORY)) // 不是文件夹(是文件) { - if (dest_dentry->name[js] == '.') + if (name[js] == '.') continue; - else if (tmp_dEntry->DIR_Name[x] == dest_dentry->name[js]) + else if (tmp_dEntry->DIR_Name[x] == name[js]) { ++js; break; @@ -165,13 +162,12 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru } else // 是文件夹 { - if (js < dest_dentry->name_length && - tmp_dEntry->DIR_Name[x] == dest_dentry->name[js]) // 当前位正确匹配 + if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) // 当前位正确匹配 { ++js; break; // 进行下一位的匹配 } - else if (js == dest_dentry->name_length) + else if (js == name_len) continue; else goto continue_cmp_fail; @@ -183,7 +179,7 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru case 'a' ... 'z': if (tmp_dEntry->DIR_NTRes & LOWERCASE_BASE) // 为兼容windows系统,检测DIR_NTRes字段 { - if (js < dest_dentry->name_length && (tmp_dEntry->DIR_Name[x] + 32 == dest_dentry->name[js])) + if (js < name_len && (tmp_dEntry->DIR_Name[x] + 32 == name[js])) { ++js; break; @@ -193,7 +189,7 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru } else { - if (js < dest_dentry->name_length && tmp_dEntry->DIR_Name[x] == dest_dentry->name[js]) + if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) { ++js; break; @@ -203,7 +199,7 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru } break; case '0' ... '9': - if (js < dest_dentry->name_length && tmp_dEntry->DIR_Name[x] == dest_dentry->name[js]) + if (js < name_len && tmp_dEntry->DIR_Name[x] == name[js]) { ++js; break; @@ -218,9 +214,9 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru break; } } - if (js > dest_dentry->name_length) + if (js > name_len) { - kdebug("js > namelen"); + // kdebug("js > namelen"); goto continue_cmp_fail; } // 若短目录项为文件,则匹配扩展名 @@ -236,7 +232,7 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru case 'a' ... 'z': if (tmp_dEntry->DIR_NTRes & LOWERCASE_EXT) // 为兼容windows系统,检测DIR_NTRes字段 { - if ((tmp_dEntry->DIR_Name[x] + 32 == dest_dentry->name[js])) + if ((tmp_dEntry->DIR_Name[x] + 32 == name[js])) { ++js; break; @@ -246,7 +242,7 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru } else { - if (tmp_dEntry->DIR_Name[x] == dest_dentry->name[js]) + if (tmp_dEntry->DIR_Name[x] == name[js]) { ++js; break; @@ -257,7 +253,7 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru break; case '0' ... '9': case ' ': - if (tmp_dEntry->DIR_Name[x] == dest_dentry->name[js]) + if (tmp_dEntry->DIR_Name[x] == name[js]) { ++js; break; @@ -273,12 +269,13 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru } } } - if (js > dest_dentry->name_length) + if (js > name_len) { - kdebug("js > namelen"); + // kdebug("js > namelen"); goto continue_cmp_fail; } - goto find_lookup_success; + cnt_long_dir = 0; + goto success; continue_cmp_fail:; } @@ -288,21 +285,53 @@ struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, stru if (cluster >= 0x0ffffff7) // 寻找完父目录的所有簇,都没有找到目标文件名 { kfree(buf); - return NULL; + return -ENOENT; } } - if(unlikely(tmp_dEntry==NULL)) + if (unlikely(tmp_dEntry == NULL)) { BUG_ON(1); - return NULL; + kfree(buf); + return -ENOENT; } +success:; + + // 填充sinfo + sinfo->buffer = buf; + sinfo->de = tmp_dEntry; + sinfo->i_pos = __fat32_calculate_LBA(fsbi->first_data_sector, fsbi->sec_per_clus, cluster); + sinfo->num_slots = cnt_long_dir + 1; + sinfo->slot_off = tmp_dEntry - (struct fat32_Directory_t *)buf; + // kdebug("successfully found:%s", name); + return 0; +} + +/** + * @brief 在父目录中寻找指定的目录项 + * + * @param parent_inode 父目录项的inode + * @param dest_dentry 搜索目标目录项 + * @return struct vfs_dir_entry_t* 目标目录项 + */ +struct vfs_dir_entry_t *fat32_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dentry) +{ + int errcode = 0; + fat32_sb_info_t *fsbi = (fat32_sb_info_t *)parent_inode->sb->private_sb_info; + struct fat32_inode_info_t *finode = NULL; + + struct fat32_slot_info sinfo = {0}; + errcode = vfat_find(parent_inode, dest_dentry->name, &sinfo); + + if (unlikely(errcode != 0)) + return NULL; + find_lookup_success:; // 找到目标dentry struct vfs_index_node_t *p = vfs_alloc_inode(); - p->file_size = tmp_dEntry->DIR_FileSize; + p->file_size = sinfo.de->DIR_FileSize; // 计算文件占用的扇区数, 由于最小存储单位是簇,因此需要按照簇的大小来对齐扇区 p->blocks = (p->file_size + fsbi->bytes_per_clus - 1) / fsbi->bytes_per_sec; - p->attribute = (tmp_dEntry->DIR_Attr & ATTR_DIRECTORY) ? VFS_IF_DIR : VFS_IF_FILE; + p->attribute = (sinfo.de->DIR_Attr & ATTR_DIRECTORY) ? VFS_IF_DIR : VFS_IF_FILE; p->sb = parent_inode->sb; p->file_ops = &fat32_file_ops; p->inode_ops = &fat32_inode_ops; @@ -311,19 +340,19 @@ find_lookup_success:; // 找到目标dentry p->private_inode_info = (void *)kzalloc(sizeof(fat32_inode_info_t), 0); finode = (fat32_inode_info_t *)p->private_inode_info; - finode->first_clus = ((tmp_dEntry->DIR_FstClusHI << 16) | tmp_dEntry->DIR_FstClusLO) & 0x0fffffff; - finode->dEntry_location_clus = cluster; - finode->dEntry_location_clus_offset = tmp_dEntry - (struct fat32_Directory_t *)buf; // 计算dentry的偏移量 + finode->first_clus = ((sinfo.de->DIR_FstClusHI << 16) | sinfo.de->DIR_FstClusLO) & 0x0fffffff; + finode->dEntry_location_clus = __fat32_LBA_to_cluster(fsbi->first_data_sector, fsbi->sec_per_clus, sinfo.i_pos); + finode->dEntry_location_clus_offset = sinfo.slot_off; // 计算dentry的偏移量 // kdebug("finode->dEntry_location_clus=%#018lx", finode->dEntry_location_clus); // kdebug("finode->dEntry_location_clus_offset=%#018lx", finode->dEntry_location_clus_offset); - finode->create_date = tmp_dEntry->DIR_CrtDate; - finode->create_time = tmp_dEntry->DIR_CrtTime; - finode->write_date = tmp_dEntry->DIR_WrtDate; - finode->write_time = tmp_dEntry->DIR_WrtTime; + finode->create_date = sinfo.de->DIR_CrtDate; + finode->create_time = sinfo.de->DIR_CrtTime; + finode->write_date = sinfo.de->DIR_WrtDate; + finode->write_time = sinfo.de->DIR_WrtTime; // 暂时使用fat32的高4bit来标志设备文件 // todo: 引入devfs后删除这段代码 - if ((tmp_dEntry->DIR_FstClusHI >> 12) && (p->attribute & VFS_IF_FILE)) + if ((sinfo.de->DIR_FstClusHI >> 12) && (p->attribute & VFS_IF_FILE)) p->attribute |= VFS_IF_DEVICE; dest_dentry->dir_inode = p; @@ -331,7 +360,7 @@ find_lookup_success:; // 找到目标dentry list_init(&dest_dentry->child_node_list); list_init(&dest_dentry->subdirs_list); - kfree(buf); + kfree(sinfo.buffer); return dest_dentry; } @@ -681,7 +710,7 @@ long fat32_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *po // 读取一个簇的数据 int errno = blk->bd_disk->fops->transfer(blk->bd_disk, AHCI_CMD_READ_DMA_EXT, sector, fsbi->sec_per_clus, (uint64_t)tmp_buffer); - if (errno != AHCI_SUCCESS) + if (errno != 0) { // kerror("FAT32 FS(write) read disk error!"); retval = -EIO; @@ -792,7 +821,8 @@ long fat32_lseek(struct vfs_file_t *file_ptr, long offset, long whence) } // todo: ioctl long fat32_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) -{return 0; +{ + return 0; } /** @@ -875,9 +905,9 @@ long fat32_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t retval = -ENOSPC; goto fail; } - // kdebug("new dir clus=%ld", new_dir_clus); - // kdebug("dest_dEntry->name=%s",dest_dEntry->name); + // kdebug("dest_dEntry->name=%s", dest_dEntry->name); + // ====== 填写短目录项 fat32_fill_shortname(dest_dEntry, empty_fat32_dentry, new_dir_clus); // kdebug("dest_dEntry->name=%s",dest_dEntry->name); @@ -885,7 +915,7 @@ long fat32_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t // 计算校验和 uint8_t short_dentry_ChkSum = fat32_ChkSum(empty_fat32_dentry->DIR_Name); - // kdebug("dest_dEntry->name=%s",dest_dEntry->name); + // kdebug("dest_dEntry->name=%s", dest_dEntry->name); // ======== 填写长目录项 fat32_fill_longname(dest_dEntry, (struct fat32_LongDirectory_t *)(empty_fat32_dentry - 1), short_dentry_ChkSum, cnt_longname); @@ -1068,6 +1098,54 @@ int64_t fat32_setAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) { return 0; } + +/** + * @brief 从fat32中卸载inode + * + * @param inode 要被卸载的inode + * @return int 错误码 + */ +static int fat32_detach_inode(struct vfs_index_node_t *inode) +{ + // todo: 当引入哈希表管理inode之后,这个函数负责将inode从哈希表中删除 + // 参考Linux的fat_detach + return 0; +} + +/** + * @brief 取消inode和dentry之间的链接关系(删除文件) + * + * @param inode 要被取消关联关系的目录项的【父目录项】 + * @param dentry 要被取消关联关系的子目录项 + */ +int64_t fat32_unlink(struct vfs_index_node_t *dir, struct vfs_dir_entry_t *dentry) +{ + int retval = 0; + struct vfs_superblock_t *sb = dir->sb; + struct vfs_index_node_t *inode_to_remove = dentry->dir_inode; + fat32_sb_info_t *fsbi = (fat32_sb_info_t *)sb->private_sb_info; + struct fat32_slot_info sinfo = {0}; + // todo: 对fat32的超级块加锁 + + retval = vfat_find(dir, dentry->name, &sinfo); + + if (unlikely(retval != 0)) + goto out; + + // 从fat表删除目录项 + retval = fat32_remove_entries(dir, &sinfo); + if (unlikely(retval != 0)) + goto out; + retval = fat32_detach_inode(dentry->dir_inode); + if (unlikely(retval != 0)) + goto out; +out:; + if (sinfo.buffer != NULL) + kfree(sinfo.buffer); + // todo: 对fat32的超级块放锁 + return retval; +} + /** * @brief 读取文件夹(在指定目录中找出有效目录项) * @@ -1269,9 +1347,57 @@ struct vfs_inode_operations_t fat32_inode_ops = { .rename = fat32_rename, .getAttr = fat32_getAttr, .setAttr = fat32_setAttr, + .unlink = fat32_unlink, }; +/** + * @brief 给定字符串长度,计算去除字符串尾部的'.'后,剩余部分的长度 + * + * @param len 字符串长度(不包括\0) + * @param name 名称字符串 + * @return unsigned int 去除'.'后的 + */ +static unsigned int vfat_striptail_len(unsigned int len, const char *name) +{ + while (len && name[len - 1] == '.') + --len; + return len; +} + +/** + * @brief 在指定inode的长目录项中搜索目标子目录项 + * + * @param dir 父目录项inode + * @param name 要查找的子目录项的名称 + * @param len 子目录项名称长度 + * @param slot_info 返回的对应的子目录项的短目录项。 + * @return int 错误码 + */ +static int fat_search_long(struct vfs_index_node_t *dir, const char *name, int len, struct fat32_slot_info *slot_info) +{ + int retval = 0; + retval = __fat32_search_long_short(dir, name, len, slot_info); + return retval; +} +/** + * @brief 在fat32中,根据父inode,寻找给定名称的子inode + * + * @param dir 父目录项的inode + * @param name 子目录项名称 + * @param slot_info 找到的slot的信息 + * @return int 错误码 + */ +static int vfat_find(struct vfs_index_node_t *dir, const char *name, struct fat32_slot_info *slot_info) +{ + uint32_t len = vfat_striptail_len(strnlen(name, PAGE_4K_SIZE - 1), name); + + if (len == 0) + return -ENOENT; + + return fat_search_long(dir, name, len, slot_info); +} + struct vfs_filesystem_type_t fat32_fs_type = { .name = "FAT32", .fs_flags = 0, diff --git a/kernel/filesystem/fat32/fat32.h b/kernel/filesystem/fat32/fat32.h index 8f904f37..47e55842 100644 --- a/kernel/filesystem/fat32/fat32.h +++ b/kernel/filesystem/fat32/fat32.h @@ -16,6 +16,8 @@ #define FAT32_MAX_PARTITION_NUM 128 // 系统支持的最大的fat32分区数量 +#define FAT32_DELETED_FLAG 0xe5 // 如果短目录项的name[0]为这个值,那么意味着这个短目录项是空闲的 + /** * @brief fat32文件系统引导扇区结构体 * @@ -128,6 +130,7 @@ struct fat32_LongDirectory_t struct fat32_partition_info_t { uint16_t partition_id; // 全局fat32分区id + // todo: 增加mutex,使得对fat32文件系统的访问是互斥的 struct fat32_BootSector_t bootsector; struct fat32_FSInfo_t fsinfo; @@ -164,6 +167,21 @@ struct fat32_inode_info_t typedef struct fat32_inode_info_t fat32_inode_info_t; +/** + * @brief FAT32目录项插槽信息 + * 一个插槽指的是 一个长目录项/短目录项 + */ +struct fat32_slot_info +{ + off_t i_pos; // on-disk position of directory entry(扇区号) + off_t slot_off; // offset for slot or (de) start + int num_slots; // number of slots +1(de) in filename + struct fat32_Directory_t * de; + + // todo: 加入block io层后,在这里引入buffer_head + void *buffer; // 记得释放这个buffer!!! +}; + /** * @brief 注册指定磁盘上的指定分区的fat32文件系统 * diff --git a/kernel/filesystem/fat32/fat_ent.c b/kernel/filesystem/fat32/fat_ent.c index 270c5d06..b0a50dbf 100644 --- a/kernel/filesystem/fat32/fat_ent.c +++ b/kernel/filesystem/fat32/fat_ent.c @@ -1,4 +1,5 @@ #include "fat_ent.h" +#include "internal.h" #include #include #include @@ -22,10 +23,8 @@ int fat32_alloc_clusters(struct vfs_index_node_t *inode, uint32_t *clusters, int struct block_device *blk = inode->sb->blk_device; uint64_t sec_per_fat = fsbi->sec_per_FAT; - // todo: 对alloc的过程加锁 - // 申请1扇区的缓冲区 - uint32_t *buf = (uint32_t *)kmalloc(fsbi->bytes_per_sec, 0); + uint32_t *buf = (uint32_t *)kzalloc(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) @@ -67,7 +66,7 @@ done:; } else { - // todo: 跳转到文件当前的最后一个簇 + // 跳转到文件当前的最后一个簇 idx = 0; int tmp_clus = finode->first_clus; cluster = tmp_clus; @@ -150,7 +149,7 @@ uint32_t fat32_read_FAT_entry(struct block_device *blk, fat32_sb_info_t *fsbi, u * @param value 要写入该fat表项的值 * @return uint32_t errcode */ -uint32_t fat32_write_FAT_entry(struct block_device *blk, fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value) +int fat32_write_FAT_entry(struct block_device *blk, fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value) { // 计算每个扇区内含有的FAT表项数 // FAT每项4bytes @@ -216,7 +215,8 @@ struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *paren // 查找连续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)) + if (!(tmp_dEntry->DIR_Name[0] == 0xe5 || tmp_dEntry->DIR_Name[0] == 0x00 || + tmp_dEntry->DIR_Name[0] == 0x05)) { count_continuity = 0; continue; @@ -234,6 +234,7 @@ struct fat32_Directory_t *fat32_find_empty_dentry(struct vfs_index_node_t *paren *res_sector = sector; *res_data_buf_base = (uint64_t)buf; *res_cluster = cluster; + return result_dEntry; } @@ -332,12 +333,6 @@ void fat32_fill_shortname(struct vfs_dir_entry_t *dEntry, struct fat32_Directory else target->DIR_Name[tmp_index] = 0x20; } - // 在字符串末尾加入\0 - if (tmp_index < 8 && tmp_index == dEntry->name_length) - { - target->DIR_Name[tmp_index] = '\0'; - ++tmp_index; - } // 不满的部分使用0x20填充 while (tmp_index < 8) @@ -390,35 +385,31 @@ void fat32_fill_longname(struct vfs_dir_entry_t *dEntry, struct fat32_LongDirect uint32_t current_name_index = 0; struct fat32_LongDirectory_t *Ldentry = (struct fat32_LongDirectory_t *)(target + 1); // kdebug("filling long name, name=%s, namelen=%d", dEntry->name, dEntry->name_length); + int name_length = dEntry->name_length + 1; for (int i = 1; i <= cnt_longname; ++i) { --Ldentry; + Ldentry->LDIR_Ord = i; for (int j = 0; j < 5; ++j, ++current_name_index) { - if (current_name_index < dEntry->name_length) + if (current_name_index < name_length) Ldentry->LDIR_Name1[j] = dEntry->name[current_name_index]; - else if (current_name_index == dEntry->name_length) - Ldentry->LDIR_Name1[j] = '\0'; else Ldentry->LDIR_Name1[j] = 0xffff; } for (int j = 0; j < 6; ++j, ++current_name_index) { - if (current_name_index < dEntry->name_length) + if (current_name_index < name_length) Ldentry->LDIR_Name2[j] = dEntry->name[current_name_index]; - else if (current_name_index == dEntry->name_length) - Ldentry->LDIR_Name1[j] = '\0'; else Ldentry->LDIR_Name2[j] = 0xffff; } for (int j = 0; j < 2; ++j, ++current_name_index) { - if (current_name_index < dEntry->name_length) + if (current_name_index < name_length) Ldentry->LDIR_Name3[j] = dEntry->name[current_name_index]; - else if (current_name_index == dEntry->name_length) - Ldentry->LDIR_Name1[j] = '\0'; else Ldentry->LDIR_Name3[j] = 0xffff; } @@ -430,4 +421,61 @@ void fat32_fill_longname(struct vfs_dir_entry_t *dEntry, struct fat32_LongDirect // 最后一个长目录项的ord要|=0x40 Ldentry->LDIR_Ord |= 0x40; +} + +/** + * @brief 删除目录项 + * + * @param dir 父目录的inode + * @param sinfo 待删除的dentry的插槽信息 + * @return int 错误码 + */ +int fat32_remove_entries(struct vfs_index_node_t *dir, struct fat32_slot_info *sinfo) +{ + int retval = 0; + struct vfs_superblock_t *sb = dir->sb; + struct fat32_Directory_t *de = sinfo->de; + fat32_sb_info_t *fsbi = (fat32_sb_info_t *)sb->private_sb_info; + int cnt_dentries = sinfo->num_slots; + + // 获取文件数据区的起始簇号 + int data_cluster = ((((uint32_t)de->DIR_FstClusHI) << 16) | ((uint32_t)de->DIR_FstClusLO)) & 0x0fffffff; + // kdebug("data_cluster=%d, cnt_dentries=%d, offset=%d", data_cluster, cnt_dentries, sinfo->slot_off); + // kdebug("fsbi->first_data_sector=%d, sec per clus=%d, i_pos=%d", fsbi->first_data_sector, fsbi->sec_per_clus, + // sinfo->i_pos); + // === 第一阶段,先删除短目录项 + while (cnt_dentries > 0) + { + de->DIR_Name[0] = FAT32_DELETED_FLAG; + --cnt_dentries; + --de; + } + + // === 第二阶段:将对目录项的更改写入磁盘 + + sb->blk_device->bd_disk->fops->transfer(sb->blk_device->bd_disk, AHCI_CMD_WRITE_DMA_EXT, sinfo->i_pos, + fsbi->sec_per_clus, (uint64_t)sinfo->buffer); + + // === 第三阶段:清除文件的数据区 + uint32_t next_clus; + int js = 0; + // kdebug("data_cluster=%#018lx", data_cluster); + while (data_cluster < 0x0ffffff8 && data_cluster >= 2) + { + // 读取下一个表项 + next_clus = fat32_read_FAT_entry(sb->blk_device, fsbi, data_cluster); + // kdebug("data_cluster=%#018lx, next_clus=%#018lx", data_cluster, next_clus); + // 清除当前表项 + retval = fat32_write_FAT_entry(sb->blk_device, fsbi, data_cluster, 0); + if (unlikely(retval != 0)) + { + kerror("fat32_remove_entries: Failed to mark fat entry as unused for cluster:%d", data_cluster); + goto out; + } + ++js; + data_cluster = next_clus; + } +out:; + // kdebug("Successfully remove %d clusters.", js); + return retval; } \ No newline at end of file diff --git a/kernel/filesystem/fat32/fat_ent.h b/kernel/filesystem/fat32/fat_ent.h index 46fc641e..3144267d 100644 --- a/kernel/filesystem/fat32/fat_ent.h +++ b/kernel/filesystem/fat32/fat_ent.h @@ -42,7 +42,7 @@ uint32_t fat32_read_FAT_entry(struct block_device * blk, fat32_sb_info_t *fsbi, * @param value 要写入该fat表项的值 * @return uint32_t errcode */ -uint32_t fat32_write_FAT_entry(struct block_device * blk, fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value); +int fat32_write_FAT_entry(struct block_device * blk, fat32_sb_info_t *fsbi, uint32_t cluster, uint32_t value); /** * @brief 在父亲inode的目录项簇中,寻找连续num个空的目录项 @@ -94,4 +94,6 @@ void fat32_fill_shortname(struct vfs_dir_entry_t *dEntry, struct fat32_Directory * @param checksum 短目录项的校验和 * @param cnt_longname 总的长目录项的个数 */ -void fat32_fill_longname(struct vfs_dir_entry_t *dEntry, struct fat32_LongDirectory_t *target, uint8_t checksum, uint32_t cnt_longname); \ No newline at end of file +void fat32_fill_longname(struct vfs_dir_entry_t *dEntry, struct fat32_LongDirectory_t *target, uint8_t checksum, uint32_t cnt_longname); + +int fat32_remove_entries(struct vfs_index_node_t *dir, struct fat32_slot_info *sinfo); \ No newline at end of file diff --git a/kernel/filesystem/fat32/internal.h b/kernel/filesystem/fat32/internal.h new file mode 100644 index 00000000..26b5be95 --- /dev/null +++ b/kernel/filesystem/fat32/internal.h @@ -0,0 +1,28 @@ +#pragma once +#include + +/** + * @brief 根据簇号计算该簇的起始扇区号(LBA地址) + * + * @param first_data_sector 数据区的其实扇区号 + * @param sec_per_clus 每个簇的扇区数量 + * @param cluster 簇号 + * @return uint32_t LBA地址 + */ +static inline uint32_t __fat32_calculate_LBA(uint32_t first_data_sector, uint32_t sec_per_clus, uint32_t cluster) +{ + return first_data_sector + (cluster - 2) * sec_per_clus; +} + +/** + * @brief 计算LBA地址所在的簇 + * + * @param first_data_sector 数据区的其实扇区号 + * @param sec_per_clus 每个簇的扇区数量 + * @param LBA LBA地址 + * @return uint32_t 所在的簇 + */ +static inline uint32_t __fat32_LBA_to_cluster(uint32_t first_data_sector, uint32_t sec_per_clus, uint32_t LBA) +{ + return ((LBA - first_data_sector) / sec_per_clus) + 2; +} \ No newline at end of file diff --git a/user/apps/shell/cmd.c b/user/apps/shell/cmd.c index 6895a641..e1efebab 100644 --- a/user/apps/shell/cmd.c +++ b/user/apps/shell/cmd.c @@ -1,18 +1,17 @@ #include "cmd.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "cmd_help.h" #include "cmd_test.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 当前工作目录(在main_loop中初始化) char *shell_current_path = NULL; @@ -20,22 +19,11 @@ char *shell_current_path = NULL; * @brief shell 内建函数的主命令与处理函数的映射表 * */ -struct built_in_cmd_t shell_cmds[] = - { - {"cd", shell_cmd_cd}, - {"cat", shell_cmd_cat}, - {"exec", shell_cmd_exec}, - {"ls", shell_cmd_ls}, - {"mkdir", shell_cmd_mkdir}, - {"pwd", shell_cmd_pwd}, - {"rm", shell_cmd_rm}, - {"rmdir", shell_cmd_rmdir}, - {"reboot", shell_cmd_reboot}, - {"touch", shell_cmd_touch}, - {"about", shell_cmd_about}, - {"free", shell_cmd_free}, - {"help", shell_help}, - {"pipe", shell_pipe_test}, +struct built_in_cmd_t shell_cmds[] = { + {"cd", shell_cmd_cd}, {"cat", shell_cmd_cat}, {"exec", shell_cmd_exec}, {"ls", shell_cmd_ls}, + {"mkdir", shell_cmd_mkdir}, {"pwd", shell_cmd_pwd}, {"rm", shell_cmd_rm}, {"rmdir", shell_cmd_rmdir}, + {"reboot", shell_cmd_reboot}, {"touch", shell_cmd_touch}, {"about", shell_cmd_about}, {"free", shell_cmd_free}, + {"help", shell_help}, {"pipe", shell_pipe_test}, }; // 总共的内建命令数量 @@ -210,7 +198,6 @@ int shell_cmd_cd(int argc, char **argv) new_path[current_dir_len] = '/'; strcat(new_path, argv[1] + dest_offset); int x = chdir(new_path); - if (x == 0) // 成功切换目录 { free(shell_current_path); @@ -221,6 +208,7 @@ int shell_cmd_cd(int argc, char **argv) } else { + free(new_path); printf("ERROR: Cannot switch to directory: %s\n", new_path); goto fail; } @@ -326,6 +314,7 @@ int shell_cmd_cat(int argc, char **argv) close(fd); free(buf); + free(file_path); if (argv != NULL) free(argv); return 0; @@ -342,10 +331,11 @@ int shell_cmd_touch(int argc, char **argv) { int path_len = 0; char *file_path; + bool alloc_full_path=false; if (argv[1][0] == '/') file_path = argv[1]; else - file_path = get_target_filepath(argv[1], &path_len); + {file_path = get_target_filepath(argv[1], &path_len);alloc_full_path=true;} // 打开文件 int fd = open(file_path, O_CREAT); @@ -361,19 +351,11 @@ int shell_cmd_touch(int argc, char **argv) close(fd); if (argv != NULL) free(argv); + if(alloc_full_path) + free(file_path); return 0; } -/** - * @brief 删除命令 - * - * @param argc - * @param argv - * @return int - */ -// todo: -int shell_cmd_rm(int argc, char **argv) {return 0;} - /** * @brief 创建文件夹的命令 * @@ -384,19 +366,22 @@ int shell_cmd_rm(int argc, char **argv) {return 0;} int shell_cmd_mkdir(int argc, char **argv) { int result_path_len = -1; - const char *full_path = NULL; + char *full_path = NULL; + bool alloc_full_path = false; if (argv[1][0] == '/') full_path = argv[1]; else { full_path = get_target_filepath(argv[1], &result_path_len); + alloc_full_path = true; } // printf("mkdir: full_path = %s\n", full_path); int retval = mkdir(full_path, 0); if (argv != NULL) free(argv); - + if (alloc_full_path) + free(full_path); return retval; } @@ -407,20 +392,60 @@ int shell_cmd_mkdir(int argc, char **argv) * @param argv * @return int */ -// todo: int shell_cmd_rmdir(int argc, char **argv) { - const char *full_path = NULL; + char *full_path = NULL; int result_path_len = -1; + bool alloc_full_path = false; + if (argv[1][0] == '/') full_path = argv[1]; else + { full_path = get_target_filepath(argv[1], &result_path_len); + alloc_full_path = true; + } int retval = rmdir(full_path); + if (retval != 0) + printf("Failed to remove %s, retval=%d\n", full_path, retval); // printf("rmdir: path=%s, retval=%d\n", full_path, retval); if (argv != NULL) free(argv); + if (alloc_full_path) + free(full_path); + return retval; +} +/** + * @brief 删除文件的命令 + * + * @param argc + * @param argv + * @return int + */ +int shell_cmd_rm(int argc, char **argv) +{ + char *full_path = NULL; + int result_path_len = -1; + int retval = 0; + bool alloc_full_path = false; + + if (argv[1][0] == '/') + full_path = argv[1]; + else + { + full_path = get_target_filepath(argv[1], &result_path_len); + alloc_full_path = true; + } + + retval = rm(full_path); + // printf("rmdir: path=%s, retval=%d\n", full_path, retval); + if (retval != 0) + printf("Failed to remove %s, retval=%d\n", full_path, retval); + if (alloc_full_path) + free(full_path); + if (argv != NULL) + free(argv); return retval; } @@ -446,9 +471,9 @@ int shell_cmd_exec(int argc, char **argv) // printf("before execv, path=%s, argc=%d\n", file_path, argc); execv(file_path, argv); free(argv); - while (1) - ; - exit(0); + free(file_path); + + exit(-1); } else { @@ -510,11 +535,13 @@ int shell_cmd_free(int argc, char **argv) printf("Mem:\t"); if (argc == 1) // 按照kb显示 { - printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total >> 10, mst.used >> 10, mst.free >> 10, mst.shared >> 10, mst.cache_used >> 10, mst.available >> 10); + printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total >> 10, mst.used >> 10, mst.free >> 10, mst.shared >> 10, + mst.cache_used >> 10, mst.available >> 10); } else // 按照MB显示 { - printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total >> 20, mst.used >> 20, mst.free >> 20, mst.shared >> 20, mst.cache_used >> 20, mst.available >> 20); + printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total >> 20, mst.used >> 20, mst.free >> 20, mst.shared >> 20, + mst.cache_used >> 20, mst.available >> 20); } done:; diff --git a/user/libs/libc/unistd.c b/user/libs/libc/unistd.c index fff215cf..1f8581ce 100644 --- a/user/libs/libc/unistd.c +++ b/user/libs/libc/unistd.c @@ -161,6 +161,17 @@ int rmdir(const char *path) return syscall_invoke(SYS_UNLINK_AT, 0, (uint64_t)path, AT_REMOVEDIR, 0, 0, 0, 0, 0); } +/** + * @brief 删除文件 + * + * @param path 绝对路径 + * @return int + */ +int rm(const char * path) +{ + return syscall_invoke(SYS_UNLINK_AT, 0, (uint64_t)path, 0, 0, 0, 0, 0, 0); +} + /** * @brief 交换n字节 * @param src 源地址 diff --git a/user/libs/libc/unistd.h b/user/libs/libc/unistd.h index c207bcc5..30c08145 100644 --- a/user/libs/libc/unistd.h +++ b/user/libs/libc/unistd.h @@ -106,6 +106,8 @@ extern int usleep(useconds_t usec); */ int rmdir(const char *path); +int rm(const char * path); + /** * @brief 交换n字节 * @param src 源地址