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
11static struct vfs_mount **mount_table = NULL;
12static uint64_t mount_table_count = 0;
13static uint64_t mount_table_capacity = 0;
14
15LOG_SITE_DECLARE_DEFAULT(vfs);
16LOG_HANDLE_DECLARE_DEFAULT(vfs);
17
18static 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
35static 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
44void 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
62static 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
70struct 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
94enum 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
120enum 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
132void 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