diff options
| author | Anton Kling <anton@kling.gg> | 2023-10-30 22:12:14 +0100 | 
|---|---|---|
| committer | Anton Kling <anton@kling.gg> | 2023-10-31 00:18:38 +0100 | 
| commit | 8a9208612eec8ddae4c418485d848ecfa0613699 (patch) | |
| tree | 2f4b29200c2f0c19ae52f45bdb9b38a41b356e30 /kernel/fs/vfs.c | |
| parent | ca76600acc8bf7a02346efa5bd8f17072210ec01 (diff) | |
Meta: Move kernel and userland to their own folders.
This is to allow both the kernel and the userland to share certain
header files and to make the folder structure a bit more clear.
Diffstat (limited to 'kernel/fs/vfs.c')
| -rw-r--r-- | kernel/fs/vfs.c | 318 | 
1 files changed, 318 insertions, 0 deletions
| diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c new file mode 100644 index 0000000..0c616a2 --- /dev/null +++ b/kernel/fs/vfs.c @@ -0,0 +1,318 @@ +#include <assert.h> +#include <errno.h> +#include <fs/vfs.h> +#include <mmu.h> +#include <poll.h> + +vfs_inode_t *root_dir; +vfs_mounts_t mounts[10]; +int num_mounts = 0; + +vfs_fd_t *get_vfs_fd(int fd) { +  if (fd >= 100) { +    klog("get_vfs_fd(): Tried to get out of range fd", LOG_WARN); +    dump_backtrace(12); +    return NULL; +  } +  if (fd < 0) { +    klog("get_vfs_fd(): Tried to get out of range fd", LOG_WARN); +    dump_backtrace(12); +    return NULL; +  } +  return get_current_task()->file_descriptors[fd]; +} + +vfs_inode_t *vfs_create_inode( +    int inode_num, int type, uint8_t has_data, uint8_t can_write, +    uint8_t is_open, void *internal_object, uint64_t file_size, +    vfs_inode_t *(*open)(const char *path), +    int (*create_file)(const char *path, int mode), +    int (*read)(uint8_t *buffer, uint64_t offset, uint64_t len, vfs_fd_t *fd), +    int (*write)(uint8_t *buffer, uint64_t offset, uint64_t len, vfs_fd_t *fd), +    void (*close)(vfs_fd_t *fd), +    int (*create_directory)(const char *path, int mode), +    vfs_vm_object_t *(*get_vm_object)(uint64_t length, uint64_t offset, +                                      vfs_fd_t *fd), +    int (*truncate)(vfs_fd_t *fd, size_t length)) { +  vfs_inode_t *r = kmalloc(sizeof(inode_t)); +  r->inode_num = inode_num; +  r->type = type; +  r->has_data = has_data; +  r->can_write = can_write; +  r->is_open = is_open; +  r->internal_object = internal_object; +  r->file_size = file_size; +  r->open = open; +  r->create_file = create_file; +  r->read = read; +  r->write = write; +  r->close = close; +  r->create_directory = create_directory; +  r->get_vm_object = get_vm_object; +  r->truncate = truncate; +  return r; +} + +int vfs_create_fd(int flags, int mode, vfs_inode_t *inode, vfs_fd_t **fd) { +  process_t *p = (process_t *)get_current_task(); +  int i; +  for (i = 0; i < 100; i++) +    if (!p->file_descriptors[i]) +      break; +  if (p->file_descriptors[i]) +    return -1; +  vfs_fd_t *r = kmalloc(sizeof(vfs_fd_t)); +  r->flags = flags; +  r->mode = mode; +  r->inode = inode; +  r->reference_count = 1; +  p->file_descriptors[i] = r; +  if (fd) +    *fd = r; +  return i; +} + +int vfs_create_file(const char *file) { +  vfs_mounts_t *file_mount = 0; +  int length = 0; +  for (int i = 0; i < num_mounts; i++) { +    int path_len = strlen(mounts[i].path); +    if (path_len <= length) +      continue; + +    if (isequal_n(mounts[i].path, file, path_len)) { +      length = path_len; +      file_mount = &mounts[i]; +    } +  } +  if (1 != length) +    file += length; + +  if (!file_mount) { +    kprintf("vfs_internal_open could not find mounted path for file : %s\n", +            file); +    return 0; +  } +  //  ext2_create_file("/etc/oscreated", 0); +  assert(file_mount->local_root->create_file); +  kprintf("Creating a file\n"); +  return file_mount->local_root->create_file(file, 0); +} + +vfs_inode_t *vfs_internal_open(const char *file) { +  vfs_mounts_t *file_mount = 0; +  int length = 0; +  for (int i = 0; i < num_mounts; i++) { +    int path_len = strlen(mounts[i].path); +    if (path_len <= length) +      continue; + +    if (isequal_n(mounts[i].path, file, path_len)) { +      length = path_len; +      file_mount = &mounts[i]; +    } +  } +  if (1 != length) +    file += length; + +  if (!file_mount) { +    kprintf("vfs_internal_open could not find mounted path for file : %s\n", +            file); +    return NULL; +  } + +  vfs_inode_t *ret = file_mount->local_root->open(file); +  return ret; +} + +char *vfs_clean_path(const char *path, char *resolved_path) { +  //  char *const clean = kmalloc(strlen(path) + 1); +  char *clean = resolved_path; +  int prev_slash = 0; +  char *ptr = clean; +  for (; *path; path++) { +    if (prev_slash && '/' == *path) { +      continue; +    } +    prev_slash = ('/' == *path); +    *ptr = *path; +    ptr++; +  } +  *ptr = '\0'; +  return clean; +} + +char *vfs_resolve_path(const char *file, char *resolved_path) { +  if ('/' == *file) { +    return vfs_clean_path(file, resolved_path); +  } +  const char *cwd = get_current_task()->current_working_directory; +  size_t l = strlen(cwd); +  assert(l > 0); +  assert('/' == cwd[l - 1]); +  //  char *r = kmalloc(l + strlen(file) + 1); +  char r[256]; +  strcpy(r, cwd); +  strcat(r, file); +  char *final = vfs_clean_path(r, resolved_path); +  //  kfree(r); +  return final; +} + +int vfs_mkdir(const char *path, int mode) { +  vfs_mounts_t *file_mount = 0; +  int length = 0; +  for (int i = 0; i < num_mounts; i++) { +    int path_len = strlen(mounts[i].path); +    if (path_len <= length) +      continue; + +    if (isequal_n(mounts[i].path, path, path_len)) { +      length = path_len; +      file_mount = &mounts[i]; +    } +  } +  if (1 != length) +    path += length; + +  if (!file_mount) { +    kprintf("vfs_internal_open could not find mounted path for file : %s\n", +            path); +    return 0; +  } +  assert(file_mount->local_root->create_directory); +  // TODO: Error checking, don't just assume it is fine +  file_mount->local_root->create_directory(path, mode); +  return 0; +} + +int vfs_open(const char *file, int flags, int mode) { +  char resolved_path[256] = {0}; +  vfs_resolve_path(file, resolved_path); +  vfs_inode_t *inode = vfs_internal_open(resolved_path); +  if (0 == inode) { +    if (mode & O_CREAT) { +      if (vfs_create_file(resolved_path)) { +        klog("VFS: File created", LOG_NOTE); +        return vfs_open(file, flags, mode); +      } +      klog("VFS: Could not create file", LOG_WARN); +    } +    return -ENOENT; +  } +  if (inode->type == FS_TYPE_UNIX_SOCKET) { +    return uds_open(resolved_path); +  } + +  return vfs_create_fd(flags, mode, inode, NULL); +} + +int vfs_close(int fd) { +  vfs_fd_t *fd_ptr = get_vfs_fd(fd); +  if (NULL == fd_ptr) { +    return -1; +  } +  assert(0 < fd_ptr->reference_count); +  // Remove process reference +  fd_ptr->reference_count--; +  get_current_task()->file_descriptors[fd] = 0; +  // If no references left then free the contents +  if (0 == fd_ptr->reference_count) { +    if (fd_ptr->inode->close) +      fd_ptr->inode->close(fd_ptr); + +    kfree(fd_ptr); +  } +  return 0; +} + +int raw_vfs_pread(vfs_fd_t *vfs_fd, void *buf, uint64_t count, +                  uint64_t offset) { +  if (!(vfs_fd->flags & O_READ)) +    return -EBADF; +  return vfs_fd->inode->read(buf, offset, count, vfs_fd); +} + +int vfs_pread(int fd, void *buf, uint64_t count, uint64_t offset) { +  if (fd >= 100) { +    kprintf("EBADF : %x\n", fd); +    return -EBADF; +  } +  if (fd < 0) { +    dump_backtrace(12); +    kprintf("EBADF : %x\n", fd); +    return -EBADF; +  } +  vfs_fd_t *vfs_fd = get_current_task()->file_descriptors[fd]; +  if (!vfs_fd) +    return -EBADF; +  int rc = raw_vfs_pread(vfs_fd, buf, count, offset); +  if (-EAGAIN == rc && count > 0) { +    if (!(vfs_fd->flags & O_NONBLOCK)) { +      struct pollfd fds; +      fds.fd = fd; +      fds.events = POLLIN; +      fds.revents = 0; +      poll(&fds, 1, 0); +      return vfs_pread(fd, buf, count, offset); +    } +  } +  return rc; +} + +int raw_vfs_pwrite(vfs_fd_t *vfs_fd, void *buf, uint64_t count, +                   uint64_t offset) { +  assert(vfs_fd); +  assert(vfs_fd->inode); +  assert(vfs_fd->inode->write); +  return vfs_fd->inode->write(buf, offset, count, vfs_fd); +} + +int vfs_pwrite(int fd, void *buf, uint64_t count, uint64_t offset) { +  vfs_fd_t *vfs_fd = get_vfs_fd(fd); +  if (!vfs_fd) +    return -EBADF; +  if (!(vfs_fd->flags & O_WRITE)) { +    return -EBADF; +  } +  return raw_vfs_pwrite(vfs_fd, buf, count, offset); +} + +vfs_vm_object_t *vfs_get_vm_object(int fd, uint64_t length, uint64_t offset) { +  vfs_fd_t *vfs_fd = get_vfs_fd(fd); +  if (!vfs_fd) +    return NULL; +  vfs_vm_object_t *r = vfs_fd->inode->get_vm_object(length, offset, vfs_fd); +  return r; +} + +int vfs_dup2(int org_fd, int new_fd) { +  get_current_task()->file_descriptors[new_fd] = +      get_current_task()->file_descriptors[org_fd]; +  get_current_task()->file_descriptors[new_fd]->reference_count++; +  return 1; +} + +int vfs_ftruncate(int fd, size_t length) { +  vfs_fd_t *fd_ptr = get_vfs_fd(fd); +  if (!fd_ptr) +    return -EBADF; +  if (!(fd_ptr->flags & O_READ)) +    return -EINVAL; +  vfs_inode_t *inode = fd_ptr->inode; +  if (!inode) +    return -EINVAL; +  if (!inode->truncate) +    return -EINVAL; + +  return inode->truncate(fd_ptr, length); +} + +void vfs_mount(char *path, vfs_inode_t *local_root) { +  int len = strlen(path); +  mounts[num_mounts].path = kmalloc_eternal(len + 1); +  memcpy(mounts[num_mounts].path, path, len); +  mounts[num_mounts].path[len] = '\0'; +  mounts[num_mounts].local_root = local_root; +  num_mounts++; +} |