vfs: initial symlink implementation

This commit is contained in:
Matheus
2022-10-20 21:05:39 -03:00
parent 185fd9dd22
commit 2aaa3da856
4 changed files with 159 additions and 10 deletions
+6
View File
@@ -178,6 +178,12 @@ void initrd_parse(){
if(err)
printf("Failed creating %s: ERROR %lu\n", entry.name, err);
break;
case TAR_SYMLINK:
err = vfs_symlink(vfs_root(), entry.name, entry.link, entry.mode);
if(err)
printf("Failed creating %s: ERROR %lu\n", entry.name, err);
break;
}
+39 -1
View File
@@ -182,8 +182,46 @@ static int tmpfs_mksocket(dirnode_t* parent, char* name, mode_t mode){
return 0;
}
static int tmpfs_symlink(dirnode_t* parent, char* name, char* target, mode_t mode){
int error = tmpfs_create(parent, name, mode);
if(error)
return error;
vnode_t* node = hashtable_get(&parent->children, name);
node->st.st_mode = MAKETYPE(TYPE_LINK) | mode;
tmpfs_write(&error, node, target, strlen(target)+1, 0);
return 0;
}
static int tmpfs_readlink(vnode_t *node, char** buff, size_t* linksize){
if(node->st.st_size >= 512)
return ENAMETOOLONG;
*buff = alloc(node->st.st_size+1);
if(!*buff)
return ENOMEM;
int error;
*linksize = tmpfs_read(&error, node, *buff, 512, 0);
if(error)
free(*buff);
return error;
}
static fscalls_t funcs = {
tmpfs_mount, tmpfs_unmount, tmpfs_open, tmpfs_close, tmpfs_mkdir, tmpfs_create, tmpfs_write, tmpfs_read, tmpfs_getdirent, tmpfs_chmod, tmpfs_mksocket
tmpfs_mount, tmpfs_unmount, tmpfs_open, tmpfs_close, tmpfs_mkdir, tmpfs_create, tmpfs_write, tmpfs_read, tmpfs_getdirent, tmpfs_chmod, tmpfs_mksocket, tmpfs_symlink, tmpfs_readlink
};
+107 -8
View File
@@ -9,6 +9,8 @@
#include <kernel/pipe.h>
#include <arch/timekeeper.h>
#define VFS_MAX_LOOP 5
dirnode_t* vfsroot;
hashtable fsfuncs;
static int lock;
@@ -219,7 +221,7 @@ int vfs_open(vnode_t** buff, dirnode_t* ref, char* path){
spinlock_acquire(&lock);
int res = vfs_resolvepath(&node, NULL, ref, path, NULL);
int res = vfs_resolvepath(&node, NULL, ref, path, NULL, true, VFS_MAX_LOOP);
if(res){
spinlock_release(&lock);
@@ -244,7 +246,7 @@ int vfs_create(dirnode_t* ref, char* path, mode_t mode){
spinlock_acquire(&lock);
int result = vfs_resolvepath(&buff, &parent, ref, path, name);
int result = vfs_resolvepath(&buff, &parent, ref, path, name, true, VFS_MAX_LOOP);
if(buff){
spinlock_release(&lock);
@@ -274,7 +276,7 @@ int vfs_mksocket(dirnode_t* ref, char* path, mode_t mode){
spinlock_acquire(&lock);
int result = vfs_resolvepath(&buff, &parent, ref, path, name);
int result = vfs_resolvepath(&buff, &parent, ref, path, name, true, VFS_MAX_LOOP);
if(buff){
spinlock_release(&lock);
@@ -300,6 +302,44 @@ int vfs_mksocket(dirnode_t* ref, char* path, mode_t mode){
return 0;
}
int vfs_symlink(dirnode_t* ref, char* path, char* target, mode_t mode){
if(strlen(target) >= 512)
return ENAMETOOLONG;
dirnode_t* parent = NULL;
dirnode_t* buff = NULL;
char name[512];
spinlock_acquire(&lock);
int result = vfs_resolvepath(&buff, &parent, ref, path, name, true, VFS_MAX_LOOP);
if(buff){
spinlock_release(&lock);
return EEXIST;
}
if(!parent){
spinlock_release(&lock);
return result;
}
if(!parent->vnode.fs->calls->symlink){
spinlock_release(&lock);
return ENOSYS;
}
result = parent->vnode.fs->calls->symlink(parent, name, target, mode);
spinlock_release(&lock);
if(result) return result;
}
int vfs_mkdir(dirnode_t* ref, char* path, mode_t mode){
dirnode_t* parent = NULL;
@@ -309,7 +349,7 @@ int vfs_mkdir(dirnode_t* ref, char* path, mode_t mode){
spinlock_acquire(&lock);
int result = vfs_resolvepath(&buff, &parent, ref, path, name);
int result = vfs_resolvepath(&buff, &parent, ref, path, name, true, VFS_MAX_LOOP);
if(buff){
spinlock_release(&lock);
@@ -346,7 +386,7 @@ int vfs_mount(dirnode_t* ref, char* device, char* mountpoint, char* fs, int moun
if(device){
dev = ref;
if(*device){
int result = vfs_resolvepath(&dev, &parent, ref, device, NULL);
int result = vfs_resolvepath(&dev, &parent, ref, device, NULL, true, VFS_MAX_LOOP);
if(result){
spinlock_release(&lock);
@@ -356,7 +396,7 @@ int vfs_mount(dirnode_t* ref, char* device, char* mountpoint, char* fs, int moun
}
int result = vfs_resolvepath(&mountdir, &parent, ref, mountpoint, NULL);
int result = vfs_resolvepath(&mountdir, &parent, ref, mountpoint, NULL, true, VFS_MAX_LOOP);
if(result){
spinlock_release(&lock);
@@ -429,13 +469,21 @@ dirnode_t* vfs_newdirnode(char* name, fs_t* fs, void* fsdata, dirnode_t* parent)
}
int vfs_resolvepath(vnode_t** result, dirnode_t** resultparent, dirnode_t* ref, char *path, char* namebuff){
// TODO the stack usage is scarily high
int vfs_resolvepath(vnode_t** result, dirnode_t** resultparent, dirnode_t* ref, char *path, char* namebuff, bool followlinks, int maxloop){
if(strlen(path) >= 512)
return ENAMETOOLONG;
if(maxloop == 0)
return ELOOP;
dirnode_t* iterator = ref;
char name[512];
off_t nameoffset = 0;
memset(name, 0, 512);
memset(name, 0, 256);
iterator = mountpoint(iterator);
@@ -457,6 +505,33 @@ int vfs_resolvepath(vnode_t** result, dirnode_t** resultparent, dirnode_t* ref,
++nameoffset;
name[offset] = 0;
// do we need to follow a symlink
if(GETTYPE(iterator->vnode.st.st_mode) == TYPE_LINK && followlinks){
if(!iterator->vnode.fs->calls->readlink)
return ENOSYS;
size_t size;
char* linkname;
int error = iterator->vnode.fs->calls->readlink(iterator, &linkname, &size);
if(error)
return error;
linkname[size] = '\0';
printf("reading link: %s\n", linkname);
error = vfs_resolvepath(&iterator, NULL, iterator, linkname, namebuff, true, maxloop-1); // XXX this might break some parent stuff when following links
free(linkname);
if(error)
return error;
}
// make sure we're a directory
@@ -501,6 +576,30 @@ int vfs_resolvepath(vnode_t** result, dirnode_t** resultparent, dirnode_t* ref,
if(GETTYPE(iterator->vnode.st.st_mode) == TYPE_DIR)
iterator = mountpoint(iterator);
// check if result is a symlink
if(GETTYPE(iterator->vnode.st.st_mode) == TYPE_LINK && followlinks){
if(!iterator->vnode.fs->calls->readlink)
return ENOSYS;
size_t size;
char* linkname;
int error = iterator->vnode.fs->calls->readlink(iterator, &linkname, &size);
if(error)
return error;
linkname[size] = '\0';
error = vfs_resolvepath(&iterator, NULL, iterator->vnode.parent, linkname, namebuff, true, maxloop-1); // XXX this might break some parent stuff when following links
free(linkname);
if(error)
return error;
}
*result = (vnode_t*)iterator;
return 0;
+7 -1
View File
@@ -6,6 +6,7 @@
#include <errno.h>
#include <dirent.h>
#include <poll.h>
#include <stdbool.h>
struct _vnode_t;
struct _fscalls_t;
@@ -65,6 +66,10 @@ typedef struct _fscalls_t {
int (*chmod)(vnode_t* node, mode_t mode);
// create socket in address
int (*mksocket)(dirnode_t* ref, char* path, mode_t mode);
// creates a symlink
int (*symlink)(dirnode_t* ref, char* path, char* target, mode_t mode);
// reads a symlink
int (*readlink)(vnode_t* node, char** buff, size_t* linksize);
} fscalls_t;
int vfs_mksocket(dirnode_t* ref, char* path, mode_t mode);
@@ -81,6 +86,7 @@ int vfs_getdirent(dirnode_t* node, dent_t* buff, size_t count, uintmax_t offset,
int vfs_ioctl(vnode_t* node, unsigned long request, void* arg, int* result);
int vfs_poll(vnode_t* node, pollfd* fd);
int vfs_chmod(vnode_t* node, mode_t mode);
int vfs_symlink(dirnode_t* ref, char* path, char* target, mode_t mode);
void vfs_init();
dirnode_t* vfs_root();
@@ -89,7 +95,7 @@ void vfs_releasenode(vnode_t* node);
vnode_t* vfs_newnode(char* name, fs_t* fs, void* fsdata);
dirnode_t* vfs_newdirnode(char* name, fs_t* fs, void* fsdata, dirnode_t* parent);
void vfs_destroynode(vnode_t* node);
int vfs_resolvepath(vnode_t** result, dirnode_t** parent, dirnode_t* ref, char* path, char* name);
int vfs_resolvepath(vnode_t** result, dirnode_t** parent, dirnode_t* ref, char* path, char* name, bool followlinks, int maxloop);
#define UNIMPLEMENTED { return ENOSYS; }