vfs.c
1 #include "vfs.h" 2 #include "memory.h" 3 #include "string.h" 4 #include "kernel.h" 5 6 // Global VFS root 7 vfs_node_t* vfs_root = NULL; 8 9 // Mount points 10 static vfs_mount_t* mount_points = NULL; 11 12 // Initialize VFS 13 void vfs_init(void) { 14 // Create root directory node 15 vfs_root = (vfs_node_t*)kmalloc(sizeof(vfs_node_t)); 16 memset(vfs_root, 0, sizeof(vfs_node_t)); 17 18 strcpy(vfs_root->name, "/"); 19 vfs_root->flags = VFS_DIRECTORY; 20 vfs_root->inode = 0; 21 vfs_root->uid = 0; 22 vfs_root->gid = 0; 23 vfs_root->refcount = 1; 24 25 terminal_writestring("VFS initialized\n"); 26 } 27 28 // Split path into components 29 static char** split_path(const char* path, int* count) { 30 char* path_copy = (char*)kmalloc(strlen(path) + 1); 31 strcpy(path_copy, path); 32 33 // Count components 34 int components = 0; 35 char* p = path_copy; 36 while (*p) { 37 if (*p == '/' && *(p+1) && *(p+1) != '/') { 38 components++; 39 } 40 p++; 41 } 42 43 char** parts = (char**)kmalloc(sizeof(char*) * (components + 1)); 44 *count = 0; 45 46 // Split by '/' 47 char* token = strtok(path_copy, "/"); 48 while (token && *count < components) { 49 parts[*count] = (char*)kmalloc(strlen(token) + 1); 50 strcpy(parts[*count], token); 51 (*count)++; 52 token = strtok(NULL, "/"); 53 } 54 55 kfree(path_copy); 56 return parts; 57 } 58 59 // Free split path 60 static void free_split_path(char** parts, int count) { 61 for (int i = 0; i < count; i++) { 62 kfree(parts[i]); 63 } 64 kfree(parts); 65 } 66 67 // Find mount point for path 68 static vfs_mount_t* find_mount(const char* path) { 69 vfs_mount_t* best_match = NULL; 70 size_t best_len = 0; 71 72 vfs_mount_t* mount = mount_points; 73 while (mount) { 74 size_t mount_len = strlen(mount->path); 75 if (strncmp(path, mount->path, mount_len) == 0) { 76 if (mount_len > best_len) { 77 best_match = mount; 78 best_len = mount_len; 79 } 80 } 81 mount = mount->next; 82 } 83 84 return best_match; 85 } 86 87 // Resolve path to node 88 vfs_node_t* vfs_resolve_path(const char* path) { 89 if (!path || !*path) return NULL; 90 91 // Handle absolute vs relative paths 92 vfs_node_t* node; 93 const char* remaining_path; 94 95 if (path[0] == '/') { 96 // Check for mount point 97 vfs_mount_t* mount = find_mount(path); 98 if (mount && strcmp(mount->path, "/") != 0) { 99 node = mount->root; 100 remaining_path = path + strlen(mount->path); 101 if (*remaining_path == '/') remaining_path++; 102 } else { 103 node = vfs_root; 104 remaining_path = path + 1; 105 } 106 } else { 107 // TODO: Handle relative paths with current directory 108 node = vfs_root; 109 remaining_path = path; 110 } 111 112 if (!*remaining_path) { 113 node->refcount++; 114 return node; 115 } 116 117 // Split path and traverse 118 int count; 119 char** parts = split_path(remaining_path, &count); 120 121 for (int i = 0; i < count && node; i++) { 122 if (!(node->flags & VFS_DIRECTORY)) { 123 node = NULL; 124 break; 125 } 126 127 if (node->ops && node->ops->finddir) { 128 vfs_node_t* next = node->ops->finddir(node, parts[i]); 129 if (i > 0) { 130 // Decrement refcount of intermediate nodes 131 node->refcount--; 132 } 133 node = next; 134 } else { 135 node = NULL; 136 } 137 } 138 139 free_split_path(parts, count); 140 141 if (node) { 142 node->refcount++; 143 } 144 145 return node; 146 } 147 148 // Open file/directory 149 vfs_node_t* vfs_open(const char* path, uint32_t flags) { 150 vfs_node_t* node = vfs_resolve_path(path); 151 152 if (!node && (flags & O_CREAT)) { 153 // TODO: Create file 154 return NULL; 155 } 156 157 if (node) { 158 if ((flags & O_DIRECTORY) && !(node->flags & VFS_DIRECTORY)) { 159 node->refcount--; 160 return NULL; 161 } 162 163 if (node->ops && node->ops->open) { 164 node->ops->open(node, flags); 165 } 166 } 167 168 return node; 169 } 170 171 // Close file/directory 172 void vfs_close(vfs_node_t* node) { 173 if (!node) return; 174 175 if (node->ops && node->ops->close) { 176 node->ops->close(node); 177 } 178 179 node->refcount--; 180 if (node->refcount == 0) { 181 // TODO: Possibly free the node 182 } 183 } 184 185 // Read from file 186 uint32_t vfs_read(vfs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { 187 if (!node || !buffer) return 0; 188 189 if (node->ops && node->ops->read) { 190 return node->ops->read(node, offset, size, buffer); 191 } 192 193 return 0; 194 } 195 196 // Write to file 197 uint32_t vfs_write(vfs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { 198 if (!node || !buffer) return 0; 199 200 if (node->ops && node->ops->write) { 201 return node->ops->write(node, offset, size, buffer); 202 } 203 204 return 0; 205 } 206 207 // Read directory entry 208 vfs_dirent_t* vfs_readdir(vfs_node_t* node, uint32_t index) { 209 if (!node || !(node->flags & VFS_DIRECTORY)) return NULL; 210 211 if (node->ops && node->ops->readdir) { 212 return node->ops->readdir(node, index); 213 } 214 215 return NULL; 216 } 217 218 // Find directory entry 219 vfs_node_t* vfs_finddir(vfs_node_t* node, const char* name) { 220 if (!node || !(node->flags & VFS_DIRECTORY)) return NULL; 221 222 if (node->ops && node->ops->finddir) { 223 return node->ops->finddir(node, name); 224 } 225 226 return NULL; 227 } 228 229 // Get file stats 230 int vfs_stat(const char* path, struct stat* st) { 231 if (!path || !st) return -1; 232 233 vfs_node_t* node = vfs_resolve_path(path); 234 if (!node) return -1; 235 236 // Fill in basic stats 237 st->st_ino = node->inode; 238 st->st_mode = node->flags & 0xFFFF; 239 st->st_uid = node->uid; 240 st->st_gid = node->gid; 241 st->st_size = node->size; 242 st->st_atime = node->atime; 243 st->st_mtime = node->mtime; 244 st->st_ctime = node->ctime; 245 246 // Call filesystem-specific stat if available 247 if (node->ops && node->ops->stat) { 248 int result = node->ops->stat(node, st); 249 vfs_close(node); 250 return result; 251 } 252 253 vfs_close(node); 254 return 0; 255 } 256 257 // Mount filesystem 258 int vfs_mount(const char* path, vfs_node_t* root) { 259 if (!path || !root) return -1; 260 261 // Create mount point 262 vfs_mount_t* mount = (vfs_mount_t*)kmalloc(sizeof(vfs_mount_t)); 263 strcpy(mount->path, path); 264 mount->root = root; 265 mount->next = mount_points; 266 mount_points = mount; 267 268 terminal_writestring("Mounted filesystem at "); 269 terminal_writestring(path); 270 terminal_writestring("\n"); 271 272 return 0; 273 } 274 275 // Unmount filesystem 276 int vfs_unmount(const char* path) { 277 if (!path) return -1; 278 279 vfs_mount_t** prev = &mount_points; 280 vfs_mount_t* mount = mount_points; 281 282 while (mount) { 283 if (strcmp(mount->path, path) == 0) { 284 *prev = mount->next; 285 kfree(mount); 286 return 0; 287 } 288 prev = &mount->next; 289 mount = mount->next; 290 } 291 292 return -1; 293 }