Browse Source

new: devfs删除文件夹

fslongjin 2 years ago
parent
commit
9f2b080cda

+ 5 - 1
.vscode/settings.json

@@ -132,7 +132,11 @@
         "limits.h": "c",
         "block.h": "c",
         "blk_types.h": "c",
-        "mutex.h": "c"
+        "mutex.h": "c",
+        "mount.h": "c",
+        "internal.h": "c",
+        "devfs.h": "c",
+        "devfs-types.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 3 - 3
docs/kernel/filesystem/vfs/overview.md

@@ -173,11 +173,11 @@ struct vfs_index_node_t
 
   inode的属性。可选值如下:
 
-> - VFS_ATTR_FILE
+> - VFS_IF_FILE
 > 
-> - VFS_ATTR_DIR
+> - VFS_IF_DIR
 > 
-> - VFS_ATTR_DEVICE
+> - VFS_IF_DEVICE
 
 **sb**
 

+ 3 - 3
docs/userland/libc/apis/api-list/dirent.md

@@ -48,11 +48,11 @@
 
     文件夹类型:
 
-    ``#define VFS_ATTR_FILE (1UL << 0)``
+    ``#define VFS_IF_FILE (1UL << 0)``
     
-    ``#define VFS_ATTR_DIR (1UL << 1)``
+    ``#define VFS_IF_DIR (1UL << 1)``
     
-    ``#define VFS_ATTR_DEVICE (1UL << 2)``
+    ``#define VFS_IF_DEVICE (1UL << 2)``
     
     缓冲区长度的默认值
     

+ 12 - 0
kernel/debug/bug.h

@@ -4,6 +4,18 @@
 
 #pragma GCC push_options
 #pragma GCC optimize("O0")
+
+/**
+ * @brief 当condition为true时,认为产生了bug
+ * 
+ */
+#define BUG_ON(condition) ({                      \
+    int __ret_bug_on = !!(condition);             \
+    if (unlikely(__ret_bug_on))                   \
+        kBUG("BUG at %s:%d", __FILE__, __LINE__); \
+    unlikely(__ret_bug_on);                       \
+})
+
 /**
  * @brief 当condition为true时输出警告信息
  *

+ 132 - 14
kernel/filesystem/VFS/VFS.c

@@ -1,6 +1,8 @@
 #include "VFS.h"
 #include "mount.h"
+#include "internal.h"
 #include <common/kprint.h>
+#include <debug/bug.h>
 #include <common/dirent.h>
 #include <common/string.h>
 #include <common/errno.h>
@@ -46,7 +48,9 @@ struct vfs_superblock_t *vfs_mount_fs(const char *path, char *name, struct block
         {
             struct vfs_superblock_t *sb = p->read_superblock(blk);
             if (strcmp(path, "/") == 0) // 如果挂载到的是'/'挂载点,则让其成为最顶层的文件系统
+            {
                 vfs_root_sb = sb;
+            }
             else
             {
                 kdebug("to mount %s", name);
@@ -168,7 +172,7 @@ struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags)
         // 如果没有找到dentry缓存,则申请新的dentry
         if (dentry == NULL)
         {
-            dentry = vfs_alloc_dentry(tmp_path_len+1);
+            dentry = vfs_alloc_dentry(tmp_path_len + 1);
 
             memcpy(dentry->name, (void *)tmp_path, tmp_path_len);
             dentry->name[tmp_path_len] = '\0';
@@ -236,13 +240,13 @@ int vfs_fill_dirent(void *buf, ino_t d_ino, char *name, int namelen, unsigned ch
 
 /**
  * @brief 创建文件夹
- * 
+ *
  * @param path 文件夹路径
  * @param mode 创建模式
- * @param from_userland 该创建请求是否来自用户态 
+ * @param from_userland 该创建请求是否来自用户态
  * @return int64_t 错误码
  */
-int64_t vfs_mkdir(const char* path, mode_t mode, bool from_userland)
+int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland)
 {
     uint32_t pathlen;
     if (from_userland)
@@ -267,10 +271,9 @@ int64_t vfs_mkdir(const char* path, mode_t mode, bool from_userland)
 
     // 路径格式不合法(必须使用绝对路径)
     if (last_slash < 0)
-        return ENOTDIR;
+        return -ENOTDIR;
 
-    char *buf = (char *)kmalloc(last_slash + 1, 0);
-    memset(buf, 0, pathlen + 1);
+    char *buf = (char *)kzalloc(last_slash + 2, 0);
 
     // 拷贝字符串(不包含要被创建的部分)
     if (from_userland)
@@ -341,13 +344,12 @@ uint64_t sys_mkdir(struct pt_regs *regs)
         return vfs_mkdir(path, mode, true);
     else
         return vfs_mkdir(path, mode, false);
-    
 }
 
 /**
  * @brief 打开文件
- * 
- * @param filename 文件路径 
+ *
+ * @param filename 文件路径
  * @param flags 标志位
  * @return uint64_t 错误码
  */
