:: commit 0c12e2f4da8b8d6a1a35874a08776470500f8696

mintsuki <mintsuki@protonmail.com> — 2021-02-08 17:47

parents: 6db8694d7f

Revert "ext2: Change line endings of source files to UNIX"

This reverts commit 6db8694d7fc3a35f3d8c3a109bc56ba44af93e9a.
diff --git a/stage2/fs/ext2.c b/stage2/fs/ext2.c
index a809aaf4..014d6b68 100644
--- a/stage2/fs/ext2.c
+++ b/stage2/fs/ext2.c
@@ -1,451 +1,451 @@
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <fs/ext2.h>
-#include <drivers/disk.h>
-#include <lib/libc.h>
-#include <lib/blib.h>
-#include <lib/print.h>
-#include <mm/pmm.h>
-
-/* Inode types */
-#define S_IFIFO  0x1000
-#define S_IFCHR  0x2000
-#define S_IFDIR  0x4000
-#define S_IFBLK  0x6000
-#define S_IFREG  0x8000
-#define S_IFLNK  0xa000
-#define S_IFSOCK 0xc000
-
-#define FMT_MASK 0xf000
-
-/* EXT2 Filesystem States */
-#define EXT2_FS_UNRECOVERABLE_ERRORS 3
-
-/* Ext2 incompatible features */
-#define EXT2_IF_COMPRESSION 0x01
-#define EXT2_IF_EXTENTS 0x40
-#define EXT2_IF_64BIT 0x80
-#define EXT2_IF_INLINE_DATA 0x8000
-#define EXT2_IF_ENCRYPT 0x10000
-#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
-
-/* Ext4 flags */
-#define EXT4_EXTENTS_FLAG 0x80000
-
-#define EXT2_S_MAGIC    0xEF53
-
-/* EXT2 Block Group Descriptor */
-struct ext2_bgd {
-    uint32_t bg_block_bitmap;
-    uint32_t bg_inode_bitmap;
-    uint32_t bg_inode_table;
-
-    uint16_t bg_free_blocks_count;
-    uint16_t bg_free_inodes_count;
-    uint16_t bg_dirs_count;
-
-    uint16_t reserved[7];
-} __attribute__((packed));
-
-struct ext4_bgd {
-    uint32_t bg_block_bitmap;
-    uint32_t bg_inode_bitmap;
-    uint32_t bg_inode_table;
-
-    uint16_t bg_free_blocks_count;
-    uint16_t bg_free_inodes_count;
-    uint16_t bg_dirs_count;
-
-    uint16_t pad;
-    uint32_t reserved[3];
-    uint32_t block_id_hi;
-    uint32_t inode_id_hi;
-    uint32_t inode_table_id_hi;
-    uint16_t free_blocks_hi;
-    uint16_t free_inodes_hi;
-    uint16_t used_dirs_hi;
-    uint16_t pad2;
-    uint32_t reserved2[3];
-} __attribute__((packed));
-
-/* EXT2 Inode Types */
-#define EXT2_INO_DIRECTORY  0x4000
-
-/* EXT2 Directory Entry */
-struct ext2_dir_entry {
-    uint32_t inode;
-    uint16_t rec_len;
-    uint8_t  name_len;
-    uint8_t  type;
-} __attribute__((packed));
-
-struct ext4_extent_header {
-    uint16_t magic;
-    uint16_t entries;
-    uint16_t max;
-    uint16_t depth;
-    uint16_t generation;
-} __attribute__((packed));
-
-struct ext4_extent {
-    uint32_t block;
-    uint16_t len;
-    uint16_t start_hi;
-    uint32_t start;
-} __attribute__((packed));
-
-struct ext4_extent_idx {
-    uint32_t block;
-    uint32_t leaf;
-    uint16_t leaf_hi;
-    uint16_t empty;
-} __attribute__((packed));
-
-static int inode_read(void *buf, uint64_t loc, uint64_t count,
-                      struct ext2_inode *inode, struct ext2_file_handle *fd,
-                      uint32_t *alloc_map);
-static bool ext2_parse_dirent(struct ext2_dir_entry *dir, struct ext2_file_handle *fd, const char *path);
-
-// parse an inode given the partition base and inode number
-static bool ext2_get_inode(struct ext2_inode *ret,
-                          struct ext2_file_handle *fd, uint64_t inode) {
-    if (inode == 0)
-        return false;
-
-    struct ext2_superblock *sb = &fd->sb;
-
-    //determine if we need to use 64 bit inode ids
-    bool bit64 = false;
-    if (sb->s_rev_level != 0
-        && (sb->s_feature_incompat & (EXT2_IF_64BIT))
-        && sb->group_desc_size != 0
-        && ((sb->group_desc_size & (sb->group_desc_size - 1)) == 0)) {
-                if(sb->group_desc_size > 32) {
-                    bit64 = true;
-                }
-            }
-
-    const uint64_t ino_blk_grp = (inode - 1) / sb->s_inodes_per_group;
-    const uint64_t ino_tbl_idx = (inode - 1) % sb->s_inodes_per_group;
-
-    const uint64_t block_size = ((uint64_t)1024 << sb->s_log_block_size);
-    uint64_t ino_offset;
-    const uint64_t bgd_start_offset = block_size >= 2048 ? block_size : block_size * 2;
-    const uint64_t ino_size = sb->s_rev_level == 0 ? sizeof(struct ext2_inode) : sb->s_inode_size;
-
-    if (!bit64) {
-        struct ext2_bgd target_descriptor;
-        const uint64_t bgd_offset = bgd_start_offset + (sizeof(struct ext2_bgd) * ino_blk_grp);
-
-        volume_read(&fd->part, &target_descriptor, bgd_offset, sizeof(struct ext2_bgd));
-
-        ino_offset = ((target_descriptor.bg_inode_table) * block_size) +
-                                    (ino_size * ino_tbl_idx);
-    } else {
-        struct ext4_bgd target_descriptor;
-        const uint64_t bgd_offset = bgd_start_offset + (sizeof(struct ext4_bgd) * ino_blk_grp);
-
-        volume_read(&fd->part, &target_descriptor, bgd_offset, sizeof(struct ext4_bgd));
-
-        ino_offset = ((target_descriptor.bg_inode_table | (bit64 ? ((uint64_t)target_descriptor.inode_id_hi << 32) : 0)) * block_size) +
-                                    (ino_size * ino_tbl_idx);
-    }
-
-    volume_read(&fd->part, ret, ino_offset, sizeof(struct ext2_inode));
-
-    return true;
-}
-
-static uint32_t *create_alloc_map(struct ext2_file_handle *fd,
-                                  struct ext2_inode *inode) {
-    if (inode->i_flags & EXT4_EXTENTS_FLAG)
-        return NULL;
-
-    size_t entries_per_block = fd->block_size / sizeof(uint32_t);
-
-    // Cache the map of blocks
-    uint32_t *alloc_map = ext_mem_alloc(inode->i_blocks_count * sizeof(uint32_t));
-    for (uint32_t i = 0; i < inode->i_blocks_count; i++) {
-        uint32_t block = i;
-        if (block < 12) {
-            // Direct block
-            alloc_map[i] = inode->i_blocks[block];
-        } else {
-            // Indirect block
-            block -= 12;
-            if (block >= entries_per_block) {
-                // Double indirect block
-                block -= entries_per_block;
-                uint32_t index = block / entries_per_block;
-                if (index >= entries_per_block) {
-                    // Triple indirect block
-                    panic("ext2: triply indirect blocks unsupported");
-                }
-                uint32_t indirect_block;
-                volume_read(
-                    &fd->part, &indirect_block,
-                    inode->i_blocks[13] * fd->block_size + index * sizeof(uint32_t),
-                    sizeof(uint32_t)
-                );
-                for (uint32_t j = 0; j < entries_per_block; j++) {
-                    if (i + j >= inode->i_blocks_count)
-                        return alloc_map;
-                    volume_read(
-                        &fd->part, &alloc_map[i + j],
-                        indirect_block * fd->block_size + j * sizeof(uint32_t),
-                        sizeof(uint32_t)
-                    );
-                }
-                i += entries_per_block - 1;
-            } else {
-                // Single indirect block
-                volume_read(
-                    &fd->part, &alloc_map[i],
-                    inode->i_blocks[12] * fd->block_size + block * sizeof(uint32_t),
-                    sizeof(uint32_t)
-                );
-            }
-        }
-    }
-
-    return alloc_map;
-}
-
-static bool symlink_to_inode(struct ext2_inode *inode, struct ext2_file_handle *fd) {
-    // I cannot find whether this is 0-terminated or not, so I'm gonna take the
-    // safe route here and assume it is not.
-    if (inode->i_size < 59) {
-        struct ext2_dir_entry dir;
-        char *symlink = (char *)inode->i_blocks;
-        symlink[59] = 0;
-        if (!ext2_parse_dirent(&dir, fd, symlink))
-            return false;
-        ext2_get_inode(inode, fd, dir.inode);
-        return true;
-    } else {
-        print("ext2: Symlinks with destination paths longer than 60 chars unsupported\n");
-        return false;
-    }
-}
-
-static bool ext2_parse_dirent(struct ext2_dir_entry *dir, struct ext2_file_handle *fd, const char *path) {
-    if (*path == '/')
-        path++;
-
-    struct ext2_inode current_inode = fd->root_inode;
-
-    bool escape = false;
-    static char token[256];
-
-next:
-    memset(token, 0, 256);
-
-    for (size_t i = 0; i < 255 && *path != '/' && *path != '\0'; i++, path++)
-        token[i] = *path;
-
-    if (*path == '\0')
-        escape = true;
-    else
-        path++;
-
-    uint32_t *alloc_map = create_alloc_map(fd, &current_inode);
-
-    for (uint32_t i = 0; i < current_inode.i_size; ) {
-        // preliminary read
-        inode_read(dir, i, sizeof(struct ext2_dir_entry),
-                   &current_inode, fd, alloc_map);
-
-        // name read
-        char name[dir->name_len + 1];
-
-        memset(name, 0, dir->name_len + 1);
-        inode_read(name, i + sizeof(struct ext2_dir_entry), dir->name_len,
-                   &current_inode, fd, alloc_map);
-
-        if (!strcmp(token, name)) {
-            if (escape) {
-                return true;
-            } else {
-                // update the current inode
-                ext2_get_inode(&current_inode, fd, dir->inode);
-                while ((current_inode.i_mode & FMT_MASK) != S_IFDIR) {
-                    if ((current_inode.i_mode & FMT_MASK) == S_IFLNK) {
-                        if (!symlink_to_inode(&current_inode, fd))
-                            return false;
-                    } else {
-                        print("ext2: Part of path is not directory nor symlink\n");
-                        return false;
-                    }
-                }
-                goto next;
-            }
-        }
-
-        i += dir->rec_len;
-    }
-
-    return false;
-}
-
-int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path) {
-    ret->part = *part;
-
-    volume_read(&ret->part, &ret->sb, 1024, sizeof(struct ext2_superblock));
-
-    struct ext2_superblock *sb = &ret->sb;
-
-    if (sb->s_state == EXT2_FS_UNRECOVERABLE_ERRORS)
-        panic("ext2: unrecoverable errors found");
-
-    ret->block_size = ((uint64_t)1024 << ret->sb.s_log_block_size);
-
-    ext2_get_inode(&ret->root_inode, ret, 2);
-
-    struct ext2_dir_entry entry;
-
-    if (!ext2_parse_dirent(&entry, ret, path))
-        return -1;
-
-    ext2_get_inode(&ret->inode, ret, entry.inode);
-
-    while ((ret->inode.i_mode & FMT_MASK) != S_IFREG) {
-        if ((ret->inode.i_mode & FMT_MASK) == S_IFLNK) {
-            if (!symlink_to_inode(&ret->inode, ret))
-                return -1;
-        } else {
-            print("ext2: Entity is not regular file nor symlink\n");
-            return -1;
-        }
-    }
-
-    ret->size = ret->inode.i_size;
-
-    ret->alloc_map = create_alloc_map(ret, &ret->inode);
-
-    return 0;
-}
-
-int ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
-    return inode_read(buf, loc, count, &file->inode, file, file->alloc_map);
-}
-
-static struct ext4_extent_header* ext4_find_leaf(struct ext4_extent_header* ext_block, uint32_t read_block, uint64_t block_size, struct volume *part) {
-    struct ext4_extent_idx* index;
-    void* buf = NULL;
-
-    while (1) {
-        index = (struct ext4_extent_idx*)((size_t)ext_block + 12);
-
-        #define EXT4_EXT_MAGIC 0xf30a
-        if (ext_block->magic != EXT4_EXT_MAGIC)
-            panic("invalid extent magic");
-
-        if (ext_block->depth == 0) {
-            return ext_block;
-        }
-
-        int i;
-        for (i = 0; i < ext_block->entries; i++) {
-            if(read_block < index[i].block)
-                break;
-        }
-
-        if (--i < 0)
-            panic("extent not found");
-
-        uint64_t block = ((uint64_t)index[i].leaf_hi << 32) | index[i].leaf;
-        if(!buf)
-            buf = ext_mem_alloc(block_size);
-        volume_read(part, buf, (block * block_size), block_size);
-        ext_block = buf;
-    }
-}
-
-static int inode_read(void *buf, uint64_t loc, uint64_t count,
-                      struct ext2_inode *inode, struct ext2_file_handle *fd,
-                      uint32_t *alloc_map) {
-    for (uint64_t progress = 0; progress < count;) {
-        uint64_t block = (loc + progress) / fd->block_size;
-
-        uint64_t chunk = count - progress;
-        uint64_t offset = (loc + progress) % fd->block_size;
-        if (chunk > fd->block_size - offset)
-            chunk = fd->block_size - offset;
-
-        uint32_t block_index;
-
-        if (inode->i_flags & EXT4_EXTENTS_FLAG) {
-            struct ext4_extent_header *leaf;
-            struct ext4_extent *ext;
-            int i;
-
-            leaf = ext4_find_leaf((struct ext4_extent_header*)inode->i_blocks, block, fd->block_size, &fd->part);
-
-            if (!leaf)
-                panic("invalid extent");
-            ext = (struct ext4_extent*)((size_t)leaf + 12);
-
-            for (i = 0; i < leaf->entries; i++) {
-                if (block < ext[i].block) {
-                    break;
-                }
-            }
-
-            if (--i >= 0) {
-                block -= ext[i].block;
-                if (block >= ext[i].len) {
-                    panic("block longer than extent");
-                } else {
-                    uint64_t start = ((uint64_t)ext[i].start_hi << 32) + ext[i].start;
-                    block_index = start + block;
-                }
-            } else {
-                panic("extent for block not found");
-            }
-        } else {
-            block_index = alloc_map[block];
-        }
-
-        volume_read(&fd->part, buf + progress, (block_index * fd->block_size) + offset, chunk);
-
-        progress += chunk;
-    }
-
-    return 0;
-}
-
-// attempts to initialize the ext2 filesystem
-// and checks if all features are supported
-int ext2_check_signature(struct volume *part) {
-    struct ext2_superblock sb;
-    volume_read(part, &sb, 1024, sizeof(struct ext2_superblock));
-
-    if (sb.s_magic != EXT2_S_MAGIC)
-        return 0;
-
-    // If the revision level is 0, we can't test for features.
-    if (sb.s_rev_level == 0)
-        return 1;
-
-    if (sb.s_feature_incompat & EXT2_IF_COMPRESSION ||
-        sb.s_feature_incompat & EXT2_IF_INLINE_DATA ||
-        sb.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG ||
-        sb.s_feature_incompat & EXT2_IF_ENCRYPT)
-        panic("EXT2: filesystem has unsupported features %x", sb.s_feature_incompat);
-
-    return 1;
-}
-
-bool ext2_get_guid(struct guid *guid, struct volume *part) {
-    struct ext2_superblock sb;
-    volume_read(part, &sb, 1024, sizeof(struct ext2_superblock));
-
-    if (sb.s_magic != EXT2_S_MAGIC)
-        return false;
-
-    ((uint64_t *)guid)[0] = sb.s_uuid[0];
-    ((uint64_t *)guid)[1] = sb.s_uuid[1];
-
-    return true;
-}
+#include <stdint.h>

