コード例 #1
0
ファイル: ext4_dir_idx.c プロジェクト: piotrkowalczuk/lwext4
static struct ext4_directory_dx_countlimit *
ext4_dir_dx_get_countlimit(struct ext4_inode_ref *inode_ref,
			struct ext4_directory_entry_ll *dirent,
			int *offset)
{
	struct ext4_directory_entry_ll *dp;
	struct ext4_directory_dx_root *root;
	struct ext4_sblock *sb = &inode_ref->fs->sb;
	int count_offset;

	if (ext4_dir_entry_ll_get_entry_length(dirent) ==
			ext4_sb_get_block_size(sb))
		count_offset = 8;
	else if (ext4_dir_entry_ll_get_entry_length(dirent) == 12) {
		root = (struct ext4_directory_dx_root *)dirent;
		dp = (struct ext4_directory_entry_ll *)&root->dots[1];
		if (ext4_dir_entry_ll_get_entry_length(dp) !=
		    ext4_sb_get_block_size(sb) - 12)
			return NULL;
		if (root->info.reserved_zero ||
		    root->info.info_length != sizeof(struct ext4_directory_dx_root_info))
			return NULL;
		count_offset = 32;
	} else
		return NULL;

	if (offset)
		*offset = count_offset;
	return (struct ext4_directory_dx_countlimit *)(((char *)dirent) + count_offset);
}
コード例 #2
0
ファイル: ext4_super.c プロジェクト: gkostka/lwext4
uint32_t ext4_num_base_meta_clusters(struct ext4_sblock *s,
				     uint32_t block_group)
{
	uint32_t num;
	uint32_t dsc_per_block =
	    ext4_sb_get_block_size(s) / ext4_sb_get_desc_size(s);

	num = ext4_sb_is_super_in_bg(s, block_group);

	if (!ext4_sb_feature_incom(s, EXT4_FINCOM_META_BG) ||
	    block_group < ext4_sb_first_meta_bg(s) * dsc_per_block) {
		if (num) {
			num += ext4_bg_num_gdb(s, block_group);
			num += ext4_get16(s, s_reserved_gdt_blocks);
		}
	} else {
		num += ext4_bg_num_gdb(s, block_group);
	}

	uint32_t clustersize = 1024 << ext4_get32(s, log_cluster_size);
	uint32_t cluster_ratio = clustersize / ext4_sb_get_block_size(s);
	uint32_t v =
	    (num + cluster_ratio - 1) >> ext4_get32(s, log_cluster_size);

	return v;
}
コード例 #3
0
ファイル: ext4_dir_idx.c プロジェクト: piotrkowalczuk/lwext4
static void
ext4_dir_set_dx_checksum(struct ext4_inode_ref *inode_ref,
			struct ext4_directory_entry_ll *dirent)
{
	int count_offset, limit, count;
	struct ext4_sblock *sb = &inode_ref->fs->sb;

	if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
		struct ext4_directory_dx_countlimit *countlimit =
			ext4_dir_dx_get_countlimit(inode_ref, dirent, &count_offset);
		if (!countlimit) {
			/* Directory seems corrupted. */
			return;
		}
		struct ext4_directory_dx_tail *t;
		limit = ext4_dir_dx_countlimit_get_limit(countlimit);
		count = ext4_dir_dx_countlimit_get_count(countlimit);
		if (count_offset + (limit * sizeof(struct ext4_directory_dx_entry)) >
				ext4_sb_get_block_size(sb) -
				sizeof(struct ext4_directory_dx_tail)) {
			/* There is no space to hold the checksum */
			return;
		}
		t = (struct ext4_directory_dx_tail *)
			(((struct ext4_directory_dx_entry *)countlimit) + limit);

		t->checksum =
			to_le32(ext4_dir_dx_checksum(inode_ref, dirent, count_offset, count, t));
	}
}
コード例 #4
0
ファイル: ext4_dir_idx.c プロジェクト: piotrkowalczuk/lwext4
/**@brief Initialize hash info structure necessary for index operations.
 * @param hinfo      Pointer to hinfo to be initialized
 * @param root_block Root block (number 0) of index
 * @param sb         Pointer to superblock
 * @param name_len   Length of name to be computed hash value from
 * @param name       Name to be computed hash value from
 * @return Standard error code
 */
