| 1 | #include <console/printf.h> |
| 2 | #include <fs/vfs.h> |
| 3 | #include <log.h> |
| 4 | #include <mem/alloc.h> |
| 5 | #include <stdint.h> |
| 6 | #include <string.h> |
| 7 | |
| 8 | #include "errno.h" |
| 9 | #include "fs/detect.h" |
| 10 | |
| 11 | static struct vfs_mount **mount_table = NULL; |
| 12 | static uint64_t mount_table_count = 0; |
| 13 | static uint64_t mount_table_capacity = 0; |
| 14 | |
| 15 | LOG_SITE_DECLARE_DEFAULT(vfs); |
| 16 | LOG_HANDLE_DECLARE_DEFAULT(vfs); |
| 17 | |
| 18 | static void mount_table_add(struct vfs_mount *mnt) { |
| 19 | if (mount_table_count == mount_table_capacity) { |
| 20 | uint64_t new_capacity = |
| 21 | (mount_table_capacity == 0) ? 4 : mount_table_capacity * 2; |
| 22 | |
| 23 | struct vfs_mount **new_table; |
| 24 | new_table = krealloc(mount_table, new_capacity * sizeof(*mount_table)); |
| 25 | |
| 26 | if (!new_table) |
| 27 | return; |
| 28 | mount_table = new_table; |
| 29 | mount_table_capacity = new_capacity; |
| 30 | } |
| 31 | |
| 32 | mount_table[mount_table_count++] = mnt; |
| 33 | } |
| 34 | |
| 35 | static void mount_table_remove(struct vfs_mount *mnt) { |
| 36 | for (uint64_t i = 0; i < mount_table_count; i++) { |
| 37 | if (mount_table[i] == mnt) { |
| 38 | mount_table[i] = mount_table[--mount_table_count]; |
| 39 | return; |
| 40 | } |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | void vfs_node_print(const struct vfs_node *node) { |
| 45 | if (!node) { |
| 46 | printf(format: "vfs_node: (null)\n" ); |
| 47 | return; |
| 48 | } |
| 49 | |
| 50 | printf(format: "=== VFS Node ===\n" ); |
| 51 | printf(format: "Type : %s (%d)\n" , detect_fstr(type: node->fs_type), node->fs_type); |
| 52 | printf(format: "Open : %s\n" , node->open_handles ? "Yes" : "No" ); |
| 53 | printf(format: "Flags : 0x%08X\n" , node->flags); |
| 54 | printf(format: "Mode : 0%o\n" , node->mode); |
| 55 | printf(format: "Size : %llu bytes\n" , (unsigned long long) node->size); |
| 56 | printf(format: "FS Data : 0x%llx\n" , node->fs_data); |
| 57 | printf(format: "FS Node : 0x%llx\n" , node->fs_node_data); |
| 58 | printf(format: "Ops Table: 0x%llx\n" , (void *) node->ops); |
| 59 | printf(format: "=================\n" ); |
| 60 | } |
| 61 | |
| 62 | static struct vfs_mount *find_mount_for_node(struct vfs_node *node) { |
| 63 | for (uint64_t i = 0; i < mount_table_count; i++) { |
| 64 | if (mount_table[i]->mount_point->unique_id == node->unique_id) |
| 65 | return mount_table[i]; |
| 66 | } |
| 67 | return NULL; |
| 68 | } |
| 69 | |
| 70 | struct vfs_node *vfs_finddir(struct vfs_node *node, const char *fname) { |
| 71 | if (!node || !fname) |
| 72 | return NULL; |
| 73 | |
| 74 | struct vfs_mount *mnt = find_mount_for_node(node); |
| 75 | if (mnt) |
| 76 | node = mnt->root; |
| 77 | |
| 78 | if (!node->ops || !node->ops->finddir) |
| 79 | return NULL; |
| 80 | |
| 81 | struct vfs_dirent ent = {0}; |
| 82 | |
| 83 | node->ops->finddir(node, fname, &ent); |
| 84 | |
| 85 | struct vfs_node *found = ent.node; |
| 86 | |
| 87 | mnt = find_mount_for_node(node: found); |
| 88 | if (mnt) |
| 89 | return mnt->root; |
| 90 | |
| 91 | return found; |
| 92 | } |
| 93 | |
| 94 | enum errno vfs_mount(struct vfs_node *mountpoint, struct vfs_node *target, |
| 95 | const char *name) { |
| 96 | if (!mountpoint || !target) |
| 97 | return ERR_INVAL; |
| 98 | |
| 99 | if (!(mountpoint->mode & VFS_MODE_DIR)) |
| 100 | return ERR_NOT_DIR; |
| 101 | |
| 102 | if (mountpoint->child_mount) |
| 103 | return ERR_BUSY; // Already mounted here |
| 104 | |
| 105 | struct vfs_mount *mnt = kmalloc(sizeof(struct vfs_mount)); |
| 106 | if (!mnt) |
| 107 | return ERR_NO_MEM; |
| 108 | |
| 109 | memcpy(mnt->name, name, sizeof(mnt->name)); |
| 110 | mnt->root = target; |
| 111 | mnt->mount_point = mountpoint; |
| 112 | mnt->ops = target->ops; |
| 113 | mnt->fs_data = target->fs_data; |
| 114 | mnt->mount_point->child_mount = mnt; |
| 115 | |
| 116 | mount_table_add(mnt); |
| 117 | return ERR_OK; |
| 118 | } |
| 119 | |
| 120 | enum errno vfs_unmount(struct vfs_mount *mnt) { |
| 121 | if (!mnt) |
| 122 | return ERR_INVAL; |
| 123 | |
| 124 | if (mnt->mount_point) |
| 125 | mnt->mount_point->child_mount = NULL; |
| 126 | |
| 127 | mount_table_remove(mnt); |
| 128 | kfree(mnt); |
| 129 | return ERR_OK; |
| 130 | } |
| 131 | |
| 132 | void vfs_clear_mounts(void) { |
| 133 | for (uint64_t i = 0; i < mount_table_count; i++) { |
| 134 | kfree(mount_table[i]); |
| 135 | } |
| 136 | kfree(mount_table); |
| 137 | mount_table = NULL; |
| 138 | mount_table_count = 0; |
| 139 | mount_table_capacity = 0; |
| 140 | } |
| 141 | |