#include "ext4_config.h"
#include "ext4_types.h"
-#include "ext4_fs.h"
+#include "ext4_misc.h"
#include "ext4_errno.h"
+#include "ext4_debug.h"
+
+#include "ext4_trans.h"
+#include "ext4_fs.h"
#include "ext4_blockdev.h"
#include "ext4_super.h"
#include "ext4_crc32.h"
-#include "ext4_debug.h"
#include "ext4_block_group.h"
#include "ext4_balloc.h"
#include "ext4_bitmap.h"
#include <string.h>
-int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
+int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev,
+ bool read_only)
{
int r, i;
uint16_t tmp;
uint32_t bsize;
- bool read_only = false;
ext4_assert(fs && bdev);
fs->bdev = bdev;
+ fs->read_only = read_only;
+
r = ext4_sb_read(fs->bdev, &fs->sb);
if (r != EOK)
return r;
return r;
if (read_only)
- return ENOTSUP;
+ fs->read_only = read_only;
/* Compute limits for indirect block levels */
uint32_t blocks_id = bsize / sizeof(uint32_t);
"last umount error: superblock fs_error flag\n");
- /* Mark system as mounted */
- ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
- r = ext4_sb_write(fs->bdev, &fs->sb);
- if (r != EOK)
- return r;
+ if (!fs->read_only) {
+ /* Mark system as mounted */
+ ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
+ r = ext4_sb_write(fs->bdev, &fs->sb);
+ if (r != EOK)
+ return r;
- /*Update mount count*/
- ext4_set16(&fs->sb, mount_count, ext4_get16(&fs->sb, mount_count) + 1);
+ /*Update mount count*/
+ ext4_set16(&fs->sb, mount_count, ext4_get16(&fs->sb, mount_count) + 1);
+ }
return r;
}
/*Set superblock state*/
ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_VALID_FS);
- return ext4_sb_write(fs->bdev, &fs->sb);
+ if (!fs->read_only)
+ return ext4_sb_write(fs->bdev, &fs->sb);
+
+ return EOK;
}
static void ext4_fs_debug_features_inc(uint32_t features_incompatible)
struct ext4_bgroup *bg = bg_ref->block_group;
int rc;
- uint32_t i, bit, bit_max;
+ uint32_t bit, bit_max;
uint32_t group_blocks;
uint16_t inode_size = ext4_get16(sb, inode_size);
uint32_t block_size = ext4_sb_get_block_size(sb);
uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+ ext4_fsblk_t i;
ext4_fsblk_t bmp_blk = ext4_bg_get_block_bitmap(bg, sb);
ext4_fsblk_t bmp_inode = ext4_bg_get_inode_bitmap(bg, sb);
ext4_fsblk_t inode_table = ext4_bg_get_inode_table_first_block(bg, sb);
return EXT4_INODE_MODE_FILE;
case EXT4_DE_SYMLINK:
return EXT4_INODE_MODE_SOFTLINK;
- default:
- /* FIXME: right now we only support 3 file type. */
- ext4_assert(0);
+ case EXT4_DE_CHRDEV:
+ return EXT4_INODE_MODE_CHARDEV;
+ case EXT4_DE_BLKDEV:
+ return EXT4_INODE_MODE_BLOCKDEV;
+ case EXT4_DE_FIFO:
+ return EXT4_INODE_MODE_FIFO;
+ case EXT4_DE_SOCK:
+ return EXT4_INODE_MODE_SOCKET;
}
- return 0;
+ /* FIXME: unsupported filetype */
+ return EXT4_INODE_MODE_FILE;
}
int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
{
/* Check if newly allocated i-node will be a directory */
bool is_dir;
+ uint32_t type;
uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
is_dir = (filetype == EXT4_DE_DIR);
/* Initialize i-node */
struct ext4_inode *inode = inode_ref->inode;
+ memset(inode, 0, inode_size);
+
uint32_t mode;
if (is_dir) {
/*
mode = 0777;
mode |= EXT4_INODE_MODE_DIRECTORY;
+ } else if (filetype == EXT4_DE_SYMLINK) {
+ /*
+ * Default symbolic link permissions to be compatible with other systems
+ * 0777 (octal) == rwxrwxrwx
+ */
+
+ mode = 0777;
+ mode |= EXT4_INODE_MODE_SOFTLINK;
} else {
/*
* Default file permissions to be compatible with other systems
if (inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
uint16_t off = offsetof(struct ext4_inode, extra_isize);
uint16_t size = sizeof(struct ext4_inode) - off;
- ext4_inode_set_extra_isize(inode, size);
+ ext4_inode_set_extra_isize(&fs->sb, inode, size);
}
- /* Reset blocks array. For symbolic link inode, just
+ /* Reset blocks array. For inode which is not directory or file, just
* fill in blocks with 0 */
- if (ext4_inode_is_type(&fs->sb, inode, EXT4_INODE_MODE_SOFTLINK)) {
+ type = ext4_inode_type(&fs->sb, inode_ref->inode);
+ if (type == EXT4_INODE_MODE_CHARDEV ||
+ type == EXT4_INODE_MODE_BLOCKDEV ||
+ type == EXT4_INODE_MODE_SOCKET ||
+ type == EXT4_INODE_MODE_SOFTLINK) {
for (int i = 0; i < EXT4_INODE_BLOCKS; i++)
inode->blocks[i] = 0;
* @return Error code
*/
static int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
- uint32_t iblock)
+ ext4_lblk_t iblock)
{
ext4_fsblk_t fblock;
/* Compute offsets for the topmost level */
uint32_t block_offset_in_level =
- iblock - fs->inode_block_limits[level - 1];
+ (uint32_t)(iblock - fs->inode_block_limits[level - 1]);
ext4_fsblk_t current_block =
ext4_inode_get_indirect_block(inode, level - 1);
uint32_t offset_in_block =
- block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+ (uint32_t)(block_offset_in_level / fs->inode_blocks_per_level[level - 1]);
/*
* Navigate through other levels, until we find the block number
/* Visit the next level */
block_offset_in_level %= fs->inode_blocks_per_level[level];
- offset_in_block = block_offset_in_level /
- fs->inode_blocks_per_level[level - 1];
+ offset_in_block = (uint32_t)(block_offset_in_level /
+ fs->inode_blocks_per_level[level - 1]);
}
fblock = current_block;
struct ext4_sblock *sb = &inode_ref->fs->sb;
uint32_t i;
int r;
+ bool v;
/* Check flags, if i-node can be truncated */
if (!ext4_inode_can_truncate(sb, inode_ref->inode))
if (old_size < new_size)
return EINVAL;
- bool v;
+ /* For symbolic link which is small enough */
v = ext4_inode_is_type(sb, inode_ref->inode, EXT4_INODE_MODE_SOFTLINK);
if (v && old_size < sizeof(inode_ref->inode->blocks) &&
!ext4_inode_get_blocks_count(sb, inode_ref->inode)) {
return EOK;
}
+ i = ext4_inode_type(sb, inode_ref->inode);
+ if (i == EXT4_INODE_MODE_CHARDEV ||
+ i == EXT4_INODE_MODE_BLOCKDEV ||
+ i == EXT4_INODE_MODE_SOCKET) {
+ inode_ref->inode->blocks[0] = 0;
+ inode_ref->inode->blocks[1] = 0;
+
+ inode_ref->dirty = true;
+ return EOK;
+ }
+
/* Compute how many blocks will be released */
uint32_t block_size = ext4_sb_get_block_size(sb);
uint32_t new_blocks_cnt = (uint32_t)((new_size + block_size - 1) / block_size);
}
static int ext4_fs_get_inode_dblk_idx_internal(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, ext4_fsblk_t *fblock,
+ ext4_lblk_t iblock, ext4_fsblk_t *fblock,
bool extent_create,
bool support_unwritten __unused)
{
return EIO;
/* Compute offsets for the topmost level */
- uint32_t blk_off_in_lvl = iblock - fs->inode_block_limits[l - 1];
+ uint32_t blk_off_in_lvl = (uint32_t)(iblock - fs->inode_block_limits[l - 1]);
current_block = ext4_inode_get_indirect_block(inode, l - 1);
- uint32_t off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
+ uint32_t off_in_blk = (uint32_t)(blk_off_in_lvl / fs->inode_blocks_per_level[l - 1]);
/* Sparse file */
if (current_block == 0) {
/* Visit the next level */
blk_off_in_lvl %= fs->inode_blocks_per_level[l];
- off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
+ off_in_blk = (uint32_t)(blk_off_in_lvl / fs->inode_blocks_per_level[l - 1]);
}
*fblock = current_block;
int ext4_fs_get_inode_dblk_idx(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, ext4_fsblk_t *fblock,
+ ext4_lblk_t iblock, ext4_fsblk_t *fblock,
bool support_unwritten)
{
return ext4_fs_get_inode_dblk_idx_internal(inode_ref, iblock, fblock,
}
int ext4_fs_init_inode_dblk_idx(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, ext4_fsblk_t *fblock)
+ ext4_lblk_t iblock, ext4_fsblk_t *fblock)
{
return ext4_fs_get_inode_dblk_idx_internal(inode_ref, iblock, fblock,
true, true);
}
static int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint32_t iblock, ext4_fsblk_t fblock)
+ ext4_lblk_t iblock, ext4_fsblk_t fblock)
{
struct ext4_fs *fs = inode_ref->fs;
uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
/* Compute offsets for the topmost level */
- uint32_t blk_off_in_lvl = iblock - fs->inode_block_limits[l - 1];
+ uint32_t blk_off_in_lvl = (uint32_t)(iblock - fs->inode_block_limits[l - 1]);
ext4_fsblk_t current_block =
ext4_inode_get_indirect_block(inode_ref->inode, l - 1);
- uint32_t off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
+ uint32_t off_in_blk = (uint32_t)(blk_off_in_lvl / fs->inode_blocks_per_level[l - 1]);
ext4_fsblk_t new_blk;
/* Visit the next level */
blk_off_in_lvl %= fs->inode_blocks_per_level[l];
- off_in_blk = blk_off_in_lvl / fs->inode_blocks_per_level[l - 1];
+ off_in_blk = (uint32_t)(blk_off_in_lvl / fs->inode_blocks_per_level[l - 1]);
}
return EOK;
int ext4_fs_append_inode_dblk(struct ext4_inode_ref *inode_ref,
- ext4_fsblk_t *fblock, uint32_t *iblock)
+ ext4_fsblk_t *fblock, ext4_lblk_t *iblock)
{
#if CONFIG_EXTENT_ENABLE
/* Handle extents separately */
rc = ext4_extent_get_blocks(inode_ref, *iblock, 1,
¤t_fsblk, true, NULL);
+ if (rc != EOK)
+ return rc;
*fblock = current_fsblk;
ext4_assert(*fblock);