aboutsummaryrefslogtreecommitdiff
path: root/kernel/fs
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/fs')
-rw-r--r--kernel/fs/namev.c168
-rw-r--r--kernel/fs/open.c99
-rw-r--r--kernel/fs/s5fs/s5fs.c471
-rw-r--r--kernel/fs/vfs_syscall.c628
-rw-r--r--kernel/fs/vnode_specials.c32
5 files changed, 1332 insertions, 66 deletions
diff --git a/kernel/fs/namev.c b/kernel/fs/namev.c
index e8b01e8..dd44450 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,89 @@ 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')
+ {
+ break;
+ }
+
+ // Check if the whole path is a sequence of '/' then a null
+ int index = 0;
+ while (path[index] == '/')
+ {
+ index++;
+ }
+ if (path[index] == '\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;
+ }
+
+ // Reduce refcount and move to the next token
+ vput(&dir);
+ dir = next;
+ }
+
+ // Check if it's a directory
+ if (!S_ISDIR(dir->vn_mode))
+ {
+ vput(&dir);
+ return -ENOTDIR;
+ }
+
+ // Assign the ret vars
+ *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 +315,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..8f0d893 100644
--- a/kernel/fs/open.c
+++ b/kernel/fs/open.c
@@ -62,6 +62,101 @@ 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)))
+ {
+ vput(&res_vnode);
+ 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;
+ }
+
+ vput(&res_vnode);
+ return fd;
}
diff --git a/kernel/fs/s5fs/s5fs.c b/kernel/fs/s5fs/s5fs.c
index d1df3a5..2bcec7d 100644
--- a/kernel/fs/s5fs/s5fs.c
+++ b/kernel/fs/s5fs/s5fs.c
@@ -210,7 +210,56 @@ long s5fs_mount(fs_t *fs)
*/
static void s5fs_read_vnode(fs_t *fs, vnode_t *vn)
{
- NOT_YET_IMPLEMENTED("S5FS: s5fs_read_vnode");
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_read_vnode");
+
+ // Get the s5_node from the vnode
+ s5_node_t *s5_node = VNODE_TO_S5NODE(vn);
+
+ // Get the inode
+ s5_inode_t *s5_inode = &s5_node->inode;
+ KASSERT(s5_inode);
+ // Update linkcount
+ s5_inode->s5_linkcount++;
+
+ // Get the inode from the disk
+ pframe_t *pf;
+ s5_get_file_disk_block(vn, S5_INODE_BLOCK(vn->vn_vno), S5_INODE_OFFSET(vn->vn_vno), 0, &pf);
+ memcpy(s5_inode, pf->pf_addr, sizeof(s5_inode_t));
+
+ // Release the disk block
+ s5_release_disk_block(&pf);
+
+ // Initialize the dirtied_inode field
+ s5_node->dirtied_inode = 0;
+
+ // Initialize the vnode fields
+ // lan and inode trivial
+ vn->vn_len = s5_inode->s5_un.s5_size;
+ vn->vn_i = s5_inode;
+ // Initialize the vn_ops and mode field based on the type
+ switch (s5_inode->s5_type)
+ {
+ case S5_TYPE_DIR: // directory
+ vn->vn_ops = &s5fs_dir_vops;
+ vn->vn_mode = S_IFDIR;
+ break;
+ case S5_TYPE_CHR: // character device
+ vn->vn_ops = NULL;
+ vn->vn_mode = S_IFCHR;
+ vn->vn_devid = s5_inode->s5_indirect_block;
+ break;
+ case S5_TYPE_BLK: // block device
+ vn->vn_ops = NULL;
+ vn->vn_mode = S_IFBLK;
+ vn->vn_devid = s5_inode->s5_indirect_block;
+ break;
+ case S5_TYPE_DATA: // regular file
+ vn->vn_ops = &s5fs_file_vops;
+ vn->vn_mode = S_IFREG;
+ break;
+ default: // unknown type
+ panic("Unknown inode type %d\n", s5_inode->s5_type);
+ }
}
/* Clean up the inode corresponding to the given vnode.
@@ -226,7 +275,38 @@ static void s5fs_read_vnode(fs_t *fs, vnode_t *vn)
*/
static void s5fs_delete_vnode(fs_t *fs, vnode_t *vn)
{
- NOT_YET_IMPLEMENTED("S5FS: s5fs_delete_vnode");
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_delete_vnode");
+
+ // Get the s5_node from the vnode
+ s5_node_t *s5_node = VNODE_TO_S5NODE(vn);
+
+ // Get the inode
+ s5_inode_t *s5_inode = &s5_node->inode;
+ KASSERT(s5_inode);
+
+ // Update linkcount
+ s5_inode->s5_linkcount--;
+
+ // Check if the inode is no longer in use
+ if (s5_inode->s5_linkcount == 0)
+ {
+ // Free the inode and return
+ s5_free_inode(FS_TO_S5FS(fs), s5_inode->s5_number);
+ return;
+ }
+
+ // Check if the inode is dirty
+ if (s5_node->dirtied_inode)
+ {
+ // Write the inode back to disk and return
+ pframe_t *pf;
+ s5_get_file_disk_block(vn, S5_INODE_BLOCK(vn->vn_vno), S5_INODE_OFFSET(vn->vn_vno), 1, &pf);
+ memcpy(pf->pf_addr, s5_inode, sizeof(s5_inode_t));
+ s5_release_disk_block(&pf);
+ return;
+ }
+
+ // Do nothing if the inode is unchanged
}
/*
@@ -285,8 +365,8 @@ static void s5fs_sync(fs_t *fs)
static ssize_t s5fs_read(vnode_t *vnode, size_t pos, void *buf, size_t len)
{
KASSERT(!S_ISDIR(vnode->vn_mode) && "should be handled at the VFS level");
- NOT_YET_IMPLEMENTED("S5FS: s5fs_read");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_read");
+ return s5_read_file(VNODE_TO_S5NODE(vnode), pos, buf, len);
}
/* Wrapper around s5_write_file. */
@@ -294,8 +374,8 @@ static ssize_t s5fs_write(vnode_t *vnode, size_t pos, const void *buf,
size_t len)
{
KASSERT(!S_ISDIR(vnode->vn_mode) && "should be handled at the VFS level");
- NOT_YET_IMPLEMENTED("S5FS: s5fs_write");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_write");
+ return s5_write_file(VNODE_TO_S5NODE(vnode), pos, buf, len);
}
/*
@@ -334,8 +414,68 @@ static long s5fs_mknod(struct vnode *dir, const char *name, size_t namelen,
int mode, devid_t devid, struct vnode **out)
{
KASSERT(S_ISDIR(dir->vn_mode) && "should be handled at the VFS level");
- NOT_YET_IMPLEMENTED("S5FS: s5fs_mknod");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_mknod");
+
+ // Check if the mode is not supported
+ if (mode != S_IFCHR && mode != S_IFBLK && mode != S_IFREG)
+ {
+ return -ENOTSUP;
+ }
+
+ // Allocate a new inode, get its properties first
+ s5fs_t *s5fs = VNODE_TO_S5FS(dir);
+ uint16_t type;
+ if(S_ISCHR(mode))
+ {
+ type = S5_TYPE_CHR;
+ }
+ else if(S_ISBLK(mode))
+ {
+ type = S5_TYPE_BLK;
+ }
+ else if(S_ISREG(mode))
+ {
+ type = S5_TYPE_DATA;
+ }
+ else
+ {
+ panic("Invalid s5 mode!\n");
+ }
+
+ // Allocate the inode
+ s5_inode_t *s5_inode;
+ long inode_num = s5_alloc_inode(s5fs, type, &s5_inode);
+ // Check if the inode allocation failed
+ if (inode_num < 0)
+ {
+ return inode_num;
+ }
+
+ // Create the new vnode
+ vnode_t *new_vnode = vget(dir->vn_fs, inode_num);
+ // Check if the vnode creation failed
+ if (!new_vnode)
+ {
+ s5_free_inode(s5fs, inode_num);
+ return -ENOMEM;
+ }
+
+ // Set the devid for the new inode
+ s5_inode->s5_indirect_block = devid;
+
+ // Link the new inode/vnode to the parent directory
+ long link = s5_link(dir, name, namelen, new_vnode);
+ // Check if the link operation failed
+ if (link < 0)
+ {
+ vput(new_vnode);
+ s5_free_inode(s5fs, inode_num);
+ return link;
+ }
+
+ // Set the out pointer to the new vnode
+ *out = new_vnode;
+ return 0;
}
/* Search for a given entry within a directory.
@@ -356,8 +496,37 @@ static long s5fs_mknod(struct vnode *dir, const char *name, size_t namelen,
long s5fs_lookup(vnode_t *dir, const char *name, size_t namelen,
vnode_t **ret)
{
- NOT_YET_IMPLEMENTED("S5FS: s5fs_lookup");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_lookup");
+
+ // Find the directory entry
+ size_t filepos;
+ long ino = s5_find_dirent(VNODE_TO_S5NODE(dir), name, namelen, &filepos);
+ // Check if the directory entry was not found
+ if (ino < 0)
+ {
+ return ino;
+ }
+
+ // Check if the found vnode is the directory itself
+ if (ino == dir->vn_vno)
+ {
+ vref(dir);
+ *ret = dir;
+ return 0;
+ }
+
+
+ // If not, get the found vnode
+ vnode_t *found_vnode = vget(dir->vn_fs, ino);
+ // Check if the vnode creation failed
+ if (!found_vnode)
+ {
+ return -ENOMEM;
+ }
+ // Increment the reference count
+ // vref(found_vnode);
+ *ret = found_vnode;
+ return 0;
}
/* Wrapper around s5_link.
@@ -369,8 +538,15 @@ static long s5fs_link(vnode_t *dir, const char *name, size_t namelen,
vnode_t *child)
{
KASSERT(S_ISDIR(dir->vn_mode) && "should be handled at the VFS level");
- NOT_YET_IMPLEMENTED("S5FS: s5fs_link");
- return -1;
+ //NOT_YET_IMPLEMENTED("S5FS: s5fs_link");
+
+ // Check if the child is a directory
+ if (S_ISDIR(child->vn_mode))
+ {
+ return -EISDIR;
+ }
+
+ return s5_link(VNODE_TO_S5NODE(dir), name, namelen, VNODE_TO_S5NODE(child));
}
/* Remove the directory entry in dir corresponding to name and namelen.
@@ -389,8 +565,29 @@ static long s5fs_unlink(vnode_t *dir, const char *name, size_t namelen)
KASSERT(S_ISDIR(dir->vn_mode) && "should be handled at the VFS level");
KASSERT(!name_match(".", name, namelen));
KASSERT(!name_match("..", name, namelen));
- NOT_YET_IMPLEMENTED("S5FS: s5fs_unlink");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_unlink");
+
+ // Find the directory entry
+ s5_node_t *s5_node = VNODE_TO_S5NODE(dir);
+ size_t filepos;
+ long ino = s5_find_dirent(s5_node, name, namelen, &filepos);
+ // Check if the directory entry was not found
+ if (ino < 0)
+ {
+ return ino;
+ }
+
+ // Get the found vnode
+ vnode_t *child = vget_locked(dir->vn_fs, ino);
+ KASSERT(!S_ISDIR(child->vn_mode) && "should be handled at the VFS level");
+
+ // Remove the directory entry
+ s5_remove_dirent(s5_node, name, namelen, filepos);
+ // Check to see if this failed (TODO: ask in hours)
+
+ // Release the vnode
+ vput_locked(&child);
+ return 0;
}
/* Change the name or location of a file.
@@ -441,8 +638,98 @@ static long s5fs_rename(vnode_t *olddir, const char *oldname, size_t oldnamelen,
vnode_t *newdir, const char *newname,
size_t newnamelen)
{
- NOT_YET_IMPLEMENTED("S5FS: s5fs_rename");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_rename");
+
+ // Check if the new name is too long
+ if (newnamelen >= NAME_LEN)
+ {
+ return -ENAMETOOLONG;
+ }
+
+ // Find the old directory entry
+ s5_node_t *s5_node = VNODE_TO_S5NODE(olddir);
+ size_t filepos;
+ long ino = s5_find_dirent(s5_node, oldname, oldnamelen, &filepos);
+ // Check if the directory entry was not found
+ if (ino < 0)
+ {
+ return ino;
+ }
+
+ // Get the found vnode
+ vnode_t *child = vget_locked(olddir->vn_fs, ino);
+ KASSERT(!S_ISDIR(child->vn_mode) && "should be handled at the VFS level");
+
+ // Check if the new directory is not a directory
+ if (!S_ISDIR(newdir->vn_mode))
+ {
+ vput_locked(&child);
+ return -ENOTDIR;
+ }
+
+ // Find the new directory entry
+ s5_node_t *new_s5_node = VNODE_TO_S5NODE(newdir);
+ size_t new_filepos;
+ long new_ino = s5_find_dirent(new_s5_node, newname, newnamelen, &new_filepos);
+ // Check if the directory entry is new
+ if (new_ino == -ENOENT)
+ {
+ // Link the new directory
+ long link = s5_link(new_s5_node, newname, newnamelen, VNODE_TO_S5NODE(child));
+ // Check if the link operation failed
+ if (link < 0)
+ {
+ vput_locked(&child);
+ return link;
+ }
+
+ // Remove the old directory entry
+ s5_remove_dirent(s5_node, oldname, oldnamelen, filepos);
+ // Check if this failed (TODO: ask in hours)
+
+ return link;
+ }
+
+ // Else, the new directory entry was found and we need to replace it
+ // Get the new found vnode
+ vnode_t *new_child = vget_locked(newdir->vn_fs, new_ino);
+ KASSERT(!S_ISDIR(new_child->vn_mode) && "should be handled at the VFS level");
+
+ // Check if the old and new vnodes are the same
+ if (child->vn_vno == new_child->vn_vno)
+ {
+ vput_locked(&child);
+ vput_locked(&new_child);
+ return 0;
+ }
+
+ // Check if the new vnode is a directory
+ if (S_ISDIR(new_child->vn_mode))
+ {
+ vput_locked(&child);
+ vput_locked(&new_child);
+ return -EISDIR;
+ }
+
+ // Remove the new directory entry
+ s5_remove_dirent(new_s5_node, newname, newnamelen, new_filepos);
+ // Check if this failed (TODO: ask in hours)
+ // Link the new directory
+ long link = s5_link(new_s5_node, newname, newnamelen, VNODE_TO_S5NODE(child));
+ // Check if the link operation failed
+ if (link < 0)
+ {
+ vput_locked(&child);
+ vput_locked(&new_child);
+ return link;
+ }
+
+ // Remove the old directory entry
+ s5_remove_dirent(s5_node, oldname, oldnamelen, filepos);
+
+ vput_locked(&child);
+ vput_locked(&new_child);
+ return link;
}
/* Create a directory.
@@ -473,8 +760,66 @@ static long s5fs_mkdir(vnode_t *dir, const char *name, size_t namelen,
struct vnode **out)
{
KASSERT(S_ISDIR((dir)->vn_mode) && "should be handled at the VFS level");
- NOT_YET_IMPLEMENTED("S5FS: s5fs_mkdir");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_mkdir");
+
+ // Allocate a new inode, get its properties first
+ s5fs_t *s5fs = VNODE_TO_S5FS(dir);
+ uint16_t type = S5_TYPE_DIR;
+
+ // Allocate the inode
+ s5_inode_t *s5_inode;
+ long inode_num = s5_alloc_inode(s5fs, type, &s5_inode);
+ // Check if the inode allocation failed
+ if (inode_num < 0)
+ {
+ return inode_num;
+ }
+
+ // Create the new vnode
+ vnode_t *new_vnode = vget(dir->vn_fs, inode_num);
+ // Check if the vnode creation failed
+ if (!new_vnode)
+ {
+ s5_free_inode(s5fs, inode_num);
+ return -ENOMEM;
+ }
+
+ // Create the "." entry
+ long link = s5_link(VNODE_TO_S5NODE(new_vnode), ".", 1, VNODE_TO_S5NODE(new_vnode));
+ // Check if the link operation failed
+ if (link < 0)
+ {
+ vput(new_vnode);
+ s5_free_inode(s5fs, inode_num);
+ return link;
+ }
+
+ // Create the ".." entry
+ long link2 = s5_link(VNODE_TO_S5NODE(new_vnode), "..", 2, VNODE_TO_S5NODE(dir));
+ // Check if the link operation failed
+ if (link2 < 0)
+ {
+ s5_remove_dirent(VNODE_TO_S5NODE(new_vnode), ".", 1, 0);
+ vput(new_vnode);
+ s5_free_inode(s5fs, inode_num);
+ return link2;
+ }
+
+ // Link the new directory to the parent
+ long link3 = s5_link(VNODE_TO_S5NODE(dir), name, namelen, VNODE_TO_S5NODE(new_vnode));
+ // Check if the link operation failed
+ if (link3 < 0)
+ {
+ s5_remove_dirent(VNODE_TO_S5NODE(new_vnode), ".", 1, 0);
+ s5_remove_dirent(VNODE_TO_S5NODE(new_vnode), "..", 2, 0);
+ vput(new_vnode);
+ s5_free_inode(s5fs, inode_num);
+ return link3;
+ }
+
+ // Set the out pointer to the new vnode
+ *out = new_vnode;
+ return 0;
}
/* Remove a directory.
@@ -495,8 +840,50 @@ static long s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen)
KASSERT(!name_match(".", name, namelen));
KASSERT(!name_match("..", name, namelen));
KASSERT(S_ISDIR(parent->vn_mode) && "should be handled at the VFS level");
- NOT_YET_IMPLEMENTED("S5FS: s5fs_rmdir");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_rmdir");
+
+ // Find the directory entry
+ s5_node_t *s5_node = VNODE_TO_S5NODE(parent);
+ size_t filepos;
+ long ino = s5_find_dirent(s5_node, name, namelen, &filepos);
+ // Check if the directory entry was not found
+ if (ino < 0)
+ {
+ return ino;
+ }
+
+ // Get the found vnode
+ vnode_t *child = vget_locked(parent->vn_fs, ino);
+ KASSERT(S_ISDIR(child->vn_mode) && "should be handled at the VFS level");
+
+ // Check if this is a directory
+ if (!S_ISDIR(child->vn_mode))
+ {
+ vput_locked(&child);
+ return -ENOTDIR;
+ }
+
+ // Check if the directory is not empty
+ if (child->vn_len > 2 * sizeof(s5_dirent_t))
+ {
+ vput_locked(&child);
+ return -ENOTEMPTY;
+ }
+
+ // Remove the "." entry
+ s5_remove_dirent(VNODE_TO_S5NODE(child), ".", 1, 0);
+ // Check if this failed (TODO: ask in hours)
+
+ // Remove the ".." entry
+ s5_remove_dirent(VNODE_TO_S5NODE(child), "..", 2, 0);
+
+ // Remove the directory entry
+ s5_remove_dirent(s5_node, name, namelen, filepos);
+ // Check if this failed (TODO: ask in hours)
+
+ // Release the vnode
+ vput_locked(&child);
+ return 0;
}
/* Read a directory entry.
@@ -518,8 +905,23 @@ static long s5fs_rmdir(vnode_t *parent, const char *name, size_t namelen)
static long s5fs_readdir(vnode_t *vnode, size_t pos, struct dirent *d)
{
KASSERT(S_ISDIR(vnode->vn_mode) && "should be handled at the VFS level");
- NOT_YET_IMPLEMENTED("S5FS: s5fs_readdir");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_readdir");
+
+ // Read the directory entry
+ s5_dirent_t s5_dirent;
+ long bytes_read = s5_read_file(VNODE_TO_S5NODE(vnode), pos, &s5_dirent, sizeof(s5_dirent_t));
+ // Check if the read operation failed
+ if (bytes_read < 0)
+ {
+ return bytes_read;
+ }
+
+ // Initialize the dirent
+ d->d_ino = s5_dirent.s5d_inode;
+ d->d_off = pos + sizeof(s5_dirent_t);
+ memcpy(d->d_name, s5_dirent.s5d_name, 28);
+
+ return bytes_read;
}
/* Get file status.
@@ -542,8 +944,29 @@ static long s5fs_readdir(vnode_t *vnode, size_t pos, struct dirent *d)
*/
static long s5fs_stat(vnode_t *vnode, stat_t *ss)
{
- NOT_YET_IMPLEMENTED("S5FS: s5fs_stat");
- return -1;
+ // NOT_YET_IMPLEMENTED("S5FS: s5fs_stat");
+
+ // Get the inode
+ s5_inode_t *s5_inode = &VNODE_TO_S5NODE(vnode)->inode;
+
+ // Initialize the stat struct
+ ss->st_blocks = s5_inode_blocks(s5_inode);
+ ss->st_mode = vnode->vn_mode;
+ ss->st_rdev = vnode->vn_devid;
+ ss->st_ino = s5_inode->s5_number;
+ ss->st_nlink = s5_inode->s5_linkcount;
+ ss->st_blksize = S5_BLOCK_SIZE;
+ ss->st_size = s5_inode->s5_un.s5_size;
+ ss->st_dev = VNODE_TO_S5FS(vnode)->s5f_bdev->bd_id;
+
+ // Set all other fields to 0
+ ss->st_uid = 0;
+ ss->st_gid = 0;
+ ss->st_atime = 0;
+ ss->st_mtime = 0;
+ ss->st_ctime = 0;
+
+ return 0;
}
/**
diff --git a/kernel/fs/vfs_syscall.c b/kernel/fs/vfs_syscall.c
index e05fe5f..205020b 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,60 @@ 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);
+ return bytes_written;
+ }
+
+ file->f_pos += bytes_written;
+ fput(&file);
+ return bytes_written;
}
/*
@@ -63,8 +165,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
+ fput(&file);
+ fput(&curproc->p_files[fd]);
+
+ return 0;
}
/*
@@ -78,8 +198,33 @@ 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)
+ {
+ fput(&file);
+ return ret;
+ }
+
+ // Copy the file
+ curproc->p_files[new_fd] = file;
+ return new_fd;
}
/*
@@ -94,8 +239,40 @@ 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)
+ {
+ fput(&new_file);
+ do_close(nfd);
+ }
+
+ // Copy the file
+ curproc->p_files[nfd] = file;
+ return nfd;
}
/*
@@ -117,8 +294,20 @@ 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);
+ vput(&vnode);
+ return ret;
}
/*
@@ -143,8 +332,53 @@ 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
+ long err = dir->vn_ops->mkdir(dir, name, len, &base);
+ if (err < 0)
+ {
+ vput(&dir);
+ return err;
+ }
+
+ vput(&base);
+ vput(&dir);
+ return 0;
}
/*
@@ -165,8 +399,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;
+ }
+
+ vput(&base);
+ // Remove the directory
+ vlock(dir);
+ ret = dir->vn_ops->rmdir(dir, name, len);
+ vunlock(dir);
+ vput(&dir);
+
+ return ret;
}
/*
@@ -183,8 +484,62 @@ 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;
+ }
+
+ vput(&base);
+ // Call the unlink operation
+ vlock(dir);
+ ret = dir->vn_ops->unlink(dir, name, len);
+ vunlock(dir);
+ vput(&dir);
+
+ return ret;
}
/*
@@ -206,8 +561,56 @@ 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);
+ return -ENOTDIR;
+ }
+ // Check if name is too long
+ if (len > NAME_LEN)
+ {
+ vput(&old_vnode);
+ 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 +634,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 +647,57 @@ 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))
+ {
+ 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);
+ return -ENOTDIR;
+ }
+
+ // Check if the names are too long
+ if (old_len > NAME_LEN || new_len > NAME_LEN)
+ {
+ vput(&old_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 +714,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 +753,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 +807,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 +861,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..fb6df0b 100644
--- a/kernel/fs/vnode_specials.c
+++ b/kernel/fs/vnode_specials.c
@@ -110,8 +110,20 @@ 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");
- return 0;
+ // 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;
}
/*
@@ -125,8 +137,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;
}
/*