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++) {
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)) {
}
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)
(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;
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;
}
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) {
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
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;
dno->g.type = FSW_DNODE_TYPE_SYMLINK;
else
dno->g.type = FSW_DNODE_TYPE_SPECIAL;
-
+
return FSW_SUCCESS;
}
sb->used_bytes = 0;
else
sb->used_bytes = dno->sd_v1->u.sd_blocks * vol->g.log_blocksize;
- sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v1->sd_ctime);
- sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v1->sd_atime);
- sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v1->sd_mtime);
- sb->store_attr_posix(sb, dno->sd_v1->sd_mode);
+ fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v1->sd_ctime);
+ fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v1->sd_atime);
+ fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v1->sd_mtime);
+ fsw_store_attr_posix(sb, dno->sd_v1->sd_mode);
} else if (dno->sd_v2) {
sb->used_bytes = dno->sd_v2->sd_blocks * vol->g.log_blocksize;
- sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v2->sd_ctime);
- sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v2->sd_atime);
- sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime);
- sb->store_attr_posix(sb, dno->sd_v2->sd_mode);
+ fsw_store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v2->sd_ctime);
+ fsw_store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v2->sd_atime);
+ fsw_store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime);
+ fsw_store_attr_posix(sb, dno->sd_v2->sd_mode);
}
-
+
return FSW_SUCCESS;
}
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);
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;
}
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));
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)
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;
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;
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;
-
+
}
}
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)
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;
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)
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;
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;
-
+
}
}
{
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) {
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)
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++) {
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++) {
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);
}
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;
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);
}
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) {
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
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)
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);
}
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;
}
{
if (!item->valid)
return;
-
+
if (item->block_bno > 0) {
fsw_block_release(vol, item->block_bno, item->block_buffer);
item->block_bno = 0;