mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 15:26:47 +00:00
* 对mkdir加锁 * 给mkdir和do_open的dentry加锁 * 对加锁进行了修改 * modified * bugfix: 修复一些死锁及空指针的错误 Co-authored-by: longjin <longjin@RinGoTek.cn>
720 lines
20 KiB
C
720 lines
20 KiB
C
#include "VFS.h"
|
||
#include "internal.h"
|
||
#include "mount.h"
|
||
#include <common/dirent.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';
|
||
|
||
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)
|
||
{
|
||
// 搜索失败
|
||
// kerror("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];
|
||
}
|
||
// kdebug("last_slash=%d", last_slash);
|
||
// kdebug("name=%s", path + last_slash + 1);
|
||
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 (regs->cs & USER_CS)
|
||
return vfs_mkdir(path, mode, true);
|
||
else
|
||
return vfs_mkdir(path, mode, false);
|
||
}
|
||
|
||
/**
|
||
* @brief 打开文件
|
||
*
|
||
* @param filename 文件路径
|
||
* @param flags 标志位
|
||
* @return uint64_t 错误码
|
||
*/
|
||
uint64_t do_open(const char *filename, int flags)
|
||
{
|
||
long path_len = strnlen_user(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;
|
||
|
||
strncpy_from_user(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 - 1;
|
||
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;
|
||
|
||
// 对父目录项加锁
|
||
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;
|
||
|
||
struct vfs_file_t **f = current_pcb->fds;
|
||
|
||
int fd_num = -1;
|
||
|
||
// 在指针数组中寻找空位
|
||
// todo: 当pcb中的指针数组改为动态指针数组之后,需要更改这里(目前还是静态指针数组)
|
||
for (int i = 0; i < PROC_MAX_FD_NUM; ++i)
|
||
{
|
||
if (f[i] == NULL) // 找到指针数组中的空位
|
||
{
|
||
fd_num = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 指针数组没有空位了
|
||
if (fd_num == -1)
|
||
{
|
||
kfree(file_ptr);
|
||
spin_unlock(&dentry->lockref.lock);
|
||
return -ENFILE;
|
||
}
|
||
// 保存文件描述符
|
||
f[fd_num] = file_ptr;
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* @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;
|
||
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加锁
|
||
spin_lock(&dentry->lockref.lock);
|
||
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); // 清理同样挂载在该路径的所有挂载点的挂载树
|
||
|
||
if (vfs_dentry_put(dentry) != 0)
|
||
goto out; // 释放dentry
|
||
return retval;
|
||
out:;
|
||
spin_unlock(&dentry->lockref.lock);
|
||
// 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 分配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;
|
||
} |