summaryrefslogtreecommitdiffstats
path: root/sw/z80/kernel/fs/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sw/z80/kernel/fs/fs.c')
-rw-r--r--sw/z80/kernel/fs/fs.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/sw/z80/kernel/fs/fs.c b/sw/z80/kernel/fs/fs.c
new file mode 100644
index 0000000..584f934
--- /dev/null
+++ b/sw/z80/kernel/fs/fs.c
@@ -0,0 +1,236 @@
+#include "fs/fs.h"
+#include "fs/users.h"
+#include "fs/dev.h"
+
+/* from users.h */
+struct fs_user c_user;
+
+/* from inode.h */
+inode_t c_inode;
+
+struct fs_dev devices[FS_MOUNT_LIMIT];
+
+/* filesystem basic implementation */
+
+devsize_t fs_block(blk_t block)
+{
+ // TODO
+ return 0;
+}
+
+devsize_t fs_inode(struct fs_inode *buf)
+{
+ struct fs_superblock * sb;
+ devsize_t seek;
+
+ if (FS_USE_ROM(c_inode))
+ {
+ seek = FS_ROM_SPACE;
+ sb = (struct fs_superblock*) seek;
+
+ } else {
+
+ seek = 0;
+
+ if (c_inode.dev > 0x7)
+ panic("Invalid device"); // TODO, still to implement
+
+ sb = &devices[c_inode.dev].superblock;
+ }
+
+ if (c_inode.inode >= sb->imap_size)
+ {
+ // TODO, set errno
+ return 0; // inode doesn't exist
+ }
+
+ seek += sizeof(struct fs_superblock) +
+ sizeof(struct fs_inode) * c_inode.inode;
+
+ if (FS_USE_ROM(c_inode))
+ *buf = *(struct fs_inode*)seek;
+ else
+ {
+ /* set sio port */
+ sio_port = devices[c_inode.dev].port_no;
+ sio_seek = seek;
+
+ if (sio_read((void *)buf, INODE_META_SIZE) < INODE_META_SIZE)
+ {
+ // TODO, set errno
+ return 0; // cannot read to device
+ }
+ }
+
+ return seek + INODE_META_SIZE;
+}
+
+/* from fd.h */
+int8_t __fd_new()
+{
+ int8_t fd;
+ for (int8_t = 0; i < FD_TABLE_SIZE / 8; i++)
+ {
+ for (uint8_t bit = 0x80, j = 0; bit > 0; bit >>= 1, j++)
+ {
+ if (!(bit & fd_bmap[i]))
+ return i * 8 + j;
+ }
+ }
+
+ return -1;
+}
+
+/* from fd.h */
+int8_t __open_c_inode(uint8_t flags)
+{
+ /* read meta data */
+ struct fs_inode inode;
+
+ /* init file_desc buffer */
+ struct file_desc desc = {c_inode, 0};
+
+ desc.begin = fs_inode(&inode);
+
+ /* bind operations */
+
+ if (flags & OPEN_DIR)
+ {
+ /* dir handler */
+
+ if (inode.type == INODE_TYPE_DIR)
+ {
+ /* bind dir functions */
+ if (FS_USE_ROM(c_inode))
+ /* bind address space functions */
+ FD_BIND_AS_DIR(desc.opers)
+ else
+ /* bind serial space functions */
+ FD_BIND_SS_DIR(desc.opers)
+
+ } else {
+
+ // TODO, set errno
+ return -1; // not a directory
+ }
+
+ } else if (flags & OPEN_LINK) {
+
+ /* link handler */
+
+ if (inode.type == INODE_TYPE_LINK)
+ {
+ if (FS_USE_ROM(c_inode))
+ FD_BIND_AS_FILE(desc.opers, flags)
+ else
+ FD_BIND_SS_FILE(desc.opers, flags)
+
+ if (flags & OPEN_ERASE)
+ /* empty file content */
+ __inode_empty(desc.begin);
+
+ } else {
+
+ // TODO, set errno
+ return -1; // not a link
+ }
+
+ } else {
+
+ /* file */
+
+ if (inode.type == INODE_TYPE_FILE)
+ ; // do nothing
+ else if (inode.type == INODE_TYPE_SPECIAL) {
+
+ // TODO, bind special callbacks
+
+ } else {
+
+ // TODO, set errno
+ return -1;
+ }
+
+ /* bind operations */
+
+ if (FS_USE_ROM(c_inode))
+ {
+ if (flags & OPEN_BIN)
+ FD_BIND_AS_BINFILE(desc.opers, flags)
+ else
+ FD_BIND_AS_FILE(desc.opers, flags)
+
+ } else {
+
+ if (flags & OPEN_BIN)
+ FD_BIND_SS_BINFILE(desc.opers, flags)
+ else
+ FD_BIND_SS_FILE(desc.opers, flags)
+ }
+ }
+
+ /* find a free fd space */
+
+ int8_t fd = __fd_new();
+
+ if (fd < 0)
+ {
+ // TODO, set errno, fd not available
+
+ } else
+ fd_table[fd] = desc; // copy buffer into the table
+
+ return fd;
+}
+
+inode_t fs_rec_path(const char *path);
+
+inode_t fs_parse_path(const char *path)
+{
+ inode_t ino, cwd = c_inode;
+
+ switch (path[0])
+ {
+ case '0':
+ FS_INODE_NULL(ino)
+ return ino;
+
+ case '/':
+ FS_INODE_ROOT(ino)
+ c_inode = ino; // set cwd to root
+ path++;
+ break;
+
+ case '~':
+
+ if (path[1] = '/')
+ {
+ c_inode.dev = FS_DEV_ROM;
+ c_inode.inode = c_user.home; // set cwd to home
+ path += 2;
+ }
+
+ break;
+ }
+
+ ino = fs_rec_path(path);
+ c_inode = cwd;
+ return ino;
+}
+
+inode_t fs_rec_path(const char *path)
+{
+ devsize_t inode = fs_inode(c_inode.inode);
+ inode_t rel;
+
+ if (!inode) // if not exists
+ {
+ FS_INODE_NULL(rel)
+ return rel;
+ }
+
+ // TODO, check if dir or file
+ // TODO, if dir, find name
+ // TODO, set fs_cwd to new inode
+ // TODO, recall fs_rec_path
+}