@@ -445,23 +447,23 @@ uint64_t do_open(const char *filename, int flags)
         return -ENOENT;
 
     // 要求打开文件夹而目标不是文件夹
-    if ((flags & O_DIRECTORY) && (dentry->dir_inode->attribute != VFS_ATTR_DIR))
+    if ((flags & O_DIRECTORY) && (dentry->dir_inode->attribute != VFS_IF_DIR))
         return -ENOTDIR;
 
     // // 要找的目标是文件夹
-    // if ((flags & O_DIRECTORY) && dentry->dir_inode->attribute == VFS_ATTR_DIR)
+    // if ((flags & O_DIRECTORY) && dentry->dir_inode->attribute == VFS_IF_DIR)
     //     return -EISDIR;
 
     // // todo: 引入devfs后删除这段代码
     // // 暂时遇到设备文件的话,就将其first clus设置为特定值
     // if (path_len >= 5 && filename[0] == '/' && filename[1] == 'd' && filename[2] == 'e' && filename[3] == 'v' && filename[4] == '/')
     // {
-    //     if (dentry->dir_inode->attribute & VFS_ATTR_FILE)
+    //     if (dentry->dir_inode->attribute & VFS_IF_FILE)
     //     {
     //         // 对于fat32文件系统上面的设备文件,设置其起始扇区
     //         ((struct fat32_inode_info_t *)(dentry->dir_inode->private_inode_info))->first_clus |= 0xf0000000;
     //         dentry->dir_inode->sb->sb_ops->write_inode(dentry->dir_inode);
-    //         dentry->dir_inode->attribute |= VFS_ATTR_DEVICE;
+    //         dentry->dir_inode->attribute |= VFS_IF_DEVICE;
     //     }
     // }
 
@@ -544,6 +546,122 @@ struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size)
     return dentry;
 }
 
+/**
+ * @brief 判断是否可以删除指定的dentry
+ *
+ * 1、我们不能删除一个只读的dentry
+ * 2、我们应当对这个dentry的inode拥有写、执行权限(暂时还没有实现权限)
+ * 3、如果dentry指向的是文件夹,而isdir为false,则不能删除
+ * 3、如果dentry指向的是文件,而isdir为true,则不能删除
+ * @param dentry 将要被删除的dentry
+ * @param isdir 是否要删除文件夹
+ * @return int 错误码
+ */
+int vfs_may_delete(struct vfs_dir_entry_t *dentry, bool isdir)
+{
+    // 当dentry没有inode的时候,认为是bug
+    BUG_ON(dentry->dir_inode == NULL);
+
+    // todo: 进行权限检查
+
+    if (isdir) // 要删除文件夹
+    {
+        if (!D_ISDIR(dentry))
+            return -ENOTDIR;
+        else if (IS_ROOT(dentry))
+            return -EBUSY;
+    }
+    else if (D_ISDIR(dentry)) // 要删除文件但是当前是文件夹
+        return -EISDIR;
+
+    return 0;
+}
+
+/**
+ * @brief 删除文件夹
+ *
+ * @param path 文件夹路径
+ * @param from_userland 请求是否来自用户态
+ * @return int64_t 错误码
+ */
+int64_t vfs_rmdir(const char *path, bool from_userland)
+{
+    uint32_t pathlen;
+    if (from_userland)
+        pathlen = strnlen_user(path, PAGE_4K_SIZE - 1);
+    else
+        pathlen = strnlen(path, PAGE_4K_SIZE - 1);
+
+    if (pathlen == 0)
+        return -ENOENT;
+
+    int last_slash = -1;
+
+    // 去除末尾的'/'
+    for (int i = pathlen - 1; i >= 0; --i)
+    {
+        if (path[i] != '/')
+        {
+            last_slash = i + 1;
+            break;
+        }
+    }
+
+    // 路径格式不合法
+    if (last_slash < 0)
+        return -ENOTDIR;
+    else if (path[0] != '/')
+        return -EINVAL;
+
+    char *buf = (char *)kzalloc(last_slash + 2, 0);
+
+    // 拷贝字符串(不包含要被创建的部分)
+    if (from_userland)
+        strncpy_from_user(buf, path, last_slash);
+    else
+        strncpy(buf, path, last_slash);
+    buf[last_slash + 1] = '\0';
+
+    struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0);
+
+    if (dentry == NULL)
+        return -ENOENT;
+
+    int retval = vfs_may_delete(dentry, true);
+    if (retval != 0)
+        return retval;
+    // todo: 对dentry和inode加锁
+    retval = -EBUSY;
+    if (is_local_mountpoint(dentry))
+        goto out;
+    // todo:
+    retval = dentry->dir_inode->inode_ops->rmdir(dentry->dir_inode, dentry);
+    if (retval != 0)
+        goto out;
+
+    dentry->dir_inode->attribute |= VFS_IF_DEAD; // 将当前inode标记为dead
+    dont_mount(dentry);                          // 将当前dentry标记为不可被挂载
+    detach_mounts(dentry);                       // 清理同样挂载在该路径的所有挂载点的挂载树
+
+    vfs_dentry_put(dentry); // 释放dentry
+out:;
+    // todo: 对dentry和inode放锁
+    return retval;
+}
+
+/**
+ * @brief 删除文件夹的系统调用函数
+ *
+ * @param r8 文件夹路径
+ * @return uint64_t 错误码
+ */
+uint64_t sys_rmdir(struct pt_regs *regs)
+{
+    if (SYSCALL_FROM_USER(regs))
+        return vfs_rmdir((char *)regs->r8, true);
+    else
+        return vfs_rmdir((char *)regs->r8, false);
+}
 /**
  * @brief 初始化vfs
  *

+ 22 - 9
kernel/filesystem/VFS/VFS.h

@@ -28,12 +28,13 @@ extern struct vfs_superblock_t *vfs_root_sb;
 #define VFS_MAX_PATHLEN 1024
 
 /**
- * @brief 目录项的属性
+ * @brief inode的属性
  *
  */