static int ext4_dir_hinfo_init(struct ext4_hash_info *hinfo,
			       struct ext4_block *root_block,
			       struct ext4_sblock *sb, size_t name_len,
			       const char *name)
{
	struct ext4_directory_dx_root *root =
	    (struct ext4_directory_dx_root *)root_block->data;

	if ((root->info.hash_version != EXT2_HTREE_LEGACY) &&
	    (root->info.hash_version != EXT2_HTREE_HALF_MD4) &&
	    (root->info.hash_version != EXT2_HTREE_TEA))
		return EXT4_ERR_BAD_DX_DIR;

	/* Check unused flags */
	if (root->info.unused_flags != 0)
		return EXT4_ERR_BAD_DX_DIR;

	/* Check indirect levels */
	if (root->info.indirect_levels > 1)
		return EXT4_ERR_BAD_DX_DIR;

	/* Check if node limit is correct */
	uint32_t block_size = ext4_sb_get_block_size(sb);
	uint32_t entry_space = block_size;
	entry_space -= 2 * sizeof(struct ext4_directory_dx_dot_entry);
	entry_space -= sizeof(struct ext4_directory_dx_root_info);
	if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
		entry_space -= sizeof(struct ext4_directory_dx_tail);
	entry_space = entry_space / sizeof(struct ext4_directory_dx_entry);

	uint16_t limit = ext4_dir_dx_countlimit_get_limit(
	    (struct ext4_directory_dx_countlimit *)&root->entries);
	if (limit != entry_space)
		return EXT4_ERR_BAD_DX_DIR;

	/* Check hash version and modify if necessary */
	hinfo->hash_version =
	    ext4_dir_dx_root_info_get_hash_version(&root->info);
	if ((hinfo->hash_version <= EXT2_HTREE_TEA) &&
	    (ext4_sb_check_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) {
		/* Use unsigned hash */
		hinfo->hash_version += 3;
	}

	/* Load hash seed from superblock */

	hinfo->seed = ext4_get8(sb, hash_seed);

	/* Compute hash value of name */
	if (name)
		return ext4_dir_dx_hash_string(hinfo, name_len, name);

	return EOK;
}
コード例 #5
0
ファイル: ext4_super.c プロジェクト: gkostka/lwext4
uint32_t ext4_bg_num_gdb(struct ext4_sblock *s, uint32_t group)
{
	uint32_t dsc_per_block =
	    ext4_sb_get_block_size(s) / ext4_sb_get_desc_size(s);
	uint32_t first_meta_bg = ext4_sb_first_meta_bg(s);
	uint32_t metagroup = group / dsc_per_block;

	if (!ext4_sb_feature_incom(s,EXT4_FINCOM_META_BG) ||
	    metagroup < first_meta_bg)
		return ext4_bg_num_gdb_nometa(s, group);

	return ext4_bg_num_gdb_meta(s, group);
}
コード例 #6
0
ファイル: ext4_super.c プロジェクト: gkostka/lwext4
static uint32_t ext4_bg_num_gdb_meta(struct ext4_sblock *s, uint32_t group)
{
	uint32_t dsc_per_block =
	    ext4_sb_get_block_size(s) / ext4_sb_get_desc_size(s);

	uint32_t metagroup = group / dsc_per_block;
	uint32_t first = metagroup * dsc_per_block;
	uint32_t last = first + dsc_per_block - 1;

	if (group == first || group == first + 1 || group == last)
		return 1;
	return 0;
}
コード例 #7
0
ファイル: ext4_super.c プロジェクト: gkostka/lwext4
static uint32_t ext4_bg_num_gdb_nometa(struct ext4_sblock *s, uint32_t group)
{
	if (!ext4_sb_is_super_in_bg(s, group))
		return 0;
	uint32_t dsc_per_block =
	    ext4_sb_get_block_size(s) / ext4_sb_get_desc_size(s);

	uint32_t db_count =
	    (ext4_block_group_cnt(s) + dsc_per_block - 1) / dsc_per_block;

	if (ext4_sb_feature_incom(s, EXT4_FINCOM_META_BG))
		return ext4_sb_first_meta_bg(s);

	return db_count;
}
コード例 #8
0
ファイル: ext4_dir_idx.c プロジェクト: piotrkowalczuk/lwext4
/**@brief Walk through index tree and load leaf with corresponding hash value.
 * @param hinfo      Initialized hash info structure
 * @param inode_ref  Current i-node
 * @param root_block Root block (iblock 0), where is root node located
 * @param dx_block   Pointer to leaf node in dx_blocks array
 * @param dx_blocks  Array with the whole path from root to leaf
 * @return Standard error code
 */
static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo,
				struct ext4_inode_ref *inode_ref,
				struct ext4_block *root_block,
				struct ext4_directory_dx_block **dx_block,
				struct ext4_directory_dx_block *dx_blocks)
{
	struct ext4_directory_dx_block *tmp_dx_block = dx_blocks;
	struct ext4_directory_dx_root *root =
	    (struct ext4_directory_dx_root *)root_block->data;
	struct ext4_directory_dx_entry *entries =
	    (struct ext4_directory_dx_entry *)&root->entries;

