#include "VFS.h"
#include "internal.h"
#include "mount.h"
#include <common/dirent.h>
#include <common/err.h>
#include <common/errno.h>
#include <common/kprint.h>
#include <common/string.h>
#include <debug/bug.h>
#include <filesystem/rootfs/rootfs.h>
#include <mm/mm.h>
#include <mm/slab.h>
#include <process/process.h>
#include <process/ptrace.h>

// 为filesystem_type_t结构体实例化一个链表头
static struct vfs_filesystem_type_t vfs_fs = {"filesystem", 0};
struct vfs_superblock_t *vfs_root_sb = NULL;

struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size);

/**
 * @brief 挂载文件系统
 *
 * @param path 要挂载到的路径
 * @param name 文件系统名
 * @param blk 块设备结构体
 * @return struct vfs_superblock_t* 挂载后，文件系统的超级块
 */
struct vfs_superblock_t *vfs_mount_fs(const char *path, char *name, struct block_device *blk)
{

    // 判断挂载点是否存在
    struct vfs_dir_entry_t *target_dentry = NULL;

    target_dentry = vfs_path_walk(path, 0);
    if (target_dentry == NULL)
        return NULL;

    struct vfs_filesystem_type_t *p = NULL;
    for (p = &vfs_fs; p; p = p->next)
    {
        if (!strcmp(p->name, name)) // 存在符合的文件系统
        {
            struct vfs_superblock_t *sb = p->read_superblock(blk);
            if (strcmp(path, "/") == 0) // 如果挂载到的是'/'挂载点，则让其成为最顶层的文件系统
            {
                vfs_root_sb = sb;
            }
            else
            {
                kdebug("to mount %s", name);
                // 调用mount机制，挂载文件系统
                struct vfs_dir_entry_t *new_dentry = sb->root;
                // 注意，umount的时候需要释放这些内存
                new_dentry->name = kzalloc(target_dentry->name_length + 1, 0);
                new_dentry->name_length = target_dentry->name_length;

                do_mount(target_dentry, new_dentry);
            }
            return sb;
        }
    }

    kdebug("unsupported fs: %s", name);
    return NULL;
}

/**
 * @brief 在VFS中注册文件系统
 *
 * @param fs 文件系统类型结构体
 * @return uint64_t
 */
uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs)
{
    struct vfs_filesystem_type_t *p = NULL;
    for (p = &vfs_fs; p; p = p->next)
    {
        if (!strcmp(p->name, fs->name)) // 已经注册相同名称的文件系统
            return -EEXIST;
    }

    fs->next = vfs_fs.next;
    vfs_fs.next = fs;
    return 0;
}

uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs)
{
    struct vfs_filesystem_type_t *p = &vfs_fs;
    while (p->next)
    {
        if (p->next == fs)
        {
            p->next = p->next->next;
            fs->next = NULL;
            return 0;
        }
        else
            p = p->next;
    }
    return -EINVAL;
}

/**
 * @brief 在dentry的sub_dir_list中搜索指定名称的dentry
 *
 * @param dentry 目录项结构体dentry
 * @param name 待搜索的dentry名称
 * @return struct vfs_dir_entry_t* 目标dentry （无结果则返回NULL）
 */
static struct vfs_dir_entry_t *vfs_search_dentry_list(struct vfs_dir_entry_t *dentry, const char *name)
{
    if (list_empty(&dentry->subdirs_list))
        return NULL;

    struct List *ptr = &dentry->subdirs_list;
    struct vfs_dir_entry_t *d_ptr = NULL;
    do
    {
        ptr = list_next(ptr);
        d_ptr = container_of(ptr, struct vfs_dir_entry_t, child_node_list);
        if (strcmp(name, d_ptr->name) == 0)
            return d_ptr;
    } while (list_next(ptr) != (&dentry->subdirs_list));

    return NULL;
}

/**
 * @brief 按照路径查找文件
 *
 * @param path 路径
 * @param flags 1：返回父目录项， 0：返回结果目录项
 * @return struct vfs_dir_entry_t* 目录项
 */
struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags)
{

    struct vfs_dir_entry_t *parent = vfs_root_sb->root;
    // 去除路径前的斜杠
    while (*path == '/')
        ++path;

    if ((!*path) || (*path == '\0'))
        return parent;

    struct vfs_dir_entry_t *dentry = NULL;
    // kdebug("path before walk:%s", path);
    while (true)
    {
        // 提取出下一级待搜索的目录名或文件名，并保存在dEntry_name中
        const char *tmp_path = path;
        while ((*path && *path != '\0') && (*path != '/'))
            ++path;
        int tmp_path_len = path - tmp_path;
        // 搜索是否有dentry缓存
        {
            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);
        }

        // 如果没有找到dentry缓存，则申请新的dentry
        if (dentry == NULL)
        {
            dentry = vfs_alloc_dentry(tmp_path_len + 1);

            memcpy(dentry->name, (void *)tmp_path, tmp_path_len);
            dentry->name[tmp_path_len] = '\0';
            // kdebug("tmp_path_len=%d, dentry->name=%s", tmp_path_len, dentry->name);
            dentry->name_length = tmp_path_len;

            if (parent->dir_inode->inode_ops->lookup(parent->dir_inode, dentry) == NULL)
            {
                // 搜索失败
                // kwarn("cannot find the file/dir : %s", dentry->name);
                kfree(dentry->name);
                kfree(dentry);
                return NULL;
            }
            // 找到子目录项
            dentry->parent = parent;

            list_add(&parent->subdirs_list, &dentry->child_node_list);
        }

        while (*path == '/')
            ++path;

        if ((!*path) || (*path == '\0')) //  已经到达末尾
        {
            if (flags & 1) // 返回父目录
            {
                return parent;
            }

            return dentry;
        }

        parent = dentry;
    }
}

/**
 * @brief 填充dentry
 *
 * @return dirent的总大小
 */
int vfs_fill_dirent(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset)
{
    struct dirent *dent = (struct dirent *)buf;

    // 如果尝试访问内核空间，则返回错误
    if (!(verify_area((uint64_t)buf, sizeof(struct dirent) + namelen)))
        return -EFAULT;

    // ====== 填充dirent结构体 =====
    memset(buf, 0, sizeof(struct dirent) + namelen);

    memcpy(dent->d_name, name, namelen);
    dent->d_name[namelen] = '\0';
    // 暂时不显示目录下的记录数
    dent->d_reclen = 0;
    dent->d_ino = d_ino;
    dent->d_off = offset;
    dent->d_type = type;

    // 返回dirent的总大小
    return sizeof(struct dirent) + namelen;
}

/**
 * @brief 创建文件夹
 *
 * @param path 文件夹路径
 * @param mode 创建模式
 * @param from_userland 该创建请求是否来自用户态
 * @return int64_t 错误码
 */
int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland)
{
    uint32_t pathlen;
    int retval = 0;
    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 - 2; i >= 0; --i)
    {
        if (path[i] == '/')
        {
            last_slash = i;
            break;
        }
    }

    // 路径格式不合法（必须使用绝对路径）
    if (last_slash < 0)
        return -ENOTDIR;

    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 *parent_dir = vfs_path_walk(buf, 0);

    if (parent_dir == NULL)
    {
        kwarn("parent dir is NULL.");
        kfree(buf);
        return -ENOENT;
    }
    kfree(buf);

    // 检查父目录中是否已经有相同的目录项
    if (vfs_path_walk((const char *)path, 0) != NULL)
    {
        // 目录中已有对应的文件夹
        kwarn("Dir '%s' aleardy exists.", path);
        return -EEXIST;
    }
    spin_lock(&parent_dir->lockref.lock);
    struct vfs_dir_entry_t *subdir_dentry = vfs_alloc_dentry(pathlen - last_slash);

    if (path[pathlen - 1] == '/')
        subdir_dentry->name_length = pathlen - last_slash - 2;
    else
        subdir_dentry->name_length = pathlen - last_slash - 1;

    for (int i = last_slash + 1, cnt = 0; i < pathlen && cnt < subdir_dentry->name_length; ++i, ++cnt)
        subdir_dentry->name[cnt] = path[i];
    // 设置subdir的dentry的父路径
    subdir_dentry->parent = parent_dir;

    // kdebug("to mkdir, parent name=%s", parent_dir->name);
    spin_lock(&parent_dir->dir_inode->lockref.lock);
    retval = parent_dir->dir_inode->inode_ops->mkdir(parent_dir->dir_inode, subdir_dentry, 0);
    spin_unlock(&parent_dir->dir_inode->lockref.lock);

    if (retval != 0)
    {
        if (vfs_dentry_put(parent_dir) != 0) // 释放dentry
            spin_unlock(&parent_dir->lockref.lock);
        return retval;
    }

    // 获取append前一个dentry并加锁
    struct List *target_list = &parent_dir->subdirs_list;
    // kdebug("target_list=%#018lx target_list->prev=%#018lx",target_list,target_list->prev);
    if (list_empty(target_list) == false)
    {
        struct vfs_dir_entry_t *prev_dentry = list_entry(target_list->prev, struct vfs_dir_entry_t, child_node_list);
        // kdebug("prev_dentry%#018lx",prev_dentry);
        spin_lock(&prev_dentry->lockref.lock);
        list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list);
        // kdebug("retval = %d", retval);
        spin_unlock(&prev_dentry->lockref.lock);
    }
    else
    {
        list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list);
        goto out;
    }

