shithub: lwext4

Download patch

ref: ab3010aeb7aff7581d67866819a1ec74ce36916a
parent: 400b183c480845e1cd2c2f49f74baade00d2653c
author: root <ngkaho1234@gmail.com>
date: Sun Sep 20 12:51:55 EDT 2015

Symbolic link support: ext4_fsymlink proposed.

--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -1279,6 +1279,30 @@
 	sblock_end = (f->fpos + size) / block_size;
 	u = (f->fpos) % block_size;
 
+	/*If the size of symlink is smaller than 60 bytes*/
+	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;
+		if (f->fpos < f->fsize) {
+			r = (u + size > f->fsize)
+				?(f->fsize - u)
+				:(size);
+			memcpy(buf, content + u, r);
+			if (rcnt)
+				*rcnt = r;
+
+		} else {
+			r = 0;
+			if (rcnt)
+				*rcnt = 0;
+
+		}
+
+		goto Finish;
+	}
+
 	if (u) {
 
 		uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
@@ -1711,6 +1735,109 @@
 	inode_ref.dirty = true;
 
 	ext4_fs_put_inode_ref(&inode_ref);
+	EXT4_MP_UNLOCK(mp);
+	return r;
+}
+
+static int ext4_fsymlink_set(ext4_file *f, const void *buf, uint32_t size)
+{
+	struct ext4_block b;
+	struct ext4_inode_ref ref;
+	uint32_t sblock, fblock;
+	uint32_t block_size;
+	int r;
+
+	ext4_assert(f && f->mp);
+
+	if (!size)
+		return EOK;
+
+	r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
+	if (r != EOK) {
+		EXT4_MP_UNLOCK(f->mp);
+		return r;
+	}
+
+	/*Sync file size*/
+	block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
+	if (size > block_size) {
+		r = EINVAL;
+		goto Finish;
+	}
+	r = ext4_ftruncate_no_lock(f, 0);
+	if (r != EOK)
+		goto Finish;
+
+	/*Start write back cache mode.*/
+	r = ext4_block_cache_write_back(f->mp->fs.bdev, 1);
+	if (r != EOK)
+		goto Finish;
+
+	/*If the size of symlink is smaller than 60 bytes*/
+	if (size < sizeof(ref.inode->blocks)) {
+		char *content = (char *)ref.inode->blocks;
+		memset(content, 0, sizeof(ref.inode->blocks));
+		memcpy(content, buf, size);
+		ext4_inode_clear_flag(ref.inode, EXT4_INODE_FLAG_EXTENTS);
+	} else {
+		ext4_fs_inode_blocks_init(&f->mp->fs, &ref);
+		r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
+		if (r != EOK)
+			goto Finish;
+
+		r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+		if (r != EOK)
+			goto Finish;
+
+		memcpy(b.data, buf, size);
+		b.dirty = true;
+		r = ext4_block_set(f->mp->fs.bdev, &b);
+		if (r != EOK)
+			goto Finish;
+
+	}
+
+	/*Stop write back cache mode*/
+	ext4_block_cache_write_back(f->mp->fs.bdev, 0);
+
+	if (r != EOK)
+		goto Finish;
+
+	ext4_inode_set_size(ref.inode, size);
+	ext4_inode_set_mode(&f->mp->fs.sb, ref.inode,
+			ext4_inode_get_mode(&f->mp->fs.sb, ref.inode) | EXT4_INODE_MODE_SOFTLINK);
+	ref.dirty = true;
+
+	f->fsize = size;
+	if (f->fpos > size)
+		f->fpos = size;
+
+Finish:
+	ext4_fs_put_inode_ref(&ref);
+	return r;
+}
+
+int ext4_fsymlink(const char *path, const char *target)
+{
+	struct ext4_mountpoint *mp = ext4_get_mount(path);
+	int r;
+	ext4_file f;
+	int filetype;
+
+	if (!mp)
+		return ENOENT;
+
+	filetype = EXT4_DIRECTORY_FILETYPE_SYMLINK;
+
+	EXT4_MP_LOCK(mp);
+	ext4_block_cache_write_back(mp->fs.bdev, 1);
+	r = ext4_generic_open2(&f, path, O_RDWR, filetype, 0, 0);
+	if (r == EOK)
+		r = ext4_fsymlink_set(&f, target, strlen(target));
+
+	ext4_fclose(&f);
+
+	ext4_block_cache_write_back(mp->fs.bdev, 0);
 	EXT4_MP_UNLOCK(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 symlink against target
+ * @param   path path to file
+ * @param   target path to target
+ * @return  standard error code */
+int ext4_fsymlink(const char *path, const char *target);
+
 /**@brief   create a hardlink for a file.
  * @param   path path to file
  * @param   hardlink_path path of hardlink
--- a/lwext4/ext4_fs.c
+++ b/lwext4/ext4_fs.c
@@ -613,11 +613,40 @@
 	return ext4_block_set(ref->fs->bdev, &ref->block);
 }
 
+void ext4_fs_inode_blocks_init(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref)
+{
+	int i;
+	struct ext4_inode *inode = inode_ref->inode;
+
+	for (i = 0; i < EXT4_INODE_BLOCKS; i++)
+		inode->blocks[i] = 0;
+
+#if CONFIG_EXTENT_ENABLE
+	/* Initialize extents if needed */
+	if (ext4_sb_has_feature_incompatible(&fs->sb,
+				EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+		ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
+
+		/* Initialize extent root header */
+		struct ext4_extent_header *header = ext4_inode_get_extent_header(inode);
+		ext4_extent_header_set_depth(header, 0);
+		ext4_extent_header_set_entries_count(header, 0);
+		ext4_extent_header_set_generation(header, 0);
+		ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
+
+		uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
+				sizeof(struct ext4_extent_header)) /
+			sizeof(struct ext4_extent);
+
+		ext4_extent_header_set_max_entries_count(header, max_entries);
+	}
+#endif
+}
+
 int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
 			bool is_directory)
 {
 	/* Check if newly allocated i-node will be a directory */
-	uint32_t i;
 	bool is_dir;
 
 	is_dir = is_directory;
@@ -673,30 +702,7 @@
 	ext4_inode_set_generation(inode, 0);
 
 	/* Reset blocks array */
-	for (i = 0; i < EXT4_INODE_BLOCKS; i++)
-		inode->blocks[i] = 0;
-
-#if CONFIG_EXTENT_ENABLE
-	/* Initialize extents if needed */
-	if (ext4_sb_has_feature_incompatible(&fs->sb,
-					     EXT4_FEATURE_INCOMPAT_EXTENTS)) {
-		ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
-
-		/* Initialize extent root header */
-		struct ext4_extent_header *header =
-		    ext4_inode_get_extent_header(inode);
-		ext4_extent_header_set_depth(header, 0);
-		ext4_extent_header_set_entries_count(header, 0);
-		ext4_extent_header_set_generation(header, 0);
-		ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
-
-		uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
-					sizeof(struct ext4_extent_header)) /
-				       sizeof(struct ext4_extent);
-
-		ext4_extent_header_set_max_entries_count(header, max_entries);
-	}
-#endif
+	ext4_fs_inode_blocks_init(fs, inode_ref);
 
 	inode_ref->dirty = true;
 
--- a/lwext4/ext4_fs.h
+++ b/lwext4/ext4_fs.h
@@ -155,6 +155,13 @@
  */
 int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref);
 
+/**@brief Reset blocks field of i-node.
+ * @param fs        Filesystem to reset blocks field of i-inode on
+ * @param inode_ref ref Pointer for inode to be operated on
+ */
+void ext4_fs_inode_blocks_init(struct ext4_fs *fs,
+			       struct ext4_inode_ref *inode_ref);
+
 /**@brief Truncate i-node data blocks.
  * @param inode_ref I-node to be truncated
  * @param new_size  New size of inode (must be < current size)