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/vfs_syscall.c | |
parent | d970aa2698d831645986effded059eb344a77486 (diff) |
old vfs fixes
Diffstat (limited to 'kernel/fs/vfs_syscall.c')
-rw-r--r-- | kernel/fs/vfs_syscall.c | 626 |
1 files changed, 595 insertions, 31 deletions
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__ |