From 990e4785820136f2ab4a3bf4c1afbf0e8cf28b3c Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Tue, 24 Feb 2015 18:52:09 +0100 Subject: Complete ISO9660 impl ; some strange wtf is going on. --- make_cdrom.sh | 1 + menu_cdrom.lst | 2 +- src/kernel/core/kmain.c | 16 +++ src/kernel/dev/pciide.c | 1 - src/kernel/fs/iso9660.c | 267 +++++++++++++++++++++++++++++++++++++++- src/kernel/include/fs/iso9660.h | 19 +++ 6 files changed, 302 insertions(+), 4 deletions(-) diff --git a/make_cdrom.sh b/make_cdrom.sh index cccca8e..b481fcc 100755 --- a/make_cdrom.sh +++ b/make_cdrom.sh @@ -10,6 +10,7 @@ fi cp menu_cdrom.lst cdrom/boot/grub/menu.lst cp src/kernel/kernel.bin cdrom; strip cdrom/kernel.bin cp src/apps/init/init.bin cdrom; strip cdrom/init.bin +cp README.md cdrom genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot \ -boot-load-size 4 -boot-info-table -input-charset ascii \ diff --git a/menu_cdrom.lst b/menu_cdrom.lst index f055427..16cf6b5 100644 --- a/menu_cdrom.lst +++ b/menu_cdrom.lst @@ -3,7 +3,7 @@ default 1 title kogata OS -kernel /kernel.bin root=io:/atapi0 init=root:/init.bin +kernel /kernel.bin root=io:/atapi0 root_opts=l init=root:/init.bin title kogata OS without root kernel /kernel.bin init=io:/mod/init.bin diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c index 8242f99..c08d749 100644 --- a/src/kernel/core/kmain.c +++ b/src/kernel/core/kmain.c @@ -155,6 +155,22 @@ void kernel_init_stage2(void* data) { fs_t *rootfs = 0; if (btree_find(cmdline, "root") != 0) rootfs = setup_rootfs(cmdline, iofs); + if (rootfs != 0) { + fs_handle_t *readme = fs_open(rootfs, "/readme.md", FM_READ); + if (readme != 0) { + char buf[100]; + dbg_printf("Read %d.\n", file_read(readme, 0, 100, buf)); + buf[99] = 0; + dbg_printf("%s\n", buf); + unref_file(readme); + } + } + + void iter(void* a, void* b) { + dbg_printf("'%s': '%s' (0x%p, 0x%p)\n", a, b, a, b); + } + btree_iter(cmdline, iter); + launch_init(cmdline, iofs, rootfs); // We are done here diff --git a/src/kernel/dev/pciide.c b/src/kernel/dev/pciide.c index ad7375b..f4474ba 100644 --- a/src/kernel/dev/pciide.c +++ b/src/kernel/dev/pciide.c @@ -754,7 +754,6 @@ int ide_vfs_ioctl(fs_handle_ptr f, int command, void* data) { if (command == IOCTL_BLOCKDEV_GET_BLOCK_COUNT) ret = d->c->devices[d->device].size; - dbg_printf("ioctl (0x%p) %d -> %d\n", f, command, ret); return ret; } diff --git a/src/kernel/fs/iso9660.c b/src/kernel/fs/iso9660.c index d8c103f..505f279 100644 --- a/src/kernel/fs/iso9660.c +++ b/src/kernel/fs/iso9660.c @@ -1,13 +1,71 @@ +#include #include #include static bool iso9660_make(fs_handle_t *source, const char* opts, fs_t *t); +static void iso9660_fs_shutdown(fs_ptr f); + +static bool iso9660_node_stat(fs_node_ptr n, stat_t *st); +static void iso9660_node_dispose(fs_node_ptr n); +static bool iso9660_dir_open(fs_node_ptr n, int mode, fs_handle_t *s); +static bool iso9660_dir_walk(fs_node_ptr n, const char* file, struct fs_node *node_d); +static bool iso9660_file_open(fs_node_ptr n, int mode, fs_handle_t *s); + +static size_t iso9660_fh_read(fs_handle_ptr f, size_t offset, size_t len, char* buf); +static void iso9660_fh_close(fs_handle_ptr f); +static bool iso9660_dh_readdir(fs_handle_ptr f, dirent_t *d); +static void iso9660_dh_close(fs_handle_ptr f); static fs_driver_ops_t iso9660_driver_ops = { .make = iso9660_make, }; +static fs_ops_t iso9660_fs_ops = { + .add_source = 0, + .shutdown = iso9660_fs_shutdown +}; + +static fs_node_ops_t iso9660_dir_ops = { + .open = iso9660_dir_open, + .stat = iso9660_node_stat, + .walk = iso9660_dir_walk, + .dispose = iso9660_node_dispose, + .delete = 0, + .move = 0, + .create = 0, +}; + +static fs_node_ops_t iso9660_file_ops = { + .open = iso9660_file_open, + .stat = iso9660_node_stat, + .dispose = iso9660_node_dispose, + .walk = 0, + .delete = 0, + .move = 0, + .create = 0, +}; + +static fs_handle_ops_t iso9660_dh_ops = { + .readdir = iso9660_dh_readdir, + .close = iso9660_dh_close, + .read = 0, + .write = 0, + .ioctl = 0, + .get_page = 0, + .commit_page = 0, +}; + +static fs_handle_ops_t iso9660_fh_ops = { + .readdir = 0, + .close = iso9660_fh_close, + .read = iso9660_fh_read, + .write = 0, + .ioctl = 0, + .get_page = 0, + .commit_page = 0, +}; + void register_iso9660_driver() { ASSERT(sizeof(iso9660_dr_date_t) == 7); ASSERT(sizeof(iso9660_dr_t) == 34); @@ -20,7 +78,7 @@ void register_iso9660_driver() { // FILESYSTEM DETECTION AND SETUP // // ============================== // -static bool iso9660_make(fs_handle_t *source, const char* opts, fs_t *t) { +bool iso9660_make(fs_handle_t *source, const char* opts, fs_t *t) { stat_t st; if (!file_stat(source, &st)) return false; if ((st.type & FT_BLOCKDEV) == 0) return false; @@ -38,7 +96,212 @@ static bool iso9660_make(fs_handle_t *source, const char* opts, fs_t *t) { ent_sect++; } - return false; // TODO + // Looks like we are good, go ahead. + iso9660_fs_t *fs = (iso9660_fs_t*)malloc(sizeof(iso9660_fs_t)); + if (fs == 0) return false; + + iso9660_node_t *root = (iso9660_node_t*)malloc(sizeof(iso9660_node_t)); + if (root == 0) { + free(fs); + return false; + } + + memcpy(&fs->vol_descr, &ent.prim, sizeof(iso9660_pvd_t)); + fs->disk = source; + fs->use_lowercase = (strchr(opts, 'l') != 0); + + memcpy(&root->dr, &ent.prim.root_directory, sizeof(iso9660_dr_t)); + root->fs = fs; + + t->data = fs; + t->ops = &iso9660_fs_ops; + + t->root->data = root; + t->root->ops = &iso9660_dir_ops; + + return true; // TODO +} + +void iso9660_fs_shutdown(fs_ptr f) { + iso9660_fs_t *fs = (iso9660_fs_t*)f; + free(fs); +} + +// ======================================= // +// READING STUFF THAT IS ON THE FILESYSTEM // +// ======================================= // + +static void convert_dr_to_lowercase(iso9660_dr_t *dr) { + for (int i = 0; i < dr->name_len; i++) { + if (dr->name[i] >= 'A' && dr->name[i] <= 'Z') + dr->name[i] += ('a' - 'A'); + } +} + +static void dr_stat(iso9660_dr_t *dr, stat_t *st) { + if (dr->flags & ISO9660_DR_FLAG_DIR) { + st->type = FT_DIR; + st->access = FM_READDIR; + st->size = (dr->size.lsb / 256); + } else { + st->type = FT_REGULAR; + st->access = FM_READ; + st->size = dr->size.lsb; + } +} + +bool iso9660_node_stat(fs_node_ptr n, stat_t *st) { + iso9660_node_t *node = (iso9660_node_t*)n; + + dr_stat(&node->dr, st); + return true; +} + +void iso9660_node_dispose(fs_node_ptr n) { + iso9660_node_t *node = (iso9660_node_t*)n; + free(node); +} + +bool iso9660_dir_open(fs_node_ptr n, int mode, fs_handle_t *s) { + iso9660_node_t *node = (iso9660_node_t*)n; + + if (mode != FM_READDIR) return false; + + iso9660_dh_t *handle = (iso9660_dh_t*)malloc(sizeof(iso9660_dh_t)); + if (handle == 0) return false; + + handle->n = node; + handle->pos = 0; + + s->mode = mode; + s->data = handle; + s->ops = &iso9660_dh_ops; + + return true; +} +bool iso9660_dir_walk(fs_node_ptr n, const char* search_for, struct fs_node *node_d) { + iso9660_node_t *node = (iso9660_node_t*)n; + + size_t filename_len = strlen(search_for); + + dbg_printf("Looking up %s...\n", search_for); + + char buffer[2048]; + size_t dr_len = 0; + for (size_t pos = 0; pos < node->dr.size.lsb; pos += dr_len) { + if (pos % 2048 == 0) { + if (file_read(node->fs->disk, node->dr.lba_loc.lsb * 2048 + pos, 2048, buffer) != 2048) + return false; + } + + iso9660_dr_t *dr = (iso9660_dr_t*)(buffer + (pos % 2048)); + dr_len = dr->len; + if (dr_len == 0) return false; + + if (node->fs->use_lowercase) convert_dr_to_lowercase(dr); + + char* name = dr->name; + size_t len = dr->name_len - 2; + + if (name[len] != ';') continue; + if (len != filename_len) continue; + + if (strncmp(name, search_for, len) == 0) { + // Found it ! + iso9660_node_t *n = (iso9660_node_t*)malloc(sizeof(iso9660_node_t*)); + if (n == 0) return false; + + memcpy(&n->dr, dr, sizeof(iso9660_dr_t)); + n->fs = node->fs; + + node_d->data = n; + node_d->ops = (dr->flags & ISO9660_DR_FLAG_DIR ? &iso9660_dir_ops : &iso9660_file_ops); + + return true; + } + } + return false; // not found +} + +bool iso9660_file_open(fs_node_ptr n, int mode, fs_handle_t *s) { + iso9660_node_t *node = (iso9660_node_t*)n; + + if (mode != FM_READ) return false; + + s->data = node; + s->ops = &iso9660_fh_ops; + s->mode = mode; + return true; +} + +size_t iso9660_fh_read(fs_handle_ptr f, size_t offset, size_t len, char* buf) { + iso9660_node_t *node = (iso9660_node_t*)f; + + if (offset >= node->dr.size.lsb) return 0; + if (offset + len > node->dr.size.lsb) len = node->dr.size.lsb - offset; + + size_t ret = 0; + + size_t off0 = offset % 2048; + char buffer[2048]; + for (size_t i = offset - off0; i < offset + len; i += 2048) { + if (file_read(node->fs->disk, node->dr.lba_loc.lsb * 2048 + i, 2048, buffer) != 2048) { + dbg_printf("Could not read data at %d\n", i); + break; + } + + size_t block_pos; + size_t block_buf_ofs; + if (i <= offset) { + block_pos = 0; + block_buf_ofs = off0; + } else { + block_pos = i - off0; + block_buf_ofs = 0; + } + size_t block_len = (i + 2048 > offset + len ? offset + len - i : 2048); + + memcpy(buf + block_pos, buffer + block_buf_ofs, block_len); + ret += block_len; + } + + return ret; +} +void iso9660_fh_close(fs_handle_ptr f) { + // nothing to do +} +bool iso9660_dh_readdir(fs_handle_ptr f, dirent_t *d) { + iso9660_dh_t *handle = (iso9660_dh_t*)f; + iso9660_node_t *node = handle->n; + + while (true) { + if (handle->pos >= node->dr.size.lsb) return false; + + if (handle->pos % 2048 == 0) { + if (file_read(node->fs->disk, node->dr.lba_loc.lsb * 2048 + handle->pos, 2048, handle->buffer) != 2048) + return false; + } + + iso9660_dr_t *dr = (iso9660_dr_t*)(handle->buffer + (handle->pos % 2048)); + if (node->fs->use_lowercase) convert_dr_to_lowercase(dr); + + handle->pos += dr->len; + + size_t len = dr->name_len - 2; + if (dr->name_len > 0 && dr->name[len] == ';') { + if (len >= DIR_MAX) len = DIR_MAX - 1; + memcpy(d->name, dr->name, len); + d->name[len] = 0; + dr_stat(dr, &d->st); + + return true; + } + // else skip this record + } +} +void iso9660_dh_close(fs_handle_ptr f) { + iso9660_dh_t* handle = (iso9660_dh_t*)f; + free(handle); } /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/include/fs/iso9660.h b/src/kernel/include/fs/iso9660.h index 292b4dd..85e9b7b 100644 --- a/src/kernel/include/fs/iso9660.h +++ b/src/kernel/include/fs/iso9660.h @@ -8,6 +8,8 @@ #define ISO9660_VDT_PARTITION 3 #define ISO9660_VDT_TERMINATOR 255 +#define ISO9660_DR_FLAG_DIR (1 << 1) + typedef struct { uint32_t lsb, msb; } uint32_lsb_msb_t; @@ -87,6 +89,23 @@ typedef union { char buf[2048]; } iso9660_vdt_entry_t; +typedef struct { + iso9660_pvd_t vol_descr; + fs_handle_t *disk; + bool use_lowercase; // lowercase all names +} iso9660_fs_t; + +typedef struct { + iso9660_dr_t dr; + iso9660_fs_t *fs; +} iso9660_node_t; + +typedef struct { + iso9660_node_t *n; + size_t pos; + char buffer[2048]; +} iso9660_dh_t; // handle to an open directory + void register_iso9660_driver(); /* vim: set ts=4 sw=4 tw=0 noet :*/ -- cgit v1.2.3