+#include <stddef.h>

+#include <stdbool.h>

+#include <fs/ext2.h>

+#include <drivers/disk.h>

+#include <lib/libc.h>

+#include <lib/blib.h>

+#include <lib/print.h>

+#include <mm/pmm.h>

+

+/* Inode types */

+#define S_IFIFO  0x1000

+#define S_IFCHR  0x2000

+#define S_IFDIR  0x4000

+#define S_IFBLK  0x6000

+#define S_IFREG  0x8000

+#define S_IFLNK  0xa000

+#define S_IFSOCK 0xc000

+

+#define FMT_MASK 0xf000

+

+/* EXT2 Filesystem States */

+#define EXT2_FS_UNRECOVERABLE_ERRORS 3

+

+/* Ext2 incompatible features */

+#define EXT2_IF_COMPRESSION 0x01

+#define EXT2_IF_EXTENTS 0x40

+#define EXT2_IF_64BIT 0x80

+#define EXT2_IF_INLINE_DATA 0x8000

+#define EXT2_IF_ENCRYPT 0x10000

+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010

+

+/* Ext4 flags */

+#define EXT4_EXTENTS_FLAG 0x80000

+

+#define EXT2_S_MAGIC    0xEF53

+

+/* EXT2 Block Group Descriptor */

+struct ext2_bgd {

+    uint32_t bg_block_bitmap;

+    uint32_t bg_inode_bitmap;

+    uint32_t bg_inode_table;

+

+    uint16_t bg_free_blocks_count;

+    uint16_t bg_free_inodes_count;

+    uint16_t bg_dirs_count;

+

+    uint16_t reserved[7];

+} __attribute__((packed));

