Skip to content

Commit

Permalink
✨ 092 系统调用 mkdir,rmdir
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenBaby committed Oct 28, 2022
1 parent c0b1aa3 commit 48f6534
Showing 7 changed files with 219 additions and 8 deletions.
11 changes: 11 additions & 0 deletions docs/11 文件系统/092 系统调用 mkdir,rmdir.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# 系统调用 mkdir,rmdir

完成以下系统调用:

```c++
// 创建目录
int mkdir(char *pathname, int mode);

// 删除目录
int rmdir(char *pathname);
```
186 changes: 182 additions & 4 deletions src/fs/namei.c
Original file line number Diff line number Diff line change
@@ -273,12 +273,190 @@ inode_t *namei(char *pathname)
return inode;
}

#include <onix/memory.h>
int sys_mkdir(char *pathname, int mode)
{
char *next = NULL;
buffer_t *ebuf = NULL;
inode_t *dir = named(pathname, &next);

// 父目录不存在
if (!dir)
goto rollback;

// 目录名为空
if (!*next)
goto rollback;

// 父目录无写权限
if (!permission(dir, P_WRITE))
goto rollback;

char *name = next;
dentry_t *entry;

ebuf = find_entry(&dir, name, &next, &entry);
// 目录项已存在
if (ebuf)
goto rollback;

void dir_test()
ebuf = add_entry(dir, name, &entry);
ebuf->dirty = true;
entry->nr = ialloc(dir->dev);

task_t *task = running_task();
inode_t *inode = iget(dir->dev, entry->nr);
inode->buf->dirty = true;

inode->desc->gid = task->gid;
inode->desc->uid = task->uid;
inode->desc->mode = (mode & 0777 & ~task->umask) | IFDIR;
inode->desc->size = sizeof(dentry_t) * 2; // 当前目录和父目录两个目录项
inode->desc->mtime = time(); // 时间戳
inode->desc->nlinks = 2; // 一个是 '.' 一个是 name

// 父目录链接数加 1
dir->buf->dirty = true;
dir->desc->nlinks++; // ..

// 写入 inode 目录中的默认目录项
buffer_t *zbuf = bread(inode->dev, bmap(inode, 0, true));
zbuf->dirty = true;

entry = (dentry_t *)zbuf->data;

strcpy(entry->name, ".");
entry->nr = inode->nr;

entry++;
strcpy(entry->name, "..");
entry->nr = dir->nr;

iput(inode);
iput(dir);

brelse(ebuf);
brelse(zbuf);
return 0;

rollback:
brelse(ebuf);
iput(dir);
return EOF;
}

static bool is_empty(inode_t *inode)
{
inode_t *inode = namei("/d1/d2/d3/../../../hello.txt");
assert(ISDIR(inode->desc->mode));

int entries = inode->desc->size / sizeof(dentry_t);
if (entries < 2 || !inode->desc->zone[0])
{
LOGK("bad directory on dev %d\n", inode->dev);
return false;
}

idx_t i = 0;
idx_t block = 0;
buffer_t *buf = NULL;
dentry_t *entry;
int count = 0;

for (; i < entries; i++, entry++)
{
if (!buf || (u32)entry >= (u32)buf->data + BLOCK_SIZE)
{
brelse(buf);
block = bmap(inode, i / BLOCK_DENTRIES, false);
assert(block);

buf = bread(inode->dev, block);
entry = (dentry_t *)buf->data;
}
if (entry->nr)
count++;
};

brelse(buf);

if (count < 2)
{
LOGK("bad directory on dev %d\n", inode->dev);
return false;
}

return count == 2;
}