out:;
    spin_unlock(&parent_dir->lockref.lock);
    return retval;
}

/**
 * @brief 创建文件夹
 *
 * @param path(r8) 路径
 * @param mode(r9) 模式
 * @return uint64_t
 */
uint64_t sys_mkdir(struct pt_regs *regs)
{
    const char *path = (const char *)regs->r8;
    // kdebug("path = %s", path);
    mode_t mode = (mode_t)regs->r9;

    if (user_mode(regs))
        return vfs_mkdir(path, mode, true);
    else
        return vfs_mkdir(path, mode, false);
}

/**
 * @brief 打开文件
 *
 * @param filename 文件路径
 * @param flags 标志位
 * @param from_user 是否由用户态调用,1为是，0为否
 * @return uint64_t 错误码
 */
uint64_t do_open(const char *filename, int flags, bool from_user)
{
    long path_len = 0;
    if (from_user)
        path_len = strnlen_user(filename, PAGE_4K_SIZE) + 1;
    else
        path_len = strnlen(filename, PAGE_4K_SIZE) + 1;

    if (path_len <= 0) // 地址空间错误
        return -EFAULT;
    else if (path_len >= PAGE_4K_SIZE) // 名称过长
        return -ENAMETOOLONG;

    // 为待拷贝文件路径字符串分配内存空间
    char *path = (char *)kzalloc(path_len, 0);
    if (path == NULL)
        return -ENOMEM;
    
    if (from_user)
        strncpy_from_user(path, filename, path_len);
    else
        strncpy(path, filename, path_len);
    
    // 去除末尾的 '/'
    if (path_len >= 2 && path[path_len - 2] == '/')
    {
        path[path_len - 2] = '\0';
        --path_len;
    }

    // 寻找文件
    struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0);
    if (dentry == NULL && flags & O_CREAT)
    {
        // 先找到倒数第二级目录
        int tmp_index = -1;
        for (int i = path_len - 1; i >= 0; --i)
        {
            if (path[i] == '/')
            {
                tmp_index = i;
                break;
            }
        }

        struct vfs_dir_entry_t *parent_dentry = NULL;
        // kdebug("tmp_index=%d", tmp_index);
        if (tmp_index > 0)
        {

            path[tmp_index] = '\0';
            parent_dentry = vfs_path_walk(path, 0);
            if (parent_dentry == NULL)
            {
                kfree(path);
                return -ENOENT;
            }
        }
        else
        {
            parent_dentry = vfs_root_sb->root;
        }
        // 创建新的文件
        dentry = vfs_alloc_dentry(path_len - tmp_index);

        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);
        dentry->parent = parent_dentry;

        // 对父目录项加锁
        spin_lock(&parent_dentry->lockref.lock);
        spin_lock(&parent_dentry->dir_inode->lockref.lock);
        // 创建子目录项
        uint64_t retval = parent_dentry->dir_inode->inode_ops->create(parent_dentry->dir_inode, dentry, 0);
        spin_unlock(&parent_dentry->dir_inode->lockref.lock); // 解锁inode

        if (retval != 0)
        {
            if (vfs_dentry_put(dentry) != 0) // 释放dentry
                BUG_ON(1);
            BUG_ON(1);
            kfree(path);
            spin_unlock(&parent_dentry->lockref.lock);
            return retval;
        }

        // ==== 将子目录项添加到链表 ====
        struct vfs_dir_entry_t *next_dentry = NULL;
        // 若list非空，则对前一个dentry加锁
        if (!list_empty(&parent_dentry->subdirs_list))
        {
            next_dentry = list_entry(list_next(&parent_dentry->subdirs_list), struct vfs_dir_entry_t, child_node_list);
            spin_lock(&next_dentry->lockref.lock);
        }
        list_add(&parent_dentry->subdirs_list, &dentry->child_node_list);
        if (next_dentry != NULL)
            spin_unlock(&next_dentry->lockref.lock);

        // 新建文件结束，对父目录项解锁
        spin_unlock(&parent_dentry->lockref.lock);
        // kdebug("created.");
    }

    kfree(path);
    if (dentry == NULL)
    {
        return -ENOENT;
    }
    spin_lock(&dentry->lockref.lock);
    // 要求打开文件夹而目标不是文件夹
    if ((flags & O_DIRECTORY) && (dentry->dir_inode->attribute != VFS_IF_DIR))
    {
        spin_unlock(&dentry->lockref.lock);
        return -ENOTDIR;
    }
    // 创建文件描述符
    struct vfs_file_t *file_ptr = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0);

    int errcode = -1;

    file_ptr->dEntry = dentry;
    file_ptr->mode = flags;

    file_ptr->file_ops = dentry->dir_inode->file_ops;

    // 如果文件系统实现了打开文件的函数
    if (file_ptr->file_ops && file_ptr->file_ops->open)
        errcode = file_ptr->file_ops->open(dentry->dir_inode, file_ptr);

    if (errcode != 0)
    {
        kfree(file_ptr);
        spin_unlock(&dentry->lockref.lock);
        return -EFAULT;
    }

    if (file_ptr->mode & O_TRUNC) // 清空文件
        file_ptr->dEntry->dir_inode->file_size = 0;

    if (file_ptr->mode & O_APPEND)
        file_ptr->position = file_ptr->dEntry->dir_inode->file_size;
    else
        file_ptr->position = 0;

    int fd_num = process_fd_alloc(file_ptr);

    // 指针数组没有空位了
    if (fd_num == -1)
    {
        kfree(file_ptr);
        spin_unlock(&dentry->lockref.lock);
        return -ENFILE;
    }
    spin_unlock(&dentry->lockref.lock);
    return fd_num;
}

