diff --git a/etc/make/conf.mk b/etc/make/conf.mk index 829b065..2864759 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -59,19 +59,20 @@ OBJS+=$(O)/sys/debug.o \ $(O)/sys/net/arp.o \ $(O)/sys/net/in.o \ $(O)/sys/net/netdev.o \ + $(O)/sys/vfs/pseudo.o \ + $(O)/sys/vfs/ext2/ext2.o \ + $(O)/sys/vfs/ext2/ext2blk.o \ + $(O)/sys/vfs/tar.o \ + $(O)/sys/blk/ram.o \ $(O)/sys/reboot.o \ $(O)/sys/random.o -# $(O)/sys/vfs/pseudo.o \ +# \ $(O)/sys/tty.o \ $(O)/sys/vfs/pty.o \ $(O)/sys/vfs/ext2/ext2alloc.o \ - $(O)/sys/vfs/ext2/ext2blk.o \ - $(O)/sys/vfs/ext2/ext2.o \ $(O)/sys/vfs/ext2/ext2dir.o \ $(O)/sys/vfs/ext2/ext2vnop.o \ - $(O)/sys/vfs/tar.o \ - $(O)/sys/blk/ram.o \ ifeq ($(VESA_ENABLE),1) OBJS+=$(O)/sys/psf.o \ diff --git a/include/sys/dev.h b/include/sys/dev.h index 9cbd3a3..84f7517 100644 --- a/include/sys/dev.h +++ b/include/sys/dev.h @@ -1,12 +1,15 @@ #pragma once #include "sys/types.h" +struct vnode; + // TODO: something like device name alias // for example, /dev/root aliased to // /dev/ramN or /dev/sdXN enum dev_class { - DEV_CLASS_BLOCK, - DEV_CLASS_CHAR + DEV_CLASS_BLOCK = 1, + DEV_CLASS_CHAR = 2, + DEV_CLASS_ANY = 255 }; #define DEV_BLOCK_SDx 1 @@ -17,19 +20,22 @@ enum dev_class { #define DEV_CHAR_TTY 1 -struct dev_entry { - char dev_name[64]; +int dev_add(enum dev_class cls, int subcls, void *dev, const char *name); +int dev_find(enum dev_class cls, const char *name, struct vnode **dev_node); - enum dev_class dev_class; - uint16_t dev_subclass; - uint16_t dev_number; +//struct dev_entry { +// char dev_name[64]; +// +// enum dev_class dev_class; +// uint16_t dev_subclass; +// uint16_t dev_number; +// +// void *dev; +// struct dev_entry *cdr; +//}; - void *dev; - struct dev_entry *cdr; -}; +//struct dev_entry *dev_iter(void); -struct dev_entry *dev_iter(void); - -int dev_alloc_name(enum dev_class cls, uint16_t subclass, char *name); -int dev_by_name(struct dev_entry **ent, const char *name); -void dev_entry_add(struct dev_entry *ent); +//int dev_alloc_name(enum dev_class cls, uint16_t subclass, char *name); +//int dev_by_name(struct dev_entry **ent, const char *name); +//void dev_entry_add(struct dev_entry *ent); diff --git a/include/sys/fs/ext2.h b/include/sys/fs/ext2.h index 14ee758..4a9277c 100644 --- a/include/sys/fs/ext2.h +++ b/include/sys/fs/ext2.h @@ -124,24 +124,24 @@ void ext2_class_init(void); enum vnode_type ext2_inode_type(struct ext2_inode *i); // Implemented in ext2blk.c -int ext2_write_superblock(fs_t *ext2); -int ext2_read_block(fs_t *ext2, uint32_t block_no, void *buf); -int ext2_write_block(fs_t *ext2, uint32_t block_no, const void *buf); -int ext2_read_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, void *buf); -int ext2_write_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, const void *buf); -int ext2_read_inode(fs_t *ext2, struct ext2_inode *inode, uint32_t ino); -int ext2_write_inode(fs_t *ext2, const struct ext2_inode *inode, uint32_t ino); +int ext2_write_superblock(struct fs *ext2); +int ext2_read_block(struct fs *ext2, uint32_t block_no, void *buf); +int ext2_write_block(struct fs *ext2, uint32_t block_no, const void *buf); +int ext2_read_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, void *buf); +int ext2_write_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, const void *buf); +int ext2_read_inode(struct fs *ext2, struct ext2_inode *inode, uint32_t ino); +int ext2_write_inode(struct fs *ext2, const struct ext2_inode *inode, uint32_t ino); // Implemented in ext2alloc.c -int ext2_alloc_block(fs_t *ext2, uint32_t *block_no); -int ext2_free_block(fs_t *ext2, uint32_t block_no); -int ext2_inode_alloc_block(fs_t *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index); -int ext2_free_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index); -int ext2_free_inode(fs_t *ext2, uint32_t ino); -int ext2_alloc_inode(fs_t *ext2, uint32_t *ino); +int ext2_alloc_block(struct fs *ext2, uint32_t *block_no); +int ext2_free_block(struct fs *ext2, uint32_t block_no); +int ext2_inode_alloc_block(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index); +int ext2_free_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index); +int ext2_free_inode(struct fs *ext2, uint32_t ino); +int ext2_alloc_inode(struct fs *ext2, uint32_t *ino); // Implemented in ext2dir.c -int ext2_dir_add_inode(fs_t *ext2, struct vnode *dir, const char *name, uint32_t ino); -int ext2_dir_remove_inode(fs_t *ext2, struct vnode *dir, const char *name, uint32_t ino); +int ext2_dir_add_inode(struct fs *ext2, struct vnode *dir, const char *name, uint32_t ino); +int ext2_dir_remove_inode(struct fs *ext2, struct vnode *dir, const char *name, uint32_t ino); extern struct vnode_operations ext2_vnode_ops; diff --git a/include/sys/fs/fs.h b/include/sys/fs/fs.h index 274b0ff..ad8ae09 100644 --- a/include/sys/fs/fs.h +++ b/include/sys/fs/fs.h @@ -3,15 +3,15 @@ #include "sys/blk.h" struct statvfs; -struct vfs_node; struct fs_class { char name[64]; int opt; - struct vnode *(*get_root) (fs_t *fs); - int (*mount) (struct fs *fs, const char *opt); + struct vnode *(*get_root) (struct fs *fs); + int (*init) (struct fs *fs, const char *opt); + int (*mount) (struct fs *fs); int (*umount) (struct fs *fs); int (*statvfs) (struct fs *fs, struct statvfs *st); }; @@ -19,9 +19,6 @@ struct fs_class { // The actual filesystem instance, // one per each mount struct fs { - // Mount details here - struct vnode *mnt_at; - // Block device on which the filesystem resides struct blkdev *blk; @@ -31,7 +28,7 @@ struct fs { struct fs_class *cls; }; -struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, struct vnode *mnt_at); +struct fs *fs_create(struct fs_class *cls, struct blkdev *blk); void fs_release(struct fs *fs); struct fs_class *fs_class_by_name(const char *name); int fs_class_register(struct fs_class *cls); diff --git a/include/sys/fs/node.h b/include/sys/fs/node.h index 0c090d7..6e9def6 100644 --- a/include/sys/fs/node.h +++ b/include/sys/fs/node.h @@ -10,62 +10,48 @@ #define NODE_MAXLEN 256 +// Means the node has no physical storage and resides only +// in memory +#define VN_MEMORY (1 << 0) + struct ofile; struct vfs_ioctx; struct vnode; -typedef struct fs fs_t; +struct fs; enum vnode_type { VN_REG, VN_DIR, VN_BLK, VN_CHR, -// VN_LNK + VN_UNK, }; struct vnode_operations { - // File tree traversal, node instance operations - int (*find) (struct vnode *node, const char *path, struct vnode **res); - void (*destroy) (struct vnode *node); - - // Symlink -// int (*readlink) (struct vnode *node, char *path); -// int (*symlink) (struct vnode *at, struct vfs_ioctx *ctx, const char *name, const char *dst); - - // File entry operations - int (*access) (struct vnode *node, uid_t *uid, gid_t *gid, mode_t *mode); - int (*creat) (struct vnode *node, struct vfs_ioctx *ctx, const char *name, mode_t mode, int opt, struct vnode **res); - int (*mkdir) (struct vnode *at, const char *name, mode_t mode); - int (*unlink) (struct vnode *at, struct vnode *vn, const char *name); - int (*stat) (struct vnode *node, struct stat *st); - int (*chmod) (struct vnode *node, mode_t mode); - int (*chown) (struct vnode *node, uid_t uid, gid_t gid); - - // Directory access - int (*opendir) (struct vnode *node, int opt); - int (*readdir) (struct ofile *fd); - - // File access - int (*open) (struct vnode *node, int opt); + int (*open) (struct ofile *fd); void (*close) (struct ofile *fd); + ssize_t (*read) (struct ofile *fd, void *buf, size_t count); ssize_t (*write) (struct ofile *fd, const void *buf, size_t count); - int (*truncate) (struct ofile *fd, size_t length); }; struct vnode { enum vnode_type type; char name[NODE_MAXLEN]; + uint32_t flags; struct vnode *first_child; struct vnode *next_child; struct vnode *parent; - uint32_t refcount; + uint32_t open_count; uint64_t ino; - fs_t *fs; + gid_t gid; + uid_t uid; + + struct fs *fs; void *fs_data; /* * (struct blkdev *) if type == VN_BLK @@ -76,4 +62,15 @@ struct vnode { struct vnode_operations *op; }; -struct vnode *vnode_create(const char *name); +// Node itself +struct vnode *vnode_create(enum vnode_type t, const char *name); + +// Tree manipulation +void vnode_attach(struct vnode *parent, struct vnode *child); +void vnode_detach(struct vnode *node); + +// Tree traversal +void vnode_dump_tree(int level, struct vnode *node, int depth); +int vnode_lookup_child(struct vnode *of, const char *name, struct vnode **child); +int vnode_lookup_tree(struct vnode *at, const char *rel_path, struct vnode **child); + diff --git a/sys/amd64/hw/ide/ahci.c b/sys/amd64/hw/ide/ahci.c index aa8f560..90dc71c 100644 --- a/sys/amd64/hw/ide/ahci.c +++ b/sys/amd64/hw/ide/ahci.c @@ -62,26 +62,35 @@ static ssize_t ahci_blk_write(struct blkdev *blk, const void *buf, size_t off, s } static int ahci_add_port_dev(struct ahci_port_registers *port) { - void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry)); - struct dev_entry *ent = (struct dev_entry *) buf; - struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry)); - _assert(ent); - + // Create a new device + // XXX: Replace kmalloc with dev_blk_create + struct blkdev *blk = kmalloc(sizeof(struct blkdev)); blk->dev_data = port; blk->read = ahci_blk_read; blk->write = ahci_blk_write; - ent->dev = blk; - ent->dev_class = DEV_CLASS_BLOCK; - ent->dev_subclass = DEV_BLOCK_SDx; - if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) { - return -1; - } - - dev_entry_add(ent); - - return 0; + return dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_SDx, blk, NULL); } +// //void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry)); +// //struct dev_entry *ent = (struct dev_entry *) buf; +// //struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry)); +// //_assert(ent); +// +// //blk->dev_data = port; +// //blk->read = ahci_blk_read; +// //blk->write = ahci_blk_write; +// +// //ent->dev = blk; +// //ent->dev_class = DEV_CLASS_BLOCK; +// //ent->dev_subclass = DEV_BLOCK_SDx; +// //if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) { +// // return -1; +// //} +// +// //dev_entry_add(ent); +// +// return 0; +//} uint32_t ahci_irq(void *ctx) { struct ahci_registers *controller = ctx; diff --git a/sys/amd64/hw/ide/ide.c b/sys/amd64/hw/ide/ide.c index 3bb410b..6615b78 100644 --- a/sys/amd64/hw/ide/ide.c +++ b/sys/amd64/hw/ide/ide.c @@ -287,39 +287,39 @@ int ide_ata_read_pio(struct ide_device *dev, void *buf, size_t nsect, uint64_t l return 0; } -static ssize_t ide_blk_read(struct blkdev *blk, void *buf, size_t off, size_t count) { - _assert(blk && blk->dev_data); - _assert(!(off & 511)); - _assert(!(count & 511)); - - size_t nsect = count / 512; - size_t lba = off / 512; - - // XXX: DMA fucks up for some reason, investigate that - ide_ata_read_pio((struct ide_device *) blk->dev_data, buf, nsect, lba); - - return count; -} +//static ssize_t ide_blk_read(struct blkdev *blk, void *buf, size_t off, size_t count) { +// _assert(blk && blk->dev_data); +// _assert(!(off & 511)); +// _assert(!(count & 511)); +// +// size_t nsect = count / 512; +// size_t lba = off / 512; +// +// // XXX: DMA fucks up for some reason, investigate that +// ide_ata_read_pio((struct ide_device *) blk->dev_data, buf, nsect, lba); +// +// return count; +//} static int ide_add_ata_dev(struct ide_device *dev) { - void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry)); - struct dev_entry *ent = (struct dev_entry *) buf; - struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry)); - _assert(ent); + //void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry)); + //struct dev_entry *ent = (struct dev_entry *) buf; + //struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry)); + //_assert(ent); - blk->dev_data = dev; - blk->write = NULL; - blk->read = ide_blk_read; - //blk->write = ahci_blk_write; + //blk->dev_data = dev; + //blk->write = NULL; + //blk->read = ide_blk_read; + ////blk->write = ahci_blk_write; - ent->dev = blk; - ent->dev_class = DEV_CLASS_BLOCK; - ent->dev_subclass = DEV_BLOCK_HDx; - if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) { - return -1; - } + //ent->dev = blk; + //ent->dev_class = DEV_CLASS_BLOCK; + //ent->dev_subclass = DEV_BLOCK_HDx; + //if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) { + // return -1; + //} - dev_entry_add(ent); + //dev_entry_add(ent); return 0; } diff --git a/sys/amd64/kernel.c b/sys/amd64/kernel.c index 7cae684..169e140 100644 --- a/sys/amd64/kernel.c +++ b/sys/amd64/kernel.c @@ -50,6 +50,9 @@ void kernel_main(struct amd64_loader_data *data) { amd64_gdt_init(); amd64_idt_init(); amd64_mm_init(data); + // XXX: HEAP IS ONLY AVAILABLE AT THIS POINT + extern void pseudo_init(); + pseudo_init(); amd64_acpi_init(); #if defined(VESA_ENABLE) amd64_vesa_init(multiboot_info); @@ -64,8 +67,8 @@ void kernel_main(struct amd64_loader_data *data) { //tty_init(); if (data->initrd_ptr) { // Create ram0 block device - //ramblk_init(MM_VIRTUALIZE(data->initrd_ptr), data->initrd_len); - //tarfs_init(); + ramblk_init(MM_VIRTUALIZE(data->initrd_ptr), data->initrd_len); + tarfs_init(); } // Initial random seed diff --git a/sys/amd64/sys/sched.c b/sys/amd64/sys/sched.c index b25a84d..7f92458 100644 --- a/sys/amd64/sys/sched.c +++ b/sys/amd64/sys/sched.c @@ -75,10 +75,54 @@ void init_func(void *arg) { // Mount rootfs if available //struct blkdev *root_blk = blk_by_name("ram0"); struct vfs_ioctx ioctx = {0}; - struct ofile fd; struct stat st; int res; - //ext2_class_init(); + + ext2_class_init(); + + struct fs_class *tarfs_class = fs_class_by_name("ustar"); + _assert(tarfs_class); + + // Find _ramblk0 + struct vnode *ramblk0; + if ((res = dev_find(DEV_CLASS_BLOCK, "ram0", &ramblk0)) != 0) { + panic("Failed to find root device\n"); + } + + kinfo("Found root device: %s\n", ramblk0->name); + + // Create a filesystem instance at this device + struct fs *fs_instance = fs_create(tarfs_class, ramblk0->dev); + _assert(fs_instance); + + // Get tarfs root node + struct vnode *root_node = tarfs_class->get_root(fs_instance); + _assert(root_node); + + vnode_dump_tree(DEBUG_INFO, root_node, 0); + + // Find some file in rootfs + struct vnode *etc_file_txt; + _assert(vnode_lookup_tree(root_node, "etc/file.txt", &etc_file_txt) == 0); + _assert(etc_file_txt); + + // Open it + _assert(etc_file_txt->op); + _assert(etc_file_txt->op->read); + + struct ofile fd = { + .vnode = etc_file_txt, + .pos = 0, + }; + + char buf[512]; + ssize_t bread; + _assert((bread = etc_file_txt->op->read(&fd, buf, sizeof(buf))) > 0); + + buf[bread] = 0; + kdebug("\n%s\n", buf); + + kinfo("Done\n"); //if (root_blk) { // if ((res = vfs_mount(&ioctx, "/", root_blk, "ustar", NULL)) != 0) { diff --git a/sys/blk.c b/sys/blk.c index 9a4eb00..ee03d50 100644 --- a/sys/blk.c +++ b/sys/blk.c @@ -28,217 +28,3 @@ ssize_t blk_write(struct blkdev *blk, const void *buf, size_t off, size_t lim) { return -EINVAL; } } - -const char GUID_EMPTY[16] = {0}; - -// TODO: guess this would better be in blk_part.c or something like that -struct mbr { - char bootstrap[440]; - uint32_t uuid; - uint16_t opt; - struct mbr_entry { - uint8_t attr; - uint8_t chs_start[3]; - uint8_t type; - uint8_t chs_end[3]; - uint32_t lba_start; - uint32_t nsectors; - } __attribute__((packed)) entries[4]; - uint16_t sign; -} __attribute__((packed)); - -struct gpt_header { - char signature[8]; - uint32_t revision; - uint32_t header_size; - uint32_t header_crc32; - uint32_t __res0; - uint64_t my_lba; - uint64_t alt_lba; - uint64_t first_lba; - uint64_t last_lba; - char disk_guid[16]; - uint64_t partition_entry_lba; - uint32_t partition_count; - uint32_t partition_entry_size; - uint32_t partition_array_crc32; -} __attribute__((packed)); - -struct gpt_part_entry { - char type_guid[16]; - char part_guid[16]; - uint64_t start_lba; - uint64_t end_lba; - uint64_t attr; - char part_name[72]; -}; - -struct blk_part { - struct blkdev *device; - uint64_t lba_start; - uint64_t lba_size; -}; - -int blk_mount_auto(struct vnode *at, struct blkdev *blk, const char *opt) { - int res; - - //if ((res = vfs_mount_internal(at, blk, "ext2", opt)) == 0) { - // return 0; - //} - - return -1; -} - -static ssize_t blk_part_write(struct blkdev *dev, const void *buf, size_t off, size_t count) { - struct blk_part *part = (struct blk_part *) dev->dev_data; - size_t part_size_bytes = part->lba_size * 512; - size_t part_off_bytes = part->lba_start * 512; - - if (off >= part_size_bytes) { - return -1; - } - - size_t l = MIN(part_size_bytes - off, count); - - return blk_write(part->device, buf, off + part_off_bytes, l); -} - -static ssize_t blk_part_read(struct blkdev *dev, void *buf, size_t off, size_t count) { - struct blk_part *part = (struct blk_part *) dev->dev_data; - size_t part_size_bytes = part->lba_size * 512; - size_t part_off_bytes = part->lba_start * 512; - - if (off >= part_size_bytes) { - return -1; - } - - size_t l = MIN(part_size_bytes - off, count); - - return blk_read(part->device, buf, off + part_off_bytes, l); -} - -static int blk_enumerate_mbr(struct blkdev *dev, uint8_t *head) { - kdebug("Enumerating MBR partitions\n"); - struct mbr *mbr = (struct mbr *) head; - - for (size_t i = 0; i < 4; ++i) { - if (mbr->entries[i].chs_start[1] && mbr->entries[i].nsectors) { - kdebug("Partition %u: Start %u, End %u, %u Sectors (%S), Type 0x%02x\n", - i, - mbr->entries[i].lba_start, - mbr->entries[i].lba_start + mbr->entries[i].nsectors, - mbr->entries[i].nsectors, - mbr->entries[i].nsectors * 512, - mbr->entries[i].type); - - struct blk_part *part = (struct blk_part *) kmalloc(sizeof(struct blk_part)); - part->device = dev; - part->lba_start = mbr->entries[i].lba_start; - part->lba_size = mbr->entries[i].nsectors * 512; - - void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry)); - struct dev_entry *ent = (struct dev_entry *) buf; - struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry)); - _assert(ent); - - blk->dev_data = part; - blk->read = blk_part_read; - blk->write = blk_part_write; - blk->ent_parent = dev->ent; - - ent->dev = blk; - ent->dev_class = DEV_CLASS_BLOCK; - ent->dev_subclass = DEV_BLOCK_PART; - // XXX: This is ugly - strcpy(ent->dev_name, dev->ent->dev_name); - char digit[2] = { '1' + i, 0 }; - strcat(ent->dev_name, digit); - - dev_entry_add(ent); - } - } - - return 0; -} - -static int blk_enumerate_gpt(struct blkdev *dev, uint8_t *head) { - // LBA1 - GPT header - struct gpt_header *hdr = (struct gpt_header *) &head[512]; - // Read a single block for partition table entries - char buf[512]; - - _assert(blk_read(dev, buf, hdr->partition_entry_lba * 512, 512) >= 0); - - size_t offset = 0; - size_t part_n = 0; - for (size_t i = 0; i < hdr->partition_count; ++i) { - struct gpt_part_entry *ent = (struct gpt_part_entry *) &buf[offset]; - - if (strncmp(ent->type_guid, GUID_EMPTY, 16)) { - // Maybe some known filesystem here, ignore partition type guid - - struct blk_part *part = (struct blk_part *) kmalloc(sizeof(struct blk_part)); - part->device = dev; - part->lba_start = ent->start_lba; - part->lba_size = ent->end_lba - ent->start_lba; - - void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry)); - struct dev_entry *ent = (struct dev_entry *) buf; - struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry)); - _assert(ent); - - blk->dev_data = part; - blk->read = blk_part_read; - blk->write = blk_part_write; - blk->ent_parent = dev->ent; - - ent->dev = blk; - ent->dev_class = DEV_CLASS_BLOCK; - ent->dev_subclass = DEV_BLOCK_PART; - // XXX: This is ugly - strcpy(ent->dev_name, dev->ent->dev_name); - char digit[2] = { '1' + part_n++, 0 }; - strcat(ent->dev_name, digit); - - dev_entry_add(ent); - } - - offset += hdr->partition_entry_size; - if (offset >= 512) { - break; - } - } - - return 0; -} - -//struct blkdev *blk_by_name(const char *name) { -// struct dev_entry *it = dev_iter(); -// -// for (; it; it = it->cdr) { -// if (!strcmp(it->dev_name, name)) { -// return (struct blkdev *) it->dev; -// } -// } -// -// return NULL; -//} - -int blk_enumerate_partitions(struct blkdev *dev) { - kdebug("Enumerating partitions of %s\n", dev->ent->dev_name); - // TODO: handle stuff where block size is not 512 - uint8_t buf[1024]; - - _assert(blk_read(dev, buf, 0, 1024) >= 0); - - if (!strncmp((const char *) (buf + 512), "EFI PART", 8)) { - // Found GPT - return blk_enumerate_gpt(dev, buf); - } else if (buf[510] == 0x55 && buf[511] == 0xAA) { - // Found MBR - return blk_enumerate_mbr(dev, buf); - } - - // No partition table - just a plain block device - return 0; -} diff --git a/sys/blk/ram.c b/sys/blk/ram.c index ff11315..eb8c1b1 100644 --- a/sys/blk/ram.c +++ b/sys/blk/ram.c @@ -32,15 +32,16 @@ void ramblk_init(uintptr_t at, size_t len) { ram_priv.begin = at; ram_priv.lim = len; - struct dev_entry *ent = (struct dev_entry *) kmalloc(sizeof(struct dev_entry)); - _assert(ent); - - ent->dev = ramblk0; - ent->dev_class = DEV_CLASS_BLOCK; - ent->dev_subclass = DEV_BLOCK_RAM; - if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) { - panic("Failed to allocate a name for ram device\n"); - } - - dev_entry_add(ent); + dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_RAM, &_ramblk0, "ram0"); +// struct dev_entry *ent = (struct dev_entry *) kmalloc(sizeof(struct dev_entry)); +// _assert(ent); +// +// ent->dev = ramblk0; +// ent->dev_class = DEV_CLASS_BLOCK; +// ent->dev_subclass = DEV_BLOCK_RAM; +// if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) { +// panic("Failed to allocate a name for ram device\n"); +// } +// +// dev_entry_add(ent); } diff --git a/sys/dev.c b/sys/dev.c index a73dace..71de196 100644 --- a/sys/dev.c +++ b/sys/dev.c @@ -10,63 +10,69 @@ #include "sys/fs/fs.h" #include "sys/attr.h" #include "sys/heap.h" +#include "sys/errno.h" static struct vnode *devfs_root = NULL; -static uint64_t dev_scsi_bitmap = 0; -static uint64_t dev_ide_bitmap = 0; -static int dev_ram_count = 0; +static uint64_t dev_count = 0; -static int dev_alloc_block_name(uint16_t subclass, char *name) { - if (subclass == DEV_BLOCK_RAM) { - strcpy(name, "ram"); - name[3] = dev_ram_count++ + '0'; - name[4] = 0; - return 0; +int dev_add(enum dev_class cls, int subcls, void *dev, const char *name) { + char node_name[5]; + struct vnode *node; + + if (!name) { + // TODO: generate proper names for device nodes + node_name[4] = 0; + node_name[3] = '0' + ++dev_count; + node_name[0] = 'd'; + node_name[1] = 'e'; + node_name[2] = 'v'; + name = node_name; } - if (subclass == DEV_BLOCK_SDx || subclass == DEV_BLOCK_HDx) { - uint64_t *bmp = subclass == DEV_BLOCK_SDx ? &dev_scsi_bitmap : &dev_ide_bitmap; - name[1] = 'd'; - name[0] = subclass == DEV_BLOCK_SDx ? 's' : 'h'; - for (size_t i = 0; i < 64; ++i) { - if (!(*bmp & (1ULL << i))) { - *bmp |= 1ULL << i; - name[2] = 'a' + i; - name[3] = 0; - return 0; - } - } + // Create a filesystem node for the device + node = vnode_create(cls == DEV_CLASS_BLOCK ? VN_BLK : VN_CHR, name); + node->dev = dev; + + // Use inode number to store full device class:subclass + node->ino = ((uint32_t) cls) | ((uint64_t) subcls << 32); + + // If root does not yet exist, make one + if (!devfs_root) { + devfs_root = vnode_create(VN_DIR, NULL); } - return -1; -} -int dev_alloc_name(enum dev_class cls, uint16_t subclass, char *name) { - switch (cls) { - case DEV_CLASS_BLOCK: - return dev_alloc_block_name(subclass, name); - default: - panic("Not implemented\n"); - } -} + // TODO: some devices are located in subdirs + vnode_attach(devfs_root, node); -static int dev_post_add(struct dev_entry *ent) { - if (ent->dev_class == DEV_CLASS_BLOCK) { - struct blkdev *blk = (struct blkdev *) ent->dev; + kinfo("Created device node: %s\n", node->name); - blk->ent = ent; - - if (ent->dev_subclass < DEV_BLOCK_PART) { - if (blk_enumerate_partitions((struct blkdev *) ent->dev) != 0) { - return -1; - } - } - } + // Self-test + struct vnode *test_node = NULL; + _assert(vnode_lookup_child(devfs_root, name, &test_node) == 0); + _assert(test_node == node); + _assert(vnode_lookup_tree(devfs_root, name, &test_node) == 0); + _assert(test_node == node); return 0; } -void dev_entry_add(struct dev_entry *ent) { - // For example: enumerate partitions on block devices - _assert(dev_post_add(ent) == 0); +int dev_find(enum dev_class cls, const char *name, struct vnode **node) { + _assert(node); + int res; + if (!devfs_root) { + return -ENODEV; + } + if ((res = vnode_lookup_tree(devfs_root, name, node)) != 0) { + return res; + } + + if (cls == DEV_CLASS_BLOCK && (*node)->type != VN_BLK) { + return -ENODEV; + } + if (cls == DEV_CLASS_CHAR && (*node)->type != VN_CHR) { + return -ENODEV; + } + + return 0; } diff --git a/sys/vfs/ext2/ext2.c b/sys/vfs/ext2/ext2.c index e949d7f..db8f61f 100644 --- a/sys/vfs/ext2/ext2.c +++ b/sys/vfs/ext2/ext2.c @@ -12,8 +12,8 @@ enum vnode_type ext2_inode_type(struct ext2_inode *i) { return VN_DIR; case EXT2_TYPE_REG: return VN_REG; - case EXT2_TYPE_LNK: - return VN_LNK; + //case EXT2_TYPE_LNK: + // return VN_LNK; default: // fprintf(stderr, "Unknown file type: %x\n", v); // abort(); @@ -22,9 +22,9 @@ enum vnode_type ext2_inode_type(struct ext2_inode *i) { } } -static int ext2_fs_mount(fs_t *fs, const char *opt) { +static int ext2_fs_init(struct fs *fs, const char *opt) { int res; - kdebug("ext2_fs_mount()\n"); + kdebug("ext2_fs_init()\n"); struct ext2_extsb *sb; // ext2's private data is its superblock structure sb = (struct ext2_extsb *) kmalloc(EXT2_SBSIZ); @@ -84,7 +84,7 @@ static int ext2_fs_mount(fs_t *fs, const char *opt) { return 0; } -static int ext2_fs_umount(fs_t *fs) { +static int ext2_fs_umount(struct fs *fs) { struct ext2_extsb *sb = (struct ext2_extsb *) fs->fs_private; // Free block group descriptor table kfree(sb->block_group_descriptor_table); @@ -93,29 +93,32 @@ static int ext2_fs_umount(fs_t *fs) { return 0; } -static vnode_t *ext2_fs_get_root(fs_t *fs) { - struct ext2_extsb *sb = fs->fs_private; - kdebug("ext2_fs_get_root()\n"); +static struct vnode *ext2_fs_get_root(struct fs *fs) { + // TODO: make sure get_root is only called once per filesystem + //struct ext2_extsb *sb = fs->fs_private; + //kdebug("ext2_fs_get_root()\n"); - struct ext2_inode *inode = (struct ext2_inode *) kmalloc(sb->inode_struct_size); - // Read root inode (2) - if (ext2_read_inode(fs, inode, EXT2_ROOTINO) != 0) { - kfree(inode); - return NULL; - } + //struct ext2_inode *inode = (struct ext2_inode *) kmalloc(sb->inode_struct_size); + //// Read root inode (2) + //if (ext2_read_inode(fs, inode, EXT2_ROOTINO) != 0) { + // kfree(inode); + // return NULL; + //} - vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t)); + //vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t)); - res->fs = fs; - res->fs_data = inode; - res->fs_number = EXT2_ROOTINO; - res->op = &ext2_vnode_ops; - res->type = ext2_inode_type(inode); + //res->fs = fs; + //res->fs_data = inode; + //res->fs_number = EXT2_ROOTINO; + //res->op = &ext2_vnode_ops; + //res->type = ext2_inode_type(inode); - return res; + //return res; + panic("ext2 get root\n"); + return NULL; } -static int ext2_fs_statvfs(fs_t *fs, struct statvfs *st) { +static int ext2_fs_statvfs(struct fs *fs, struct statvfs *st) { struct ext2_extsb *sb = fs->fs_private; st->f_blocks = sb->sb.block_count; @@ -141,7 +144,8 @@ static int ext2_fs_statvfs(fs_t *fs, struct statvfs *st) { static struct fs_class ext2_class = { .name = "ext2", .get_root = ext2_fs_get_root, - .mount = ext2_fs_mount, + .init = ext2_fs_init, + .mount = NULL, .umount = ext2_fs_umount, .statvfs = ext2_fs_statvfs }; diff --git a/sys/vfs/ext2/ext2blk.c b/sys/vfs/ext2/ext2blk.c index daa2cd9..92ca48f 100644 --- a/sys/vfs/ext2/ext2blk.c +++ b/sys/vfs/ext2/ext2blk.c @@ -6,12 +6,12 @@ #define ext2_super(e) ((struct ext2_extsb *) (e)->fs_private) -int ext2_write_superblock(fs_t *ext2) { +int ext2_write_superblock(struct fs *ext2) { struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private; return blk_write(ext2->blk, sb, EXT2_SBOFF, EXT2_SBSIZ); } -int ext2_read_block(fs_t *ext2, uint32_t block_no, void *buf) { +int ext2_read_block(struct fs *ext2, uint32_t block_no, void *buf) { if (!block_no) { return -1; } @@ -26,7 +26,7 @@ int ext2_read_block(fs_t *ext2, uint32_t block_no, void *buf) { return res; } -int ext2_write_block(fs_t *ext2, uint32_t block_no, const void *buf) { +int ext2_write_block(struct fs *ext2, uint32_t block_no, const void *buf) { if (!block_no) { return -1; } @@ -41,7 +41,7 @@ int ext2_write_block(fs_t *ext2, uint32_t block_no, const void *buf) { return res; } -int ext2_write_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, const void *buf) { +int ext2_write_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, const void *buf) { if (index < 12) { uint32_t block_number = inode->direct_blocks[index]; return ext2_write_block(ext2, block_number, buf); @@ -52,7 +52,7 @@ int ext2_write_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, } } -int ext2_read_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, void *buf) { +int ext2_read_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, void *buf) { if (index < 12) { // Use direct ptrs uint32_t block_number = inode->direct_blocks[index]; @@ -76,7 +76,7 @@ int ext2_read_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, } } -int ext2_read_inode(fs_t *ext2, struct ext2_inode *inode, uint32_t ino) { +int ext2_read_inode(struct fs *ext2, struct ext2_inode *inode, uint32_t ino) { struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private; //printf("ext2_read_inode %d\n", ino); char inode_block_buffer[sb->block_size]; @@ -104,7 +104,7 @@ int ext2_read_inode(fs_t *ext2, struct ext2_inode *inode, uint32_t ino) { return 0; } -int ext2_write_inode(fs_t *ext2, const struct ext2_inode *inode, uint32_t ino) { +int ext2_write_inode(struct fs *ext2, const struct ext2_inode *inode, uint32_t ino) { struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private; //printf("ext2_read_inode %d\n", ino); char inode_block_buffer[sb->block_size]; diff --git a/sys/vfs/fs_class.c b/sys/vfs/fs_class.c index 2cc48ae..614bdaf 100644 --- a/sys/vfs/fs_class.c +++ b/sys/vfs/fs_class.c @@ -1,5 +1,6 @@ #include "sys/string.h" #include "sys/fs/fs.h" +#include "sys/debug.h" #include "sys/errno.h" // #include @@ -9,16 +10,34 @@ static struct fs_class *fses[10] = { NULL }; static struct fs mounts[10]; -struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, struct vnode *at) { +struct fs *fs_create(struct fs_class *cls, struct blkdev *blk) { + struct fs *fs = NULL; + // XXX: I hate heap allocations, but why not use one? for (size_t i = 0; i < 10; ++i) { if (mounts[i].cls == NULL) { mounts[i].cls = cls; - mounts[i].blk= blk; - mounts[i].mnt_at = at; - return &mounts[i]; + mounts[i].blk = blk; + fs = &mounts[i]; + break; } } - return NULL; + + if (!fs) { + return NULL; + } + + // Try to initialize filesystem instance at device + if (cls->init) { + if (cls->init(fs, NULL) != 0) { + fs->cls = NULL; + kerror("%s init failed\n", cls->name); + return NULL; + } + } else { + kwarn("%s provides no init function\n", cls->name); + } + + return fs; } struct fs_class *fs_class_by_name(const char *name) { diff --git a/sys/vfs/node.c b/sys/vfs/node.c index 3978e13..88b6b04 100644 --- a/sys/vfs/node.c +++ b/sys/vfs/node.c @@ -1,20 +1,52 @@ #include "sys/fs/node.h" #include "sys/fs/vfs.h" #include "sys/fs/fs.h" +#include "sys/errno.h" #include "sys/debug.h" #include "sys/assert.h" -#include "sys/heap.h" +#include "sys/panic.h" #include "sys/string.h" +#include "sys/heap.h" -struct vnode *vnode_create(const char *name) { +static const char *path_element(const char *path, char *element) { + const char *sep = strchr(path, '/'); + if (!sep) { + strcpy(element, path); + return NULL; + } else { + _assert(sep - path < NODE_MAXLEN); + strncpy(element, path, sep - path); + element[sep - path] = 0; + + while (*sep == '/') { + ++sep; + } + if (!*sep) { + return NULL; + } + + return sep; + } +} + +struct vnode *vnode_create(enum vnode_type t, const char *name) { struct vnode *node = (struct vnode *) kmalloc(sizeof(struct vnode)); _assert(node); + node->type = t; + node->flags = 0; + node->parent = NULL; node->first_child = NULL; node->next_child = NULL; + node->fs = NULL; + node->fs_data = NULL; + + node->op = NULL; + node->dev = NULL; + if (name) { _assert(strlen(name) < NODE_MAXLEN); strcpy(node->name, name); @@ -24,3 +56,165 @@ struct vnode *vnode_create(const char *name) { return node; } + +void vnode_attach(struct vnode *parent, struct vnode *child) { + _assert(parent); + _assert(child); + _assert(!child->parent); + + child->parent = parent; + child->next_child = parent->first_child; + parent->first_child = child; +} + +void vnode_detach(struct vnode *node) { + _assert(node); + + struct vnode *parent = node->parent; + node->parent = NULL; + + if (!parent) { + return; + } + + if (node == parent->first_child) { + parent->first_child = node->next_child; + node->next_child = NULL; + return; + } + + for (struct vnode *ch = parent->first_child; ch; ch = ch->next_child) { + if (ch->next_child == node) { + ch->next_child = node->next_child; + node->next_child = NULL; + return; + } + } + + panic("Parent has no link to its child node\n"); +} + +// Only dumps cached nodes in filesystem tree +void vnode_dump_tree(int level, struct vnode *node, int depth) { + for (int i = 0; i < depth; ++i) { + debugs(level, " "); + } + switch (node->type) { + case VN_DIR: + debugs(level, "\033[33m"); + break; + case VN_REG: + debugs(level, "\033[1m"); + break; + case VN_BLK: + case VN_CHR: + debugs(level, "\033[32m"); + break; + default: + debugs(level, "\033[41m"); + break; + } + + if (node->name[0]) { + debugs(level, node->name); + } else { + debugs(level, "[root]"); + } + debugs(level, "\033[0m"); + + if (node->first_child) { + debugs(level, " {\n"); + + for (struct vnode *ch = node->first_child; ch; ch = ch->next_child) { + vnode_dump_tree(level, ch, depth + 1); + } + + for (int i = 0; i < depth; ++i) { + debugs(level, " "); + } + debugs(level, "}\n"); + } else { + debugc(level, '\n'); + } +} + +// NOTE: Only looks up in-memory nodes, does not perform any operations to fetch +// the nodes from storage +// NOTE: Resolution of .. and . is performed when resolving paths, as a node can +// have multiple parents (roots of filesystems mounted at different locations) +int vnode_lookup_child(struct vnode *of, const char *name, struct vnode **child) { + _assert(of); + _assert(child); + _assert(name); + _assert(strlen(name) < NODE_MAXLEN); + + for (struct vnode *ch = of->first_child; ch; ch = ch->next_child) { + if (!strcmp(ch->name, name)) { + *child = ch; + return 0; + } + } + + return -ENOENT; +} + +int vnode_lookup_tree(struct vnode *at, const char *path, struct vnode **child) { + char name[NODE_MAXLEN]; + const char *child_path; + struct vnode *node; + int err; + + _assert(at); + _assert(child); + + if (!path || !*path) { + *child = at; + kdebug("empty hit-final %s\n", at->name); + return 0; + } + + // The paths are always assumed to be relative + while (*path == '/') { + ++path; + } + + while (1) { + child_path = path_element(path, name); + + if (!strcmp(name, ".")) { + // Refers to this node + kdebug(". hit %s\n", at->name); + continue; + } else if (!strcmp(name, "..")) { + // Refers to node's parent + // And this won't work for filesystem mountpoints: + // Path like a/mnt/.. would still resolve the same point as + // a/mnt + struct vnode *parent = at->parent; + if (!parent) { + parent = at; + } + kdebug(".. hit %s\n", parent->name); + return vnode_lookup_tree(parent, child_path, child); + } + + break; + } + + // TODO: lookup_or_load + if ((err = vnode_lookup_child(at, name, &node)) != 0) { + kdebug("miss %s\n", name); + return err; + } + + _assert(node); + + if (!child_path) { + kdebug("hit-final %s\n", name); + *child = node; + return 0; + } else { + kdebug("hit %s\n", name); + return vnode_lookup_tree(node, child_path, child); + } +} diff --git a/sys/vfs/pseudo.c b/sys/vfs/pseudo.c index 76fabd8..ab1805e 100644 --- a/sys/vfs/pseudo.c +++ b/sys/vfs/pseudo.c @@ -31,34 +31,16 @@ static struct blkdev _dev_null = { .write = pseudo_write, .read = pseudo_read }; -static struct dev_entry _ent_null = { - .dev = &_dev_null, - .dev_class = DEV_CLASS_BLOCK, - .dev_subclass = DEV_BLOCK_PSEUDO, - .dev_name = "null" -}; static struct blkdev _dev_zero = { .dev_data = (void *) DEV_ZERO, .write = pseudo_write, .read = pseudo_read }; -static struct dev_entry _ent_zero = { - .dev = &_dev_zero, - .dev_class = DEV_CLASS_BLOCK, - .dev_subclass = DEV_BLOCK_PSEUDO, - .dev_name = "zero" -}; static struct blkdev _dev_urandom = { .dev_data = (void *) DEV_URANDOM, .write = pseudo_write, .read = pseudo_read }; -static struct dev_entry _ent_urandom = { - .dev = &_dev_urandom, - .dev_class = DEV_CLASS_BLOCK, - .dev_subclass = DEV_BLOCK_PSEUDO, - .dev_name = "urandom" -}; static ssize_t pseudo_write(struct blkdev *dev, const void *buf, size_t pos, size_t lim) { switch ((uint64_t) dev->dev_data) { @@ -87,8 +69,10 @@ static ssize_t pseudo_read(struct blkdev *dev, void *buf, size_t pos, size_t lim } } -static __init void pseudo_init(void) { - dev_entry_add(&_ent_null); - dev_entry_add(&_ent_zero); - dev_entry_add(&_ent_urandom); +// XXX: This is called before heap init, fucked up? +void pseudo_init(void) { + // FIXME: They're actually character devices + dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_PSEUDO, &_dev_null, "null"); + dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_PSEUDO, &_dev_zero, "zero"); + dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_PSEUDO, &_dev_urandom, "urandom"); } diff --git a/sys/vfs/tar.c b/sys/vfs/tar.c index 7327a3b..f5ccdb0 100644 --- a/sys/vfs/tar.c +++ b/sys/vfs/tar.c @@ -20,23 +20,15 @@ struct tar { }; struct tarfs_vnode_attr { - uint32_t type_perm; - uint32_t uid; - uint32_t gid; - size_t block; + size_t first_block; size_t size; }; -static int tarfs_vnode_access(vnode_t *vn, uid_t *uid, gid_t *gid, mode_t *mode); -static int tarfs_vnode_stat(vnode_t *vn, struct stat *st); -static int tarfs_vnode_open(vnode_t *vn, int opt); static ssize_t tarfs_vnode_read(struct ofile *fd, void *buf, size_t count); static struct vnode_operations _tarfs_vnode_op = { - .access = tarfs_vnode_access, - .stat = tarfs_vnode_stat, - .open = tarfs_vnode_open, - .read = tarfs_vnode_read + .read = tarfs_vnode_read, + NULL }; static ssize_t tarfs_octal(const char *buf, size_t lim) { @@ -52,66 +44,64 @@ static ssize_t tarfs_octal(const char *buf, size_t lim) { return res; } -static const char *tarfs_path_element(char *dst, const char *src) { - const char *sep = strchr(src, '/'); +static const char *path_element(const char *path, char *element) { + const char *sep = strchr(path, '/'); if (!sep) { - strcpy(dst, src); + strcpy(element, path); return NULL; } else { - strncpy(dst, src, sep - src); - dst[sep - src] = 0; + _assert(sep - path < NODE_MAXLEN); + strncpy(element, path, sep - path); + element[sep - path] = 0; + while (*sep == '/') { ++sep; } if (!*sep) { return NULL; } + return sep; } } -static int tarfs_node_add(struct vfs_node *at, struct vfs_node **res, const char *name) { - // Try to find the node - for (struct vfs_node *child = at->child; child; child = child->cdr) { - if (!strcmp(child->name, name)) { - *res = child; - // Already exists - return 0; - } +static int tarfs_mapper_create_node(struct vnode *at, struct vnode **res, const char *name, int dir) { + _assert(at->type == VN_DIR); // Can only attach child to a directory + + if (vnode_lookup_child(at, name, res) == 0) { + // Already exists + return 0; } - // Else we need to insert it - struct vfs_node *node_new = (struct vfs_node *) kmalloc(sizeof(struct vfs_node)); - strcpy(node_new->name, name); - node_new->ismount = 0; - node_new->parent = at; - node_new->child = NULL; - node_new->cdr = at->child; - node_new->real_vnode = NULL; - node_new->vnode = NULL; - at->child = node_new; + struct vnode *node_new = vnode_create(dir ? VN_DIR : VN_REG, name); + node_new->flags |= VN_MEMORY; + node_new->op = &_tarfs_vnode_op; + + vnode_attach(at, node_new); *res = node_new; return 0; } -static int tarfs_mapper_create_path(struct vfs_node *root, struct vfs_node **res, const char *path, int isdir) { - char path_element[256]; - const char *remaining = path; - struct vfs_node *node = root; - struct vfs_node *new_node; +static int tarfs_mapper_create_path(struct vnode *root, const char *path, struct vnode **res, int dir) { + char name[NODE_MAXLEN]; + const char *child_path = path; + struct vnode *node = root; + struct vnode *new_node; + int err; kdebug("Add path %s\n", path); - while (1) { - remaining = tarfs_path_element(path_element, remaining); - if (tarfs_node_add(node, &new_node, path_element) < 0) { - panic("Failed\n"); + while (1) { + child_path = path_element(child_path, name); + + if ((err = tarfs_mapper_create_node(node, &new_node, name, dir)) != 0) { + return err; } node = new_node; - if (!remaining) { + if (!child_path) { break; } } @@ -121,74 +111,34 @@ static int tarfs_mapper_create_path(struct vfs_node *root, struct vfs_node **res return 0; } -static vnode_t *tarfs_create_vnode(fs_t *fs, struct vfs_node *node, struct tar *hdr, size_t off) { - if (hdr) { - struct tarfs_vnode_attr *attr = (struct tarfs_vnode_attr *) kmalloc(sizeof(struct tarfs_vnode_attr)); - attr->block = off + 512; - attr->gid = tarfs_octal(hdr->gid, 8); - attr->uid = tarfs_octal(hdr->uid, 8); - attr->type_perm = tarfs_octal(hdr->mode, 8); - - if (!(hdr->typeflag[0] == '\0' || hdr->typeflag[0] == '0')) { - attr->type_perm |= (1 << 16); - attr->size = 0; - } else { - attr->size = tarfs_octal(hdr->size, 12); - } - - vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t)); - res->tree_node = node; - res->fs = fs; - res->fs_data = attr; - res->refcount = 0; - res->op = &_tarfs_vnode_op; - res->type = (attr->type_perm & (1 << 16)) ? VN_DIR : VN_REG; - - return res; - } else { - - vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t)); - res->tree_node = node; - res->fs = fs; - res->fs_data = NULL; - res->refcount = 0; - res->op = &_tarfs_vnode_op; - res->type = VN_DIR; - - return res; - } -} - -static int tarfs_node_mapper(fs_t *tar, struct vfs_node **root) { - kdebug("tar: node mapper\n"); - char block_buffer[512]; +static int tar_init(struct fs *tar, const char *opt) { + char block[512]; size_t off = 0; - int was0 = 0; + int prev_zero = 0; + ssize_t res; - struct vfs_node *_root = (struct vfs_node *) kmalloc(sizeof(struct vfs_node)); - _root->child = NULL; - _root->cdr = NULL; - _root->ismount = 0; - _root->parent = NULL; - _root->real_vnode = NULL; - _root->vnode = NULL; - struct vfs_node *curr_node; + // Create filesystem root node + struct vnode *tar_root = vnode_create(VN_DIR, NULL); + tar->fs_private = tar_root; + tar_root->fs = tar; + + struct vnode *node; while (1) { - if (blk_read(tar->blk, block_buffer, off, 512) < 0) { - return -EIO; + if ((res = blk_read(tar->blk, block, off, 512)) < 0) { + return res; } - struct tar *hdr = (struct tar *) block_buffer; - if (hdr->filename[0] == 0) { - if (was0) { - // End of archive + struct tar *hdr = (struct tar *) block; + + if (!hdr->filename[0]) { + if (prev_zero) { break; - } else { - was0 = 1; - off += 512; - continue; } + + prev_zero = 1; + off += 512; + continue; } size_t node_size = 0; @@ -199,117 +149,58 @@ static int tarfs_node_mapper(fs_t *tar, struct vfs_node **root) { isdir = 0; } - kdebug("Node %c:%s:%S\n", isdir ? 'd' : '-', hdr->filename, node_size); + if ((res = tarfs_mapper_create_path(tar_root, hdr->filename, &node, isdir)) < 0) { + return res; + } + _assert(node); - tarfs_mapper_create_path(_root, &curr_node, hdr->filename, isdir); - _assert(curr_node); - vnode_t *vnode = tarfs_create_vnode(tar, curr_node, hdr, off); - _assert(vnode); - curr_node->vnode = vnode; + // Initialize the vnode + node->uid = 0; + node->gid = 0; + + struct tarfs_vnode_attr *attr = kmalloc(sizeof(struct tarfs_vnode_attr)); + _assert(attr); + node->fs_data = attr; + node->fs = tar; + + attr->first_block = off + 512; + attr->size = node_size; off += 512 + ((node_size + 0x1FF) & ~0x1FF); } - // Make a vnode for root - vnode_t *vnode = tarfs_create_vnode(tar, _root, NULL, 0); - _root->vnode = vnode; - - *root = _root; - return 0; } +static struct vnode *tar_get_root(struct fs *tar) { + return tar->fs_private; +} + static struct fs_class _tarfs = { .name = "ustar", - .opt = FS_NODE_MAPPER, - .mapper = tarfs_node_mapper + .opt = 0, + .init = tar_init, + .get_root = tar_get_root }; // Vnode operations -static int tarfs_vnode_access(vnode_t *vn, uid_t *uid, gid_t *gid, mode_t *mode) { - _assert(vn && uid && gid && mode); - - if (!vn->fs_data) { - *uid = 0; - *gid = 0; - *mode = S_IFDIR | 0755; - } else { - struct tarfs_vnode_attr *attr = (struct tarfs_vnode_attr *) vn->fs_data; - *uid = attr->uid; - *gid = attr->gid; - *mode = (attr->type_perm & 0x1FF) | ((attr->type_perm & (1 << 16)) ? S_IFDIR : S_IFREG); - } - - return 0; -} - -static int tarfs_vnode_stat(vnode_t *vn, struct stat *st) { - _assert(vn && st); - if (!vn->fs_data) { - // Root node - st->st_atime = 0; - st->st_ctime = 0; - st->st_mtime = 0; - st->st_dev = 0; - st->st_rdev = 0; - - st->st_gid = 0; - st->st_uid = 0; - st->st_mode = S_IFDIR | 0755; - - st->st_ino = 0; - st->st_nlink = 1; - - st->st_blksize = 512; - st->st_blocks = 0; - st->st_size = 0; - - return 0; - } - struct tarfs_vnode_attr *attr = (struct tarfs_vnode_attr *) vn->fs_data; - - st->st_atime = 0; - st->st_mtime = 0; - st->st_ctime = 0; - st->st_dev = 0; - st->st_rdev = 0; - - st->st_gid = attr->gid; - st->st_uid = attr->uid; - st->st_mode = (attr->type_perm & 0x1FF) | ((attr->type_perm & (1 << 16)) ? S_IFDIR : S_IFREG); - - st->st_ino = (attr->block / 512) - 1; - st->st_nlink = 1; - - st->st_blksize = 512; - st->st_blocks = (attr->size + 511) & ~511; - st->st_size = attr->size; - - return 0; -} - -static int tarfs_vnode_open(vnode_t *vnode, int opt) { - if ((opt & O_ACCMODE) != O_RDONLY) { - return -EROFS; - } - return 0; -} - -#define MIN(x, y) ((x) < (y) ? (x) : (y)) static ssize_t tarfs_vnode_read(struct ofile *fd, void *buf, size_t count) { - _assert(fd && buf && fd->vnode); - vnode_t *vn = fd->vnode; + _assert(fd); + _assert(buf); + _assert(fd->vnode); + struct vnode *vn = fd->vnode; _assert(vn->fs_data); - struct tarfs_vnode_attr *attr = (struct tarfs_vnode_attr *) vn->fs_data; + _assert(vn->fs && vn->fs->blk); + struct tarfs_vnode_attr *attr = vn->fs_data; if (fd->pos >= attr->size) { return -1; } size_t can = MIN(attr->size - fd->pos, count); - // TODO: do it properly with block buffer - blk_read(vn->fs->blk, buf, fd->pos + attr->block, can); + // TODO: size is not block-size aligned, may fuck up + blk_read(vn->fs->blk, buf, fd->pos + attr->first_block, can); return can; }