+

+struct ext4_bgd {

+    uint32_t bg_block_bitmap;

+    uint32_t bg_inode_bitmap;

+    uint32_t bg_inode_table;

+

+    uint16_t bg_free_blocks_count;

+    uint16_t bg_free_inodes_count;

+    uint16_t bg_dirs_count;

+

+    uint16_t pad;

+    uint32_t reserved[3];

+    uint32_t block_id_hi;

+    uint32_t inode_id_hi;

+    uint32_t inode_table_id_hi;

+    uint16_t free_blocks_hi;

+    uint16_t free_inodes_hi;

+    uint16_t used_dirs_hi;

+    uint16_t pad2;

+    uint32_t reserved2[3];

+} __attribute__((packed));

+

+/* EXT2 Inode Types */

+#define EXT2_INO_DIRECTORY  0x4000

+

+/* EXT2 Directory Entry */

+struct ext2_dir_entry {

+    uint32_t inode;

+    uint16_t rec_len;

+    uint8_t  name_len;

+    uint8_t  type;

+} __attribute__((packed));

+

+struct ext4_extent_header {

+    uint16_t magic;

+    uint16_t entries;

+    uint16_t max;

+    uint16_t depth;

+    uint16_t generation;

+} __attribute__((packed));

+

+struct ext4_extent {

+    uint32_t block;

+    uint16_t len;

+    uint16_t start_hi;

+    uint32_t start;

+} __attribute__((packed));

