/ kernel / core / vfs.c
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  }