Skip to content

Commit

Permalink
Implement rename syscall, and mv
Browse files Browse the repository at this point in the history
  • Loading branch information
29jm committed Nov 25, 2020
1 parent 312c7c4 commit 4098fd2
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 1 deletion.
3 changes: 3 additions & 0 deletions kernel/include/kernel/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ typedef struct fs_t {
folder_inode_t* root;
uint32_t uid;
uint32_t (*create)(struct fs_t*, const char*, uint32_t, uint32_t);
int32_t (*rename)(struct fs_t*, uint32_t, uint32_t, uint32_t);
int32_t (*unlink)(struct fs_t*, uint32_t, uint32_t);
uint32_t (*read)(struct fs_t*, uint32_t, uint32_t, uint8_t*, uint32_t);
uint32_t (*append)(struct fs_t*, uint32_t, uint8_t*, uint32_t);
Expand All @@ -52,6 +53,7 @@ typedef sos_directory_entry_t* (*fs_readdir_t)(struct fs_t*, uint32_t, uint32_t)
typedef uint32_t (*fs_append_t)(struct fs_t*, uint32_t, uint8_t*, uint32_t);
typedef uint32_t (*fs_read_t)(struct fs_t*, uint32_t, uint32_t, uint8_t*, uint32_t);
typedef int32_t (*fs_unlink_t)(struct fs_t*, uint32_t, uint32_t);
typedef int32_t (*fs_rename_t)(struct fs_t*, uint32_t, uint32_t, uint32_t);
typedef uint32_t (*fs_create_t)(struct fs_t*, const char*, uint32_t, uint32_t);
typedef int32_t (*fs_close_t)(struct fs_t*, uint32_t);

Expand All @@ -61,6 +63,7 @@ char* fs_normalize_path(const char* p);
inode_t* fs_open(const char* path, uint32_t mode);
uint32_t fs_mkdir(const char* path, uint32_t mode);
int32_t fs_unlink(const char* path);
int32_t fs_rename(const char* oldp, const char* newp);
int32_t fs_close(inode_t* in);
uint32_t fs_read(inode_t* in, uint32_t offset, uint8_t* buf, uint32_t size);
uint32_t fs_write(inode_t* in, uint8_t* buf, uint32_t size);
Expand Down
3 changes: 2 additions & 1 deletion kernel/include/kernel/uapi/uapi_syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
#define SYS_CHDIR 17
#define SYS_GETCWD 18
#define SYS_UNLINK 19
#define SYS_MAX 20 // First invalid syscall number
#define SYS_RENAME 20
#define SYS_MAX 21 // First invalid syscall number

#define SYS_INFO_UPTIME 1
#define SYS_INFO_MEMORY 2
Expand Down
58 changes: 58 additions & 0 deletions kernel/src/misc/ext2.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ typedef struct ext2_fs_t {

uint32_t ext2_create(ext2_fs_t* fs, const char* name, uint32_t type, uint32_t parent_inode);
int32_t ext2_unlink(ext2_fs_t* fs, uint32_t d_ino, uint32_t ino);
int32_t ext2_rename(ext2_fs_t* fs, uint32_t dir_ino, uint32_t ino, uint32_t destdir_ino);
uint32_t ext2_mkdir(ext2_fs_t* fs, const char* name, uint32_t parent_inode);
uint32_t ext2_read(ext2_fs_t* fs, uint32_t inode, uint32_t offset, uint8_t* buf, uint32_t size);
uint32_t ext2_append(ext2_fs_t* fs, uint32_t inode, uint8_t* data, uint32_t size);
Expand Down Expand Up @@ -205,6 +206,7 @@ fs_t* init_ext2(uint8_t* data, uint32_t len) {

e2fs->fs.append = (fs_append_t) ext2_append;
e2fs->fs.create = (fs_create_t) ext2_create;
e2fs->fs.rename = (fs_rename_t) ext2_rename;
e2fs->fs.get_fs_inode = (fs_get_fs_inode_t) ext2_get_fs_inode;
e2fs->fs.read = (fs_read_t) ext2_read;
e2fs->fs.readdir = (fs_readdir_t) ext2_readdir;
Expand Down Expand Up @@ -254,6 +256,57 @@ int32_t ext2_unlink(ext2_fs_t* fs, uint32_t d_ino, uint32_t ino) {
return 0;
}

/* Move `ino` whose parent directory is `dir_ino`, to the directory `destdir_ino`.
*/
int32_t ext2_rename(ext2_fs_t* fs, uint32_t dir_ino, uint32_t ino, uint32_t destdir_ino) {
list_t* entries = directory_to_entries(fs, dir_ino);
list_t* iter;
dentry_t* ent;

if (!entries) {
return -1;
}

/* Look for the file to move, remove it from the list */
list_for_each(iter, ent, entries) {
if (ent->inode == ino) {
list_del(iter);
break;
}
}

/* Not found */
if (iter == entries) {
free_directory_entries(entries);
kfree(entries);

return -1;
}

/* Update the destination dir's list */
list_t* new_entries = directory_to_entries(fs, destdir_ino);

if (!new_entries) {
free_directory_entries(entries);
kfree(entries);

return -1;
}

list_add(new_entries, make_directory_entry(ent->name, ent->inode, ent->type));

/* Write changes to disk */
write_directory_entries(fs, destdir_ino, new_entries);
write_directory_entries(fs, dir_ino, entries);

free_directory_entries(entries);
kfree(entries);
free_directory_entries(new_entries);
kfree(new_entries);

return 0;
}

/* Appends `size` bytes from `data` to the file pointed to by `inode`.
* Returns the number of bytes written.
*/
Expand Down Expand Up @@ -906,6 +959,11 @@ static list_t* directory_to_entries(ext2_fs_t* fs, uint32_t ino) {
ext2_inode_t* in = get_inode(fs, ino);
uint32_t offset = 0;

if (!in) {
kfree(list);
return NULL;
}

while (offset < in->size_lower) {
ent = ext2_readdir(fs, ino, offset);

Expand Down
72 changes: 72 additions & 0 deletions kernel/src/misc/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,78 @@ int32_t fs_unlink(const char* path) {
return 0;
}

/* Renames the file pointed to by `oldp` to `newp`, moving it across directories
* as needed. See "man 2 rename" for the expected behavior.
* Note: doesn't support renaming a directory to an existing empty directory.
*/
int32_t fs_rename(const char* oldp, const char* newp) {
inode_t* old = fs_open(oldp, O_RDONLY);
inode_t* new = fs_open(newp, O_RDONLY);

if (!old) {
return -1;
}

if (old->type == DENT_DIRECTORY && new) {
return -1;
}

/* Both point to the same file */
if (new == old) {
return 0;
}

/* Moving across filesystems is unsupported right now */
if (new && new->fs != old->fs) {
return -1;
}

/* Destination will be replaced, remove it */
if (new) {
if (fs_unlink(newp) == -1) {
return -1;
}
}

/* Do the renaming on the fs */
char* noldp = fs_normalize_path(oldp);
char* nnewp = fs_normalize_path(newp);
folder_inode_t* src = (folder_inode_t*) fs_open(dirname(noldp), O_RDONLY);
folder_inode_t* dst = (folder_inode_t*) fs_open(dirname(nnewp), O_RDONLY);

int32_t ret = FS(old)->rename(FS(old), src->ino.inode_no, old->inode_no, dst->ino.inode_no);

if (ret == -1) {
kfree(noldp);
kfree(nnewp);
return -1;
}

/* Rename in VFS too: remove from the original parent directory */
list_t* to_iterate = old->type == DENT_DIRECTORY ?
&src->subfolders : &src->subfiles;
list_t* iter;
tnode_t* tn;
list_for_each(iter, tn, to_iterate) {
if (tn->inode->inode_no == old->inode_no) {
list_del(iter);
break;
}
}

/* Add to the destination parent directory */
kfree(tn->name);
tn->name = strdup(basename(nnewp));
list_t* to_add_to = old->type == DENT_DIRECTORY ?
&dst->subfolders : &dst->subfiles;
list_add(to_add_to, tn);

kfree(noldp);
kfree(nnewp);

return 0;
}

/* A process has released its grip on a file: notify the fs.
*/
int32_t fs_close(inode_t* in) {
Expand Down
9 changes: 9 additions & 0 deletions kernel/src/sys/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static void syscall_ftell(registers_t* regs);
static void syscall_chdir(registers_t* regs);
static void syscall_getcwd(registers_t* regs);
static void syscall_unlink(registers_t* regs);
static void syscall_rename(registers_t* regs);

handler_t syscall_handlers[SYSCALL_NUM] = { 0 };

Expand All @@ -60,6 +61,7 @@ void init_syscall() {
syscall_handlers[SYS_CHDIR] = syscall_chdir;
syscall_handlers[SYS_GETCWD] = syscall_getcwd;
syscall_handlers[SYS_UNLINK] = syscall_unlink;
syscall_handlers[SYS_RENAME] = syscall_rename;
}

static void syscall_handler(registers_t* regs) {
Expand Down Expand Up @@ -252,4 +254,11 @@ static void syscall_unlink(registers_t* regs) {
char* path = (char*) regs->ebx;

regs->eax = fs_unlink(path);
}

static void syscall_rename(registers_t* regs) {
char* old_path = (char*) regs->ebx;
char* new_path = (char*) regs->ecx;

regs->eax = fs_rename(old_path, new_path);
}
2 changes: 2 additions & 0 deletions libc/include/stdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ int printf(const char* __restrict, ...);
int putchar(int);
int puts(const char*);

int rename(const char* old, const char* new);

#ifndef _KERNEL_
FILE* fopen(const char* path, const char* mode);
int fclose(FILE* stream);
Expand Down
19 changes: 19 additions & 0 deletions modules/src/mv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <stdio.h>

#include <snow.h>

int main(int argc, char* argv[]) {
if (argc < 3) {
printf("usage: %s SOURCE DEST\n", argv[0]);
return 1;
}

int ret = rename(argv[1], argv[2]);

if (ret) {
printf("%s: failed\n");
return 2;
}

return 0;
}

0 comments on commit 4098fd2

Please sign in to comment.