2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018-2019 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
34 struct memfs_node *rootdir;
38 struct memfs_node *clist, *ctail;
39 struct memfs_node *cur;
43 struct memfs_dir *dir;
44 struct memfs_node *cur;
45 struct fs_dirent dent;
54 struct memfs_file *file;
60 struct memfs_file file;
64 char name[MAX_NAME + 4];
65 struct memfs_node *parent;
66 struct memfs_node *next;
67 struct fs_node *fsnode; /* we need it for crossing mounts in fs_open */
71 static void destroy(struct filesys *fs);
73 static struct fs_node *open(struct filesys *fs, const char *path, unsigned int flags);
74 static void close(struct fs_node *node);
75 static long fsize(struct fs_node *node);
76 static int seek(struct fs_node *node, int offs, int whence);
77 static long tell(struct fs_node *node);
78 static int read(struct fs_node *node, void *buf, int sz);
79 static int write(struct fs_node *node, void *buf, int sz);
80 static int rewinddir(struct fs_node *node);
81 static struct fs_dirent *readdir(struct fs_node *node);
82 static int rename(struct fs_node *node, const char *name);
83 static int remove(struct fs_node *node);
85 static struct fs_node *create_fsnode(struct filesys *fs, struct memfs_node *n);
87 static struct memfs_node *alloc_node(int type);
88 static void free_node(struct memfs_node *node);
90 static struct memfs_node *find_entry(struct memfs_node *dir, const char *name);
91 static void add_child(struct memfs_node *dir, struct memfs_node *n);
94 static struct fs_operations fs_mem_ops = {
108 struct filesys *fsmem_create(int dev, uint64_t start, uint64_t size)
113 if(dev != DEV_MEMDISK) {
117 if(!(memfs = malloc(sizeof *memfs))) {
118 panic("MEMFS: create failed to allocate memory\n");
120 if(!(memfs->rootdir = alloc_node(FSNODE_DIR))) {
121 panic("MEMFS: failed to allocate root dir\n");
124 if(!(fs = malloc(sizeof *fs))) {
125 panic("MEMFS: failed to allocate memory for the filesystem structure\n");
127 fs->type = FSTYPE_MEM;
129 fs->fsop = &fs_mem_ops;
135 static void destroy(struct filesys *fs)
137 struct memfs *memfs = fs->data;
138 free_node((struct memfs_node*)memfs->rootdir);
143 static struct fs_node *open_mount(struct filesys *fs, const char *path, unsigned int flags)
147 newpath = alloca(strlen(path) + 2);
149 strcpy(newpath + 1, path);
151 return fs->fsop->open(fs, newpath, flags);
154 #define NODE_IS_MNTPT(n) ((n)->fsnode && (n)->fsnode->mnt)
156 static struct fs_node *open(struct filesys *fs, const char *path, unsigned int flags)
158 struct memfs_node *node, *parent;
159 struct memfs *memfs = fs->data;
160 char name[MAX_NAME + 1];
163 node = memfs->rootdir;
164 path = fs_path_skipsep((char*)path);
166 if(cwdnode->fs->type != FSTYPE_MEM) {
169 node = (struct memfs_node*)((struct odir*)cwdnode->data)->dir;
171 assert(node->type == FSNODE_DIR);
174 if(node->type != FSNODE_DIR) {
175 /* we have more path components, yet the last one wasn't a dir */
179 /* check if it's another filesystem hanging off this directory, and if
180 * so, recursively call that open function to complete the operation
182 if(NODE_IS_MNTPT(node)) {
183 return open_mount(node->fsnode->mnt, path, flags);
186 path = fs_path_next((char*)path, name, sizeof name);
189 if(!(node = find_entry(node, name))) {
190 if(*path || !(flags & FSO_CREATE)) {
195 if(!(node = alloc_node((flags & FSO_DIR) ? FSNODE_DIR : FSNODE_FILE))) {
199 strcpy(node->name, name);
200 add_child(parent, node);
201 return create_fsnode(fs, node);
205 /* we need to check for mount points here too, because the check in the loop
206 * above is not going to be reached when the mount point is the last part of
207 * the path string (for instance opendir("/mnt/foo"))
209 if(NODE_IS_MNTPT(node)) {
210 return open_mount(node->fsnode->mnt, path, flags);
213 if(flags & FSO_EXCL) {
217 return create_fsnode(fs, node);
220 static struct fs_node *create_fsnode(struct filesys *fs, struct memfs_node *n)
226 if(!(fsn = calloc(1, sizeof *fsn))) {
231 if(n->type == FSNODE_FILE) {
232 if(!(of = malloc(sizeof *of))) {
241 if(!(od = malloc(sizeof *od))) {
247 od->cur = n->dir.clist;
260 static void close(struct fs_node *node)
264 free(node->data); /* free the copy of memfs_node allocated by create_fsnode */
268 static long fsize(struct fs_node *node)
271 if(!node || node->type != FSNODE_FILE) {
275 return of->file->size;
278 static int seek(struct fs_node *node, int offs, int whence)
283 if(!node || node->type != FSNODE_FILE) {
295 new_pos = of->cur_pos + offs;
299 new_pos = of->file->size + offs;
306 if(new_pos < 0) new_pos = 0;
308 of->cur_pos = new_pos;
312 static long tell(struct fs_node *node)
316 if(!node || node->type != FSNODE_FILE) {
323 static int read(struct fs_node *node, void *buf, int sz)
327 if(!node || !buf || sz < 0 || node->type != FSNODE_FILE) {
333 if(sz > of->file->size - of->cur_pos) {
334 sz = of->file->size - of->cur_pos;
336 memcpy(buf, of->file->data + of->cur_pos, sz);
341 static int write(struct fs_node *node, void *buf, int sz)
344 int total_sz, new_max_sz;
347 if(!node || !buf || sz < 0 || node->type != FSNODE_FILE) {
352 total_sz = of->cur_pos + sz;
353 if(total_sz > of->file->max_size) {
354 if(total_sz < of->file->max_size * 2) {
355 new_max_sz = of->file->max_size * 2;
357 new_max_sz = total_sz;
359 if(!(tmp = realloc(of->file->data, new_max_sz))) {
363 of->file->data = tmp;
364 of->file->max_size = new_max_sz;
367 memcpy(of->file->data + of->cur_pos, buf, sz);
369 if(of->cur_pos > of->file->size) of->file->size = of->cur_pos;
373 static int rewinddir(struct fs_node *node)
377 if(!node || node->type != FSNODE_DIR) {
382 od->cur = od->dir->clist;
386 static struct fs_dirent *readdir(struct fs_node *node)
389 struct memfs_node *n;
390 struct fs_dirent *fsd;
392 if(!node || node->type != FSNODE_DIR) {
402 od->cur = od->cur->next;
407 fsd->fsize = n->file.size;
412 static int rename(struct fs_node *node, const char *name)
414 struct memfs_node *n = (struct memfs_node*)((struct odir*)node->data)->dir;
415 strncpy(n->name, name, MAX_NAME);
416 n->name[MAX_NAME] = 0;
420 static int remove(struct fs_node *node)
424 struct ofile *of = 0;
425 struct memfs_node *n, *par, *prev, dummy;
427 if(node->type == FSNODE_DIR) {
429 n = (struct memfs_node*)od->dir;
437 n = (struct memfs_node*)of->file;
446 dummy.next = par->dir.clist;
449 if(prev->next == n) {
450 if(par->dir.ctail == n) {
451 par->dir.ctail = prev;
453 prev->next = n->next;
460 par->dir.clist = dummy.next;
464 static struct memfs_node *alloc_node(int type)
466 struct memfs_node *node;
468 if(!(node = calloc(1, sizeof *node))) {
475 static void free_node(struct memfs_node *node)
481 free(node->file.data);
485 while(node->dir.clist) {
486 struct memfs_node *n = node->dir.clist;
487 node->dir.clist = n->next;
494 static struct memfs_node *find_entry(struct memfs_node *dnode, const char *name)
496 struct memfs_node *n;
498 if(strcmp(name, ".") == 0) return dnode;
499 if(strcmp(name, "..") == 0) return dnode->parent;
501 n = dnode->dir.clist;
503 if(strcasecmp(n->name, name) == 0) {
511 static void add_child(struct memfs_node *dnode, struct memfs_node *n)
513 if(dnode->dir.clist) {
514 dnode->dir.ctail->next = n;
515 dnode->dir.ctail = n;
517 dnode->dir.clist = dnode->dir.ctail = n;