From 0ac15f45592212176fb388cd51995c6cc53950ed Mon Sep 17 00:00:00 2001 From: Kaho Ng Date: Thu, 30 Jun 2016 05:17:33 +0800 Subject: [PATCH] ext4: special inode creation support --- include/ext4.h | 8 ++++++ include/ext4_inode.h | 12 ++++++++ src/ext4.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ src/ext4_dir.c | 16 +++++++++-- src/ext4_fs.c | 45 +++++++++++++++++++++++++----- src/ext4_inode.c | 20 ++++++++++++++ 6 files changed, 158 insertions(+), 9 deletions(-) diff --git a/include/ext4.h b/include/ext4.h index fede38f..b1c7a61 100644 --- a/include/ext4.h +++ b/include/ext4.h @@ -373,6 +373,14 @@ int ext4_file_set_ctime(const char *path, uint32_t ctime); * @return standard error code*/ int ext4_fsymlink(const char *target, const char *path); +/**@brief Create special file + * @param path path to new file + * @param filetype The filetype of the new special file + * (that must not be regular file, directory, or unknown type) + * @param dev if filetype is char device or block device, + * the device number will become the payload in the inode + * @return standard error code*/ +int ext4_mknod(const char *path, int filetype, uint32_t dev); /**@brief Read symbolic link payload * @param path to symlink diff --git a/include/ext4_inode.h b/include/ext4_inode.h index 9498f0a..e0ca6e3 100644 --- a/include/ext4_inode.h +++ b/include/ext4_inode.h @@ -267,6 +267,18 @@ uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx); void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx, uint32_t block); +/**@brief Get device number + * @param inode I-node to get device number from + * @return Device number + */ +uint32_t ext4_inode_get_dev(struct ext4_inode *inode); + +/**@brief Set device number + * @param inode I-node to set device number to + * @param dev Device number + */ +void ext4_inode_set_dev(struct ext4_inode *inode, uint32_t dev); + /**@brief return the type of i-node * @param sb Superblock * @param inode I-node to return the type of diff --git a/src/ext4.c b/src/ext4.c index db7745f..0f2f07a 100644 --- a/src/ext4.c +++ b/src/ext4.c @@ -2413,6 +2413,72 @@ Finish: return r; } +static int ext4_mknod_set(ext4_file *f, uint32_t dev) +{ + struct ext4_inode_ref ref; + int r; + + ext4_assert(f && f->mp); + + r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref); + if (r != EOK) + return r; + + ext4_inode_set_dev(ref.inode, dev); + + ext4_inode_set_size(ref.inode, 0); + ref.dirty = true; + + f->fsize = 0; + f->fpos = 0; + + r = ext4_fs_put_inode_ref(&ref); + return r; +} + +int ext4_mknod(const char *path, int filetype, uint32_t dev) +{ + struct ext4_mountpoint *mp = ext4_get_mount(path); + int r; + ext4_file f; + + if (!mp) + return ENOENT; + + if (mp->fs.read_only) + return EROFS; + + if (filetype == EXT4_DE_UNKNOWN || + filetype == EXT4_DE_REG_FILE || + filetype == EXT4_DE_DIR) + return EINVAL; + + EXT4_MP_LOCK(mp); + ext4_trans_start(mp); + + ext4_block_cache_write_back(mp->fs.bdev, 1); + r = ext4_generic_open2(&f, path, O_RDWR|O_CREAT, filetype, NULL, NULL); + if (r == EOK) { + if (filetype == EXT4_DE_CHRDEV || + filetype == EXT4_DE_BLKDEV) + r = ext4_mknod_set(&f, dev); + } else + goto Finish; + + ext4_fclose(&f); + +Finish: + ext4_block_cache_write_back(mp->fs.bdev, 0); + + if (r != EOK) + ext4_trans_abort(mp); + else + ext4_trans_stop(mp); + + EXT4_MP_UNLOCK(mp); + return r; +} + int ext4_setxattr(const char *path, const char *name, size_t name_len, const void *data, size_t data_size, bool replace __unused) { diff --git a/src/ext4_dir.c b/src/ext4_dir.c index 438d386..4836d62 100644 --- a/src/ext4_dir.c +++ b/src/ext4_dir.c @@ -314,9 +314,21 @@ void ext4_dir_write_entry(struct ext4_sblock *sb, struct ext4_dir_en *en, case EXT4_INODE_MODE_SOFTLINK: ext4_dir_en_set_inode_type(sb, en, EXT4_DE_SYMLINK); break; + case EXT4_INODE_MODE_CHARDEV: + ext4_dir_en_set_inode_type(sb, en, EXT4_DE_CHRDEV); + break; + case EXT4_INODE_MODE_BLOCKDEV: + ext4_dir_en_set_inode_type(sb, en, EXT4_DE_BLKDEV); + break; + case EXT4_INODE_MODE_FIFO: + ext4_dir_en_set_inode_type(sb, en, EXT4_DE_FIFO); + break; + case EXT4_INODE_MODE_SOCKET: + ext4_dir_en_set_inode_type(sb, en, EXT4_DE_SOCK); + break; default: - /* FIXME: right now we only support 3 inode type. */ - ext4_assert(0); + /* FIXME: unsupported filetype */ + ext4_dir_en_set_inode_type(sb, en, EXT4_DE_UNKNOWN); } /* Set basic attributes */ diff --git a/src/ext4_fs.c b/src/ext4_fs.c index 8a0be5b..e8b296d 100644 --- a/src/ext4_fs.c +++ b/src/ext4_fs.c @@ -832,11 +832,17 @@ uint32_t ext4_fs_correspond_inode_mode(int filetype) 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, @@ -844,6 +850,7 @@ 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); @@ -876,6 +883,14 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, 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 @@ -904,9 +919,13 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, 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; @@ -1169,6 +1188,7 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size) 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)) @@ -1183,7 +1203,7 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size) 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)) { @@ -1196,6 +1216,17 @@ int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref, uint64_t new_size) 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); diff --git a/src/ext4_inode.c b/src/ext4_inode.c index c64ddbc..513da60 100644 --- a/src/ext4_inode.c +++ b/src/ext4_inode.c @@ -328,6 +328,26 @@ void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx, inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block); } +uint32_t ext4_inode_get_dev(struct ext4_inode *inode) +{ + uint32_t dev_0, dev_1; + dev_0 = ext4_inode_get_direct_block(inode, 0); + dev_1 = ext4_inode_get_direct_block(inode, 1); + + if (dev_0) + return dev_0; + else + return dev_1; +} + +void ext4_inode_set_dev(struct ext4_inode *inode, uint32_t dev) +{ + if (dev & ~0xFFFF) + ext4_inode_set_direct_block(inode, 1, dev); + else + ext4_inode_set_direct_block(inode, 0, dev); +} + uint32_t ext4_inode_type(struct ext4_sblock *sb, struct ext4_inode *inode) { return (ext4_inode_get_mode(sb, inode) & EXT4_INODE_MODE_TYPE_MASK); -- 2.30.2