shithub: lwext4

Download patch

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_ */
 
 /**