+

+struct ext4_extent_idx {

+    uint32_t block;

+    uint32_t leaf;

+    uint16_t leaf_hi;

+    uint16_t empty;

+} __attribute__((packed));

+

+static int inode_read(void *buf, uint64_t loc, uint64_t count,

+                      struct ext2_inode *inode, struct ext2_file_handle *fd,

+                      uint32_t *alloc_map);

+static bool ext2_parse_dirent(struct ext2_dir_entry *dir, struct ext2_file_handle *fd, const char *path);

+

+// parse an inode given the partition base and inode number

+static bool ext2_get_inode(struct ext2_inode *ret,

+                          struct ext2_file_handle *fd, uint64_t inode) {

+    if (inode == 0)

+        return false;

+

+    struct ext2_superblock *sb = &fd->sb;

+

+    //determine if we need to use 64 bit inode ids

+    bool bit64 = false;

+    if (sb->s_rev_level != 0

+        && (sb->s_feature_incompat & (EXT2_IF_64BIT))

+        && sb->group_desc_size != 0

+        && ((sb->group_desc_size & (sb->group_desc_size - 1)) == 0)) {

+                if(sb->group_desc_size > 32) {

+                    bit64 = true;

+                }

+            }

+

+    const uint64_t ino_blk_grp = (inode - 1) / sb->s_inodes_per_group;

+    const uint64_t ino_tbl_idx = (inode - 1) % sb->s_inodes_per_group;

+

+    const uint64_t block_size = ((uint64_t)1024 << sb->s_log_block_size);

+    uint64_t ino_offset;

+    const uint64_t bgd_start_offset = block_size >= 2048 ? block_size : block_size * 2;

+    const uint64_t ino_size = sb->s_rev_level == 0 ? sizeof(struct ext2_inode) : sb->s_inode_size;

+

+    if (!bit64) {

+        struct ext2_bgd target_descriptor;

+        const uint64_t bgd_offset = bgd_start_offset + (sizeof(struct ext2_bgd) * ino_blk_grp);

+

+        volume_read(&fd->part, &target_descriptor, bgd_offset, sizeof(struct ext2_bgd));

+

+        ino_offset = ((target_descriptor.bg_inode_table) * block_size) +

+                                    (ino_size * ino_tbl_idx);

+    } else {

+        struct ext4_bgd target_descriptor;

+        const uint64_t bgd_offset = bgd_start_offset + (sizeof(struct ext4_bgd) * ino_blk_grp);

+

+        volume_read(&fd->part, &target_descriptor, bgd_offset, sizeof(struct ext4_bgd));

+

+        ino_offset = ((target_descriptor.bg_inode_table | (bit64 ? ((uint64_t)target_descriptor.inode_id_hi << 32) : 0)) * block_size) +

+                                    (ino_size * ino_tbl_idx);

+    }

+

+    volume_read(&fd->part, ret, ino_offset, sizeof(struct ext2_inode));

+

+    return true;

+}

