aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2024-04-25 02:58:09 +0000
committersotech117 <michael_foiani@brown.edu>2024-04-25 02:58:09 +0000
commita3e64ef2bf31dda9a94db011a96651de918ea968 (patch)
tree67c1d65ccc219c223d261dfd4cb024201220dcff
parentd970aa2698d831645986effded059eb344a77486 (diff)
old vfs fixes
-rw-r--r--Config.mk2
-rw-r--r--kernel/fs/namev.c164
-rw-r--r--kernel/fs/open.c101
-rw-r--r--kernel/fs/vfs_syscall.c626
-rw-r--r--kernel/fs/vnode_specials.c32
-rw-r--r--kernel/main/kmain.c2
-rw-r--r--kernel/proc/proc.c33
7 files changed, 917 insertions, 43 deletions
diff --git a/Config.mk b/Config.mk
index 7281781..70edadf 100644
--- a/Config.mk
+++ b/Config.mk
@@ -11,7 +11,7 @@
# are built. To enable something set it to 1, otherwise set it to 0.
#
DRIVERS=1
- VFS=0
+ VFS=1
S5FS=0
VM=0
DYNAMIC=0
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;
}
diff --git a/kernel/fs/open.c b/kernel/fs/open.c
index 8c9fee6..811a9c4 100644
--- a/kernel/fs/open.c
+++ b/kernel/fs/open.c
@@ -62,6 +62,103 @@ long get_empty_fd(int *fd)
*/
long do_open(const char *filename, int oflags)
{
- NOT_YET_IMPLEMENTED("VFS: do_open");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_open");
+
+ // Check if oflags is valid
+ if ((oflags & O_WRONLY) && (oflags & O_RDWR))
+ {
+ return -EINVAL;
+ }
+
+ // Get an empty file descriptor
+ int fd = -1;
+ long ret = get_empty_fd(&fd);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ // Check if the file is a directory
+ if (filename[strlen(filename) - 1] == '/' && (oflags & O_WRONLY))
+ {
+ return -EISDIR;
+ }
+
+ // Open the file
+ vnode_t *res_vnode = NULL;
+ vnode_t *base = curproc->p_cwd;
+ ret = namev_open(base, filename, oflags, S_IFREG, 0, &res_vnode);
+ if (ret < 0)
+ {
+ if (res_vnode != NULL)
+ {
+ vput(&res_vnode);
+ }
+ return ret;
+ }
+
+ // Check if the vnode is a directory
+ if (S_ISDIR(res_vnode->vn_mode) && ((oflags & O_WRONLY) || (oflags & O_RDWR)))
+ {
+ return -EISDIR;
+ }
+
+ // Check if the vnode is a blockdev or chardev
+ if (S_ISCHR(res_vnode->vn_mode) && res_vnode->vn_dev.chardev == NULL)
+ {
+ vput(&res_vnode);
+ return -ENXIO;
+ }
+ if (S_ISBLK(res_vnode->vn_mode) && res_vnode->vn_dev.blockdev == NULL)
+ {
+ vput(&res_vnode);
+ return -ENXIO;
+ }
+
+ // Convert oflags to file access flags
+ int fmode = 0;
+ if (oflags & O_RDONLY)
+ {
+ fmode |= FMODE_READ;
+ }
+
+ if (oflags & O_WRONLY)
+ {
+ fmode |= FMODE_WRITE;
+ }
+ else
+ {
+ fmode |= FMODE_READ;
+ }
+
+ if (oflags & O_RDWR)
+ {
+ fmode |= FMODE_READ | FMODE_WRITE;
+ }
+
+ if (oflags & O_APPEND)
+ {
+ fmode |= FMODE_APPEND;
+ }
+ // Truncate the file if O_TRUNC is specified
+ if (oflags & O_TRUNC && S_ISREG(res_vnode->vn_mode))
+ {
+ vlock(res_vnode);
+ res_vnode->vn_ops->truncate_file(res_vnode);
+ vunlock(res_vnode);
+ }
+
+ // Create the file descriptor
+ file_t *file = fcreate(fd, res_vnode, fmode);
+ if (file == NULL)
+ {
+ vput(&res_vnode);
+ return -ENOMEM;
+ }
+
+
+ // Set the file descriptor
+ // curproc->p_files[fd] = file;
+ vput(&res_vnode);
+ return fd;
}
diff --git a/kernel/fs/vfs_syscall.c b/kernel/fs/vfs_syscall.c
index e05fe5f..ba4aa0c 100644
--- a/kernel/fs/vfs_syscall.c
+++ b/kernel/fs/vfs_syscall.c
@@ -26,8 +26,58 @@
*/
ssize_t do_read(int fd, void *buf, size_t len)
{
- NOT_YET_IMPLEMENTED("VFS: do_read");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_read");
+
+ // Check if the file descriptor is valid
+ if (fd < 0 || fd >= NFILES)
+ {
+ return -EBADF;
+ }
+
+ // fget the file
+ file_t *file = fget(fd);
+ if (file == NULL)
+ {
+ return -EBADF;
+ }
+
+ // Check if the file is open for reading
+ if (!(file->f_mode & FMODE_READ))
+ {
+ fput(&file);
+ return -EBADF;
+ }
+
+ // Check if the file is a directory
+ if (S_ISDIR(file->f_vnode->vn_mode))
+ {
+ fput(&file);
+ return -EISDIR;
+ }
+
+ // Check is read is valid
+ if (file->f_vnode->vn_ops->read == NULL)
+ {
+ fput(&file);
+ return -EISDIR;
+ }
+
+ // Read the file
+ vlock(file->f_vnode);
+ ssize_t bytes_read = file->f_vnode->vn_ops->read(file->f_vnode, file->f_pos, buf, len);
+ vunlock(file->f_vnode);
+
+ // Check if the read was successful
+ if (bytes_read < 0)
+ {
+ fput(&file);
+ return bytes_read;
+ }
+
+ // Update the file position
+ file->f_pos += bytes_read;
+ fput(&file);
+ return bytes_read;
}
/*
@@ -46,8 +96,61 @@ ssize_t do_read(int fd, void *buf, size_t len)
*/
ssize_t do_write(int fd, const void *buf, size_t len)
{
- NOT_YET_IMPLEMENTED("VFS: do_write");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_write");
+
+ // Check if the file descriptor is valid
+ if (fd < 0 || fd >= NFILES)
+ {
+ return -EBADF;
+ }
+
+ // dbg(DBG_PRINT, "VFS: do_write: fd = %d, len = %ld\n", fd, len);
+
+ // fget the file
+ file_t *file = fget(fd);
+ if (file == NULL)
+ {
+ return -EBADF;
+ }
+
+ // Check if the file is open for writing
+ if (!(file->f_mode & FMODE_WRITE))
+ {
+ fput(&file);
+ return -EBADF;
+ }
+
+ // Check is write is valid
+ if (file->f_vnode->vn_ops->write == NULL)
+ {
+ fput(&file);
+ return -EISDIR;
+ }
+
+ // Move the file position to the end of the file if the file is open in append mode
+ if (file->f_mode & FMODE_APPEND)
+ {
+ vlock(file->f_vnode);
+ file->f_pos = file->f_vnode->vn_len;
+ vunlock(file->f_vnode);
+ }
+
+ // Write the file
+ vlock(file->f_vnode);
+ ssize_t bytes_written = file->f_vnode->vn_ops->write(file->f_vnode, file->f_pos, buf, len);
+ vunlock(file->f_vnode);
+
+ // Check if the write was successful
+ if (bytes_written < 0)
+ {
+ // fput(&file);
+ dbg(DBG_PRINT, "VFS: do_write: write failed\n");
+ return bytes_written;
+ }
+
+ file->f_pos += bytes_written;
+ fput(&file);
+ return bytes_written;
}
/*
@@ -63,8 +166,26 @@ ssize_t do_write(int fd, const void *buf, size_t len)
*/
long do_close(int fd)
{
- NOT_YET_IMPLEMENTED("VFS: do_close");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_close");
+
+ // Check if the file descriptor is valid
+ if (fd < 0 || fd >= NFILES)
+ {
+ return -EBADF;
+ }
+
+ // fget the file
+ file_t *file = fget(fd);
+ if (file == NULL)
+ {
+ return -EBADF;
+ }
+
+ // Close the file
+ curproc->p_files[fd] = NULL;
+ fput(&file);
+
+ return 0;
}
/*
@@ -78,8 +199,32 @@ long do_close(int fd)
*/
long do_dup(int fd)
{
- NOT_YET_IMPLEMENTED("VFS: do_dup");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_dup");
+
+ // Check if the file descriptor is valid
+ if (fd < 0 || fd >= NFILES)
+ {
+ return -EBADF;
+ }
+
+ // fget the file
+ file_t *file = fget(fd);
+ if (file == NULL)
+ {
+ return -EBADF;
+ }
+
+ // Get an empty file descriptor
+ int new_fd = -1;
+ long ret = get_empty_fd(&new_fd);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ // Copy the file
+ curproc->p_files[new_fd] = file;
+ return new_fd;
}
/*
@@ -94,8 +239,39 @@ long do_dup(int fd)
*/
long do_dup2(int ofd, int nfd)
{
- NOT_YET_IMPLEMENTED("VFS: do_dup2");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_dup2");
+
+ // Check if the file descriptors are valid
+ if (ofd < 0 || ofd >= NFILES || nfd < 0 || nfd >= NFILES)
+ {
+ return -EBADF;
+ }
+ // Check if the file descriptors are the same
+ if (!curproc->p_files[ofd])
+ {
+ return -EBADF;
+ }
+ if (ofd == nfd)
+ {
+ return nfd;
+ }
+
+ // fget the file
+ file_t *file = fget(ofd);
+ if (file == NULL)
+ {
+ return -EBADF;
+ }
+ // figet the new file
+ file_t *new_file = fget(nfd);
+ if (new_file != NULL)
+ {
+ do_close(nfd);
+ }
+
+ // Copy the file
+ curproc->p_files[nfd] = file;
+ return nfd;
}
/*
@@ -117,8 +293,19 @@ long do_dup2(int ofd, int nfd)
*/
long do_mknod(const char *path, int mode, devid_t devid)
{
- NOT_YET_IMPLEMENTED("VFS: do_mknod");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_mknod");
+
+ // Check if the mode is valid
+ if (mode != S_IFCHR && mode != S_IFBLK && mode != S_IFREG)
+ {
+ return -EINVAL;
+ }
+
+ // get vnode
+ vnode_t *vnode = NULL;
+ vnode_t *base = curproc->p_cwd;
+ long ret = namev_open(base, path, O_CREAT, mode, devid, &vnode);
+ return ret;
}
/*
@@ -143,8 +330,47 @@ long do_mknod(const char *path, int mode, devid_t devid)
*/
long do_mkdir(const char *path)
{
- NOT_YET_IMPLEMENTED("VFS: do_mkdir");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_mkdir");
+
+ // Call namev_dir() to find the parent of the directory to be created
+ size_t len = 0;
+ const char *name = NULL;
+ vnode_t *dir = NULL;
+ long ret = namev_dir(curproc->p_cwd, path, &dir, &name, &len);
+ dbg(DBG_TEST, "VFS: do_mkdir: namev_dir returned %ld\n", ret);
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+ if (!S_ISDIR(dir->vn_mode))
+ {
+ vput(&dir);
+ return -ENOTDIR;
+ }
+ if (len > NAME_LEN)
+ {
+ vput(&dir);
+ return -ENAMETOOLONG;
+ }
+
+ vnode_t *base = NULL;
+ vlock(dir);
+ ret = namev_lookup(dir, name, len, &base);
+ vunlock(dir);
+ // Check if the directory already exists
+ if (ret >= 0)
+ {
+ vput(&base);
+ vput(&dir);
+ return -EEXIST;
+ }
+
+ // Create the directory
+ ret = dir->vn_ops->mkdir(dir, name, len, &base);
+ // vput(&base);
+ vput(&dir);
+ return ret;
}
/*
@@ -165,8 +391,75 @@ long do_mkdir(const char *path)
*/
long do_rmdir(const char *path)
{
- NOT_YET_IMPLEMENTED("VFS: do_rmdir");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_rmdir");
+
+ // Call namev_dir() to find the parent of the directory to be removed
+ size_t len = 0;
+ const char *name = NULL;
+ vnode_t *dir = NULL;
+ long ret = namev_dir(curproc->p_cwd, path, &dir, &name, &len);
+
+ // Check if the directory is valid
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ // Check if the directory is a directory
+ if (!S_ISDIR(dir->vn_mode))
+ {
+ vput(&dir);
+ return -ENOTDIR;
+ }
+
+ // Check if name is too long
+ if (len > NAME_LEN)
+ {
+ vput(&dir);
+ return -ENAMETOOLONG;
+ }
+
+ // Check if the directory is empty
+ if (len == 1 && name[0] == '.')
+ {
+ vput(&dir);
+ return -EINVAL;
+ }
+ if (len == 2 && name[0] == '.' && name[1] == '.')
+ {
+ vput(&dir);
+ return -ENOTEMPTY;
+ }
+
+ // Remove the directory
+ vnode_t *base = NULL;
+ vlock(dir);
+ ret = namev_lookup(dir, name, len, &base);
+ vunlock(dir);
+
+ // Check if the directory exists
+ if (ret < 0)
+ {
+ vput(&dir);
+ return ret;
+ }
+
+ // Check if the directory is a directory
+ if (!S_ISDIR(base->vn_mode))
+ {
+ vput(&base);
+ vput(&dir);
+ return -ENOTDIR;
+ }
+
+ // Remove the directory
+ vlock(dir);
+ ret = dir->vn_ops->rmdir(dir, name, len);
+ vunlock(dir);
+ vput(&base);
+ vput(&dir);
+
+ return ret;
}
/*
@@ -183,8 +476,63 @@ long do_rmdir(const char *path)
*/
long do_unlink(const char *path)
{
- NOT_YET_IMPLEMENTED("VFS: do_unlink");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_unlink");
+
+ // Call namev_dir() to find the parent of the file to be unlinked
+ size_t len = 0;
+ const char *name = NULL;
+ vnode_t *dir = NULL;
+ long ret = namev_dir(curproc->p_cwd, path, &dir, &name, &len);
+
+ // Check if the directory is valid
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ // Check if the directory is a directory
+ if (!S_ISDIR(dir->vn_mode))
+ {
+ vput(&dir);
+ return -ENOTDIR;
+ }
+
+ // Check if name is too long
+ if (len > NAME_LEN)
+ {
+ vput(&dir);
+ return -ENAMETOOLONG;
+ }
+
+ // Remove the link
+ vnode_t *base = NULL;
+ vlock(dir);
+ ret = namev_lookup(dir, name, len, &base);
+ vunlock(dir);
+
+ // Check if the file exists
+ if (ret < 0)
+ {
+ vput(&dir);
+ return ret;
+ }
+ // Check if the file is a directory
+ if (S_ISDIR(base->vn_mode))
+ {
+ vput(&base);
+ vput(&dir);
+ return -EPERM;
+ }
+
+ // Call the unlink operation
+ vlock(dir);
+ ret = dir->vn_ops->unlink(dir, name, len);
+ vunlock(dir);
+
+ vput(&base);
+ vput(&dir);
+
+ return ret;
}
/*
@@ -206,8 +554,58 @@ long do_unlink(const char *path)
*/
long do_link(const char *oldpath, const char *newpath)
{
- NOT_YET_IMPLEMENTED("VFS: do_link");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_link");
+
+ // Resolve the oldpath
+ vnode_t *old_vnode = NULL;
+
+ long ret = namev_resolve(NULL, oldpath, &old_vnode);
+ // Check if the oldpath is valid
+ if (ret < 0)
+ {
+ return ret;
+ }
+ // Check if the oldpath is a directory
+ if (S_ISDIR(old_vnode->vn_mode))
+ {
+ vput(&old_vnode);
+ return -EPERM;
+ }
+
+ // Get the directory of the newpath
+ size_t len = 0;
+ const char *name = NULL;
+ vnode_t *dir = NULL;
+ ret = namev_dir(curproc->p_cwd, newpath, &dir, &name, &len);
+ // Check if the directory is valid
+ if (ret < 0)
+ {
+ vput(&old_vnode);
+ return ret;
+ }
+ // Check if the directory is a directory
+ if (!S_ISDIR(dir->vn_mode))
+ {
+ vput(&old_vnode);
+ vput(&dir);
+ return -ENOTDIR;
+ }
+ // Check if name is too long
+ if (len > NAME_LEN)
+ {
+ vput(&old_vnode);
+ vput(&dir);
+ return -ENAMETOOLONG;
+ }
+
+ // Lock the vnodes and call link
+ vlock_in_order(old_vnode, dir);
+ ret = dir->vn_ops->link(old_vnode, dir, name, len);
+ vunlock_in_order(old_vnode, dir);
+
+ vput(&old_vnode);
+ vput(&dir);
+ return ret;
}
/* Rename a file or directory.
@@ -231,7 +629,7 @@ long do_link(const char *oldpath, const char *newpath)
* projects this is harder and you will get no extra credit (but you
* will get our admiration). Please make sure the normal version works first.
* Steps:
- * 1. namev_dir oldpath --> olddir vnode
+ * 1. oldpath --> olddir vnode
* 2. namev_dir newpath --> newdir vnode
* 3. Lock the global filesystem `vnode_rename_mutex`
* 4. Lock the olddir and newdir in ancestor-first order (see `vlock_in_order`)
@@ -244,8 +642,60 @@ long do_link(const char *oldpath, const char *newpath)
*/
long do_rename(const char *oldpath, const char *newpath)
{
- NOT_YET_IMPLEMENTED("VFS: do_rename");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_rename");
+
+ // Get the old directory
+ size_t old_len = 0;
+ const char *old_name = NULL;
+ vnode_t *old_dir = NULL;
+ long ret = namev_dir(curproc->p_cwd, oldpath, &old_dir, &old_name, &old_len);
+ // Check if the old directory is valid
+ if (ret < 0)
+ {
+ return ret;
+ }
+ // Check if the old directory is a directory
+ if (!S_ISDIR(old_dir->vn_mode))
+ {
+ vput(&old_dir);
+ return -ENOTDIR;
+ }
+
+ // Get the new directory
+ size_t new_len = 0;
+ const char *new_name = NULL;
+ vnode_t *new_dir = NULL;
+ ret = namev_dir(curproc->p_cwd, newpath, &new_dir, &new_name, &new_len);
+ // Check if the new directory is valid
+ if (ret < 0)
+ {
+ vput(&old_dir);
+ return ret;
+ }
+ // Check if the new directory is a directory
+ if (!S_ISDIR(new_dir->vn_mode))
+ {
+ vput(&old_dir);
+ vput(&new_dir);
+ return -ENOTDIR;
+ }
+
+ // Check if the names are too long
+ if (old_len > NAME_LEN || new_len > NAME_LEN)
+ {
+ vput(&old_dir);
+ vput(&new_dir);
+ return -ENAMETOOLONG;
+ }
+
+ // Lock the vnodes and call rename
+ vlock_in_order(old_dir, new_dir);
+ ret = old_dir->vn_ops->rename(old_dir, old_name, old_len, new_dir, new_name, new_len);
+ vunlock_in_order(old_dir, new_dir);
+
+ vput(&old_dir);
+ vput(&new_dir);
+ return ret;
}
/* Set the current working directory to the directory represented by path.
@@ -262,8 +712,27 @@ long do_rename(const char *oldpath, const char *newpath)
*/
long do_chdir(const char *path)
{
- NOT_YET_IMPLEMENTED("VFS: do_chdir");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_chdir");
+
+ // Resolve the path
+ vnode_t *vnode = NULL;
+ long ret = namev_resolve(NULL, path, &vnode);
+ // Check if the path is valid
+ if (ret < 0)
+ {
+ return ret;
+ }
+ // Check if the path is a directory
+ if (!S_ISDIR(vnode->vn_mode))
+ {
+ vput(&vnode);
+ return -ENOTDIR;
+ }
+
+ // Set the current working directory
+ vput(&curproc->p_cwd);
+ curproc->p_cwd = vnode;
+ return 0;
}
/*
@@ -282,8 +751,43 @@ long do_chdir(const char *path)
*/
ssize_t do_getdent(int fd, struct dirent *dirp)
{
- NOT_YET_IMPLEMENTED("VFS: do_getdent");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_getdent");
+
+ // Check if the file descriptor is valid
+ if (fd < 0 || fd >= NFILES)
+ {
+ return -EBADF;
+ }
+
+ // fget the file
+ file_t *file = fget(fd);
+ if (file == NULL)
+ {
+ return -EBADF;
+ }
+
+ // Check if the file is a directory
+ if (!S_ISDIR(file->f_vnode->vn_mode))
+ {
+ fput(&file);
+ return -ENOTDIR;
+ }
+
+ // Read the directory entry
+ vlock(file->f_vnode);
+ ssize_t bytes_read = file->f_vnode->vn_ops->readdir(file->f_vnode, file->f_pos, dirp);
+ vunlock(file->f_vnode);
+ // Check if the read was successful
+ if (bytes_read <= 0)
+ {
+ fput(&file);
+ return bytes_read;
+ }
+
+ // Update the file position
+ file->f_pos += bytes_read;
+ fput(&file);
+ return sizeof(dirent_t);
}
/*
@@ -301,8 +805,51 @@ ssize_t do_getdent(int fd, struct dirent *dirp)
*/
off_t do_lseek(int fd, off_t offset, int whence)
{
- NOT_YET_IMPLEMENTED("VFS: do_lseek");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_lseek");
+
+ // Check if the file descriptor is valid
+ if (fd < 0 || fd >= NFILES)
+ {
+ return -EBADF;
+ }
+
+ // fget the file
+ file_t *file = fget(fd);
+ if (file == NULL)
+ {
+ return -EBADF;
+ }
+
+ // Check if the whence is valid
+ off_t new_pos = 0;
+ switch (whence)
+ {
+ case SEEK_SET:
+ new_pos = offset;
+ break;
+ case SEEK_CUR:
+ new_pos = file->f_pos + offset;
+ break;
+ case SEEK_END:
+ new_pos = file->f_vnode->vn_len + offset;
+ break;
+ default:
+ fput(&file);
+ return -EINVAL;
+ }
+
+ // Check if the new position is negative
+ if (new_pos < 0)
+ {
+ fput(&file);
+ return -EINVAL;
+ }
+
+ // Update the file position
+ file->f_pos = new_pos;
+ off_t pos = file->f_pos;
+ fput(&file);
+ return pos;
}
/* Use buf to return the status of the file represented by path.
@@ -312,8 +859,25 @@ off_t do_lseek(int fd, off_t offset, int whence)
*/
long do_stat(const char *path, stat_t *buf)
{
- NOT_YET_IMPLEMENTED("VFS: do_stat");
- return -1;
+ // NOT_YET_IMPLEMENTED("VFS: do_stat");
+
+ // Resolve the path
+ vnode_t *vnode = NULL;
+ long ret = namev_resolve(NULL, path, &vnode);
+
+ // Check if the path is valid
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ // Get the status of the file
+ vlock(vnode);
+ ret = vnode->vn_ops->stat(vnode, buf);
+ vunlock(vnode);
+ vput(&vnode);
+
+ return ret;
}
#ifdef __MOUNTING__
diff --git a/kernel/fs/vnode_specials.c b/kernel/fs/vnode_specials.c
index cd21549..3e55830 100644
--- a/kernel/fs/vnode_specials.c
+++ b/kernel/fs/vnode_specials.c
@@ -110,7 +110,21 @@ static long special_file_stat(vnode_t *file, stat_t *ss)
static ssize_t chardev_file_read(vnode_t *file, size_t pos, void *buf,
size_t count)
{
- NOT_YET_IMPLEMENTED("VFS: chardev_file_read");
+ // NOT_YET_IMPLEMENTED("VFS: chardev_file_read");
+
+ // check if the vnode represetns a chardev
+ if (file->vn_dev.chardev == NULL)
+ {
+ return -ENXIO;
+ }
+
+ // Unlock the file and call read
+ vunlock(file);
+ ssize_t ret = file->vn_dev.chardev->cd_ops->read(file->vn_dev.chardev, pos, buf, count);
+ vlock(file);
+
+ return ret;
+
return 0;
}
@@ -125,8 +139,20 @@ static ssize_t chardev_file_read(vnode_t *file, size_t pos, void *buf,
static long chardev_file_write(vnode_t *file, size_t pos, const void *buf,
size_t count)
{
- NOT_YET_IMPLEMENTED("VFS: chardev_file_write");
- return 0;
+ // NOT_YET_IMPLEMENTED("VFS: chardev_file_write");
+
+ // check if the vnode represents a chardev
+ if (file->vn_dev.chardev == NULL)
+ {
+ return -ENXIO;
+ }
+
+ // Unlock the file and call write
+ vunlock(file);
+ long ret = file->vn_dev.chardev->cd_ops->write(file->vn_dev.chardev, pos, buf, count);
+ vlock(file);
+
+ return ret;
}
/*
diff --git a/kernel/main/kmain.c b/kernel/main/kmain.c
index 4cec7bd..4c49b9a 100644
--- a/kernel/main/kmain.c
+++ b/kernel/main/kmain.c
@@ -171,7 +171,7 @@ static void *initproc_run(long arg1, void *arg2)
// dbg(DBG_PROC, "%s", "In main thread!\n");
#ifdef __DRIVERS__
- driverstest_main(0, NULL);
+ // driverstest_main(0, NULL);
char name[32] = {0};
for (long i = 0; i < __NTERMS__; i++)
{
diff --git a/kernel/proc/proc.c b/kernel/proc/proc.c
index 7ce42dc..1e38ca8 100644
--- a/kernel/proc/proc.c
+++ b/kernel/proc/proc.c
@@ -218,6 +218,23 @@ proc_t *proc_create(const char *name)
list_insert_tail(&proc_list, &proc->p_list_link);
dbg(DBG_PROC, "SUCESSFULLY created PROCESS name=%s & pid =%d\n", name, proc_pid);
+#ifdef __VFS__
+ // clone and ref the files from curproc
+ for (int fd = 0; fd < NFILES; fd++)
+ {
+ proc->p_files[fd] = NULL;
+ }
+ if (proc->p_pid != PID_INIT)
+ {
+ proc->p_cwd = proc->p_pproc->p_cwd;
+ vref(proc->p_cwd);
+ }
+ else
+ {
+ proc->p_cwd = NULL;
+ }
+#endif
+
return proc;
}
@@ -272,6 +289,20 @@ void proc_cleanup(long status)
// } else {
curproc->p_status = status;
// }
+
+#ifdef __VFS__
+ for (int fd = 0; fd < NFILES; fd++)
+ {
+ if (curproc->p_files[fd])
+ {
+ fput(curproc->p_files + fd);
+ }
+ }
+ if (curproc->p_cwd)
+ {
+ vput(&curproc->p_cwd);
+ }
+#endif
}
/*
@@ -365,7 +396,9 @@ void proc_destroy(proc_t *proc)
for (int fd = 0; fd < NFILES; fd++)
{
if (proc->p_files[fd])
+ {
fput(proc->p_files + fd);
+ }
}
if (proc->p_cwd)
{