HelenOS sources
This source file includes following definitions.
- ext4_superblock_get_inodes_count
- ext4_superblock_set_inodes_count
- ext4_superblock_get_blocks_count
- ext4_superblock_set_blocks_count
- ext4_superblock_get_reserved_blocks_count
- ext4_superblock_set_reserved_blocks_count
- ext4_superblock_get_free_blocks_count
- ext4_superblock_set_free_blocks_count
- ext4_superblock_get_free_inodes_count
- ext4_superblock_set_free_inodes_count
- ext4_superblock_get_first_data_block
- ext4_superblock_set_first_data_block
- ext4_superblock_get_log_block_size
- ext4_superblock_set_log_block_size
- ext4_superblock_get_block_size
- ext4_superblock_set_block_size
- ext4_superblock_get_log_frag_size
- ext4_superblock_set_log_frag_size
- ext4_superblock_get_frag_size
- ext4_superblock_set_frag_size
- ext4_superblock_get_blocks_per_group
- ext4_superblock_set_blocks_per_group
- ext4_superblock_get_frags_per_group
- ext4_superblock_set_frags_per_group
- ext4_superblock_get_inodes_per_group
- ext4_superblock_set_inodes_per_group
- ext4_superblock_get_mount_time
- ext4_superblock_set_mount_time
- ext4_superblock_get_write_time
- ext4_superblock_set_write_time
- ext4_superblock_get_mount_count
- ext4_superblock_set_mount_count
- ext4_superblock_get_max_mount_count
- ext4_superblock_set_max_mount_count
- ext4_superblock_get_magic
- ext4_superblock_set_magic
- ext4_superblock_get_state
- ext4_superblock_set_state
- ext4_superblock_get_errors
- ext4_superblock_set_errors
- ext4_superblock_get_minor_rev_level
- ext4_superblock_set_minor_rev_level
- ext4_superblock_get_last_check_time
- ext4_superblock_set_last_check_time
- ext4_superblock_get_check_interval
- ext4_superblock_set_check_interval
- ext4_superblock_get_creator_os
- ext4_superblock_set_creator_os
- ext4_superblock_get_rev_level
- ext4_superblock_set_rev_level
- ext4_superblock_get_def_resuid
- ext4_superblock_set_def_resuid
- ext4_superblock_get_def_resgid
- ext4_superblock_set_def_resgid
- ext4_superblock_get_first_inode
- ext4_superblock_set_first_inode
- ext4_superblock_get_inode_size
- ext4_superblock_set_inode_size
- ext4_superblock_get_block_group_index
- ext4_superblock_set_block_group_index
- ext4_superblock_get_features_compatible
- ext4_superblock_set_features_compatible
- ext4_superblock_get_features_incompatible
- ext4_superblock_set_features_incompatible
- ext4_superblock_get_features_read_only
- ext4_superblock_set_features_read_only
- ext4_superblock_get_uuid
- ext4_superblock_set_uuid
- ext4_superblock_get_volume_name
- ext4_superblock_set_volume_name
- ext4_superblock_get_last_mounted
- ext4_superblock_set_last_mounted
- ext4_superblock_get_last_orphan
- ext4_superblock_set_last_orphan
- ext4_superblock_get_hash_seed
- ext4_superblock_set_hash_seed
- ext4_superblock_get_default_hash_version
- ext4_superblock_set_default_hash_version
- ext4_superblock_get_desc_size
- ext4_superblock_set_desc_size
- ext4_superblock_get_flags
- ext4_superblock_set_flags
- ext4_superblock_has_flag
- ext4_superblock_has_feature_compatible
- ext4_superblock_has_feature_incompatible
- ext4_superblock_has_feature_read_only
- ext4_superblock_read_direct
- ext4_superblock_write_direct
- ext4_superblock_release
- ext4_superblock_check_sanity
- ext4_superblock_get_block_group_count
- ext4_superblock_get_blocks_in_group
- ext4_superblock_get_inodes_in_group
- ext4_superblock_get_backup_groups_sparse2
- ext4_superblock_set_backup_groups_sparse2
- ext4_superblock_get_reserved_gdt_blocks
- ext4_superblock_set_reserved_gdt_blocks
- ext4_superblock_get_flex_group_size
- is_power_of
- ext4_superblock_get_group_backup_blocks
- ext4_superblock_create
#include <align.h>
#include <block.h>
#include <byteorder.h>
#include <errno.h>
#include <mem.h>
#include <stdlib.h>
#include <str.h>
#include <time.h>
#include "ext4/cfg.h"
#include "ext4/superblock.h"
uint32_t ext4_superblock_get_inodes_count(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->inodes_count);
}
void ext4_superblock_set_inodes_count(ext4_superblock_t *sb, uint32_t count)
{
sb->inodes_count = host2uint32_t_le(count);
}
uint64_t ext4_superblock_get_blocks_count(ext4_superblock_t *sb)
{
return ((uint64_t) uint32_t_le2host(sb->blocks_count_hi) << 32) |
uint32_t_le2host(sb->blocks_count_lo);
}
void ext4_superblock_set_blocks_count(ext4_superblock_t *sb, uint64_t count)
{
sb->blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
sb->blocks_count_hi = host2uint32_t_le(count >> 32);
}
uint64_t ext4_superblock_get_reserved_blocks_count(ext4_superblock_t *sb)
{
return ((uint64_t)
uint32_t_le2host(sb->reserved_blocks_count_hi) << 32) |
uint32_t_le2host(sb->reserved_blocks_count_lo);
}
void ext4_superblock_set_reserved_blocks_count(ext4_superblock_t *sb,
uint64_t count)
{
sb->reserved_blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
sb->reserved_blocks_count_hi = host2uint32_t_le(count >> 32);
}
uint64_t ext4_superblock_get_free_blocks_count(ext4_superblock_t *sb)
{
return ((uint64_t)
uint32_t_le2host(sb->free_blocks_count_hi) << 32) |
uint32_t_le2host(sb->free_blocks_count_lo);
}
void ext4_superblock_set_free_blocks_count(ext4_superblock_t *sb,
uint64_t count)
{
sb->free_blocks_count_lo = host2uint32_t_le((count << 32) >> 32);
sb->free_blocks_count_hi = host2uint32_t_le(count >> 32);
}
uint32_t ext4_superblock_get_free_inodes_count(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->free_inodes_count);
}
void ext4_superblock_set_free_inodes_count(ext4_superblock_t *sb,
uint32_t count)
{
sb->free_inodes_count = host2uint32_t_le(count);
}
uint32_t ext4_superblock_get_first_data_block(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->first_data_block);
}
void ext4_superblock_set_first_data_block(ext4_superblock_t *sb,
uint32_t first)
{
sb->first_data_block = host2uint32_t_le(first);
}
uint32_t ext4_superblock_get_log_block_size(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->log_block_size);
}
void ext4_superblock_set_log_block_size(ext4_superblock_t *sb,
uint32_t log_size)
{
sb->log_block_size = host2uint32_t_le(log_size);
}
uint32_t ext4_superblock_get_block_size(ext4_superblock_t *sb)
{
return 1024 << ext4_superblock_get_log_block_size(sb);
}
void ext4_superblock_set_block_size(ext4_superblock_t *sb, uint32_t size)
{
uint32_t log = 0;
uint32_t tmp = size / EXT4_MIN_BLOCK_SIZE;
tmp >>= 1;
while (tmp) {
log++;
tmp >>= 1;
}
ext4_superblock_set_log_block_size(sb, log);
}
uint32_t ext4_superblock_get_log_frag_size(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->log_frag_size);
}
void ext4_superblock_set_log_frag_size(ext4_superblock_t *sb,
uint32_t frag_size)
{
sb->log_frag_size = host2uint32_t_le(frag_size);
}
uint32_t ext4_superblock_get_frag_size(ext4_superblock_t *sb)
{
return 1024 << ext4_superblock_get_log_frag_size(sb);
}
void ext4_superblock_set_frag_size(ext4_superblock_t *sb, uint32_t size)
{
uint32_t log = 0;
uint32_t tmp = size / EXT4_MIN_BLOCK_SIZE;
tmp >>= 1;
while (tmp) {
log++;
tmp >>= 1;
}
ext4_superblock_set_log_frag_size(sb, log);
}
uint32_t ext4_superblock_get_blocks_per_group(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->blocks_per_group);
}
void ext4_superblock_set_blocks_per_group(ext4_superblock_t *sb,
uint32_t blocks)
{
sb->blocks_per_group = host2uint32_t_le(blocks);
}
uint32_t ext4_superblock_get_frags_per_group(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->frags_per_group);
}
void ext4_superblock_set_frags_per_group(ext4_superblock_t *sb, uint32_t frags)
{
sb->frags_per_group = host2uint32_t_le(frags);
}
uint32_t ext4_superblock_get_inodes_per_group(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->inodes_per_group);
}
void ext4_superblock_set_inodes_per_group(ext4_superblock_t *sb,
uint32_t inodes)
{
sb->inodes_per_group = host2uint32_t_le(inodes);
}
uint32_t ext4_superblock_get_mount_time(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->mount_time);
}
void ext4_superblock_set_mount_time(ext4_superblock_t *sb, uint32_t time)
{
sb->mount_time = host2uint32_t_le(time);
}
uint32_t ext4_superblock_get_write_time(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->write_time);
}
void ext4_superblock_set_write_time(ext4_superblock_t *sb, uint32_t time)
{
sb->write_time = host2uint32_t_le(time);
}
uint16_t ext4_superblock_get_mount_count(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->mount_count);
}
void ext4_superblock_set_mount_count(ext4_superblock_t *sb, uint16_t count)
{
sb->mount_count = host2uint16_t_le(count);
}
uint16_t ext4_superblock_get_max_mount_count(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->max_mount_count);
}
void ext4_superblock_set_max_mount_count(ext4_superblock_t *sb, uint16_t count)
{
sb->max_mount_count = host2uint16_t_le(count);
}
uint16_t ext4_superblock_get_magic(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->magic);
}
void ext4_superblock_set_magic(ext4_superblock_t *sb, uint16_t magic)
{
sb->magic = host2uint16_t_le(magic);
}
uint16_t ext4_superblock_get_state(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->state);
}
void ext4_superblock_set_state(ext4_superblock_t *sb, uint16_t state)
{
sb->state = host2uint16_t_le(state);
}
uint16_t ext4_superblock_get_errors(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->errors);
}
void ext4_superblock_set_errors(ext4_superblock_t *sb, uint16_t errors)
{
sb->errors = host2uint16_t_le(errors);
}
uint16_t ext4_superblock_get_minor_rev_level(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->minor_rev_level);
}
void ext4_superblock_set_minor_rev_level(ext4_superblock_t *sb, uint16_t level)
{
sb->minor_rev_level = host2uint16_t_le(level);
}
uint32_t ext4_superblock_get_last_check_time(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->last_check_time);
}
void ext4_superblock_set_last_check_time(ext4_superblock_t *sb, uint32_t time)
{
sb->last_check_time = host2uint32_t_le(time);
}
uint32_t ext4_superblock_get_check_interval(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->check_interval);
}
void ext4_superblock_set_check_interval(ext4_superblock_t *sb, uint32_t interval)
{
sb->check_interval = host2uint32_t_le(interval);
}
uint32_t ext4_superblock_get_creator_os(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->creator_os);
}
void ext4_superblock_set_creator_os(ext4_superblock_t *sb, uint32_t os)
{
sb->creator_os = host2uint32_t_le(os);
}
uint32_t ext4_superblock_get_rev_level(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->rev_level);
}
void ext4_superblock_set_rev_level(ext4_superblock_t *sb, uint32_t level)
{
sb->rev_level = host2uint32_t_le(level);
}
uint16_t ext4_superblock_get_def_resuid(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->def_resuid);
}
void ext4_superblock_set_def_resuid(ext4_superblock_t *sb, uint16_t uid)
{
sb->def_resuid = host2uint16_t_le(uid);
}
uint16_t ext4_superblock_get_def_resgid(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->def_resgid);
}
void ext4_superblock_set_def_resgid(ext4_superblock_t *sb, uint16_t gid)
{
sb->def_resgid = host2uint16_t_le(gid);
}
uint32_t ext4_superblock_get_first_inode(ext4_superblock_t *sb)
{
if (ext4_superblock_get_rev_level(sb) == 0)
return EXT4_REV0_FIRST_INO;
return uint32_t_le2host(sb->first_inode);
}
void ext4_superblock_set_first_inode(ext4_superblock_t *sb,
uint32_t first_inode)
{
sb->first_inode = host2uint32_t_le(first_inode);
}
uint16_t ext4_superblock_get_inode_size(ext4_superblock_t *sb)
{
if (ext4_superblock_get_rev_level(sb) == 0)
return EXT4_REV0_INODE_SIZE;
return uint16_t_le2host(sb->inode_size);
}
void ext4_superblock_set_inode_size(ext4_superblock_t *sb, uint16_t size)
{
sb->inode_size = host2uint16_t_le(size);
}
uint16_t ext4_superblock_get_block_group_index(ext4_superblock_t *sb)
{
return uint16_t_le2host(sb->block_group_index);
}
void ext4_superblock_set_block_group_index(ext4_superblock_t *sb, uint16_t bgid)
{
sb->block_group_index = host2uint16_t_le(bgid);
}
uint32_t ext4_superblock_get_features_compatible(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->features_compatible);
}
void ext4_superblock_set_features_compatible(ext4_superblock_t *sb,
uint32_t features)
{
sb->features_compatible = host2uint32_t_le(features);
}
uint32_t ext4_superblock_get_features_incompatible(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->features_incompatible);
}
void ext4_superblock_set_features_incompatible(ext4_superblock_t *sb,
uint32_t features)
{
sb->features_incompatible = host2uint32_t_le(features);
}
uint32_t ext4_superblock_get_features_read_only(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->features_read_only);
}
void ext4_superblock_set_features_read_only(ext4_superblock_t *sb,
uint32_t features)
{
sb->features_read_only = host2uint32_t_le(features);
}
void ext4_superblock_get_uuid(ext4_superblock_t *sb, uuid_t *uuid)
{
uuid_decode(sb->uuid, uuid);
}
void ext4_superblock_set_uuid(ext4_superblock_t *sb, uuid_t *uuid)
{
uuid_encode(uuid, sb->uuid);
}
errno_t ext4_superblock_get_volume_name(ext4_superblock_t *sb, char *buf,
size_t bufsz)
{
size_t i;
size_t wi;
char32_t ch;
errno_t rc;
i = 0;
wi = 0;
while (sb->volume_name[i] != '\0' && i < sizeof(sb->volume_name)) {
ch = (char32_t)(uint8_t)sb->volume_name[i];
rc = chr_encode(ch, buf, &wi, bufsz - 1);
if (rc != EOK)
return rc;
i++;
}
buf[wi] = '\0';
return EOK;
}
errno_t ext4_superblock_set_volume_name(ext4_superblock_t *sb, const char *name)
{
size_t off;
char32_t ch;
size_t wi;
off = 0;
wi = 0;
while (wi < sizeof(sb->volume_name)) {
ch = str_decode(name, &off, STR_NO_LIMIT);
if (ch == 0)
break;
if (ch > 255)
return EINVAL;
sb->volume_name[wi++] = ch;
}
while (wi < sizeof(sb->volume_name))
sb->volume_name[wi++] = '\0';
return EOK;
}
const char *ext4_superblock_get_last_mounted(ext4_superblock_t *sb)
{
return sb->last_mounted;
}
void ext4_superblock_set_last_mounted(ext4_superblock_t *sb, const char *last)
{
memcpy(sb->last_mounted, last, sizeof(sb->last_mounted));
}
uint32_t ext4_superblock_get_last_orphan(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->last_orphan);
}
void ext4_superblock_set_last_orphan(ext4_superblock_t *sb,
uint32_t last_orphan)
{
sb->last_orphan = host2uint32_t_le(last_orphan);
}
const uint32_t *ext4_superblock_get_hash_seed(ext4_superblock_t *sb)
{
return sb->hash_seed;
}
void ext4_superblock_set_hash_seed(ext4_superblock_t *sb, const uint32_t *seed)
{
memcpy(sb->hash_seed, seed, sizeof(sb->hash_seed));
}
uint8_t ext4_superblock_get_default_hash_version(ext4_superblock_t *sb)
{
return sb->default_hash_version;
}
void ext4_superblock_set_default_hash_version(ext4_superblock_t *sb,
uint8_t version)
{
sb->default_hash_version = version;
}
uint16_t ext4_superblock_get_desc_size(ext4_superblock_t *sb)
{
uint16_t size = uint16_t_le2host(sb->desc_size);
if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
size = EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE;
return size;
}
void ext4_superblock_set_desc_size(ext4_superblock_t *sb, uint16_t size)
{
if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
sb->desc_size =
host2uint16_t_le(EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE);
sb->desc_size = host2uint16_t_le(size);
}
uint32_t ext4_superblock_get_flags(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->flags);
}
void ext4_superblock_set_flags(ext4_superblock_t *sb, uint32_t flags)
{
sb->flags = host2uint32_t_le(flags);
}
bool ext4_superblock_has_flag(ext4_superblock_t *sb, uint32_t flag)
{
if (ext4_superblock_get_flags(sb) & flag)
return true;
return false;
}
bool ext4_superblock_has_feature_compatible(ext4_superblock_t *sb,
uint32_t feature)
{
if (ext4_superblock_get_features_compatible(sb) & feature)
return true;
return false;
}
bool ext4_superblock_has_feature_incompatible(ext4_superblock_t *sb,
uint32_t feature)
{
if (ext4_superblock_get_features_incompatible(sb) & feature)
return true;
return false;
}
bool ext4_superblock_has_feature_read_only(ext4_superblock_t *sb,
uint32_t feature)
{
if (ext4_superblock_get_features_read_only(sb) & feature)
return true;
return false;
}
errno_t ext4_superblock_read_direct(service_id_t service_id, ext4_superblock_t **sb)
{
void *data = malloc(EXT4_SUPERBLOCK_SIZE);
if (data == NULL)
return ENOMEM;
errno_t rc = block_read_bytes_direct(service_id, EXT4_SUPERBLOCK_OFFSET,
EXT4_SUPERBLOCK_SIZE, data);
if (rc != EOK) {
free(data);
return rc;
}
(*sb) = data;
return EOK;
}
errno_t ext4_superblock_write_direct(service_id_t service_id, ext4_superblock_t *sb)
{
size_t phys_block_size;
errno_t rc = block_get_bsize(service_id, &phys_block_size);
if (rc != EOK)
return rc;
uint64_t first_block = EXT4_SUPERBLOCK_OFFSET / phys_block_size;
size_t block_count = EXT4_SUPERBLOCK_SIZE / phys_block_size;
if (EXT4_SUPERBLOCK_SIZE % phys_block_size)
block_count++;
return block_write_direct(service_id, first_block, block_count, sb);
}
void ext4_superblock_release(ext4_superblock_t *sb)
{
free(sb);
}
errno_t ext4_superblock_check_sanity(ext4_superblock_t *sb)
{
if (ext4_superblock_get_magic(sb) != EXT4_SUPERBLOCK_MAGIC)
return ENOTSUP;
if (ext4_superblock_get_inodes_count(sb) == 0)
return ENOTSUP;
if (ext4_superblock_get_blocks_count(sb) == 0)
return ENOTSUP;
if (ext4_superblock_get_blocks_per_group(sb) == 0)
return ENOTSUP;
if (ext4_superblock_get_inodes_per_group(sb) == 0)
return ENOTSUP;
if (ext4_superblock_get_inode_size(sb) < 128)
return ENOTSUP;
if (ext4_superblock_get_first_inode(sb) < 11)
return ENOTSUP;
if (ext4_superblock_get_desc_size(sb) <
EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
return ENOTSUP;
if (ext4_superblock_get_desc_size(sb) >
EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE)
return ENOTSUP;
return EOK;
}
uint32_t ext4_superblock_get_block_group_count(ext4_superblock_t *sb)
{
uint64_t blocks_count = ext4_superblock_get_blocks_count(sb) - 1;
uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb);
uint32_t block_groups_count = blocks_count / blocks_per_group;
if (blocks_count % blocks_per_group)
block_groups_count++;
return block_groups_count;
}
uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *sb, uint32_t bgid)
{
uint32_t block_group_count =
ext4_superblock_get_block_group_count(sb);
uint32_t blocks_per_group =
ext4_superblock_get_blocks_per_group(sb);
uint64_t total_blocks =
ext4_superblock_get_blocks_count(sb);
uint32_t first_block =
ext4_superblock_get_first_data_block(sb);
if (bgid < block_group_count - 1)
return blocks_per_group;
else
return (total_blocks - ((block_group_count - 1) * blocks_per_group)) - first_block;
}
uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *sb, uint32_t bgid)
{
uint32_t block_group_count =
ext4_superblock_get_block_group_count(sb);
uint32_t inodes_per_group =
ext4_superblock_get_inodes_per_group(sb);
uint32_t total_inodes =
ext4_superblock_get_inodes_count(sb);
if (bgid < block_group_count - 1)
return inodes_per_group;
else
return (total_inodes - ((block_group_count - 1) * inodes_per_group));
}
void ext4_superblock_get_backup_groups_sparse2(ext4_superblock_t *sb,
uint32_t *g1, uint32_t *g2)
{
*g1 = uint32_t_le2host(sb->backup_bgs[0]);
*g2 = uint32_t_le2host(sb->backup_bgs[1]);
}
void ext4_superblock_set_backup_groups_sparse2(ext4_superblock_t *sb,
uint32_t g1, uint32_t g2)
{
sb->backup_bgs[0] = host2uint32_t_le(g1);
sb->backup_bgs[1] = host2uint32_t_le(g2);
}
uint32_t ext4_superblock_get_reserved_gdt_blocks(ext4_superblock_t *sb)
{
return uint32_t_le2host(sb->reserved_gdt_blocks);
}
void ext4_superblock_set_reserved_gdt_blocks(ext4_superblock_t *sb,
uint32_t n)
{
sb->reserved_gdt_blocks = host2uint32_t_le(n);
}
uint32_t ext4_superblock_get_flex_group_size(ext4_superblock_t *sb)
{
return 2 << sb->log_groups_per_flex;
}
static bool is_power_of(uint32_t n, unsigned p)
{
if (p == 1 && n != p)
return false;
while (n != p) {
if (n < p)
return false;
else if ((n % p) != 0)
return false;
n /= p;
}
return true;
}
uint32_t ext4_superblock_get_group_backup_blocks(ext4_superblock_t *sb,
uint32_t idx)
{
uint32_t r = 0;
bool has_backups = false;
if (idx <= 1)
has_backups = true;
else {
if (ext4_superblock_has_feature_compatible(sb,
EXT4_FEATURE_COMPAT_SPARSE_SUPER2)) {
uint32_t g1, g2;
ext4_superblock_get_backup_groups_sparse2(sb,
&g1, &g2);
if (idx == g1 || idx == g2)
has_backups = true;
} else if (!ext4_superblock_has_feature_read_only(sb,
EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
has_backups = true;
} else {
if ((idx & 1) && (is_power_of(idx, 3) ||
is_power_of(idx, 5) || is_power_of(idx, 7)))
has_backups = true;
}
}
if (has_backups) {
uint32_t bg_count;
uint32_t bg_desc_sz;
uint32_t gdt_table;
uint32_t block_size = ext4_superblock_get_block_size(sb);
r++;
bg_count = ext4_superblock_get_block_group_count(sb);
bg_desc_sz = ext4_superblock_get_desc_size(sb);
gdt_table = ROUND_UP(bg_count * bg_desc_sz, block_size) /
block_size;
r += gdt_table;
r += ext4_superblock_get_reserved_gdt_blocks(sb);
}
return r;
}
errno_t ext4_superblock_create(size_t dev_bsize, uint64_t dev_bcnt,
ext4_cfg_t *cfg, ext4_superblock_t **rsb)
{
ext4_superblock_t *sb;
uuid_t uuid;
uint32_t cur_ts;
uint64_t first_block = 0;
uint64_t fs_blocks;
uint32_t blocks_count;
uint32_t free_blocks;
uint32_t inodes_count;
uint64_t blocks_group;
uint64_t inodes_group;
uint32_t inodes_block;
uint32_t inode_table_blocks;
uint32_t res_blocks;
uint32_t ngroups;
uint32_t idx;
size_t fs_bsize;
size_t fs_bsize_log;
errno_t rc;
struct timespec ts;
sb = calloc(1, sizeof(ext4_superblock_t));
if (sb == NULL)
return ENOMEM;
rc = uuid_generate(&uuid);
if (rc != EOK)
goto error;
getrealtime(&ts);
cur_ts = ts.tv_sec;
fs_bsize = cfg->bsize;
switch (fs_bsize) {
case 1024:
first_block = 1;
fs_bsize_log = 0;
blocks_group = 8192;
break;
case 2048:
fs_bsize_log = 1;
blocks_group = 8192 * 2;
break;
case 4096:
fs_bsize_log = 2;
blocks_group = 8192 * 4;
break;
default:
return ENOTSUP;
}
if (fs_bsize % dev_bsize == 0) {
fs_blocks = dev_bcnt / (fs_bsize / dev_bsize);
} else {
fs_blocks = dev_bcnt * (dev_bsize / fs_bsize);
}
inodes_block = fs_bsize / EXT4_REV0_INODE_SIZE;
inodes_group = min((fs_blocks - first_block) / 8,
blocks_group / 4);
if (inodes_group < 16)
inodes_group = 16;
if (inodes_group % inodes_block != 0)
inodes_group += inodes_block - inodes_group % inodes_block;
inode_table_blocks = inodes_group / inodes_block;
ngroups = ((fs_blocks - first_block) + blocks_group - 1) / blocks_group;
blocks_count = fs_blocks - first_block;
inodes_count = ngroups * inodes_group;
res_blocks = (blocks_count + 19) / 20;
free_blocks = blocks_count;
ext4_superblock_set_magic(sb, EXT4_SUPERBLOCK_MAGIC);
ext4_superblock_set_inodes_count(sb, inodes_count);
ext4_superblock_set_blocks_count(sb, fs_blocks);
ext4_superblock_set_reserved_blocks_count(sb, res_blocks);
ext4_superblock_set_free_blocks_count(sb, free_blocks);
ext4_superblock_set_free_inodes_count(sb, inodes_count);
ext4_superblock_set_first_data_block(sb, first_block);
ext4_superblock_set_log_block_size(sb, fs_bsize_log);
ext4_superblock_set_log_frag_size(sb, fs_bsize_log);
ext4_superblock_set_blocks_per_group(sb, blocks_group);
ext4_superblock_set_frags_per_group(sb, blocks_group);
ext4_superblock_set_inodes_per_group(sb, inodes_group);
ext4_superblock_set_mount_time(sb, 0);
ext4_superblock_set_write_time(sb, cur_ts);
ext4_superblock_set_mount_count(sb, 0);
ext4_superblock_set_max_mount_count(sb, (uint16_t)-1);
ext4_superblock_set_state(sb, EXT4_SUPERBLOCK_STATE_VALID_FS);
ext4_superblock_set_errors(sb, EXT4_SUPERBLOCK_ERRORS_CONTINUE);
ext4_superblock_set_minor_rev_level(sb, 0);
ext4_superblock_set_last_check_time(sb, cur_ts);
ext4_superblock_set_check_interval(sb, 0);
ext4_superblock_set_creator_os(sb, EXT4_SUPERBLOCK_OS_LINUX);
if (cfg->version >= extver_ext2)
ext4_superblock_set_rev_level(sb, EXT4_DYNAMIC_REV);
else
ext4_superblock_set_rev_level(sb, EXT4_GOOD_OLD_REV);
ext4_superblock_set_def_resuid(sb, 0);
ext4_superblock_set_def_resgid(sb, 0);
if (cfg->version >= extver_ext2) {
ext4_superblock_set_first_inode(sb, EXT4_REV0_FIRST_INO);
ext4_superblock_set_inode_size(sb, EXT4_REV0_INODE_SIZE);
ext4_superblock_set_block_group_index(sb, 0);
ext4_superblock_set_features_compatible(sb, 0);
ext4_superblock_set_features_incompatible(sb, 0);
ext4_superblock_set_features_read_only(sb, 0);
ext4_superblock_set_uuid(sb, &uuid);
rc = ext4_superblock_set_volume_name(sb, cfg->volume_name);
if (rc != EOK)
goto error;
ext4_superblock_set_last_mounted(sb,
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
sb->algorithm_usage_bitmap = 0;
}
#if 0
ext4_superblock_set_desc_size(sb, EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE);
#endif
free_blocks = blocks_count;
for (idx = 0; idx < ngroups; idx++) {
free_blocks -= ext4_superblock_get_group_backup_blocks(sb, idx);
free_blocks -= 2;
free_blocks -= inode_table_blocks;
}
ext4_superblock_set_free_blocks_count(sb, free_blocks);
*rsb = sb;
return EOK;
error:
free(sb);
return rc;
}
HelenOS homepage, sources at GitHub