ref: 0bad049ee7e205f8ad11b5e03764491457d3cc4e
parent: 9e5db3d386e63d5aa3b001ae4d0167a20f472f48
parent: 400b183c480845e1cd2c2f49f74baade00d2653c
author: gkostka <kostka.grzegorz@gmail.com>
date: Sun Sep 20 14:51:46 EDT 2015
Merge pull request #2 from ngkaho1234/master Merge ngkaho1234 branch
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -232,30 +232,34 @@
parent->dirty = true;
} else {
if (ext4_inode_is_type(&mp->fs.sb, child->inode,
- EXT4_INODE_MODE_DIRECTORY)) {
- /* FIXME: SO TRICKY. */
- int has_flag_index = ext4_inode_has_flag(
- child->inode, EXT4_INODE_FLAG_INDEX);
+ EXT4_INODE_MODE_DIRECTORY)) {
+ int has_flag_index =
+ ext4_inode_has_flag(child->inode,
+ EXT4_INODE_FLAG_INDEX);
struct ext4_directory_search_result result;
- if (has_flag_index)
- ext4_inode_clear_flag(child->inode,
- EXT4_INODE_FLAG_INDEX);
+ if (!has_flag_index) {
+ rc = ext4_dir_find_entry(&result,
+ child, "..",
+ strlen(".."));
+ if (rc != EOK)
+ return EIO;
- rc = ext4_dir_find_entry(&result, child, "..",
- strlen(".."));
- if (has_flag_index)
- ext4_inode_set_flag(child->inode,
- EXT4_INODE_FLAG_INDEX);
+ ext4_dir_entry_ll_set_inode(result.dentry,
+ parent->index);
+ result.block.dirty = true;
+ rc = ext4_dir_destroy_result(child, &result);
+ if (rc != EOK)
+ return rc;
- if (rc != EOK)
- return EIO;
+ } else {
+#if CONFIG_DIR_INDEX_ENABLE
+ rc = ext4_dir_dx_reset_parent_inode(parent,
+ parent->index);
+ if (rc != EOK)
+ return rc;
- ext4_dir_entry_ll_set_inode(result.dentry,
- parent->index);
- result.block.dirty = true;
- rc = ext4_dir_destroy_result(child, &result);
- if (rc != EOK)
- return rc;
+#endif
+ }
ext4_fs_inode_links_count_inc(parent);
parent->dirty = true;
@@ -754,7 +758,7 @@
}
static int __ext4_create_hardlink(const char *path,
- struct ext4_inode_ref *child_ref)
+ struct ext4_inode_ref *child_ref)
{
bool is_goal = false;
uint8_t inode_type = EXT4_DIRECTORY_FILETYPE_DIR;
@@ -806,9 +810,9 @@
break;
}
- next_inode = ext4_dir_entry_ll_get_inode(result.dentry);
+ next_inode = result.dentry->inode;
inode_type =
- ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
+ ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
r = ext4_dir_destroy_result(&ref, &result);
if (r != EOK)
@@ -846,66 +850,93 @@
return r;
}
-static int __ext4_get_inode_ref_remove_hardlink(const char *path,
- struct ext4_inode_ref *child)
+static int __ext4_remove_hardlink(const char *path,
+ uint32_t name_off,
+ struct ext4_inode_ref *parent_ref,
+ struct ext4_inode_ref *child_ref)
{
- ext4_file f;
- uint32_t parent_inode;
- uint32_t name_off;
bool is_goal;
int r;
int len;
- struct ext4_inode_ref parent;
struct ext4_mountpoint *mp = ext4_get_mount(path);
if (!mp)
return ENOENT;
- r = ext4_generic_open2(&f, path, O_RDONLY,
- EXT4_DIRECTORY_FILETYPE_UNKNOWN, &parent_inode,
- &name_off);
+ /*Set path*/
+ path += name_off;
+
+ len = ext4_path_check(path, &is_goal);
+
+ /*Unlink from parent*/
+ r = ext4_unlink(mp, parent_ref, child_ref, path, len);
if (r != EOK)
- return r;
+ goto Finish;
- /*Load parent*/
- r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent);
- if (r != EOK) {
- return r;
- }
+Finish:
+ if (r != EOK)
+ ext4_fs_put_inode_ref(child_ref);
- /*We have file to unlink. Load it.*/
- r = ext4_fs_get_inode_ref(&mp->fs, f.inode, child);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&parent);
- return r;
- }
+ ext4_fs_put_inode_ref(parent_ref);
+ return r;
+}
+int ext4_flink(const char *path, const char *hardlink_path)
+{
+ int r;
+ ext4_file f;
+ uint32_t name_off;
+ bool child_loaded = false;
+ uint32_t parent_inode, child_inode;
+ struct ext4_mountpoint *mp = ext4_get_mount(path);
+ struct ext4_mountpoint *target_mp = ext4_get_mount(hardlink_path);
+ struct ext4_inode_ref child_ref;
+
+ if (!mp)
+ return ENOENT;
+
+ /* Will that happen? Anyway return EINVAL for such case. */
+ if (mp != target_mp)
+ return EINVAL;
+
+ EXT4_MP_LOCK(mp);
+
+ r = ext4_generic_open2(&f, path, O_RDONLY,
+ EXT4_DIRECTORY_FILETYPE_UNKNOWN,
+ &parent_inode, &name_off);
if (r != EOK)
goto Finish;
- /*Set path*/
- path += name_off;
+ child_inode = f.inode;
+ ext4_fclose(&f);
- len = ext4_path_check(path, &is_goal);
-
- /*Unlink from parent*/
- r = ext4_unlink(mp, &parent, child, path, len);
+ /*We have file to unlink. Load it.*/
+ r = ext4_fs_get_inode_ref(&mp->fs, child_inode, &child_ref);
if (r != EOK)
goto Finish;
+ child_loaded = true;
+
+ r = __ext4_create_hardlink(hardlink_path, &child_ref);
+
Finish:
- if (r != EOK)
- ext4_fs_put_inode_ref(child);
+ if (child_loaded)
+ ext4_fs_put_inode_ref(&child_ref);
- ext4_fs_put_inode_ref(&parent);
+ EXT4_MP_UNLOCK(mp);
return r;
+
}
int ext4_frename(const char *path, const char *new_path)
{
int r;
+ ext4_file f;
+ uint32_t name_off;
+ bool parent_loaded = false, child_loaded = false;
+ uint32_t parent_inode, child_inode;
struct ext4_mountpoint *mp = ext4_get_mount(path);
- struct ext4_inode_ref inode_ref;
+ struct ext4_inode_ref child_ref, parent_ref;
if (!mp)
return ENOENT;
@@ -912,19 +943,47 @@
EXT4_MP_LOCK(mp);
- r = __ext4_get_inode_ref_remove_hardlink(path, &inode_ref);
+ r = ext4_generic_open2(&f, path, O_RDONLY,
+ EXT4_DIRECTORY_FILETYPE_UNKNOWN,
+ &parent_inode, &name_off);
if (r != EOK)
goto Finish;
- r = __ext4_create_hardlink(new_path, &inode_ref);
+ child_inode = f.inode;
+ ext4_fclose(&f);
+
+ /*Load parent*/
+ r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent_ref);
if (r != EOK)
- r = __ext4_create_hardlink(path, &inode_ref);
+ goto Finish;
- ext4_fs_put_inode_ref(&inode_ref);
+ parent_loaded = true;
+ /*We have file to unlink. Load it.*/
+ r = ext4_fs_get_inode_ref(&mp->fs, child_inode, &child_ref);
+ if (r != EOK)
+ goto Finish;
+
+ child_loaded = true;
+
+ r = __ext4_create_hardlink(new_path, &child_ref);
+ if (r != EOK)
+ goto Finish;
+
+ r = __ext4_remove_hardlink(path, name_off, &parent_ref, &child_ref);
+ if (r != EOK)
+ goto Finish;
+
Finish:
+ if (parent_loaded)
+ ext4_fs_put_inode_ref(&parent_ref);
+
+ if (child_loaded)
+ ext4_fs_put_inode_ref(&child_ref);
+
EXT4_MP_UNLOCK(mp);
return r;
+
}
/****************************************************************************/
@@ -1101,18 +1160,12 @@
return EOK;
}
-int ext4_ftruncate(ext4_file *f, uint64_t size)
+static int ext4_ftruncate_no_lock(ext4_file *f, uint64_t size)
{
struct ext4_inode_ref ref;
int r;
- ext4_assert(f && f->mp);
- if (f->flags & O_RDONLY)
- return EPERM;
-
- EXT4_MP_LOCK(f->mp);
-
r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
if (r != EOK) {
EXT4_MP_UNLOCK(f->mp);
@@ -1126,6 +1179,23 @@
goto Finish;
}
+ if ((ext4_inode_get_mode(&f->mp->fs.sb, ref.inode) & EXT4_INODE_MODE_SOFTLINK)
+ == EXT4_INODE_MODE_SOFTLINK
+ && f->fsize < sizeof(ref.inode->blocks)
+ && !ext4_inode_get_blocks_count(&f->mp->fs.sb, ref.inode)) {
+ char *content = (char *)ref.inode->blocks;
+ memset(content + size, 0, sizeof(ref.inode->blocks) - size);
+ ext4_inode_set_size(ref.inode, size);
+ ref.dirty = true;
+
+ f->fsize = size;
+ if (f->fpos > size)
+ f->fpos = size;
+
+ r = EOK;
+ goto Finish;
+ }
+
/*Start write back cache mode.*/
r = ext4_block_cache_write_back(f->mp->fs.bdev, 1);
if (r != EOK)
@@ -1147,6 +1217,22 @@
Finish:
ext4_fs_put_inode_ref(&ref);
+ return r;
+
+}
+
+int ext4_ftruncate(ext4_file *f, uint64_t size)
+{
+ int r;
+ ext4_assert(f && f->mp);
+
+ if (f->flags & O_RDONLY)
+ return EPERM;
+
+ EXT4_MP_LOCK(f->mp);
+
+ r = ext4_ftruncate_no_lock(f, size);
+
EXT4_MP_UNLOCK(f->mp);
return r;
}
--- a/lwext4/ext4.h
+++ b/lwext4/ext4.h
@@ -258,6 +258,12 @@
* @return standard error code */
int ext4_fremove(const char *path);
+/**@brief create a hardlink for a file.
+ * @param path path to file
+ * @param hardlink_path path of hardlink
+ * @return standard error code */
+int ext4_flink(const char *path, const char *hardlink_path);
+
/**@brief Rename file
* @param path source
* @param new_path destination
--- a/lwext4/ext4_dir.h
+++ b/lwext4/ext4_dir.h
@@ -69,6 +69,16 @@
de->inode = to_le32(inode);
}
+/**@brief Set i-node number to directory entry. (For HTree root)
+ * @param de Directory entry
+ * @param inode I-node number
+ */
+static inline void
+ext4_dx_dot_entry_set_inode(struct ext4_directory_dx_dot_entry *de, uint32_t inode)
+{
+ de->inode = to_le32(inode);
+}
+
/**@brief Get directory entry length.
* @param de Directory entry
* @return Entry length
--- a/lwext4/ext4_dir_idx.c
+++ b/lwext4/ext4_dir_idx.c
@@ -1193,6 +1193,30 @@
return rc2;
}
+int ext4_dir_dx_reset_parent_inode(struct ext4_inode_ref *dir, uint32_t parent_inode)
+{
+ /* Load block 0, where will be index root located */
+ uint32_t fblock;
+ int rc = ext4_fs_get_inode_data_block_index(dir, 0, &fblock);
+ if (rc != EOK)
+ return rc;
+
+ struct ext4_block block;
+ rc = ext4_block_get(dir->fs->bdev, &block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ /* Initialize pointers to data structures */
+ struct ext4_directory_dx_root *root = (void *)block.data;
+
+ /* Fill the inode field with a new parent ino. */
+ ext4_dx_dot_entry_set_inode(&root->dots[1], parent_inode);
+
+ block.dirty = true;
+
+ return ext4_block_set(dir->fs->bdev, &block);
+}
+
/**
* @}
*/
--- a/lwext4/ext4_dir_idx.h
+++ b/lwext4/ext4_dir_idx.h
@@ -75,6 +75,14 @@
int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
struct ext4_inode_ref *child, const char *name);
+/**@brief Add new entry to indexed directory
+ * @param dir Directory i-node
+ * @param parent_inode parent inode index
+ * @return Error code
+ */
+int ext4_dir_dx_reset_parent_inode(struct ext4_inode_ref *dir,
+ uint32_t parent_inode);
+
#endif /* EXT4_DIR_IDX_H_ */
/**