浏览代码

new: FAT32删除文件的功能 (#73)

* new: 将sys_rmdir更改为sys_unlink,.且完成删除文件操作的vfs部分

* new: fat32删除文件

*bugfix: 解决创建文件时的bug
login 2 年之前
父节点
当前提交
31b7b49d8c

+ 2 - 1
.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": ""

+ 21 - 14
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);
 }
 

+ 3 - 0
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);
 

+ 190 - 64
kernel/filesystem/fat32/fat32.c

@@ -1,9 +1,11 @@
 #include "fat32.h"
 #include "fat_ent.h"
+#include "internal.h"
 #include <common/errno.h>
 #include <common/kprint.h>
 #include <common/spinlock.h>
 #include <common/stdio.h>
+#include <common/string.h>
 #include <driver/disk/ahci/ahci.h>
 #include <filesystem/MBR.h>
 #include <mm/slab.h>
@@ -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,

+ 18 - 0
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文件系统
  *

+ 69 - 21
kernel/filesystem/fat32/fat_ent.c

@@ -1,4 +1,5 @@
 #include "fat_ent.h"
+#include "internal.h"
 #include <common/errno.h>
 #include <driver/disk/ahci/ahci.h>
 #include <mm/slab.h>
@@ -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;
 }

+ 4 - 2
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);
+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);

+ 28 - 0
kernel/filesystem/fat32/internal.h

@@ -0,0 +1,28 @@
+#pragma once
+#include <common/sys/types.h>
+
+/**
+ * @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;
+}

+ 75 - 48
user/apps/shell/cmd.c

@@ -1,18 +1,17 @@
 #include "cmd.h"
-#include <libc/string.h>
-#include <libc/stdio.h>
-#include <libc/stddef.h>
-#include <libsystem/syscall.h>
-#include <libc/string.h>
+#include "cmd_help.h"
+#include "cmd_test.h"
+#include <libc/dirent.h>
 #include <libc/errno.h>
-#include <libc/unistd.h>
-#include <libc/stdlib.h>
 #include <libc/fcntl.h>
-#include <libc/dirent.h>
-#include <libc/sys/wait.h>
+#include <libc/stddef.h>
+#include <libc/stdio.h>
+#include <libc/stdlib.h>
+#include <libc/string.h>
 #include <libc/sys/stat.h>
-#include "cmd_help.h"
-#include "cmd_test.h"
+#include <libc/sys/wait.h>
+#include <libc/unistd.h>
+#include <libsystem/syscall.h>
 
 // 当前工作目录(在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:;

+ 11 - 0
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  源地址

+ 2 - 0
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  源地址