-#define VFS_ATTR_FILE (1UL << 0)
-#define VFS_ATTR_DIR (1UL << 1)
-#define VFS_ATTR_DEVICE (1UL << 2)
+#define VFS_IF_FILE (1UL << 0)
+#define VFS_IF_DIR (1UL << 1)
+#define VFS_IF_DEVICE (1UL << 2)
+#define VFS_IF_DEAD (1UL<<3) /* removed, but still open directory */
 
 struct vfs_super_block_operations_t;
 struct vfs_inode_operations_t;
@@ -41,10 +42,13 @@ struct vfs_inode_operations_t;
 struct vfs_index_node_t;
 struct vfs_dir_entry_operations_t;
 
+#define VFS_DF_MOUNTED (1 << 0) // 当前dentry是一个挂载点
+#define VFS_DF_CANNOT_MOUNT (1 << 1) // 当前dentry是一个挂载点
 struct vfs_dir_entry_t
 {
     char *name;
     int name_length;
+    uint32_t d_flags; // dentry标志位
     struct List child_node_list;
     struct List subdirs_list;
 
@@ -218,8 +222,8 @@ struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size);
 
 /**
  * @brief 打开文件
- * 
- * @param filename 文件路径 
+ *
+ * @param filename 文件路径
  * @param flags 标志位
  * @return uint64_t 错误码
  */
@@ -227,10 +231,19 @@ uint64_t do_open(const char *filename, int flags);
 
 /**
  * @brief 创建文件夹
- * 
+ *
  * @param path 文件夹路径
  * @param mode 创建模式
- * @param from_userland 该创建请求是否来自用户态 
+ * @param from_userland 该创建请求是否来自用户态
+ * @return int64_t 错误码
+ */
+int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland);
+
+/**
+ * @brief 删除文件夹
+ *
+ * @param path 文件夹路径
+ * @param from_userland 请求是否来自用户态
  * @return int64_t 错误码
  */
-int64_t vfs_mkdir(const char* path, mode_t mode, bool from_userland);
+int64_t vfs_rmdir(const char *path, bool from_userland);

+ 19 - 0
kernel/filesystem/VFS/dcache.c

@@ -0,0 +1,19 @@
+#include "internal.h"
+
+/**
+ * @brief 释放dentry
+ * 
+ * @param dentry 目标dentry
+ */
+void vfs_dentry_put(struct vfs_dir_entry_t * dentry)
+{
+    // todo: 加锁、放锁
+
+    list_del(&dentry->child_node_list);// 从父dentry中删除
+
+    // todo: 清除子目录的dentry
+
+    dentry->dir_ops->release(dentry);
+
+    kfree(dentry);
+}

+ 41 - 0
kernel/filesystem/VFS/internal.h