uint64_t sys_open(struct pt_regs *regs)
{
    char *filename = (char *)(regs->r8);
    int flags = (int)(regs->r9);
    return do_open(filename, flags, true);
}

/**
 * @brief 关闭文件
 *
 * @param fd_num 文件描述符
 * @return uint64_t 错误码
 */
uint64_t vfs_close(int fd_num)
{
    // 校验文件描述符范围
    if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM)
        return -EBADF;
    // 文件描述符不存在
    if (current_pcb->fds[fd_num] == NULL)
        return -EBADF;
    struct vfs_file_t *file_ptr = current_pcb->fds[fd_num];
    uint64_t ret;
    // If there is a valid close function
    if (file_ptr->file_ops && file_ptr->file_ops->close)
        ret = file_ptr->file_ops->close(file_ptr->dEntry->dir_inode, file_ptr);

    kfree(file_ptr);
    current_pcb->fds[fd_num] = NULL;
    return 0;
}
/**
 * @brief 动态分配dentry以及路径字符串名称
 *
 * @param name_size 名称字符串大小（字节）(注意考虑字符串最后需要有一个‘\0’作为结尾)
 * @return struct vfs_dir_entry_t* 创建好的dentry
 */
struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size)
{
    if (unlikely(name_size > VFS_MAX_PATHLEN))
        return NULL;
    struct vfs_dir_entry_t *dentry = (struct vfs_dir_entry_t *)kzalloc(sizeof(struct vfs_dir_entry_t), 0);
    if (unlikely(dentry == NULL))
        return NULL;
    if (name_size != 0)
        dentry->name = (char *)kzalloc(name_size, 0);

    // 初始化lockref
    spin_init(&dentry->lockref.lock);
    dentry->lockref.count = 1;
    // 初始化链表
    list_init(&dentry->child_node_list);
    list_init(&dentry->subdirs_list);
    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;
    int retval = 0;
    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);

    kfree(buf);

    if (dentry == NULL)
    {
        retval = -ENOENT;
        goto out0;
    }

    // todo: 检查文件夹是否为空

    spin_lock(&dentry->lockref.lock);
    retval = vfs_may_delete(dentry, true);
    if (retval != 0)
        goto out1;
    // todo: 对dentry和inode加锁
    retval = -EBUSY;
    if (is_local_mountpoint(dentry))
        goto out1;
    // todo:
    retval = dentry->dir_inode->inode_ops->rmdir(dentry->dir_inode, dentry);
    if (retval != 0)
    {
        BUG_ON(1);
        goto out1;
    }

    dentry->dir_inode->attribute |= VFS_IF_DEAD; // 将当前inode标记为dead
    dont_mount(dentry);                          // 将当前dentry标记为不可被挂载
    detach_mounts(dentry);                       // 清理同样挂载在该路径的所有挂载点的挂载树

    // 释放dentry
    retval = vfs_dentry_put(dentry);

    if (retval != 0)
        goto out1;
    goto out0;
