diff options
author | sotech117 <michael_foiani@brown.edu> | 2024-04-25 02:58:09 +0000 |
---|---|---|
committer | sotech117 <michael_foiani@brown.edu> | 2024-04-25 02:58:09 +0000 |
commit | a3e64ef2bf31dda9a94db011a96651de918ea968 (patch) | |
tree | 67c1d65ccc219c223d261dfd4cb024201220dcff /kernel/fs/namev.c | |
parent | d970aa2698d831645986effded059eb344a77486 (diff) |
old vfs fixes
Diffstat (limited to 'kernel/fs/namev.c')
-rw-r--r-- | kernel/fs/namev.c | 164 |
1 files changed, 159 insertions, 5 deletions
diff --git a/kernel/fs/namev.c b/kernel/fs/namev.c index e8b01e8..343f02c 100644 --- a/kernel/fs/namev.c +++ b/kernel/fs/namev.c @@ -76,8 +76,27 @@ long namev_is_descendant(vnode_t *a, vnode_t *b) long namev_lookup(vnode_t *dir, const char *name, size_t namelen, vnode_t **res_vnode) { - NOT_YET_IMPLEMENTED("VFS: namev_lookup"); - return 0; + // // NOT_YET_IMPLEMENTED("VFS: namev_lookup"); + + // KASSERT(NULL != dir); + // KASSERT(NULL != name); + // KASSERT(NULL != res_vnode); + + // if (namelen == 0) + // { + // return -EINVAL; + // } + + if ( + dir->vn_ops == NULL + || dir->vn_ops->lookup == NULL + || !S_ISDIR(dir->vn_mode) + ) + { + return -ENOTDIR; + } + + return dir->vn_ops->lookup(dir, name, namelen, res_vnode); } /* @@ -187,10 +206,85 @@ static const char *namev_tokenize(const char **search, size_t *len) long namev_dir(vnode_t *base, const char *path, vnode_t **res_vnode, const char **name, size_t *namelen) { - NOT_YET_IMPLEMENTED("VFS: namev_dir"); + // NOT_YET_IMPLEMENTED("VFS: namev_dir"); + + // Check if the pathname is nullish + if (path == NULL || *path == '\0') + { + return -EINVAL; + } + + // Get a vnode based on the pathname + vnode_t *dir = NULL; + if (*path == '/') + { + dir = vfs_root_fs.fs_root; + } + else if (base == NULL) + { + dir = curproc->p_cwd; + } + else + { + dir = base; + } + // Refcount it + vref(dir); + + // Tokenize the path + const char *token = NULL; + size_t len = 0; + while ((token = namev_tokenize(&path, &len)) && len > 0) + { + if (path == NULL || *path == '\0' || (*path == '/' && *(path + 1) == '\0')) + { + break; + } + + // Check if the name is too long + if (len > NAME_LEN) + { + vput(&dir); + return -ENAMETOOLONG; + } + + // Lookup the token + vnode_t *next = NULL; + vlock(dir); + long err = namev_lookup(dir, token, len, &next); + vunlock(dir); + if (err < 0) + { + vput(&dir); + return err; + } + + *res_vnode = dir; + *name = token; + *namelen = len; + + // Reduce refcount and move to the next token + if (next) + { + vput(&dir); + dir = next; + } + } + + // Check if it's a directory + if (!S_ISDIR(dir->vn_mode)) + { + vput(&dir); + return -ENOTDIR; + } + + // Assign the basename + *res_vnode = dir; + *name = token; + *namelen = len; + return 0; } - /* * Open the file specified by `base` and `path`, or create it, if necessary. * Return the file's vnode via `res_vnode`, which should be returned unlocked @@ -217,7 +311,67 @@ long namev_dir(vnode_t *base, const char *path, vnode_t **res_vnode, long namev_open(vnode_t *base, const char *path, int oflags, int mode, devid_t devid, struct vnode **res_vnode) { - NOT_YET_IMPLEMENTED("VFS: namev_open"); + // NOT_YET_IMPLEMENTED("VFS: namev_open"); + + // KASSERT(NULL != base); + KASSERT(NULL != path); + KASSERT(NULL != res_vnode); + + const char *name = NULL; + vnode_t *dir = NULL; + size_t namelen = 0; + + long err = namev_dir(base, path, &dir, &name, &namelen); + if (err < 0) + { + return err; + } + if (namelen > NAME_LEN) + { + vput(&dir); + return -ENAMETOOLONG; + } + + vnode_t *res = NULL; + vlock(dir); + err = namev_lookup(dir, name, namelen, &res); + vunlock(dir); + + if (err < 0) + { + if (!(oflags & O_CREAT)) + { + vput(&dir); + return err; + } + else + { + vlock(dir); + err = dir->vn_ops->mknod(dir, name, namelen, mode, devid, &res); + vunlock(dir); + + vput(&dir); + *res_vnode = res; + return err; + } + } + + if (path[strlen(path) - 1] == '/' && !S_ISDIR(res->vn_mode)) + { + vput(&dir); + vput(&res); + return -ENOTDIR; + } + + if (S_ISDIR(res->vn_mode) && (oflags & O_CREAT)) + { + vput(&dir); + vput(&res); + return -EISDIR; // TODO: check if this error + } + + vput(&dir); + *res_vnode = res; return 0; } |