diff --git a/Makefile b/Makefile index 82d300d..9242451 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,8 @@ initrd: mknod $(INITRD_MOUNT)/rd0 b 5 2 mkdir $(INITRD_MOUNT)/txt cp Makefile $(INITRD_MOUNT)/txt + ln -s txt/../txt/../txt/../txt/../txt/../txt/../txt/../txt/../txt/.. $(INITRD_MOUNT)/link + ln -s /txt/. $(INITRD_MOUNT)/yoda umount $(INITRD_MOUNT) rm -rf $(INITRD_MOUNT) diff --git a/kernel/fs/ext2.c b/kernel/fs/ext2.c index 510bb1d..9df2943 100644 --- a/kernel/fs/ext2.c +++ b/kernel/fs/ext2.c @@ -18,7 +18,7 @@ */ vfs_fs_t ext2_driver = {ext2_mount_super, ext2_umount_super, ext2_stat, - ext2__get_root_dir_inode, + ext2__get_root_dir_inode, ext2__link_deref, ext2__open_dir, ext2__read_dir, ext2__close_dir, ext2__open_file, ext2__read_file, ext2__close_file, ext2__open_block_file, ext2__read_block_file, ext2__block_file_seek, ext2__close_block_file}; @@ -370,6 +370,47 @@ u32_t ext2__get_root_dir_inode(vfs_mount_t *mount) } +// VFS interface function to dereference a symbolic link +int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link) +{ + ext2_inode_t inode; + if (ext2_read_inode(mount, link_inode, &inode)) + return -1; + if ( (inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_SYM ) + return -2; + if (!inode.i_size) + return -4; + if (inode.i_size < 61) + { + memcpy(link, inode.i_block, inode.i_size); + link[inode.i_size] = 0; + return 0; + } + else + { + ext2_open_inode_t *open_inode; + if (!(open_inode = ext2_open_inode(mount, link_inode))) + return -3; + ext2_super_block_t *super = mount->super; + void *buffer = kmalloc(1024 << super->s_log_block_size); + memset(link, 0, 4096); + int copied = 0; + while (copied < 4096) + { + int bytes_read = ext2_read_inode_block(mount, open_inode, buffer); + if (bytes_read == 0) + break; + memcpy(link + copied, buffer, bytes_read); + copied += bytes_read; + } + ext2_close_inode(mount, open_inode); + kfree(buffer); + return 0; + } +} + + + // VFS interface function to open a directory int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir) { @@ -485,4 +526,3 @@ int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file) - diff --git a/kernel/fs/ext2.h b/kernel/fs/ext2.h index 0d99495..c91d9cc 100644 --- a/kernel/fs/ext2.h +++ b/kernel/fs/ext2.h @@ -204,6 +204,7 @@ void *ext2_mount_super(major_t major, minor_t minor); int ext2_umount_super(vfs_mount_t *mount); int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat); u32_t ext2__get_root_dir_inode(vfs_mount_t *mount); +int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link); int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir); int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry); diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 6681ef2..122f16f 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -53,26 +53,66 @@ int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint) mnt->super = super; mnt->next = NULL; mnt->prev = NULL; - node->vfs_mount_inode = 0; // root not mounted on another fs - node->vfs_up_inode = 0; + mnt->mountPoint = kmalloc(2); + strcpy(mnt->mountPoint, mountPoint); + mnt->vfs_mount_inode = 0; // root not mounted on another fs + mnt->vfs_root_inode = ((vfs_inode_t)maj << 40) | ((vfs_inode_t)min << 32) | fses[fsType]->get_root_inode(mnt); + mnt->vfs_up_inode = mnt->vfs_root_inode; mounts = mnt; return 0; // successfully mounted root } if (mountPoint[0] != '/') return -3; // mount point must be absolute + if (!mounts) + return -4; int l = strlen(mountPoint); if (l < 2) - return -4; // mount point is too short - return -5; + return -5; // mount point is too short + return -6; } vfs_inode_t vfs_get_inode_number(char *path) { if (path[0] != '/') return 0; - vfs_inode_t vfs_inode = 0; - + if (!mounts) + return 0; + return vfs_get_inode_number_rel(mounts->vfs_root_inode, path + 1); +} +vfs_inode_t vfs_get_inode_number_rel(vfs_inode_t dir_inode, char *path) +{ + char *path_copy = kmalloc(strlen(path) + 1); + strcpy(path_copy, path); + int stanzas = str_split(path_copy, '/'); + char *lookup = path_copy; + vfs_inode_t vfs_inode = dir_inode; + for (; stanzas > 0; stanzas--) + { + vfs_inode_t vfs_inode_this_dir = vfs_inode; + vfs_inode = vfs_entry_lookup(vfs_inode, lookup); + vfs_stat_t stat; + if (vfs_stat_inode(vfs_inode, &stat)) + return 0x8000000000000002ULL; + if (stat.type == VFS_FT_SYMLINK) + { + char *link = kmalloc(4096); + vfs_link_deref(vfs_inode, link); + if (link[0] == '/') + vfs_inode = vfs_get_inode_number(link); + else + vfs_inode = vfs_get_inode_number_rel(vfs_inode_this_dir, link); + kfree(link); + } + if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) + { + kfree(path_copy); + return 0; + } + lookup = str_advance(lookup); + } + kfree(path_copy); + return vfs_inode; } // look for entry in dir_inode, return the vfs_inode for the entry @@ -82,38 +122,97 @@ vfs_inode_t vfs_entry_lookup(vfs_inode_t dir_inode, char *entry) if (!open_dir) return 0x8000000000000001ULL; vfs_dir_entry_t dentry; - vfs_inode_t vfs_inode = 0; while (!vfs_read_dir(open_dir, &dentry)) { if (!strcmp(dentry.name, entry)) { - vfs_inode = (dir_inode & 0xFFFFFFFF00000000ULL) | dentry.inode_number; - break; + vfs_close_dir(open_dir); + return vfs_real_inode((dir_inode & 0xFFFFFFFF00000000ULL) | dentry.inode_number); } } vfs_close_dir(open_dir); + return 0x8000000000000002ULL; +} + +// return the "real" vfs inode number (inode of the root of +// a mounted filesystem instead of the inode of the folder +// that the filesystem is mounted to) +vfs_inode_t vfs_real_inode(vfs_inode_t vfs_inode) +{ + vfs_mount_t *mnt = mounts; + while (mnt) + { + if (mnt->vfs_mount_inode == vfs_inode) + return mnt->vfs_root_inode; + mnt = mnt->next; + } return vfs_inode; } +// translage a vfs inode number into a mount pointer and relative +// inode for a mounted filesystem +vfs_file_addr_t vfs_get_file_addr(vfs_inode_t vfs_inode) +{ + vfs_inode = vfs_real_inode(vfs_inode); + vfs_file_addr_t addr = {mounts, vfs_inode & 0xFFFFFFFF}; + vfs_mount_t *mnt = mounts; + while (mnt) + { + if ( (mnt->vfs_root_inode & 0xFFFFFFFF00000000ULL) == (vfs_inode & 0xFFFFFFFF00000000ULL) ) + { + addr.mount = mnt; + return addr; + } + mnt = mnt->next; + } + return addr; +} + +int vfs_link_deref(vfs_inode_t vfs_inode, char *link) +{ + vfs_stat_t stat; + if (vfs_stat_inode(vfs_inode, &stat)) + return -1; + if (stat.type != VFS_FT_SYMLINK) + return -2; + vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode); + if (fses[addr.mount->fs]->link_deref) + return fses[addr.mount->fs]->link_deref(addr.mount, addr.inode, link); + return -3; +} // stat a file, fills a vfs_stat_t structure with stat information and returns standard status int vfs_stat(char *file, vfs_stat_t *stat) { - vfs_mount_match_t match = vfs_get_rel_path(file); - if (match.mount == NULL) + vfs_inode_t vfs_inode = vfs_get_inode_number(file); + if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) return -256; - if (fses[match.mount->fs]->stat) - return fses[match.mount->fs]->stat(match.mount, file + match.length - 1, stat); + return vfs_stat_inode(vfs_inode, stat); +} + +int vfs_stat_inode(vfs_inode_t vfs_inode, vfs_stat_t *stat) +{ + vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode); + if (fses[addr.mount->fs]->stat) + return fses[addr.mount->fs]->stat(addr.mount, addr.inode, stat); return -257; } - -vfs_open_file_t *vfs_open_dir(vfs_inode_t inode) +vfs_open_file_t *vfs_open_dir(char *path) { + vfs_inode_t vfs_inode = vfs_get_inode_number(path); + if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) + return NULL; + return vfs_open_dir_inode(vfs_inode); +} + +vfs_open_file_t *vfs_open_dir_inode(vfs_inode_t vfs_inode) +{ + vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode); vfs_open_file_t *open_dir = New(vfs_open_file_t); - if (fses[match.mount->fs]->open_dir && !(fses[match.mount->fs]->open_dir(match.mount, file + match.length - 1, open_dir))) + if (fses[addr.mount->fs]->open_dir && !(fses[addr.mount->fs]->open_dir(addr.mount, addr.inode, open_dir))) { - open_dir->mount = match.mount; + open_dir->mount = addr.mount; return open_dir; } kfree(open_dir); @@ -135,16 +234,21 @@ int vfs_close_dir(vfs_open_file_t *open_dir) return status; } - -vfs_open_file_t *vfs_open_block_file(char *file) +vfs_open_file_t *vfs_open_block_file(char *path) { - vfs_mount_match_t match = vfs_get_rel_path(file); - if (match.mount == NULL) + vfs_inode_t vfs_inode = vfs_get_inode_number(path); + if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) return NULL; + return vfs_open_block_file_inode(vfs_inode); +} + +vfs_open_file_t *vfs_open_block_file_inode(vfs_inode_t vfs_inode) +{ + vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode); vfs_open_file_t *open_file = New(vfs_open_file_t); - if (fses[match.mount->fs]->open_block_file && !(fses[match.mount->fs]->open_block_file(match.mount, file + match.length - 1, open_file))) + if (fses[addr.mount->fs]->open_block_file && !(fses[addr.mount->fs]->open_block_file(addr.mount, addr.inode, open_file))) { - open_file->mount = match.mount; + open_file->mount = addr.mount; return open_file; } kfree(open_file); @@ -174,33 +278,3 @@ int vfs_close_block_file(vfs_open_file_t *open_file) return status; } - -// DEBUG routines to draw the VFS Mount Tree -/******************************************/ -void vfs_dump_tree() -{ - if (!vfsMountTree) - kprintf("vfsMountTree == NULL!\n"); - else - vfs_dump_node(vfsMountTree, 0); -} - -void vfs_dump_node(vfs_node_t *node, int level) -{ - int i; - for (i = 0; i < level; i++) - { - putc(' '); - } - kprintf("%c (0x%x) mount: 0x%x, up: 0x%x, next:0x%x, down:0x%x\n", node->chr, node, node->mount, node->up, node->next, node->down); - node = node->down; - if (!node) - return; - while (node) - { - vfs_dump_node(node, level + 1); - node = node->next; - } -} -/******************************************/ - diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h index 74b977e..c6751f2 100644 --- a/kernel/fs/vfs.h +++ b/kernel/fs/vfs.h @@ -49,6 +49,7 @@ struct vfs_mount_s char *mountPoint; vfs_inode_t vfs_mount_inode; vfs_inode_t vfs_up_inode; + vfs_inode_t vfs_root_inode; struct vfs_mount_s *next; struct vfs_mount_s *prev; }; @@ -81,6 +82,12 @@ typedef struct u32_t inode_number; // relative inode number returned from fs } vfs_dir_entry_t; +typedef struct +{ + vfs_mount_t *mount; + u32_t inode; +} vfs_file_addr_t; + /* Every filesystem must provide pointers to its respective functions in a structure like this */ typedef struct { @@ -88,6 +95,7 @@ typedef struct int (*umount_super)(vfs_mount_t *mount); int (*stat)(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat); u32_t (*get_root_inode)(vfs_mount_t *mount); + int (*link_deref)(vfs_mount_t *mount, u32_t inode_number, char *link); int (*open_dir)(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir); int (*read_dir)(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry); @@ -108,28 +116,28 @@ typedef struct int vfs_init(); int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint); int vfs_register_fs(int fsn, vfs_fs_t *fs); -int vfs_add_mount(vfs_mount_t *mnt, char *mountPoint); -vfs_mount_t *vfs_find_mount(char *mountPoint); -vfs_mount_match_t vfs_get_rel_path(char *path); int vfs_umount(char *mountPoint); -int vfs_retire_node(vfs_node_t *node); +vfs_inode_t vfs_get_inode_number(char *path); +vfs_inode_t vfs_get_inode_number_rel(vfs_inode_t dir_inode, char *path); +vfs_inode_t vfs_real_inode(vfs_inode_t vfs_inode); +vfs_file_addr_t vfs_get_file_addr(vfs_inode_t vfs_inode); +vfs_inode_t vfs_entry_lookup(vfs_inode_t dir_inode, char *entry); +int vfs_link_deref(vfs_inode_t vfs_inode, char *link); int vfs_stat(char *file, vfs_stat_t *stat); +int vfs_stat_inode(vfs_inode_t vfs_inode, vfs_stat_t *stat); -vfs_open_file_t *vfs_open_dir(char *file); +vfs_open_file_t *vfs_open_dir(char *path); +vfs_open_file_t *vfs_open_dir_inode(vfs_inode_t inode); int vfs_read_dir(vfs_open_file_t *open_dir, vfs_dir_entry_t *dentry); int vfs_close_dir(vfs_open_file_t *open_dir); vfs_open_file_t *vfs_open_block_file(char *file); +vfs_open_file_t *vfs_open_block_file_inode(vfs_inode_t vfs_inode); int vfs_read_block_file(vfs_open_file_t *open_file, void *buffer); int vfs_block_file_seek(vfs_open_file_t *open_file, u32_t block_number); int vfs_close_block_file(vfs_open_file_t *open_file); -// DEBUG routines -void vfs_dump_tree(); -void vfs_dump_node(vfs_node_t *node, int level); - - #endif diff --git a/kernel/kernel.c b/kernel/kernel.c index fff1b5a..854ed63 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -136,18 +136,16 @@ void k_init() } } -/* vfs_open_file_t *root = vfs_open_dir("/"); + vfs_open_file_t *root = vfs_open_dir("/link"); if (root) { vfs_dir_entry_t dentry; - char *fname = kmalloc(257); vfs_stat_t fstat; while (!vfs_read_dir(root, &dentry)) { - strcpy(fname, "/"); - strcat(fname, dentry.name); - vfs_stat(fname, &fstat); - putc(fstat.type == VFS_FT_DIR ? 'd' : fstat.type == VFS_FT_CHAR ? 'c' : fstat.type == VFS_FT_BLOCK ? 'b' : '-'); + vfs_stat_inode(dentry.inode_number, &fstat); + kprintf("%d\t", fstat.inode); + putc(fstat.type == VFS_FT_DIR ? 'd' : fstat.type == VFS_FT_CHAR ? 'c' : fstat.type == VFS_FT_BLOCK ? 'b' : fstat.type == VFS_FT_SYMLINK ? 'l' : '-'); putc(fstat.permissions & VFS_PERMS_UR ? 'r' : '-'); putc(fstat.permissions & VFS_PERMS_UW ? 'w' : '-'); putc(fstat.permissions & VFS_PERMS_UX ? 'x' : '-'); @@ -163,13 +161,20 @@ void k_init() kprintf(" %d\t%d\t%d\t%d\t%s", fstat.links, fstat.uid, fstat.gid, fstat.size, dentry.name); if (fstat.type == VFS_FT_CHAR || fstat.type == VFS_FT_BLOCK) kprintf("\t(%d, %d)", fstat.dev >> 8, fstat.dev & 0xFF); + if (fstat.type == VFS_FT_SYMLINK) + { + char *link = kmalloc(4096); + vfs_link_deref(dentry.inode_number, link); + kprintf(" -> %s", link); + kfree(link); + } putc('\n'); } vfs_close_dir(root); } else - kprintf("Error: Could not open /txt/Makefile!\n"); -*/ + kprintf("Error: Could not open directory\n"); + criticalCounter--; } diff --git a/kernel/lang/lang.c b/kernel/lang/lang.c index 2782931..71d276c 100644 --- a/kernel/lang/lang.c +++ b/kernel/lang/lang.c @@ -44,6 +44,25 @@ int strncmp(char *str1, char *str2, int n) } +/* str_change changes a certain character in a string + * to a different character + * Returns: how many characters were changed + */ +int str_change(char *str, char ch1, char ch2) +{ + int count = 0; + while (*str) + { + if (*str == ch1) + { + *str = ch2; + count++; + } + str++; + } + return count; +} + // counts the occurrences of lookfor in str int str_count(char *str, char lookfor) { @@ -60,6 +79,8 @@ int str_count(char *str, char lookfor) // split the string into substrings by the splitchar, return number of substrings int str_split(char *str, char splitchar) { + if (!(*str)) + return 0; int subs = 1; while (*str) { diff --git a/kernel/lang/lang.h b/kernel/lang/lang.h index 7ce58d1..65d1ed2 100644 --- a/kernel/lang/lang.h +++ b/kernel/lang/lang.h @@ -29,6 +29,7 @@ void invlpg_(u32_t addr); /* lang.c */ int strcmp(char *str1, char *str2); int strncmp(char *str1, char *str2, int n); +int str_change(char *str, char ch1, char ch2); int str_count(char *str, char lookfor); int str_split(char *str, char splitchar); char *str_advance(char *str); diff --git a/rmmod/rmmod.asm b/rmmod/rmmod.asm index 957a799..0abe9ff 100644 --- a/rmmod/rmmod.asm +++ b/rmmod/rmmod.asm @@ -53,7 +53,7 @@ no_vesa: end_rmmod: ; get ready to go back to pmode and return to kernel initialization - call con_getkey +; call con_getkey mov ebx, [dat_retn] lgdt [gdtrlin32] mov eax, cr0