summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKaho Ng <ngkaho1234@gmail.com>2016-06-30 05:17:33 +0800
committerKaho Ng <ngkaho1234@gmail.com>2016-06-30 05:40:06 +0800
commit0ac15f45592212176fb388cd51995c6cc53950ed (patch)
tree4cc4aeac7bbfcffa37fb22db1d0313f8ff482c2d /src
parenta84a1b68d698d9a5cfa5efd55b057df7724996b2 (diff)
ext4: special inode creation support
Diffstat (limited to 'src')
-rw-r--r--src/ext4.c66
-rw-r--r--src/ext4_dir.c16
-rw-r--r--src/ext4_fs.c45
-rw-r--r--src/ext4_inode.c20
4 files changed, 138 insertions, 9 deletions
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);