@@ -0,0 +1,41 @@
+#pragma once
+#include "VFS.h"
+#include "mount.h"
+
+/**
+ * @brief 判断是否可以删除指定的dentry
+ *
+ * 1、我们不能删除一个只读的dentry
+ * 2、我们应当对这个dentry拥有写、执行权限(暂时还没有实现权限)
+ * 3、如果dentry指向的是文件夹,而isdir为false,则不能删除
+ * 3、如果dentry指向的是文件,而isdir为true,则不能删除
+ * @param dentry 将要被删除的dentry
+ * @param isdir 是否要删除文件夹
+ * @return int 错误码
+ */
+int vfs_may_delete(struct vfs_dir_entry_t *dentry, bool isdir);
+
+#define D_ISDIR(dentry) ((dentry)->dir_inode->attribute & VFS_IF_DIR)
+
+// 判断是否为根目录
+#define IS_ROOT(x) ((x) == (x)->parent)
+
+/**
+ * @brief 判断当前dentry是否为挂载点
+ *
+ * @param dentry
+ */
+static inline bool is_local_mountpoint(struct vfs_dir_entry_t *dentry)
+{
+    if (D_MOUNTED(dentry))
+        return true;
+    else
+        return false;
+}
+
+/**
+ * @brief 释放dentry
+ * 
+ * @param dentry 目标dentry
+ */
+void vfs_dentry_put(struct vfs_dir_entry_t * dentry);

+ 5 - 4
kernel/filesystem/VFS/mount.c

@@ -29,16 +29,17 @@ int do_mount(struct vfs_dir_entry_t *old_dentry, struct vfs_dir_entry_t *new_den
     list_init(&mp->mnt_list);
     mp->dentry = old_dentry;
     mp->parent_dentry = old_dentry->parent;
-    
+
     // kdebug("&new_dentry->name=%#018lx, &old_dentry->name=%#018lx", &new_dentry->name, &old_dentry->name);
     // 拷贝名称
     strncpy(new_dentry->name, old_dentry->name, old_dentry->name_length);
 
+    new_dentry->d_flags |= VFS_DF_MOUNTED; // 标记新的dentry是一个挂载点
+    
     list_init(&new_dentry->child_node_list);
     list_init(&new_dentry->subdirs_list);
     new_dentry->parent = old_dentry->parent;
 
-
     // 将新的dentry的list结点替换掉父dentry的列表中的old_dentry的list结点
     list_replace(&old_dentry->child_node_list, &new_dentry->child_node_list);
 
@@ -50,11 +51,11 @@ int do_mount(struct vfs_dir_entry_t *old_dentry, struct vfs_dir_entry_t *new_den
 
 /**
  * @brief 取消某个文件系统的挂载
- * 
+ *
  * @param dentry 对应文件系统的根dentry
  * @return int 错误码
  */
-int do_umount(struct vfs_dir_entry_t* dentry)
+int do_umount(struct vfs_dir_entry_t *dentry)
 {
     // todo: 实现umount(主要是结点的恢复问题)
 

+ 26 - 3
kernel/filesystem/VFS/mount.h

@@ -1,6 +1,6 @@
 #pragma once
 #include <common/glib.h>
-
+#include "VFS.h"
 /**
  * @brief 挂载点结构体(用来表示dentry被挂载其他文件系统之后,原先存在的数据)
  *
@@ -30,8 +30,31 @@ int do_mount(struct vfs_dir_entry_t *old_dentry, struct vfs_dir_entry_t *new_den
 
 /**
  * @brief 取消某个文件系统的挂载
- * 
+ *
  * @param dentry 对应文件系统的根dentry
  * @return int 错误码
  */
-int do_umount(struct vfs_dir_entry_t* dentry);
+int do_umount(struct vfs_dir_entry_t *dentry);
+
+// 判断dentry是否是一个挂载点
+#define D_MOUNTED(x) ((x)->d_flags & VFS_DF_MOUNTED)
+
+/**
+ * @brief 将给定的dentry标记为“不可挂载”
+ *
+ * @param dentry 目标dentry
+ */
+static inline void dont_mount(struct vfs_dir_entry_t *dentry)
+{
+    // todo: 对dentry加锁
+    dentry->d_flags |= VFS_DF_CANNOT_MOUNT;
+}
+
+static inline void detach_mounts(struct vfs_dir_entry_t *dentry)
+{
+    if (!D_MOUNTED(dentry))
+        return; // 如果当前文件夹不是一个挂载点,则直接返回
+
+    // todo:如果当前文件夹是一个挂载点,则对同样挂载在当前文件夹下的dentry进行清理。以免造成内存泄露
+    // 可参考 linux5.17或以上的detach_mounts()函数
+}

+ 1 - 1
kernel/filesystem/devfs/chardev.c

@@ -55,7 +55,7 @@ int __devfs_chardev_register(struct devfs_private_inode_info_t *private_info, st
 
     struct vfs_dir_entry_t *dentry = vfs_alloc_dentry(namelen + 1);
     __devfs_fill_dentry(dentry, devname);
-    __devfs_fill_inode(dentry, __devfs_alloc_inode(), VFS_ATTR_DEVICE, private_info);
+    __devfs_fill_inode(dentry, __devfs_alloc_inode(), VFS_IF_DEVICE, private_info);
 
     // 将dentry挂载到char文件夹下
     __devfs_dentry_bind_parent(chardev_folder_dentry, dentry);

+ 22 - 22
kernel/filesystem/devfs/devfs.c

@@ -33,11 +33,11 @@ struct vfs_superblock_t *devfs_read_superblock(struct block_device *blk)
     return &devfs_sb;
 }
 
-static void devfs_write_superblock(struct vfs_superblock_t *sb) {}
+static void devfs_write_superblock(struct vfs_superblock_t *sb) {return 0; }
 
-static void devfs_put_superblock(struct vfs_superblock_t *sb) {}
+static void devfs_put_superblock(struct vfs_superblock_t *sb) {return 0; }
 
-static void devfs_write_inode(struct vfs_index_node_t *inode) {}
+static void devfs_write_inode(struct vfs_index_node_t *inode) {return 0; }
 struct vfs_super_block_operations_t devfs_sb_ops =
     {
         .write_superblock = &devfs_write_superblock,
@@ -45,13 +45,13 @@ struct vfs_super_block_operations_t devfs_sb_ops =
         .write_inode = &devfs_write_inode,
 };
 
-static long devfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) {}
+static long devfs_compare(struct vfs_dir_entry_t *parent_dEntry, char *source_filename, char *dest_filename) {return 0; }
 
-static long devfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) {}
+static long devfs_hash(struct vfs_dir_entry_t *dEntry, char *filename) {return 0; }
 
-static long devfs_release(struct vfs_dir_entry_t *dEntry) {}
+static long devfs_release(struct vfs_dir_entry_t *dEntry) { return 0; }
 
-static long devfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) {}
+static long devfs_iput(struct vfs_dir_entry_t *dEntry, struct vfs_index_node_t *inode) {return 0; }
 
 struct vfs_dir_entry_operations_t devfs_dentry_ops =
     {
@@ -65,10 +65,10 @@ static long devfs_open(struct vfs_index_node_t *inode, struct vfs_file_t *file_p
 {
     return 0;
 }
-static long devfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) {}
-static long devfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) {}
-static long devfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) {}
-static long devfs_lseek(struct vfs_file_t *file_ptr, long offset, long origin) {}
+static long devfs_close(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr) {return 0; }
+static long devfs_read(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) {return 0; }
+static long devfs_write(struct vfs_file_t *file_ptr, char *buf, int64_t count, long *position) {return 0; }
+static long devfs_lseek(struct vfs_file_t *file_ptr, long offset, long origin) {return 0; }
 static long devfs_ioctl(struct vfs_index_node_t *inode, struct vfs_file_t *file_ptr, uint64_t cmd, uint64_t arg) { return 0; }
 
 static long devfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler)