+

+static uint32_t *create_alloc_map(struct ext2_file_handle *fd,

+                                  struct ext2_inode *inode) {

+    if (inode->i_flags & EXT4_EXTENTS_FLAG)

+        return NULL;

+

+    size_t entries_per_block = fd->block_size / sizeof(uint32_t);

+

+    // Cache the map of blocks

+    uint32_t *alloc_map = ext_mem_alloc(inode->i_blocks_count * sizeof(uint32_t));

+    for (uint32_t i = 0; i < inode->i_blocks_count; i++) {

+        uint32_t block = i;

+        if (block < 12) {

+            // Direct block

+            alloc_map[i] = inode->i_blocks[block];

+        } else {

+            // Indirect block

+            block -= 12;

+            if (block >= entries_per_block) {

+                // Double indirect block

+                block -= entries_per_block;

+                uint32_t index = block / entries_per_block;

+                if (index >= entries_per_block) {

+                    // Triple indirect block

+                    panic("ext2: triply indirect blocks unsupported");

+                }

+                uint32_t indirect_block;

+                volume_read(

+                    &fd->part, &indirect_block,

+                    inode->i_blocks[13] * fd->block_size + index * sizeof(uint32_t),

+                    sizeof(uint32_t)

+                );

+                for (uint32_t j = 0; j < entries_per_block; j++) {

+                    if (i + j >= inode->i_blocks_count)

+                        return alloc_map;

+                    volume_read(

+                        &fd->part, &alloc_map[i + j],

+                        indirect_block * fd->block_size + j * sizeof(uint32_t),

+                        sizeof(uint32_t)

+                    );

+                }

+                i += entries_per_block - 1;

+            } else {

+                // Single indirect block

+                volume_read(

+                    &fd->part, &alloc_map[i],

+                    inode->i_blocks[12] * fd->block_size + block * sizeof(uint32_t),

+                    sizeof(uint32_t)

+                );

+            }

+        }

+    }

+

+    return alloc_map;

+}

+

+static bool symlink_to_inode(struct ext2_inode *inode, struct ext2_file_handle *fd) {

+    // I cannot find whether this is 0-terminated or not, so I'm gonna take the

+    // safe route here and assume it is not.

+    if (inode->i_size < 59) {

+        struct ext2_dir_entry dir;

+        char *symlink = (char *)inode->i_blocks;

+        symlink[59] = 0;

+        if (!ext2_parse_dirent(&dir, fd, symlink))

+            return false;

+        ext2_get_inode(inode, fd, dir.inode);

+        return true;

+    } else {

+        print("ext2: Symlinks with destination paths longer than 60 chars unsupported\n");

+        return false;

+    }

+}

+

