Files
EMILE/libext2/ext2_utils.c
CheetahPixie f1690f87ce Maintenance change: Update i_dir_acl to i_size_high
The former macro has long since been removed from upstream, causing build failures on modern tools. This was fixed in ext4magic all the way back in 2018, for example.

See here: https://sourceforge.net/p/ext4magic/tickets/10/
2025-01-09 14:58:24 +00:00

336 lines
10 KiB
C

/*
*
* (c) 2008 Laurent Vivier <Laurent@Vivier.EU>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <asm/byteorder.h>
#include "libext2.h"
#include "ext2_utils.h"
void ext2_get_super(device_io_t *device, struct ext2_super_block *super)
{
device->read_sector(device->data, 2, super, sizeof (*super));
super->s_inodes_count = __le32_to_cpu(super->s_inodes_count);
super->s_blocks_count = __le32_to_cpu(super->s_blocks_count);
super->s_r_blocks_count = __le32_to_cpu(super->s_r_blocks_count);
super->s_free_blocks_count = __le32_to_cpu(super->s_free_blocks_count);
super->s_free_inodes_count = __le32_to_cpu(super->s_free_inodes_count);
super->s_first_data_block = __le32_to_cpu(super->s_first_data_block);
super->s_log_block_size = __le32_to_cpu(super->s_log_block_size);
#ifdef CONFIG_E2FSLIBS
super->s_log_cluster_size = __le32_to_cpu(super->s_log_cluster_size);
#else
super->s_log_frag_size = __le32_to_cpu(super->s_log_frag_size);
#endif
super->s_blocks_per_group = __le32_to_cpu(super->s_blocks_per_group);
#ifdef CONFIG_E2FSLIBS
super->s_clusters_per_group = __le32_to_cpu(super->s_clusters_per_group);
#else
super->s_frags_per_group = __le32_to_cpu(super->s_frags_per_group);
#endif
super->s_inodes_per_group = __le32_to_cpu(super->s_inodes_per_group);
super->s_mtime = __le32_to_cpu(super->s_mtime);
super->s_wtime = __le32_to_cpu(super->s_wtime);
super->s_mnt_count = __le16_to_cpu(super->s_mnt_count);
super->s_max_mnt_count = __le16_to_cpu(super->s_max_mnt_count);
super->s_magic = __le16_to_cpu(super->s_magic);
super->s_state = __le16_to_cpu(super->s_state);
super->s_errors = __le16_to_cpu(super->s_errors);
super->s_minor_rev_level = __le16_to_cpu(super->s_minor_rev_level);
super->s_lastcheck = __le32_to_cpu(super->s_lastcheck);
super->s_checkinterval = __le32_to_cpu(super->s_checkinterval);
super->s_creator_os = __le32_to_cpu(super->s_creator_os);
super->s_rev_level = __le32_to_cpu(super->s_rev_level);
super->s_def_resuid = __le16_to_cpu(super->s_def_resuid);
super->s_def_resgid = __le16_to_cpu(super->s_def_resgid);
super->s_first_ino = __le32_to_cpu(super->s_first_ino);
super->s_inode_size = __le16_to_cpu(super->s_inode_size);
super->s_block_group_nr = __le16_to_cpu(super->s_block_group_nr);
super->s_feature_compat = __le32_to_cpu(super->s_feature_compat);
super->s_feature_incompat = __le32_to_cpu(super->s_feature_incompat);
super->s_feature_ro_compat = __le32_to_cpu(super->s_feature_ro_compat);
super->s_algorithm_usage_bitmap =
__le32_to_cpu(super->s_algorithm_usage_bitmap);
super->s_journal_inum = __le32_to_cpu(super->s_journal_inum);
super->s_journal_dev = __le32_to_cpu(super->s_journal_dev);
super->s_last_orphan = __le32_to_cpu(super->s_last_orphan);
super->s_hash_seed[0] = __le32_to_cpu(super->s_hash_seed[0]);
super->s_hash_seed[1] = __le32_to_cpu(super->s_hash_seed[1]);
super->s_hash_seed[2] = __le32_to_cpu(super->s_hash_seed[2]);
super->s_hash_seed[3] = __le32_to_cpu(super->s_hash_seed[3]);
super->s_default_mount_opts =
__le32_to_cpu(super->s_default_mount_opts);
super->s_first_meta_bg = __le32_to_cpu(super->s_first_meta_bg);
}
void ext2_read_block(ext2_VOLUME* volume, unsigned int fsblock)
{
off_t block;
int blocksize;
if (fsblock == volume->current)
return;
volume->current = fsblock;
blocksize = volume->device->get_blocksize(volume->device->data);
block = fsblock * (EXT2_BLOCK_SIZE(volume->super) / blocksize);
volume->device->read_sector(volume->device->data, block,
volume->buffer,
EXT2_BLOCK_SIZE(volume->super));
}
void ext2_get_group_desc(ext2_VOLUME* volume,
int group_id, struct ext2_group_desc *gdp)
{
unsigned int block, offset;
struct ext2_group_desc *le_gdp;
block = 1 + volume->super->s_first_data_block;
block += group_id / EXT2_DESC_PER_BLOCK(volume->super);
ext2_read_block(volume, block);
offset = group_id % EXT2_DESC_PER_BLOCK(volume->super);
offset *= sizeof(*gdp);
le_gdp = (struct ext2_group_desc *)(volume->buffer + offset);
gdp->bg_block_bitmap = __le32_to_cpu(le_gdp->bg_block_bitmap);
gdp->bg_inode_bitmap = __le32_to_cpu(le_gdp->bg_inode_bitmap);
gdp->bg_inode_table = __le32_to_cpu(le_gdp->bg_inode_table);
gdp->bg_free_blocks_count = __le16_to_cpu(le_gdp->bg_free_blocks_count);
gdp->bg_free_inodes_count = __le16_to_cpu(le_gdp->bg_free_inodes_count);
gdp->bg_used_dirs_count = __le16_to_cpu(le_gdp->bg_used_dirs_count);
}
int ext2_get_inode(ext2_VOLUME* volume,
unsigned int ino, struct ext2_inode *inode)
{
struct ext2_group_desc desc;
unsigned int block;
unsigned int group_id;
unsigned int offset;
struct ext2_inode *le_inode;
int i;
ino--;
group_id = ino / EXT2_INODES_PER_GROUP(volume->super);
ext2_get_group_desc(volume, group_id, &desc);
ino %= EXT2_INODES_PER_GROUP(volume->super);
block = desc.bg_inode_table;
block += ino / (EXT2_BLOCK_SIZE(volume->super) /
EXT2_INODE_SIZE(volume->super));
ext2_read_block(volume, block);
offset = ino % (EXT2_BLOCK_SIZE(volume->super) /
EXT2_INODE_SIZE(volume->super));
offset *= EXT2_INODE_SIZE(volume->super);
le_inode = (struct ext2_inode *)(volume->buffer + offset);
inode->i_mode = __le16_to_cpu(le_inode->i_mode);
inode->i_uid = __le16_to_cpu(le_inode->i_uid);
inode->i_size = __le32_to_cpu(le_inode->i_size);
inode->i_atime = __le32_to_cpu(le_inode->i_atime);
inode->i_ctime = __le32_to_cpu(le_inode->i_ctime);
inode->i_mtime = __le32_to_cpu(le_inode->i_mtime);
inode->i_dtime = __le32_to_cpu(le_inode->i_dtime);
inode->i_gid = __le16_to_cpu(le_inode->i_gid);
inode->i_links_count = __le16_to_cpu(le_inode->i_links_count);
inode->i_blocks = __le32_to_cpu(le_inode->i_blocks);
inode->i_flags = __le32_to_cpu(le_inode->i_flags);
if (S_ISLNK(inode->i_mode)) {
memcpy(inode->i_block, le_inode->i_block, EXT2_N_BLOCKS * 4);
} else {
for (i = 0; i < EXT2_N_BLOCKS; i++)
inode->i_block[i] = __le32_to_cpu(le_inode->i_block[i]);
}
inode->i_generation = __le32_to_cpu(le_inode->i_generation);
inode->i_file_acl = __le32_to_cpu(le_inode->i_file_acl);
inode->i_size_high = __le32_to_cpu(le_inode->i_size_high);
inode->i_faddr = __le32_to_cpu(le_inode->i_faddr);
#ifdef CONFIG_E2FSLIBS
inode->osd2.linux2.l_i_blocks_hi =
__le16_to_cpu(le_inode->osd2.linux2.l_i_blocks_hi);
inode->osd2.linux2.l_i_file_acl_high =
__le16_to_cpu(le_inode->osd2.linux2.l_i_file_acl_high);
#else
inode->osd2.linux2.l_i_frag = le_inode->osd2.linux2.l_i_frag;
inode->osd2.linux2.l_i_fsize = le_inode->osd2.linux2.l_i_fsize;
#endif
inode->osd2.linux2.l_i_uid_high =
__le16_to_cpu(le_inode->osd2.linux2.l_i_uid_high);
inode->osd2.linux2.l_i_gid_high =
__le16_to_cpu(le_inode->osd2.linux2.l_i_gid_high);
#ifdef CONFIG_E2FSLIBS
#endif
return 0;
}
unsigned int ext2_get_block_addr(ext2_VOLUME* volume, struct ext2_inode *inode,
unsigned int logical)
{
unsigned int physical;
unsigned int addr_per_block;
/* direct */
if (logical < EXT2_NDIR_BLOCKS) {
physical = inode->i_block[logical];
return physical;
}
/* indirect */
logical -= EXT2_NDIR_BLOCKS;
addr_per_block = EXT2_ADDR_PER_BLOCK (volume->super);
if (logical < addr_per_block) {
ext2_read_block(volume, inode->i_block[EXT2_IND_BLOCK]);
physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical]);
return physical;
}
/* double indirect */
logical -= addr_per_block;
if (logical < addr_per_block * addr_per_block) {
ext2_read_block(volume, inode->i_block[EXT2_DIND_BLOCK]);
physical = __le32_to_cpu(((unsigned int *)volume->buffer)
[logical / addr_per_block]);
ext2_read_block(volume, physical);
physical = __le32_to_cpu(((unsigned int *)volume->buffer)
[logical % addr_per_block]);
return physical;
}
/* triple indirect */
logical -= addr_per_block * addr_per_block;
ext2_read_block(volume, inode->i_block[EXT2_DIND_BLOCK]);
physical = __le32_to_cpu(((unsigned int *)volume->buffer)
[logical / (addr_per_block * addr_per_block)]);
ext2_read_block(volume, physical);
logical = logical % (addr_per_block * addr_per_block);
physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical / addr_per_block]);
ext2_read_block(volume, physical);
physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical % addr_per_block]);
return physical;
}
int ext2_read_data(ext2_VOLUME* volume, struct ext2_inode *inode,
off_t offset, char *buffer, size_t length)
{
unsigned int logical, physical;
int blocksize = EXT2_BLOCK_SIZE(volume->super);
int shift;
size_t read;
if (offset >= inode->i_size)
return -1;
if (offset + length >= inode->i_size)
length = inode->i_size - offset;
read = 0;
logical = offset / blocksize;
shift = offset % blocksize;
if (shift) {
physical = ext2_get_block_addr(volume, inode, logical);
ext2_read_block(volume, physical);
if (length < blocksize - shift) {
memcpy(buffer, volume->buffer + shift, length);
return length;
}
read += blocksize - shift;
memcpy(buffer, volume->buffer + shift, read);
buffer += read;
length -= read;
logical++;
}
while (length) {
physical = ext2_get_block_addr(volume, inode, logical);
ext2_read_block(volume, physical);
if (length < blocksize) {
memcpy(buffer, volume->buffer, length);
read += length;
return read;
}
memcpy(buffer, volume->buffer, blocksize);
buffer += blocksize;
length -= blocksize;
read += blocksize;
logical++;
}
return read;
}
off_t ext2_dir_entry(ext2_VOLUME *volume, struct ext2_inode *inode,
off_t index, struct ext2_dir_entry_2 *entry)
{
int ret;
ret = ext2_read_data(volume, inode, index,
(char*)entry, sizeof(*entry));
if (ret == -1)
return -1;
entry->inode = __le32_to_cpu(entry->inode);
entry->rec_len = __le16_to_cpu(entry->rec_len);
return index + entry->rec_len;
}
unsigned int ext2_seek_name(ext2_VOLUME *volume, char *name)
{
struct ext2_inode inode;
int ret;
unsigned int ino;
off_t index;
struct ext2_dir_entry_2 entry;
ino = EXT2_ROOT_INO;
while(1) {
while (*name == '/')
name++;
if (!*name)
break;
ret = ext2_get_inode(volume, ino, &inode);
if (ret == -1)
return 0;
index = 0;
while (1) {
index = ext2_dir_entry(volume, &inode, index, &entry);
if (index == -1)
return 0;
ret = strncmp(name, entry.name, entry.name_len);
if (ret == 0 &&
(name[entry.name_len] == 0 ||
name[entry.name_len] == '/')) {
ino = entry.inode;
break;
}
}
name += entry.name_len;
}
return ino;
}