@@ -94,10 +94,10 @@ static long devfs_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir
     char *name = (char *)kzalloc(target_dent->name_length + 1, 0);
     strncpy(name, target_dent->name, target_dent->name_length);
     uint32_t dentry_type;
-    if (target_dent->dir_inode->attribute & VFS_ATTR_DIR)
-        dentry_type = VFS_ATTR_DIR;
+    if (target_dent->dir_inode->attribute & VFS_IF_DIR)
+        dentry_type = VFS_IF_DIR;
     else
-        dentry_type = VFS_ATTR_DEVICE;
+        dentry_type = VFS_IF_DEVICE;
 
     return filler(dirent, file_ptr->position - 1, name, target_dent->name_length, dentry_type, file_ptr->position - 1);
 failed:;
@@ -123,6 +123,7 @@ struct vfs_file_operations_t devfs_file_ops =
  */
 static long devfs_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode)
 {
+    return 0; 
 }
 
 static struct vfs_dir_entry_t *devfs_lookup(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry)
@@ -148,18 +149,18 @@ static long devfs_mkdir(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *
     dEntry->dir_inode = (struct vfs_index_node_t *)kzalloc(sizeof(struct vfs_index_node_t), 0);
     dEntry->dir_inode->file_ops = &devfs_file_ops;
     dEntry->dir_inode->inode_ops = &devfs_inode_ops;
-
+    dEntry->dir_ops = &devfs_dentry_ops;
     // todo: 增加private inode info
     dEntry->dir_inode->private_inode_info = NULL;
     dEntry->dir_inode->sb = &devfs_sb;
-    dEntry->dir_inode->attribute = VFS_ATTR_DIR;
+    dEntry->dir_inode->attribute = VFS_IF_DIR;
     return 0;
 }
 
