X-Git-Url: https://code.delx.au/refind/blobdiff_plain/ad41af04b0b2e3c789935776eb65f52821cfa8ff..98fc627eb1821561982571ea1d734d148d15d4a0:/filesystems/fsw_reiserfs.c diff --git a/filesystems/fsw_reiserfs.c b/filesystems/fsw_reiserfs.c index 05e8163..ee33aea 100644 --- a/filesystems/fsw_reiserfs.c +++ b/filesystems/fsw_reiserfs.c @@ -94,12 +94,12 @@ static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol) fsw_u32 blocksize; int i; struct fsw_string s; - + // allocate memory to keep the superblock around status = fsw_alloc(sizeof(struct reiserfs_super_block), &vol->sb); if (status) return status; - + // read the superblock into its buffer fsw_set_blocksize(vol, REISERFS_SUPERBLOCK_BLOCKSIZE, REISERFS_SUPERBLOCK_BLOCKSIZE); for (i = 0; superblock_offsets[i]; i++) { @@ -108,7 +108,7 @@ static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol) return status; fsw_memcpy(vol->sb, buffer, sizeof(struct reiserfs_super_block)); fsw_block_release(vol, superblock_offsets[i], buffer); - + // check for one of the magic strings if (fsw_memeq(vol->sb->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING, 8)) { @@ -127,11 +127,11 @@ static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol) } if (superblock_offsets[i] == 0) return FSW_UNSUPPORTED; - + // check the superblock if (vol->sb->s_v1.s_root_block == -1) // unfinished 'reiserfsck --rebuild-tree' return FSW_VOLUME_CORRUPTED; - + /* if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV && vol->sb->s_rev_level != EXT2_DYNAMIC_REV) @@ -140,18 +140,18 @@ static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol) (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER))) return FSW_UNSUPPORTED; */ - + // set real blocksize blocksize = vol->sb->s_v1.s_blocksize; fsw_set_blocksize(vol, blocksize, blocksize); - + // get other info from superblock /* vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb); vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt; vol->inode_size = EXT2_INODE_SIZE(vol->sb); */ - + for (i = 0; i < 16; i++) if (vol->sb->s_label[i] == 0) break; @@ -161,16 +161,16 @@ static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol) status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s); if (status) return status; - + // setup the root dnode status = fsw_dnode_create_root(vol, REISERFS_ROOT_OBJECTID, &vol->g.root); if (status) return status; vol->g.root->dir_id = REISERFS_ROOT_PARENT_OBJECTID; - + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_volume_mount: success, blocksize %d tree height %d\n"), blocksize, vol->sb->s_v1.s_tree_height)); - + return FSW_SUCCESS; } @@ -210,12 +210,12 @@ static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, str fsw_status_t status; fsw_u32 item_len, mode; struct fsw_reiserfs_item item; - + if (dno->sd_v1 || dno->sd_v2) return FSW_SUCCESS; - + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_dnode_fill: object %d/%d\n"), dno->dir_id, dno->g.dnode_id)); - + // find stat data item in reiserfs tree status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, 0, &item); if (status == FSW_NOT_FOUND) { @@ -231,7 +231,7 @@ static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, str return FSW_VOLUME_CORRUPTED; } item_len = item.ih.ih_item_len; - + // get data in appropriate version if (item.ih.ih_version == KEY_FORMAT_3_5 && item_len == SD_V1_SIZE) { // have stat_data_v1 structure @@ -239,29 +239,29 @@ static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, str fsw_reiserfs_item_release(vol, &item); if (status) return status; - + // get info from the inode dno->g.size = dno->sd_v1->sd_size; mode = dno->sd_v1->sd_mode; - + } else if (item.ih.ih_version == KEY_FORMAT_3_6 && item_len == SD_V2_SIZE) { // have stat_data_v2 structure status = fsw_memdup((void **)&dno->sd_v2, item.item_data, item_len); fsw_reiserfs_item_release(vol, &item); if (status) return status; - + // get info from the inode dno->g.size = dno->sd_v2->sd_size; mode = dno->sd_v2->sd_mode; - + } else { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: version %d(%d) and size %d(%d) not recognized for stat_data\n"), item.ih.ih_version, KEY_FORMAT_3_6, item_len, SD_V2_SIZE)); fsw_reiserfs_item_release(vol, &item); return FSW_VOLUME_CORRUPTED; } - + // get node type from mode field if (S_ISREG(mode)) dno->g.type = FSW_DNODE_TYPE_FILE; @@ -271,7 +271,7 @@ static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, str dno->g.type = FSW_DNODE_TYPE_SYMLINK; else dno->g.type = FSW_DNODE_TYPE_SPECIAL; - + return FSW_SUCCESS; } @@ -315,7 +315,7 @@ static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, str sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime); sb->store_attr_posix(sb, dno->sd_v2->sd_mode); } - + return FSW_SUCCESS; } @@ -334,17 +334,17 @@ static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, str fsw_u64 search_offset, intra_offset; struct fsw_reiserfs_item item; fsw_u32 intra_bno, nr_item; - + // Preconditions: The caller has checked that the requested logical block // is within the file's size. The dnode has complete information, i.e. // fsw_reiserfs_dnode_read_info was called successfully on it. - + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_get_extent: mapping block %d of object %d/%d\n"), extent->log_start, dno->dir_id, dno->g.dnode_id)); - + extent->type = FSW_EXTENT_TYPE_SPARSE; extent->log_count = 1; - + // get the item for the requested block search_offset = (fsw_u64)extent->log_start * vol->g.log_blocksize + 1; status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, search_offset, &item); @@ -355,11 +355,11 @@ static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, str return FSW_SUCCESS; // no data items found, assume all-sparse file } intra_offset = search_offset - item.item_offset; - + // check the kind of block if (item.item_type == TYPE_INDIRECT || item.item_type == V1_INDIRECT_UNIQUENESS) { // indirect item, contains block numbers - + if (intra_offset & (vol->g.log_blocksize - 1)) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not block-aligned for indirect block\n"))); goto bail; @@ -372,37 +372,37 @@ static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, str } extent->type = FSW_EXTENT_TYPE_PHYSBLOCK; extent->phys_start = ((fsw_u32 *)item.item_data)[intra_bno]; - + // TODO: check if the following blocks can be aggregated into one extent - + fsw_reiserfs_item_release(vol, &item); return FSW_SUCCESS; - + } else if (item.item_type == TYPE_DIRECT || item.item_type == V1_DIRECT_UNIQUENESS) { // direct item, contains file data - + // TODO: Check if direct items always start on block boundaries. If not, we may have // to do extra work here. - + if (intra_offset != 0) { FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not aligned for direct block\n"))); goto bail; } - + extent->type = FSW_EXTENT_TYPE_BUFFER; status = fsw_memdup(&extent->buffer, item.item_data, item.ih.ih_item_len); fsw_reiserfs_item_release(vol, &item); if (status) return status; - + return FSW_SUCCESS; - + } - + bail: fsw_reiserfs_item_release(vol, &item); return FSW_VOLUME_CORRUPTED; - + /* // check if the following blocks can be aggregated into one extent file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1)); @@ -432,14 +432,14 @@ static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, str fsw_u32 child_dir_id; struct reiserfs_de_head *dhead; struct fsw_string entry_name; - + // Preconditions: The caller has checked that dno is a directory node. - + // BIG TODOS: Use the hash function to start with the item containing the entry. // Use binary search within the item. - + entry_name.type = FSW_STRING_TYPE_ISO88591; - + // get the item for that position status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, FIRST_ITEM_OFFSET, &item); if (status) @@ -448,9 +448,9 @@ static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, str fsw_reiserfs_item_release(vol, &item); return FSW_NOT_FOUND; // empty directory or something } - + for(;;) { - + // search the directory item dhead = (struct reiserfs_de_head *)item.item_data; nr_item = item.ih.u.ih_entry_count; @@ -461,14 +461,14 @@ static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, str name_len = next_name_offset - name_offset; while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0) name_len--; - + entry_name.len = entry_name.size = name_len; entry_name.data = item.item_data + name_offset; - + // compare name if (fsw_streq(lookup_name, &entry_name)) { // found the entry we're looking for! - + // setup a dnode for the child item status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); child_dir_id = dhead->deh_dir_id; @@ -476,18 +476,18 @@ static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, str if (status) return status; (*child_dno_out)->dir_id = child_dir_id; - + return FSW_SUCCESS; } } - + // We didn't find the next directory entry in this item. Look for the next // item of the directory. - + status = fsw_reiserfs_item_next(vol, &item); if (status) return status; - + } } @@ -508,17 +508,17 @@ static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struc fsw_u32 child_dir_id; struct reiserfs_de_head *dhead; struct fsw_string entry_name; - + // Preconditions: The caller has checked that dno is a directory node. The caller // has opened a storage handle to the directory's storage and keeps it around between // calls. - + // BIG TODOS: Use binary search within the item. - + // adjust pointer to first entry if necessary if (shand->pos == 0) shand->pos = FIRST_ITEM_OFFSET; - + // get the item for that position status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, shand->pos, &item); if (status) @@ -527,9 +527,9 @@ static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struc fsw_reiserfs_item_release(vol, &item); return FSW_NOT_FOUND; // empty directory or something } - + for(;;) { - + // search the directory item dhead = (struct reiserfs_de_head *)item.item_data; nr_item = item.ih.u.ih_entry_count; @@ -538,7 +538,7 @@ static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struc continue; // not yet past the last entry returned if (dhead->deh_offset == DOT_OFFSET || dhead->deh_offset == DOT_DOT_OFFSET) continue; // never report . or .. - + // get the name name_offset = dhead->deh_location; if (i == 0) @@ -548,17 +548,17 @@ static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struc name_len = next_name_offset - name_offset; while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0) name_len--; - + entry_name.type = FSW_STRING_TYPE_ISO88591; entry_name.len = entry_name.size = name_len; entry_name.data = item.item_data + name_offset; - + if (fsw_streq_cstr(&entry_name, ".reiserfs_priv")) continue; // never report this special file - + // found the next entry! shand->pos = dhead->deh_offset + 1; - + // setup a dnode for the child item status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out); child_dir_id = dhead->deh_dir_id; @@ -566,17 +566,17 @@ static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struc if (status) return status; (*child_dno_out)->dir_id = child_dir_id; - + return FSW_SUCCESS; } - + // We didn't find the next directory entry in this item. Look for the next // item of the directory. - + status = fsw_reiserfs_item_next(vol, &item); if (status) return status; - + } } @@ -601,17 +601,17 @@ static int fsw_reiserfs_compare_key(struct reiserfs_key *key, { fsw_u32 key_type; fsw_u64 key_offset; - + if (key->k_dir_id > dir_id) return FIRST_GREATER; if (key->k_dir_id < dir_id) return SECOND_GREATER; - + if (key->k_objectid > objectid) return FIRST_GREATER; if (key->k_objectid < objectid) return SECOND_GREATER; - + // determine format of the on-disk key key_type = (fsw_u32)FSW_U64_SHR(key->u.k_offset_v2.v, 60); if (key_type != TYPE_DIRECT && key_type != TYPE_INDIRECT && key_type != TYPE_DIRENTRY) { @@ -643,19 +643,19 @@ static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, struct block_head *bhead; struct reiserfs_key *key; struct item_head *ihead; - + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: searching %d/%d/%lld\n"), dir_id, objectid, offset)); - + // BIG TODOS: Use binary search within the item. // Remember tree path for "get next item" function. - + item->valid = 0; item->block_bno = 0; - + // walk the tree tree_bno = vol->sb->s_v1.s_root_block; for (tree_level = vol->sb->s_v1.s_tree_height - 1; ; tree_level--) { - + // get the current tree block into memory status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); if (status) @@ -669,11 +669,11 @@ static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, nr_item = bhead->blk_nr_item; FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_search: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); item->path_bno[tree_level] = tree_bno; - + // check if we have reached a leaf block if (tree_level == DISK_LEAF_NODE_LEVEL) break; - + // search internal node block, look for the path to follow key = (struct reiserfs_key *)(buffer + BLKH_SIZE); for (i = 0; i < nr_item; i++, key++) { @@ -685,7 +685,7 @@ static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, fsw_block_release(vol, tree_bno, buffer); tree_bno = next_tree_bno; } - + // search leaf node block, look for our data ihead = (struct item_head *)(buffer + BLKH_SIZE); for (i = 0; i < nr_item; i++, ihead++) { @@ -716,7 +716,7 @@ static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, fsw_block_release(vol, tree_bno, buffer); return FSW_NOT_FOUND; // Found no key for this object at all } - + // return results fsw_memcpy(&item->ih, ihead, sizeof(struct item_head)); item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60); @@ -732,11 +732,11 @@ static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol, } item->item_data = buffer + ihead->ih_item_location; item->valid = 1; - + // add information for block release item->block_bno = tree_bno; item->block_buffer = buffer; - + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: found %d/%d/%lld (%d)\n"), ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type)); return FSW_SUCCESS; @@ -755,20 +755,20 @@ static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, fsw_u8 *buffer; struct block_head *bhead; struct item_head *ihead; - + if (!item->valid) return FSW_NOT_FOUND; fsw_reiserfs_item_release(vol, item); // TODO: maybe delay this and/or use the cached block! - + dir_id = item->ih.ih_key.k_dir_id; objectid = item->ih.ih_key.k_objectid; - + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: next for %d/%d/%lld\n"), dir_id, objectid, item->item_offset)); - + // find a node that has more items, moving up until we find one - + for (tree_level = DISK_LEAF_NODE_LEVEL; tree_level < vol->sb->s_v1.s_tree_height; tree_level++) { - + // get the current tree block into memory tree_bno = item->path_bno[tree_level]; status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); @@ -782,7 +782,7 @@ static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, } nr_item = bhead->blk_nr_item; FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); - + nr_ptr_item = nr_item + ((tree_level > DISK_LEAF_NODE_LEVEL) ? 1 : 0); // internal nodes have (nr_item) keys and (nr_item+1) pointers item->path_index[tree_level]++; if (item->path_index[tree_level] >= nr_ptr_item) { @@ -790,7 +790,7 @@ static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, fsw_block_release(vol, tree_bno, buffer); continue; // this node doesn't have any more items, move up one level } - + // we have a new path to follow, move down to the leaf node again while (tree_level > DISK_LEAF_NODE_LEVEL) { // get next pointer from current block @@ -798,7 +798,7 @@ static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, fsw_block_release(vol, tree_bno, buffer); tree_bno = next_tree_bno; tree_level--; - + // get the current tree block into memory status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer); if (status) @@ -813,17 +813,17 @@ static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item)); item->path_bno[tree_level] = tree_bno; } - + // get the item from the leaf node ihead = ((struct item_head *)(buffer + BLKH_SIZE)) + item->path_index[tree_level]; - + // We now have the item that follows the previous one in the tree. Check that it // belongs to the same object. if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) { fsw_block_release(vol, tree_bno, buffer); return FSW_NOT_FOUND; // Found no next key for this object } - + // return results fsw_memcpy(&item->ih, ihead, sizeof(struct item_head)); item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60); @@ -839,16 +839,16 @@ static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol, } item->item_data = buffer + ihead->ih_item_location; item->valid = 1; - + // add information for block release item->block_bno = tree_bno; item->block_buffer = buffer; - + FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: found %d/%d/%lld (%d)\n"), ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type)); return FSW_SUCCESS; } - + // we went to the highest level node and there still were no more items... return FSW_NOT_FOUND; } @@ -862,7 +862,7 @@ static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol, { if (!item->valid) return; - + if (item->block_bno > 0) { fsw_block_release(vol, item->block_bno, item->block_buffer); item->block_bno = 0;