	uint16_t limit = ext4_dir_dx_countlimit_get_limit(
	    (struct ext4_directory_dx_countlimit *)entries);
	uint8_t indirect_level =
	    ext4_dir_dx_root_info_get_indirect_levels(&root->info);

	struct ext4_block *tmp_block = root_block;
	struct ext4_directory_dx_entry *p;
	struct ext4_directory_dx_entry *q;
	struct ext4_directory_dx_entry *m;
	struct ext4_directory_dx_entry *at;

	/* Walk through the index tree */
	while (true) {
		uint16_t count = ext4_dir_dx_countlimit_get_count(
		    (struct ext4_directory_dx_countlimit *)entries);
		if ((count == 0) || (count > limit))
			return EXT4_ERR_BAD_DX_DIR;

		/* Do binary search in every node */
		p = entries + 1;
		q = entries + count - 1;

		while (p <= q) {
			m = p + (q - p) / 2;
			if (ext4_dir_dx_entry_get_hash(m) > hinfo->hash)
				q = m - 1;
			else
				p = m + 1;
		}

		at = p - 1;

		/* Write results */

		memcpy(&tmp_dx_block->block, tmp_block,
		       sizeof(struct ext4_block));
		tmp_dx_block->entries = entries;
		tmp_dx_block->position = at;

		/* Is algorithm in the leaf? */
		if (indirect_level == 0) {
			*dx_block = tmp_dx_block;
			return EOK;
		}

		/* Goto child node */
		uint32_t next_block = ext4_dir_dx_entry_get_block(at);

		indirect_level--;

		ext4_fsblk_t fblock;
		int rc = ext4_fs_get_inode_data_block_index(
		    inode_ref, next_block, &fblock, false);
		if (rc != EOK)
			return rc;

		rc = ext4_block_get(inode_ref->fs->bdev, tmp_block, fblock);
		if (rc != EOK)
			return rc;

		entries =
		    ((struct ext4_directory_dx_node *)tmp_block->data)->entries;
		limit = ext4_dir_dx_countlimit_get_limit(
		    (struct ext4_directory_dx_countlimit *)entries);

		uint16_t entry_space =
		    ext4_sb_get_block_size(&inode_ref->fs->sb) -
		    sizeof(struct ext4_fake_directory_entry);

		if (ext4_sb_feature_ro_com(&inode_ref->fs->sb,
				EXT4_FRO_COM_METADATA_CSUM))
			entry_space -= sizeof(struct ext4_directory_dx_tail);

		entry_space =
		    entry_space / sizeof(struct ext4_directory_dx_entry);

		if (limit != entry_space) {
			ext4_block_set(inode_ref->fs->bdev, tmp_block);
			return EXT4_ERR_BAD_DX_DIR;
		}

		++tmp_dx_block;
	}