-static long devfs_rmdir(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry) {}
-static long devfs_rename(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry) {}
-static long devfs_getAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) {}
-static long devfs_setAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) {}
+static long devfs_rmdir(struct vfs_index_node_t *inode, struct vfs_dir_entry_t *dEntry) { return 0; }
+static long devfs_rename(struct vfs_index_node_t *old_inode, struct vfs_dir_entry_t *old_dEntry, struct vfs_index_node_t *new_inode, struct vfs_dir_entry_t *new_dEntry) {return 0; }
+static long devfs_getAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) {return 0; }
+static long devfs_setAttr(struct vfs_dir_entry_t *dEntry, uint64_t *attr) {return 0; }
 struct vfs_inode_operations_t devfs_inode_ops = {
     .create = &devfs_create,
     .lookup = &devfs_lookup,
@@ -187,7 +188,7 @@ static __always_inline void __devfs_init_root_inode()
     // todo: 增加private inode info
     devfs_root_dentry->dir_inode->private_inode_info = NULL;
     devfs_root_dentry->dir_inode->sb = &devfs_sb;
-    devfs_root_dentry->dir_inode->attribute = VFS_ATTR_DIR;
+    devfs_root_dentry->dir_inode->attribute = VFS_IF_DIR;
 }
 /**
  * @brief 初始化devfs的根dentry
@@ -251,7 +252,6 @@ void devfs_init()
     vfs_register_filesystem(&devfs_fs_type);
     vfs_mount_fs(__devfs_mount_path, "DEVFS", NULL);
 
-
     __devfs_chardev_init();
 
     // todo: 当rootfs实现后,将ps/2键盘的注册改为在驱动程序中进行(目前没有rootfs,因此还不能在不依赖fat32的情况下,挂载设备)

+ 1 - 1
kernel/filesystem/devfs/internal.h

@@ -58,7 +58,7 @@ static inline struct vfs_dir_entry_t *__devfs_find_dentry(struct vfs_dir_entry_t
 static inline struct vfs_dir_entry_t *__devfs_find_dir(struct vfs_dir_entry_t *parent_dentry, const char *name)
 {
     struct vfs_dir_entry_t *target_dent = __devfs_find_dentry(parent_dentry, name);
-    if (target_dent->dir_inode->attribute & VFS_ATTR_DIR) // 名称相符且为目录,则返回dentry
+    if (target_dent->dir_inode->attribute & VFS_IF_DIR) // 名称相符且为目录,则返回dentry
         return target_dent;
     else
         return NULL; // 否则直接返回空

+ 8 - 8
kernel/filesystem/fat32/fat32.c

@@ -293,7 +293,7 @@ find_lookup_success:; // 找到目标dentry
     p->file_size = tmp_dEntry->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_ATTR_DIR : VFS_ATTR_FILE;
+    p->attribute = (tmp_dEntry->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;
@@ -315,8 +315,8 @@ find_lookup_success:; // 找到目标dentry
 
     // 暂时使用fat32的高4bit来标志设备文件
     // todo: 引入devfs后删除这段代码
-    if ((tmp_dEntry->DIR_FstClusHI >> 12) && (p->attribute & VFS_ATTR_FILE))
-        p->attribute |= VFS_ATTR_DEVICE;
+    if ((tmp_dEntry->DIR_FstClusHI >> 12) && (p->attribute & VFS_IF_FILE))
+        p->attribute |= VFS_IF_DEVICE;
 
     dest_dentry->dir_inode = p;
     dest_dentry->dir_ops = &fat32_dEntry_ops;
@@ -394,7 +394,7 @@ struct vfs_superblock_t *fat32_read_superblock(struct block_device *blk)
     sb_ptr->root->dir_inode->file_size = 0;
     // 计算文件占用的扇区数, 由于最小存储单位是簇,因此需要按照簇的大小来对齐扇区
     sb_ptr->root->dir_inode->blocks = (sb_ptr->root->dir_inode->file_size + fsbi->bytes_per_clus - 1) / fsbi->bytes_per_sec;
-    sb_ptr->root->dir_inode->attribute = VFS_ATTR_DIR;
+    sb_ptr->root->dir_inode->attribute = VFS_IF_DIR;
     sb_ptr->root->dir_inode->sb = sb_ptr; // 反向绑定对应的超级块
 
     // 初始化inode信息
@@ -826,7 +826,7 @@ long fat32_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t
 
     struct fat32_inode_info_t *finode = (struct fat32_inode_info_t *)kmalloc(sizeof(struct fat32_inode_info_t), 0);
     memset((void *)finode, 0, sizeof(struct fat32_inode_info_t));
-    inode->attribute = VFS_ATTR_FILE;
+    inode->attribute = VFS_IF_FILE;
     inode->file_ops = &fat32_file_ops;
     inode->file_size = 0;
     inode->sb = parent_inode->sb;
@@ -933,7 +933,7 @@ int64_t fat32_mkdir(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_
     // ====== 初始化inode =======
     struct vfs_index_node_t *inode = (struct vfs_index_node_t *)kmalloc(sizeof(struct vfs_index_node_t), 0);
     memset(inode, 0, sizeof(struct vfs_index_node_t));
-    inode->attribute = VFS_ATTR_DIR;
+    inode->attribute = VFS_IF_DIR;
     inode->blocks = fsbi->sec_per_clus;
     inode->file_ops = &fat32_file_ops;
     inode->file_size = 0;
@@ -1230,9 +1230,9 @@ find_dir_success:;
     file_ptr->position += 32;
     // todo: 计算ino_t
     if (dentry_type & ATTR_DIRECTORY)
-        dentry_type = VFS_ATTR_DIR;
+        dentry_type = VFS_IF_DIR;
     else
-        dentry_type = VFS_ATTR_FILE;
+        dentry_type = VFS_IF_FILE;
 
     return filler(dirent, 0, dir_name, name_len, dentry_type, 0);
 }

+ 2 - 2
kernel/filesystem/fat32/fat_ent.c

@@ -335,7 +335,7 @@ void fat32_fill_shortname(struct vfs_dir_entry_t *dEntry, struct fat32_Directory
             target->DIR_Name[tmp_index] = 0x20;
             ++tmp_index;
         }
-        if (dEntry->dir_inode->attribute & VFS_ATTR_DIR)
+        if (dEntry->dir_inode->attribute & VFS_IF_DIR)
         {
             while (tmp_index < 11)
             {
@@ -355,7 +355,7 @@ void fat32_fill_shortname(struct vfs_dir_entry_t *dEntry, struct fat32_Directory
 
     struct vfs_index_node_t *inode = dEntry->dir_inode;
     target->DIR_Attr = 0;
-    if (inode->attribute & VFS_ATTR_DIR)
+    if (inode->attribute & VFS_IF_DIR)
         target->DIR_Attr |= ATTR_DIRECTORY;
 
     target->DIR_FileSize = dEntry->dir_inode->file_size;

+ 1 - 1
kernel/process/process.c

@@ -154,7 +154,7 @@ struct vfs_file_t *process_open_exec_file(char *path)
     if (dentry == NULL)
         return (void *)-ENOENT;
 
-    if (dentry->dir_inode->attribute == VFS_ATTR_DIR)
+    if (dentry->dir_inode->attribute == VFS_IF_DIR)
         return (void *)-ENOTDIR;
 
     filp = (struct vfs_file_t *)kmalloc(sizeof(struct vfs_file_t), 0);

+ 4 - 2
kernel/syscall/syscall.c

@@ -19,6 +19,7 @@ extern void syscall_int(void);
 extern uint64_t sys_clock(struct pt_regs *regs);
 extern uint64_t sys_mstat(struct pt_regs *regs);
 extern uint64_t sys_open(struct pt_regs *regs);
+extern uint64_t sys_rmdir(struct pt_regs *regs);
 
 /**
  * @brief 导出系统调用处理函数的符号
@@ -415,7 +416,7 @@ uint64_t sys_chdir(struct pt_regs *regs)
         return -ENOENT;
     // kdebug("dentry->name=%s, namelen=%d", dentry->name, dentry->name_length);
     // 目标不是目录
-    if (dentry->dir_inode->attribute != VFS_ATTR_DIR)
+    if (dentry->dir_inode->attribute != VFS_IF_DIR)
         return -ENOTDIR;
 
     return 0;
@@ -602,5 +603,6 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] =
         [19] = sys_clock,
         [20] = sys_pipe,
         [21] = sys_mstat,
-        [22 ... 254] = system_call_not_exists,
+        [22] = sys_rmdir,
+        [23 ... 254] = system_call_not_exists,
         [255] = sys_ahci_end_req};

+ 5 - 0
kernel/syscall/syscall.h

@@ -15,6 +15,11 @@ extern void ret_from_system_call(void); // 导出从系统调用返回的函数
 
 extern system_call_t system_call_table[MAX_SYSTEM_CALL_NUM];
 
+// 判断系统调用是否来自用户态
+#define SYSCALL_FROM_USER(regs) ((regs)->cs & USER_CS)
+// 判断系统调用是否来自内核态
+#define SYSCALL_FROM_KERNEL(regs) (!SYSCALL_FROM_USER(regs))
+
 /**
  * @brief 初始化系统调用模块
  *

+ 1 - 0
kernel/syscall/syscall_num.h

@@ -33,6 +33,7 @@
 #define SYS_PIPE 20
 
 #define SYS_MSTAT 21    // 获取系统的内存状态信息
+#define SYS_RMDIR 22    // 删除文件夹
 
 
 #define SYS_AHCI_END_REQ 255    // AHCI DMA请求结束end_request的系统调用

+ 26 - 12
user/apps/shell/cmd.c

@@ -210,7 +210,7 @@ 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);
@@ -257,12 +257,12 @@ int shell_cmd_ls(int argc, char **argv)
             break;
 
         int color = COLOR_WHITE;
-        if (buf->d_type & VFS_ATTR_DIR)
+        if (buf->d_type & VFS_IF_DIR)
             color = COLOR_YELLOW;
-        else if (buf->d_type & VFS_ATTR_FILE)
+        else if (buf->d_type & VFS_IF_FILE)
             color = COLOR_INDIGO;
-        else if(buf->d_type & VFS_ATTR_DEVICE)
-            color= COLOR_GREEN;
+        else if (buf->d_type & VFS_IF_DEVICE)
+            color = COLOR_GREEN;
 
         char output_buf[256] = {0};
 
@@ -405,7 +405,21 @@ int shell_cmd_mkdir(int argc, char **argv)
  * @return int
  */
 // todo:
-int shell_cmd_rmdir(int argc, char **argv) {}
+int shell_cmd_rmdir(int argc, char **argv)
+{
+    const char *full_path = NULL;
+    int result_path_len = -1;
+    if (argv[1][0] == '/')
+        full_path = argv[1];
+    else
+        full_path = get_target_filepath(argv[1], &result_path_len);
+    int retval = rmdir(full_path);
+    printf("rmdir: path=%s, retval=%d", full_path, retval);
+    if (argv != NULL)
+        free(argv);
+
+    return retval;
+}
 
 /**
  * @brief 执行新的程序的命令
@@ -483,7 +497,7 @@ int shell_cmd_free(int argc, char **argv)
 
     struct mstat_t mst = {0};
     retval = mstat(&mst);
-    if(retval!=0)
+    if (retval != 0)
     {
         printf("Failed: retval=%d", retval);
         goto done;
@@ -491,15 +505,15 @@ int shell_cmd_free(int argc, char **argv)
 
     printf("\ttotal\tused\tfree\tshared\tcache\tavailable\n");
     printf("Mem:\t");
-    if(argc==1) // 按照kb显示
+    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显示
+    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:;
     if (argv != NULL)
         free(argv);

+ 4 - 4
user/libs/libc/dirent.h

@@ -3,12 +3,12 @@
 
 
 /**
- * @brief 目录项的属性(copy from vfs.h)
+ * @brief inode的属性(copy from vfs.h)
  *
  */