int sys_rmdir(char *pathname)
{
char *next = NULL;
buffer_t *ebuf = NULL;
inode_t *dir = named(pathname, &next);
inode_t *inode = NULL;
int ret = EOF;

// 父目录不存在
if (!dir)
goto rollback;

// 目录名为空
if (!*next)
goto rollback;

// 父目录无写权限
if (!permission(dir, P_WRITE))
goto rollback;

char *name = next;
dentry_t *entry;

ebuf = find_entry(&dir, name, &next, &entry);
// 目录项不存在
if (!ebuf)
goto rollback;

inode = iget(dir->dev, entry->nr);
if (!inode)
goto rollback;

if (inode == dir)
goto rollback;

if (!ISDIR(inode->desc->mode))
goto rollback;

task_t *task = running_task();
if ((dir->desc->mode & ISVTX) && task->uid != inode->desc->uid)
goto rollback;

if (dir->dev != inode->dev || inode->count > 1)
goto rollback;

if (!is_empty(inode))
goto rollback;

assert(inode->desc->nlinks == 2);

inode_truncate(inode);
ifree(inode->dev, inode->nr);

inode->desc->nlinks = 0;
inode->buf->dirty = true;
inode->nr = 0;

dir->desc->nlinks--;
dir->ctime = dir->atime = dir->desc->mtime = time();
dir->buf->dirty = true;
assert(dir->desc->nlinks > 0);

entry->nr = 0;
ebuf->dirty = true;

ret = 0;

rollback:
iput(inode);
}
iput(dir);
brelse(ebuf);
return ret;
}
5 changes: 5 additions & 0 deletions src/include/onix/syscall.h
Original file line number Diff line number Diff line change
@@ -16,6 +16,8 @@ typedef enum syscall_t
SYS_NR_WAITPID = 7,
SYS_NR_TIME = 13,
SYS_NR_GETPID = 20,
SYS_NR_MKDIR = 39,
SYS_NR_RMDIR = 40,
SYS_NR_BRK = 45,
SYS_NR_UMASK = 60,
SYS_NR_GETPPID = 64,
@@ -39,6 +41,9 @@ int32 brk(void *addr);

int32 write(fd_t fd, char *buf, u32 len);

int mkdir(char *pathname, int mode);
int rmdir(char *pathname);

time_t time();

mode_t umask(mode_t mask);
9 changes: 6 additions & 3 deletions src/kernel/gate.c
Original file line number Diff line number Diff line change
@@ -30,9 +30,6 @@ static void sys_default()

static u32 sys_test()
{
extern void dir_test();
dir_test();

char ch;
device_t *device;

@@ -60,6 +57,9 @@ int32 sys_write(fd_t fd, char *buf, u32 len)
return 0;
}

extern int sys_mkdir();
extern int sys_rmdir();

extern time_t sys_time();
extern mode_t sys_umask();

@@ -86,6 +86,9 @@ void syscall_init()

syscall_table[SYS_NR_WRITE] = sys_write;

syscall_table[SYS_NR_MKDIR] = sys_mkdir;
syscall_table[SYS_NR_RMDIR] = sys_rmdir;

syscall_table[SYS_NR_TIME] = sys_time;

syscall_table[SYS_NR_UMASK] = sys_umask;
5 changes: 4 additions & 1 deletion src/kernel/thread.c
Original file line number Diff line number Diff line change
@@ -58,9 +58,12 @@ void init_thread()
void test_thread()
{
set_interrupt_state(true);
test();
// test();
mkdir("/world.txt", 0755);
rmdir("/empty");
while (true)
{
test();
sleep(10);
}
}
10 changes: 10 additions & 0 deletions src/lib/syscall.c
Original file line number Diff line number Diff line change
@@ -90,6 +90,16 @@ int32 write(fd_t fd, char *buf, u32 len)
return _syscall3(SYS_NR_WRITE, fd, (u32)buf, len);
}

int mkdir(char *pathname, int mode)
{
return _syscall2(SYS_NR_MKDIR, (u32)pathname, (u32)mode);
}

int rmdir(char *pathname)
{
return _syscall1(SYS_NR_RMDIR, (u32)pathname);
}

time_t time()
{
return _syscall0(SYS_NR_TIME);
1 change: 1 addition & 0 deletions src/utils/image.mk
Original file line number Diff line number Diff line change
@@ -36,6 +36,7 @@ $(BUILD)/master.img: $(BUILD)/boot/boot.bin \
sudo chown ${USER} /mnt

# 创建目录
mkdir -p /mnt/empty
mkdir -p /mnt/home
mkdir -p /mnt/d1/d2/d3/d4

0 comments on commit 48f6534

Please sign in to comment.