+static bool ext2_parse_dirent(struct ext2_dir_entry *dir, struct ext2_file_handle *fd, const char *path) {

+    if (*path == '/')

+        path++;

+

+    struct ext2_inode current_inode = fd->root_inode;

+

+    bool escape = false;

+    static char token[256];

+

+next:

+    memset(token, 0, 256);

+

+    for (size_t i = 0; i < 255 && *path != '/' && *path != '\0'; i++, path++)

+        token[i] = *path;

+

+    if (*path == '\0')

+        escape = true;

+    else

+        path++;

+

+    uint32_t *alloc_map = create_alloc_map(fd, &current_inode);

+

+    for (uint32_t i = 0; i < current_inode.i_size; ) {

+        // preliminary read

+        inode_read(dir, i, sizeof(struct ext2_dir_entry),

+                   &current_inode, fd, alloc_map);

+

+        // name read

+        char name[dir->name_len + 1];

+

+        memset(name, 0, dir->name_len + 1);

+        inode_read(name, i + sizeof(struct ext2_dir_entry), dir->name_len,

+                   &current_inode, fd, alloc_map);

+

+        if (!strcmp(token, name)) {

+            if (escape) {

+                return true;

+            } else {

+                // update the current inode

+                ext2_get_inode(&current_inode, fd, dir->inode);

+                while ((current_inode.i_mode & FMT_MASK) != S_IFDIR) {

+                    if ((current_inode.i_mode & FMT_MASK) == S_IFLNK) {

+                        if (!symlink_to_inode(&current_inode, fd))

+                            return false;

+                    } else {

+                        print("ext2: Part of path is not directory nor symlink\n");

+                        return false;

+                    }

+                }

+                goto next;

+            }

+        }

+

+        i += dir->rec_len;

+    }

+

+    return false;

+}

+

+int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path) {

+    ret->part = *part;

+

+    volume_read(&ret->part, &ret->sb, 1024, sizeof(struct ext2_superblock));

+

+    struct ext2_superblock *sb = &ret->sb;

+

+    if (sb->s_state == EXT2_FS_UNRECOVERABLE_ERRORS)

+        panic("ext2: unrecoverable errors found");

+

+    ret->block_size = ((uint64_t)1024 << ret->sb.s_log_block_size);

+

+    ext2_get_inode(&ret->root_inode, ret, 2);

+

+    struct ext2_dir_entry entry;

+

+    if (!ext2_parse_dirent(&entry, ret, path))

+        return -1;

+

+    ext2_get_inode(&ret->inode, ret, entry.inode);

+

+    while ((ret->inode.i_mode & FMT_MASK) != S_IFREG) {

+        if ((ret->inode.i_mode & FMT_MASK) == S_IFLNK) {

+            if (!symlink_to_inode(&ret->inode, ret))

+                return -1;

+        } else {

+            print("ext2: Entity is not regular file nor symlink\n");

+            return -1;

+        }

+    }

+

+    ret->size = ret->inode.i_size;

+

+    ret->alloc_map = create_alloc_map(ret, &ret->inode);

+

+    return 0;

+}

+

+int ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count) {

+    return inode_read(buf, loc, count, &file->inode, file, file->alloc_map);

+}

+

+static struct ext4_extent_header* ext4_find_leaf(struct ext4_extent_header* ext_block, uint32_t read_block, uint64_t block_size, struct volume *part) {

+    struct ext4_extent_idx* index;

+    void* buf = NULL;

+

+    while (1) {

+        index = (struct ext4_extent_idx*)((size_t)ext_block + 12);

+

+        #define EXT4_EXT_MAGIC 0xf30a

+        if (ext_block->magic != EXT4_EXT_MAGIC)

+            panic("invalid extent magic");

+

+        if (ext_block->depth == 0) {

+            return ext_block;

+        }

+

+        int i;

+        for (i = 0; i < ext_block->entries; i++) {

+            if(read_block < index[i].block)

+                break;

+        }

+

+        if (--i < 0)

+            panic("extent not found");

+

+        uint64_t block = ((uint64_t)index[i].leaf_hi << 32) | index[i].leaf;

+        if(!buf)

+            buf = ext_mem_alloc(block_size);

+        volume_read(part, buf, (block * block_size), block_size);

+        ext_block = buf;

+    }

+}

+

+static int inode_read(void *buf, uint64_t loc, uint64_t count,

+                      struct ext2_inode *inode, struct ext2_file_handle *fd,

+                      uint32_t *alloc_map) {

+    for (uint64_t progress = 0; progress < count;) {

+        uint64_t block = (loc + progress) / fd->block_size;

+

+        uint64_t chunk = count - progress;

+        uint64_t offset = (loc + progress) % fd->block_size;

+        if (chunk > fd->block_size - offset)

+            chunk = fd->block_size - offset;

+

+        uint32_t block_index;

+

+        if (inode->i_flags & EXT4_EXTENTS_FLAG) {

+            struct ext4_extent_header *leaf;

+            struct ext4_extent *ext;

+            int i;

+

+            leaf = ext4_find_leaf((struct ext4_extent_header*)inode->i_blocks, block, fd->block_size, &fd->part);

+

+            if (!leaf)

+                panic("invalid extent");

+            ext = (struct ext4_extent*)((size_t)leaf + 12);

+

+            for (i = 0; i < leaf->entries; i++) {

+                if (block < ext[i].block) {

+                    break;

+                }

+            }

+

+            if (--i >= 0) {

+                block -= ext[i].block;

+                if (block >= ext[i].len) {

+                    panic("block longer than extent");

+                } else {

+                    uint64_t start = ((uint64_t)ext[i].start_hi << 32) + ext[i].start;

+                    block_index = start + block;

+                }

+            } else {

+                panic("extent for block not found");

+            }

+        } else {

+            block_index = alloc_map[block];

+        }

+

+        volume_read(&fd->part, buf + progress, (block_index * fd->block_size) + offset, chunk);

+

+        progress += chunk;

+    }

+

+    return 0;

+}

