/** * Return the 'index'th directory entry in the directory represented by 'inode'. * Caller should free the memory. */ ext2_dir_t *ext2_disk_direntry(ext2_inodetable_t *inode, uint32_t no, uint32_t index) { uint8_t *block = malloc(BLOCKSIZE); uint8_t block_nr = 0; ext2_disk_inode_read_block(inode, no, block_nr, block); uint32_t dir_offset = 0; uint32_t total_offset = 0; uint32_t dir_index = 0; while (total_offset < inode->size && dir_index <= index) { ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); if (dir_index == index) { ext2_dir_t *out = malloc(d_ent->rec_len); memcpy(out, d_ent, d_ent->rec_len); free(block); return out; } dir_offset += d_ent->rec_len; total_offset += d_ent->rec_len; dir_index++; // move on to the next block of this directory if needed. if (dir_offset >= BLOCKSIZE) { block_nr++; dir_offset -= BLOCKSIZE; ext2_disk_inode_read_block(inode, no, block_nr, block); } } free(block); return NULL; }
uint32_t write_ext2_disk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { ext2_inodetable_t *inode = ext2_disk_inode(node->inode); uint32_t end = offset + size; uint32_t start_block = offset / BLOCKSIZE; uint32_t end_block = end / BLOCKSIZE; uint32_t end_size = end - end_block * BLOCKSIZE; uint32_t size_to_write = end - offset; kprintf("[kernel/ext2] Write at node 0x%x, offset %d, size %d, buffer=0x%x\n", node, offset, size, buffer); if (end_size == 0) { end_block--; } // need to update if size has increased. if (inode->size < end) { inode->size = end; ext2_disk_write_inode(inode, node->inode); } if (start_block == end_block) { void *buf = malloc(BLOCKSIZE); ext2_disk_inode_read_block(inode, node->inode, start_block, buf); memcpy((uint8_t *)((uintptr_t)buf + (offset % BLOCKSIZE)), buffer, size_to_write); kprintf("[kernel/ext2] Single-block write.\n"); ext2_disk_inode_write_block(inode, node->inode, start_block, buf); free(buf); free(inode); return size_to_write; } else { uint32_t block_offset; uint32_t blocks_read = 0; for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { if (block_offset == start_block) { void *buf = malloc(BLOCKSIZE); ext2_disk_inode_read_block(inode, node->inode, block_offset, buf); memcpy((uint8_t *)((uint32_t)buf + (offset % BLOCKSIZE)), buffer, BLOCKSIZE - (offset % BLOCKSIZE)); kprintf("[kernel/ext2] Writing block [loop...]...\n"); ext2_disk_inode_write_block(inode, node->inode, start_block, buf); free(buf); } else { kprintf("[kernel/ext2] Writing block [buffer...?]...\n"); ext2_disk_inode_write_block(inode, node->inode, block_offset, buffer + BLOCKSIZE * blocks_read - (block_offset % BLOCKSIZE)); } } void *buf = malloc(BLOCKSIZE); ext2_disk_inode_read_block(inode, node->inode, end_block, buf); memcpy(buf, buffer + BLOCKSIZE * blocks_read - (block_offset % BLOCKSIZE), end_size); kprintf("[kernel/ext2] Writing block [tail]...\n"); ext2_disk_inode_write_block(inode, node->inode, end_block, buf); free(buf); } free(inode); return size_to_write; }
uint32_t read_ext2_disk(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { ext2_inodetable_t *inode = ext2_disk_inode(node->inode); uint32_t end; if (offset + size > inode->size) { end = inode->size; } else { end = offset + size; } uint32_t start_block = offset / BLOCKSIZE; uint32_t end_block = end / BLOCKSIZE; uint32_t end_size = end - end_block * BLOCKSIZE; uint32_t size_to_read = end - offset; if (end_size == 0) { end_block--; } if (start_block == end_block) { void *buf = malloc(BLOCKSIZE); ext2_disk_inode_read_block(inode, node->inode, start_block, buf); memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), size_to_read); free(buf); free(inode); return size_to_read; } else { uint32_t block_offset; uint32_t blocks_read = 0; for (block_offset = start_block; block_offset < end_block; block_offset++, blocks_read++) { if (block_offset == start_block) { void *buf = malloc(BLOCKSIZE); ext2_disk_inode_read_block(inode, node->inode, block_offset, buf); memcpy(buffer, (uint8_t *)(((uint32_t)buf) + (offset % BLOCKSIZE)), BLOCKSIZE - (offset % BLOCKSIZE)); free(buf); } else { void *buf = malloc(BLOCKSIZE); ext2_disk_inode_read_block(inode, node->inode, block_offset, buf); memcpy(buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), buf, BLOCKSIZE); free(buf); } } void *buf = malloc(BLOCKSIZE); ext2_disk_inode_read_block(inode, node->inode, end_block, buf); memcpy(buffer + BLOCKSIZE * blocks_read - (offset % BLOCKSIZE), buf, end_size); free(buf); } free(inode); return size_to_read; }
/** * Find the actual inode in the ramdisk image for the requested file. */ fs_node_t *finddir_ext2_disk(fs_node_t *node, char *name) { ext2_inodetable_t *inode = ext2_disk_inode(node->inode); assert(inode->mode & EXT2_S_IFDIR); void *block = malloc(BLOCKSIZE); ext2_dir_t *direntry = NULL; uint8_t block_nr = 0; ext2_disk_inode_read_block(inode, node->inode, block_nr, block); uint32_t dir_offset = 0; uint32_t total_offset = 0; // Look through the requested entries until we find what we're looking for #if EXT2_DEBUG_BLOCK_DESCRIPTORS kprintf("file looking for: %s\n", name); kprintf("total size: %d\n", inode->size); #endif while (total_offset < inode->size) { #if EXT2_DEBUG_BLOCK_DESCRIPTORS kprintf("dir_offset: %d\n", dir_offset); kprintf("total_offset: %d\n", total_offset); #endif ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); if (strlen(name) != d_ent->name_len) { dir_offset += d_ent->rec_len; total_offset += d_ent->rec_len; // move on to the next block of this directory if need. if (dir_offset >= BLOCKSIZE) { block_nr++; dir_offset -= BLOCKSIZE; ext2_disk_inode_read_block(inode, node->inode, block_nr, block); } continue; } char *dname = malloc(sizeof(char) * (d_ent->name_len + 1)); memcpy(dname, &(d_ent->name), d_ent->name_len); dname[d_ent->name_len] = '\0'; #if EXT2_DEBUG_BLOCK_DESCRIPTORS kprintf("cur file: %s\n", dname); #endif if (!strcmp(dname, name)) { free(dname); direntry = malloc(d_ent->rec_len); memcpy(direntry, d_ent, d_ent->rec_len); break; } free(dname); dir_offset += d_ent->rec_len; total_offset += d_ent->rec_len; // move on to the next block of this directory if need. if (dir_offset >= BLOCKSIZE) { block_nr++; dir_offset -= BLOCKSIZE; ext2_disk_inode_read_block(inode, node->inode, block_nr, block); } } free(inode); free(block); if (!direntry) { // We could not find the requested entry in this directory. return NULL; } fs_node_t *outnode = malloc(sizeof(fs_node_t)); inode = ext2_disk_inode(direntry->inode); ext2_disk_node_from_file(inode, direntry, outnode); free(inode); return outnode; }
/** * Insert an entry named 'name' with type 'type' into a directory 'p_node' * at the end. * This function assumes that parent directory 'p_node' does not contain * any entry with same name as 'name'. Caller should ensure this. */ void insertdir_ext2_disk(ext2_inodetable_t *p_node, uint32_t no, uint32_t inode, char *name, uint8_t type) { /* XXX HACK This needs to be seriously fixed up. */ kprintf("[kernel/ext2] Request to insert new directory entry at 0x%x#%d->%d '%s' type %d\n", p_node, no, inode, name, type); assert(p_node->mode & EXT2_S_IFDIR); void *block = malloc(BLOCKSIZE); uint32_t block_nr = 0; ext2_disk_inode_read_block(p_node, no, block_nr, block); uint32_t dir_offset = 0; uint32_t total_offset = 0; // first, iterate pass the last entry in the parent directory. while (total_offset < p_node->size) { ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); if (d_ent->rec_len + total_offset == p_node->size) { d_ent->rec_len = d_ent->name_len + sizeof(ext2_dir_t); while (d_ent->rec_len % 4 > 0) { d_ent->rec_len++; } dir_offset += d_ent->rec_len; total_offset += d_ent->rec_len; break; } dir_offset += d_ent->rec_len; total_offset += d_ent->rec_len; // move on to the next block of this directory if needed. if (dir_offset >= BLOCKSIZE) { block_nr++; dir_offset -= BLOCKSIZE; ext2_disk_inode_read_block(p_node, no, block_nr, block); kprintf("[kernel/ext2] Advancing to next block...\n"); } } kprintf("[kernel/ext2] Total Offset = %d; block = %d; offset within block = %d\n", total_offset, block_nr, dir_offset); // Put the new directory entry at 'dir_offset' in block 'block_nr'. uint32_t size = p_node->size - total_offset; if (dir_offset + size > BLOCKSIZE) { kprintf("\033[1;31m[kernel/ext2] Just a warning: You probably just f****d everything.\033[0m\n"); } ext2_dir_t *new_entry = malloc(size); // Initialize the new entry. new_entry->inode = inode; new_entry->rec_len = size; new_entry->name_len = (uint8_t)strlen(name); new_entry->file_type = type; memcpy(&new_entry->name, name, strlen(name)); // Write back to block. memcpy(((uint8_t *)block) + dir_offset, new_entry, size); memset(((uint8_t *)block) + dir_offset + new_entry->rec_len, 0x00, 4); ext2_disk_inode_write_block(p_node, no, block_nr, block); // Update parent node size //p_node->size += size; ext2_disk_write_inode(p_node, no); free(block); }
/** * Insert an entry named 'name' with type 'type' into a directory 'p_node' * at the end. * This function assumes that parent directory 'p_node' does not contain * any entry with same name as 'name'. Caller should ensure this. */ void insertdir_ext2_disk(ext2_inodetable_t *p_node, uint32_t no, uint32_t inode, char *name, uint8_t type) { /* XXX HACK This needs to be seriously fixed up. */ debug_print(NOTICE, "Request to insert new directory entry at 0x%x#%d->%d '%s' type %d", p_node, no, inode, name, type); assert(p_node->mode & EXT2_S_IFDIR); void *block = malloc(BLOCKSIZE); uint32_t block_nr = 0; ext2_disk_inode_read_block(p_node, no, block_nr, block); uint32_t dir_offset = 0; uint32_t total_offset = 0; // first, iterate pass the last entry in the parent directory. while (total_offset < p_node->size) { ext2_dir_t *d_ent = (ext2_dir_t *)((uintptr_t)block + dir_offset); if (d_ent->rec_len + total_offset == p_node->size) { d_ent->rec_len = d_ent->name_len + sizeof(ext2_dir_t); while (d_ent->rec_len % 4 > 0) { d_ent->rec_len++; } dir_offset += d_ent->rec_len; total_offset += d_ent->rec_len; break; } dir_offset += d_ent->rec_len; total_offset += d_ent->rec_len; // move on to the next block of this directory if needed. if (dir_offset >= BLOCKSIZE) { block_nr++; dir_offset -= BLOCKSIZE; ext2_disk_inode_read_block(p_node, no, block_nr, block); debug_print(NOTICE, "Advancing to next block..."); } } debug_print(NOTICE, "total offset = %d; block = %d; offset within block = %d", total_offset, block_nr, dir_offset); // Put the new directory entry at 'dir_offset' in block 'block_nr'. uint32_t size = p_node->size - total_offset; if (dir_offset + size > BLOCKSIZE) { debug_print(WARNING, "Directory entry is beyond first block of directory. This might be bad."); } ext2_dir_t *new_entry = malloc(size); // Initialize the new entry. new_entry->inode = inode; new_entry->rec_len = size; new_entry->name_len = (uint8_t)strlen(name); new_entry->file_type = type; memcpy(&new_entry->name, name, strlen(name)); // Write back to block. memcpy(((uint8_t *)block) + dir_offset, new_entry, size); memset(((uint8_t *)block) + dir_offset + new_entry->rec_len, 0x00, 4); ext2_disk_inode_write_block(p_node, no, block_nr, block); free(new_entry); // Update parent node size //p_node->size += size; ext2_disk_write_inode(p_node, no); free(block); }