-#define VFS_ATTR_FILE (1UL << 0)
-#define VFS_ATTR_DIR (1UL << 1)
-#define VFS_ATTR_DEVICE (1UL << 2)
+#define VFS_IF_FILE (1UL << 0)
+#define VFS_IF_DIR (1UL << 1)
+#define VFS_IF_DEVICE (1UL << 2)
 
 #define DIR_BUF_SIZE 256
 /**

+ 14 - 2
user/libs/libc/unistd.c

@@ -142,7 +142,19 @@ int execv(const char *path, char *const argv[])
         return -1;
     }
     int retval = syscall_invoke(SYS_EXECVE, (uint64_t)path, (uint64_t)argv, 0, 0, 0, 0, 0, 0);
-    if(retval != 0)
+    if (retval != 0)
         return -1;
-    else return 0;
+    else
+        return 0;
+}
+
+/**
+ * @brief 删除文件夹
+ *
+ * @param path 绝对路径
+ * @return int 错误码
+ */
+int rmdir(const char *path)
+{
+    return syscall_invoke(SYS_RMDIR, (uint64_t)path, 0, 0, 0, 0, 0, 0, 0);
 }

+ 8 - 0
user/libs/libc/unistd.h

@@ -97,3 +97,11 @@ int execv(const char* path, char * const argv[]);
  * @return int 
  */
 extern int usleep(useconds_t usec);
+
+/**
+ * @brief 删除文件夹
+ * 
+ * @param path 绝对路径
+ * @return int 错误码
+ */
+int rmdir(const char* path);

+ 1 - 0
user/libs/libsystem/syscall.h

@@ -27,6 +27,7 @@
 #define SYS_PIPE 20
 
 #define SYS_MSTAT 21    // 获取系统的内存状态信息
+#define SYS_RMDIR 22    // 删除文件夹
 
 /**
  * @brief 用户态系统调用函数