Untitled
unknown
plain_text
18 days ago
15 kB
5
Indexable
#pragma once #include "ide.h" #include "shared.h" #include "block_io.h" #include "debug.h" struct 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; uint32_t i_flags; uint32_t i_osd1; uint32_t i_block[15]; uint32_t i_generation; uint32_t i_file_acl; uint32_t i_dir_acl; uint32_t i_faddr; uint8_t i_osd2[12]; }; struct 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_resgid; // extended 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; uint8_t s_uuid[16]; char s_volume_name[16]; char s_last_mounted[64]; uint32_t s_algorithm_usage_bitmap; uint8_t s_prealloc_blocks; uint8_t s_prealloc_dir_blocks; uint16_t s_reserved_gdt_blocks; uint8_t s_journal_uuid[16]; uint32_t s_journal_inum; uint32_t s_journal_dev; uint32_t s_last_orphan; uint32_t s_hash_seed[4]; uint8_t s_def_hash_version; uint8_t s_reserved_char_pad; uint16_t s_reserved_word_pad; uint32_t s_default_mount_opts; uint32_t s_first_meta_bg; uint32_t s_mkfs_time; uint32_t s_jnl_blocks[17]; }; struct BlockGD { 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_used_dirs_count; uint16_t bg_pad; uint32_t bg_reserved[3]; }; struct DirEntry { uint32_t inode; uint16_t rec_len; uint8_t name_len; uint8_t file_type; char name[255]; }; // A wrapper around an i-node class Node : public BlockIO { // we implement BlockIO because we // represent data public: Inode* currInode; StrongPtr<Ide> currIde; uint32_t number; Node(Inode* inode, uint32_t num, StrongPtr<Ide> ide, uint32_t block_size) : BlockIO(block_size), currInode(inode), currIde(ide), number(num) { } // How many bytes does this i-node represent // - for a file, the size of the file // - for a directory, implementation dependent // - for a symbolic link, the length of the name uint32_t size_in_bytes() override { return currInode->i_size; } // read the given block (panics if the block number is not valid) // remember that block size is defined by the file system not the device void read_block(uint32_t number, char* buffer) override; inline uint16_t get_type() { return currInode->i_mode & 0xF000; } // true if this node is a directory bool is_dir() { return (currInode->i_mode & 0xF000) == 0x4000; } // true if this node is a file bool is_file() { return (currInode->i_mode & 0xF000) == 0x8000; } // true if this node is a symbolic link bool is_symlink() { return (currInode->i_mode & 0xF000) == 0xA000; } // If this node is a symbolic link, fill the buffer with // the name the link referes to. // // Panics if the node is not a symbolic link // // The buffer needs to be at least as big as the the value // returned by size_in_byte() void get_symbol(char* buffer); // Returns the number of hard links to this node uint32_t n_links() { return currInode->i_links_count; } void show(const char* msg) { } // Returns the number of entries in a directory node // // Panics if not a directory uint32_t entry_count(); }; // This class encapsulates the implementation of the Ext2 file system class Ext2 { public: Superblock* sb; StrongPtr<Node> root; StrongPtr<Ide> ide; // Mount an existing file system residing on the given device // Panics if the file system is invalid Ext2(StrongPtr<Ide> ide); // Returns the block size of the file system. Doesn't have // to match that of the underlying device uint32_t get_block_size() { return 1024 << sb->s_log_block_size; // block size is not stored directly, block size is 0, 1, 2, etc. } // Returns the actual size of an i-node. Ext2 specifies that // an i-node will have a minimum size of 128B but could have // more bytes for extended attributes uint32_t get_inode_size() { return sb->s_inode_size; } // Traverse "path" starting at the current node // // Follows symbolic links for intermediate nodes // // Returns StrongPtr{} (null) in case of errors. For example: // - node is not a directory // - the path is invalid // - too many symbolic link traversals (> 100) // StrongPtr<Node> find(StrongPtr<Node> dir, const char* name) { // check the path if it is a relative or not // then check the dir // first check if the passed in dir is a directory or symbolic link if (!dir->is_dir() && !dir->is_symlink()) { return StrongPtr<Node>(); } // get the length of the path int name_len = 0; while (name[name_len] != '\0') { name_len++; } // copy the given path to a mutable copy char* curr_name = new char[name_len + 1]; for (int i = 0; i < name_len; i++) { curr_name[i] = name[i]; } curr_name[name_len] = '\0'; if (curr_name[0] == '/') { dir = root; } int sl_count = 0; while (*curr_name != '\0') { // skip any '/' while (*curr_name == '/') { curr_name++; } if (*curr_name == '\0') { break; } // get the next path // ex: /Users/Thomas/Downloads/File.txt -> Users will be the target char target_name[256]; int j = 0; while (curr_name[j] != '/' && curr_name[j] != '\0' && j < 255) { target_name[j] = curr_name[j]; j++; } target_name[j] = '\0'; StrongPtr<Node> next_node; uint32_t entry_count = dir->entry_count(); uint32_t offset = 0; bool match = false; if (dir->is_dir()) { Debug::printf("*** We are in a dir\n"); // go through the directory entries for (uint32_t k = 0; k < entry_count; k++) { DirEntry entry; dir->read_all(offset, sizeof(DirEntry), (char* ) &entry); offset += entry.rec_len; Debug::printf("checking directory entry, inode=%d, name=%.*s\n", entry.inode, entry.name_len, entry.name); match = (entry.name_len == (uint8_t) j); // First, check if lengths match if (match) { for (int l = 0; l < j; l++) { if (entry.name[l] != target_name[l]) { match = false; break; } } } // if found then retrieve corresponding inode if (match) { Debug::printf("matched entry, fetching inode %d\n", entry.inode); next_node = get_inode(entry.inode); if (next_node == nullptr || next_node->currInode == nullptr) { Debug::printf("*** ERROR: Failed to retrieve inode for %s\n", target_name); //delete[] curr_name; return StrongPtr<Node>(); // Return a valid null pointer instead of crashing } Debug::printf("successfully got inode %d\n", entry.inode); if (next_node->is_file()) { uint32_t file_size = next_node->size_in_bytes(); Debug::printf("file size: %d bytes\n", file_size); if (file_size == 0) { Debug::printf("ERROR: File size is 0, nothing to read!\n"); } else { char* buffer = new char[file_size + 1]; // Dynamically allocate correct size (+1 for null terminator) Debug::printf("calling read_block() for file inode %d\n", next_node->number); next_node->read_block(0, buffer); buffer[file_size] = '\0'; // Null-terminate to avoid garbage output Debug::printf("file content: %s\n", buffer); //[] buffer; // Free allocated memory } } break; } } // if no matches, return a nullptr if (!match) { //delete[] curr_name; return StrongPtr<Node>(); } // move to the next inode dir = next_node; curr_name += j; continue; } // check if it is a symlink if (dir->is_symlink()) { Debug::printf("*** We are in a symlink\n"); sl_count++; if (sl_count > 100) { Debug::printf("too many sym links"); //delete[] curr_name; return StrongPtr<Node>(); } // make a brand new target from the symlink char sl_target[256]; dir->get_symbol(sl_target); if (sl_target[0] == '/') { dir = root; } // copy new target into curr_name (overwrite it) int sl_target_len = 0; while (sl_target[sl_target_len] != '\0') { sl_target_len++; } //delete[] curr_name; curr_name = new char[sl_target_len + 1]; // now curr_name is the target of the symlink for (int i = 0; i < sl_target_len; i++) { curr_name[i] = sl_target[i]; } curr_name[sl_target_len] = '\0'; continue; } } // now you are out of the while loop // make sure you have reaeched the correct path if (!dir->is_dir() && !dir->is_symlink()) { // means that you have traversered throguh the whole name if (*curr_name == '\0') { //delete[] curr_name; return dir; } // means that you broke out of the loop without fully traversing else { //delete[] curr_name; return StrongPtr<Node>(); } } if (dir == nullptr || dir->currInode == nullptr) { Debug::printf("ERROR: find() is returning an invalid node!\n"); Debug::panic("invalid node returned from find()"); } Debug::printf("find() successfully returning inode %d\n", dir->number); // delete[] curr_name; return dir; } // grabs the inode for find StrongPtr<Node> get_inode(uint32_t number) { Debug::printf("getting inode %d\n", number); // compute block group and the index directly uint32_t block_group = (number - 1) / sb->s_inodes_per_group; uint32_t index = (number - 1) % sb->s_inodes_per_group; // compute the block size uint32_t block_size = get_block_size(); // compute offset to the bgdt // offset = (superblock number + 1) * block_size uint32_t bgdt_offset = (block_size == 1024) ? 1024 * 2 : block_size; uint32_t bgdt_entry = bgdt_offset + (block_group * sizeof(BlockGD)); // read the bgdt BlockGD bgd; this->ide->read_all(bgdt_entry, sizeof(BlockGD), (char*)&bgd); // figure out the inode's location based on the inode table uint32_t inode_table_block = bgd.bg_inode_table; uint32_t inode_offset = (inode_table_block * block_size) + (index * sizeof(Inode)); // make a new inode object and read from disk Inode* ret_inode = new Inode(); this->ide->read_all(inode_offset, sizeof(Inode), (char*)ret_inode); Debug::printf("read inode %d: mode=0x%x, size=%d, blocks=%d, flags=0x%x\n", number, ret_inode->i_mode, ret_inode->i_size, ret_inode->i_blocks, ret_inode->i_flags); // return a node with the inode StrongPtr<Node> node = StrongPtr<Node>(new Node(ret_inode, number, ide, get_block_size())); if (node == nullptr || node->currInode == nullptr) { Debug::printf("ERROR: get_inode() returned an invalid node for inode %d!\n", number); Debug::panic("invalid inode retrieved"); } Debug::printf("trying to read block 0 for inode %d (file content block=%d)\n", number, node->currInode->i_block[0]); Debug::printf("i_block[] for inode %d: [%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d]\n", number, node->currInode->i_block[0], node->currInode->i_block[1], node->currInode->i_block[2], node->currInode->i_block[3], node->currInode->i_block[4], node->currInode->i_block[5], node->currInode->i_block[6], node->currInode->i_block[7], node->currInode->i_block[8], node->currInode->i_block[9], node->currInode->i_block[10], node->currInode->i_block[11], node->currInode->i_block[12], node->currInode->i_block[13], node->currInode->i_block[14]); return node; } };
Editor is loading...
Leave a Comment