+

+// attempts to initialize the ext2 filesystem

+// and checks if all features are supported

+int ext2_check_signature(struct volume *part) {

+    struct ext2_superblock sb;

+    volume_read(part, &sb, 1024, sizeof(struct ext2_superblock));

+

+    if (sb.s_magic != EXT2_S_MAGIC)

+        return 0;

+

+    // If the revision level is 0, we can't test for features.

+    if (sb.s_rev_level == 0)

+        return 1;

+

+    if (sb.s_feature_incompat & EXT2_IF_COMPRESSION ||

+        sb.s_feature_incompat & EXT2_IF_INLINE_DATA ||

+        sb.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG ||

+        sb.s_feature_incompat & EXT2_IF_ENCRYPT)

+        panic("EXT2: filesystem has unsupported features %x", sb.s_feature_incompat);

+

+    return 1;

+}

+

+bool ext2_get_guid(struct guid *guid, struct volume *part) {

+    struct ext2_superblock sb;

+    volume_read(part, &sb, 1024, sizeof(struct ext2_superblock));

+

+    if (sb.s_magic != EXT2_S_MAGIC)

+        return false;

+

+    ((uint64_t *)guid)[0] = sb.s_uuid[0];

+    ((uint64_t *)guid)[1] = sb.s_uuid[1];

+

+    return true;

+}

diff --git a/stage2/fs/ext2.h b/stage2/fs/ext2.h
index 540c55cc..4d33470c 100644
--- a/stage2/fs/ext2.h
+++ b/stage2/fs/ext2.h
@@ -1,131 +1,131 @@
-#ifndef __FS__EXT2_H__
-#define __FS__EXT2_H__
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <lib/part.h>
-#include <lib/blib.h>
-
-/* Superblock Fields */
-struct ext2_superblock {
-    uint32_t s_inodes_count;
-    uint32_t s_blocks_count;
-    uint32_t s_r_blocks_count;
-    uint32_t s_free_blocks_count;
-    uint32_t s_free_inodes_count;
-    uint32_t s_first_data_block;
-    uint32_t s_log_block_size;
-    uint32_t s_log_frag_size;
-    uint32_t s_blocks_per_group;
-    uint32_t s_frags_per_group;
-    uint32_t s_inodes_per_group;
-    uint32_t s_mtime;
-    uint32_t s_wtime;
-
-    uint16_t s_mnt_count;
-    uint16_t s_max_mnt_count;
-    uint16_t s_magic;
-    uint16_t s_state;
-    uint16_t s_errors;
-    uint16_t s_minor_rev_level;
-
-    uint32_t s_lastcheck;
-    uint32_t s_checkinterval;
-    uint32_t s_creator_os;
-    uint32_t s_rev_level;
-    uint16_t s_def_resuid;
-    uint16_t s_def_gid;
-
-    // if version number >= 1, we have to use the ext2 extended superblock as well
-
-    /* Extended Superblock */
-    uint32_t s_first_ino;
-
-    uint16_t s_inode_size;
-    uint16_t s_block_group_nr;
-
-    uint32_t s_feature_compat;
-    uint32_t s_feature_incompat;
-    uint32_t s_feature_ro_compat;
-
-    uint64_t s_uuid[2];
-    uint64_t s_volume_name[2];
-
-    uint64_t s_last_mounted[8];
-
-    uint32_t compression_info;
-    uint8_t prealloc_blocks;
-    uint8_t prealloc_dir_blocks;
-    uint16_t reserved_gdt_blocks;
-    uint8_t journal_uuid[16];
-    uint32_t journal_inum;
-    uint32_t journal_dev;
-    uint32_t last_orphan;
-    uint32_t hash_seed[4];
-    uint8_t def_hash_version;
-    uint8_t jnl_backup_type;
-    uint16_t group_desc_size;
-    uint32_t default_mount_opts;
-    uint32_t first_meta_bg;
-    uint32_t mkfs_time;
-    uint32_t jnl_blocks[17];
-} __attribute__((packed));
-
-struct ext2_linux {
-    uint8_t  frag_num;
-    uint8_t  frag_size;
-
-    uint16_t reserved_16;
-    uint16_t user_id_high;
-    uint16_t group_id_high;
-
-    uint32_t reserved_32;
-} __attribute__((packed));
-
-struct ext2_inode {
-    uint16_t i_mode;
-    uint16_t i_uid;
-
-    uint32_t i_size;
-    uint32_t i_atime;
-    uint32_t i_ctime;
-    uint32_t i_mtime;
-    uint32_t i_dtime;
-
-    uint16_t i_gid;
-    uint16_t i_links_count;
-
-    uint32_t i_blocks_count;
-    uint32_t i_flags;
-    uint32_t i_osd1;
-    uint32_t i_blocks[15];
-    uint32_t i_generation;
-
-    /* EXT2 v >= 1.0 */
-    uint32_t i_eab;
-    uint32_t i_maj;
-
-    /* EXT2 vAll */
-    uint32_t i_frag_block;
-
-    struct ext2_linux i_osd2;
-} __attribute__((packed));
-
-struct ext2_file_handle {
-    struct volume part;
-    struct ext2_superblock sb;
-    int size;
-    struct ext2_inode root_inode;
-    struct ext2_inode inode;
-    uint64_t block_size;
-    uint32_t *alloc_map;
-};
-
-int ext2_check_signature(struct volume *part);
-bool ext2_get_guid(struct guid *guid, struct volume *part);
-
-int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path);
-int ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count);
-
-#endif
+#ifndef __FS__EXT2_H__