	/* Unreachable */
	return EOK;
}
コード例 #9
0
ファイル: ext4_dir_idx.c プロジェクト: piotrkowalczuk/lwext4
int ext4_dir_dx_init(struct ext4_inode_ref *dir, struct ext4_inode_ref *parent)
{
	/* Load block 0, where will be index root located */
	ext4_fsblk_t fblock;
	uint32_t iblock;
	struct ext4_sblock *sb = &dir->fs->sb;
	int rc = ext4_fs_append_inode_block(dir, &fblock, &iblock);
	if (rc != EOK)
		return rc;

	struct ext4_block block;
	rc = ext4_block_get(dir->fs->bdev, &block, fblock);
	if (rc != EOK)
		return rc;

	/* Initialize pointers to data structures */
	struct ext4_directory_dx_root *root = (void *)block.data;
	struct ext4_directory_dx_root_info *info = &(root->info);

	/* Initialize dot entries */
	ext4_dir_write_entry(&dir->fs->sb,
			(struct ext4_directory_entry_ll *)root->dots,
			12,
			dir,
			".",
			strlen("."));

	ext4_dir_write_entry(&dir->fs->sb,
			(struct ext4_directory_entry_ll *)(root->dots + 1),
			ext4_sb_get_block_size(sb) - 12,
			parent,
			"..",
			strlen(".."));

	/* Initialize root info structure */
	uint8_t hash_version = ext4_get8(&dir->fs->sb, default_hash_version);

	ext4_dir_dx_root_info_set_hash_version(info, hash_version);
	ext4_dir_dx_root_info_set_indirect_levels(info, 0);
	ext4_dir_dx_root_info_set_info_length(info, 8);

	/* Set limit and current number of entries */
	struct ext4_directory_dx_countlimit *countlimit =
	    (struct ext4_directory_dx_countlimit *)&root->entries;

	ext4_dir_dx_countlimit_set_count(countlimit, 1);

	uint32_t block_size = ext4_sb_get_block_size(&dir->fs->sb);
	uint32_t entry_space = block_size -
			       2 * sizeof(struct ext4_directory_dx_dot_entry) -
			       sizeof(struct ext4_directory_dx_root_info);
	if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
		entry_space -= sizeof(struct ext4_directory_dx_tail);

	uint16_t root_limit =
	    entry_space / sizeof(struct ext4_directory_dx_entry);

	ext4_dir_dx_countlimit_set_limit(countlimit, root_limit);

	/* Append new block, where will be new entries inserted in the future */
	rc = ext4_fs_append_inode_block(dir, &fblock, &iblock);
	if (rc != EOK) {
		ext4_block_set(dir->fs->bdev, &block);
		return rc;
	}

	struct ext4_block new_block;

	rc = ext4_block_get(dir->fs->bdev, &new_block, fblock);
	if (rc != EOK) {
		ext4_block_set(dir->fs->bdev, &block);
		return rc;
	}

	/* Fill the whole block with empty entry */
	struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;

	if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
		ext4_dir_entry_ll_set_entry_length(block_entry,
				block_size -
				sizeof(struct ext4_directory_entry_tail));
		ext4_dir_entry_ll_set_name_length(sb,
						  block_entry,
						  0);
		ext4_dir_entry_ll_set_inode_type(sb,
						 block_entry,
						 EXT4_DIRENTRY_UNKNOWN);

		initialize_dir_tail(EXT4_DIRENT_TAIL(block_entry,
					ext4_sb_get_block_size(sb)));
		ext4_dir_set_checksum(dir,
				(struct ext4_directory_entry_ll *)new_block.data);
	} else {
		ext4_dir_entry_ll_set_entry_length(block_entry, block_size);
	}

	ext4_dir_entry_ll_set_inode(block_entry, 0);

	new_block.dirty = true;
	rc = ext4_block_set(dir->fs->bdev, &new_block);
	if (rc != EOK) {
		ext4_block_set(dir->fs->bdev, &block);
		return rc;
	}

	/* Connect new block to the only entry in index */
	struct ext4_directory_dx_entry *entry = root->entries;
	ext4_dir_dx_entry_set_block(entry, iblock);

	ext4_dir_set_dx_checksum(dir,
			(struct ext4_directory_entry_ll *)block.data);
	block.dirty = true;

	return ext4_block_set(dir->fs->bdev, &block);
}