out2:;
    spin_unlock(&dentry->dir_inode->lockref.lock);
out1:;
    spin_unlock(&dentry->lockref.lock);
out0:;
    return retval;
}

/**
 * @brief unlink a filesystem object
 *
 * 调用者必须持有parent_inode->lockref.lock
 *
 * @param mnt_userns 暂时未使用 用户命名空间. 请置为NULL
 * @param parent_inode 父目录项的inode
 * @param dentry 要被删除的目录项
 * @param delegated_inode 暂未使用，请置为NULL
 * @return int
 */
int vfs_unlink(struct user_namespace *mnt_userns, struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dentry,
               struct vfs_index_node_t **delegated_inode)
{
    // 暂时不支持用户命名空间，因此发出警告
    if (unlikely(mnt_userns != NULL))
    {
        WARN_ON(1);
        return -EINVAL;
    }

    int retval = 0;
    struct vfs_index_node_t *target = dentry->dir_inode;

    retval = vfs_may_delete(dentry, false);
    if (unlikely(retval != 0))
        return retval;

    // 没有unlink方法，则不允许删除
    if (!parent_inode->inode_ops->unlink)
        return -EPERM;

    // 对inode加锁
    spin_lock(&target->lockref.lock);

    if (is_local_mountpoint(dentry))
        retval = -EBUSY;
    else
    {
        retval = parent_inode->inode_ops->unlink(parent_inode, dentry);
        if (retval == 0)
        {
            dont_mount(dentry);
            detach_mounts(dentry);
        }
    }

    spin_unlock(&target->lockref.lock);

out:;
    return retval;
}
/**
 * @brief 取消dentry和inode之间的链接
 *
 * @param dfd 进程相对路径基准目录的文件描述符(fcntl.h)
 * @param pathname 路径
 * @param from_userland 请求是否来自用户态
 * @return int 错误码
 */
int do_unlink_at(int dfd, const char *pathname, bool from_userland)
{
    // 暂时不支持相对路径，只支持绝对路径
    if (dfd & AT_FDCWD)
    {
        kwarn("Not support: AT_FDCWD");
        return -EINVAL;
    }

    uint32_t pathlen;
    int retval = 0;
    if (from_userland)
        pathlen = strnlen_user(pathname, PAGE_4K_SIZE - 1);
    else
        pathlen = strnlen(pathname, PAGE_4K_SIZE - 1);

    if (pathlen == 0)
        return -ENOENT;

    int last_slash = -1;

    // 去除末尾的'/'
    for (int i = pathlen - 1; i >= 0; --i)
    {
        if (pathname[i] != '/')
        {
            last_slash = i + 1;
            break;
        }
    }

    // 路径格式不合法
    if (last_slash < 0)
        return -ENOTDIR;
    else if (pathname[0] != '/')
        return -EINVAL;

    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] = '\0';

    struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0);
    kfree(buf);

    if (dentry == NULL || dentry->parent == NULL)
    {
        retval = -ENOENT;
        goto out;
    }

    struct vfs_index_node_t *p_inode = dentry->parent->dir_inode;
    // 对父inode加锁
    spin_lock(&p_inode->lockref.lock);
    spin_lock(&dentry->lockref.lock);
    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_VALUE(retval))
        kwarn("In do_unlink_at: dentry put failed; retval=%d", retval);
    else
        retval = 0;
out:;
    return retval;
}

/**
 * @brief 删除文件夹、取消文件的链接、删除文件的系统调用
 *
 * @param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h)
 * @param regs->r9 路径名称字符串
 * @param regs->r10 flag 预留的标志位，暂时未使用，请置为0。
 * @return uint64_t 错误码
 */
uint64_t sys_unlink_at(struct pt_regs *regs)
{
    int dfd = regs->r8;
    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);
}

/**
 * @brief 分配inode并将引用计数初始化为1
 *
 * @return struct vfs_index_node_t * 分配得到的inode
 */
struct vfs_index_node_t *vfs_alloc_inode()
{
    struct vfs_index_node_t *inode = kzalloc(sizeof(struct vfs_index_node_t), 0);
    spin_init(&inode->lockref.lock);
    inode->lockref.count = 1; // 初始化引用计数为1
    return inode;
}

/**
 * @brief 初始化vfs
 *
 * @return int 错误码
 */
int vfs_init()
{
    mount_init();
    rootfs_init();
    return 0;
}