+#define __FS__EXT2_H__

+

+#include <stdint.h>

+#include <stddef.h>

+#include <stdbool.h>

+#include <lib/part.h>

+#include <lib/blib.h>

+

+/* Superblock Fields */

+struct ext2_superblock {

+    uint32_t s_inodes_count;

+    uint32_t s_blocks_count;

+    uint32_t s_r_blocks_count;

+    uint32_t s_free_blocks_count;

+    uint32_t s_free_inodes_count;

+    uint32_t s_first_data_block;

+    uint32_t s_log_block_size;

+    uint32_t s_log_frag_size;

+    uint32_t s_blocks_per_group;

+    uint32_t s_frags_per_group;

+    uint32_t s_inodes_per_group;

+    uint32_t s_mtime;

+    uint32_t s_wtime;

+

+    uint16_t s_mnt_count;

+    uint16_t s_max_mnt_count;

+    uint16_t s_magic;

+    uint16_t s_state;

+    uint16_t s_errors;

+    uint16_t s_minor_rev_level;

+

+    uint32_t s_lastcheck;

+    uint32_t s_checkinterval;

+    uint32_t s_creator_os;

+    uint32_t s_rev_level;

+    uint16_t s_def_resuid;

+    uint16_t s_def_gid;

+

+    // if version number >= 1, we have to use the ext2 extended superblock as well

+

+    /* Extended Superblock */

+    uint32_t s_first_ino;

+

+    uint16_t s_inode_size;

+    uint16_t s_block_group_nr;

+

+    uint32_t s_feature_compat;

+    uint32_t s_feature_incompat;

+    uint32_t s_feature_ro_compat;

+

+    uint64_t s_uuid[2];

+    uint64_t s_volume_name[2];

+

+    uint64_t s_last_mounted[8];

+

+    uint32_t compression_info;

+    uint8_t prealloc_blocks;

+    uint8_t prealloc_dir_blocks;

+    uint16_t reserved_gdt_blocks;

+    uint8_t journal_uuid[16];

+    uint32_t journal_inum;

+    uint32_t journal_dev;

+    uint32_t last_orphan;

+    uint32_t hash_seed[4];

+    uint8_t def_hash_version;

+    uint8_t jnl_backup_type;

+    uint16_t group_desc_size;

+    uint32_t default_mount_opts;

+    uint32_t first_meta_bg;

+    uint32_t mkfs_time;

+    uint32_t jnl_blocks[17];

+} __attribute__((packed));

+

+struct ext2_linux {

+    uint8_t  frag_num;

+    uint8_t  frag_size;

+

+    uint16_t reserved_16;

+    uint16_t user_id_high;

+    uint16_t group_id_high;

+

+    uint32_t reserved_32;

+} __attribute__((packed));

+

+struct ext2_inode {

+    uint16_t i_mode;

+    uint16_t i_uid;

+

+    uint32_t i_size;

+    uint32_t i_atime;

+    uint32_t i_ctime;

+    uint32_t i_mtime;

+    uint32_t i_dtime;

+

+    uint16_t i_gid;

+    uint16_t i_links_count;

+

+    uint32_t i_blocks_count;

+    uint32_t i_flags;

+    uint32_t i_osd1;

+    uint32_t i_blocks[15];

+    uint32_t i_generation;

+

+    /* EXT2 v >= 1.0 */

+    uint32_t i_eab;

+    uint32_t i_maj;

+

+    /* EXT2 vAll */

+    uint32_t i_frag_block;

+

+    struct ext2_linux i_osd2;

+} __attribute__((packed));

+

+struct ext2_file_handle {

+    struct volume part;

+    struct ext2_superblock sb;

+    int size;

+    struct ext2_inode root_inode;

+    struct ext2_inode inode;

+    uint64_t block_size;

+    uint32_t *alloc_map;

+};

+

+int ext2_check_signature(struct volume *part);

+bool ext2_get_guid(struct guid *guid, struct volume *part);

+

+int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path);

+int ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count);

+

+#endif

tab: 248 wrap: offon