ref: dfa54d1e23c32059b292bbbb99d4251bf15e7517
parent: 4e5365b36f1626bf784b35e09aaf6ecd47a103b3
parent: f4d662d77b4a0376d6a58475839f5a2a89b2c966
author: gkostka <kostka.grzegorz@gmail.com>
date: Tue Sep 22 03:36:56 EDT 2015
Merge pull request #5 from ngkaho1234/master Initial Symbolic link support.(Creation, deletion, readlink, but no modification can be made.)
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -284,7 +284,7 @@
/* Cannot unlink non-empty node */
if (has_children)
- return ENOTSUP;
+ return ENOTEMPTY;
/* Remove entry from parent directory */
rc = ext4_dir_remove_entry(parent, name, name_len);
@@ -582,7 +582,7 @@
uint32_t *name_off)
{
bool is_goal = false;
- uint8_t inode_type = EXT4_DIRECTORY_FILETYPE_DIR;
+ uint8_t inode_type;
uint32_t next_inode;
int r;
@@ -642,8 +642,8 @@
struct ext4_inode_ref child_ref;
r = ext4_fs_alloc_inode(
&mp->fs, &child_ref,
- is_goal ? (filetype == EXT4_DIRECTORY_FILETYPE_DIR)
- : true);
+ is_goal ? filetype
+ : EXT4_DIRECTORY_FILETYPE_DIR);
if (r != EOK)
break;
@@ -1028,7 +1028,9 @@
return ENOENT;
EXT4_MP_LOCK(mp);
- r = ext4_generic_open(&f, path, "r", true, &parent_inode, &name_off);
+ r = ext4_generic_open2(&f, path, O_RDWR,
+ EXT4_DIRECTORY_FILETYPE_UNKNOWN,
+ &parent_inode, &name_off);
if (r != EOK) {
EXT4_MP_UNLOCK(mp);
return r;
@@ -1147,6 +1149,28 @@
return r;
}
+int ext4_fopen_all(ext4_file *f, const char *path, int flags)
+{
+ struct ext4_mountpoint *mp = ext4_get_mount(path);
+ int r;
+ int filetype;
+
+ if (!mp)
+ return ENOENT;
+
+ if (flags & O_CREAT)
+ return EINVAL;
+
+ filetype = EXT4_DIRECTORY_FILETYPE_UNKNOWN;
+
+ EXT4_MP_LOCK(mp);
+ ext4_block_cache_write_back(mp->fs.bdev, 1);
+ r = ext4_generic_open2(f, path, flags, filetype, 0, 0);
+ ext4_block_cache_write_back(mp->fs.bdev, 0);
+ EXT4_MP_UNLOCK(mp);
+ return r;
+}
+
int ext4_fclose(ext4_file *f)
{
ext4_assert(f && f->mp);
@@ -1178,23 +1202,6 @@
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)
@@ -1278,6 +1285,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_is_type(&f->mp->fs.sb, ref.inode, 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;
+
+ }
+
+ r = EOK;
+ goto Finish;
+ }
+
if (u) {
uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
@@ -1710,6 +1741,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);
+ 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 *target, const char *path)
+{
+ 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|O_CREAT, filetype, 0, 0);
+ if (r == EOK)
+ r = ext4_fsymlink_set(&f, target, strlen(target));
+ else
+ goto Finish;
+
+ ext4_fclose(&f);
+
+Finish:
+ ext4_block_cache_write_back(mp->fs.bdev, 0);
EXT4_MP_UNLOCK(mp);
return r;
}
--- a/lwext4/ext4.h
+++ b/lwext4/ext4.h
@@ -360,6 +360,8 @@
int ext4_file_set_mtime(ext4_file *f, uint32_t mtime);
int ext4_file_set_ctime(ext4_file *f, uint32_t ctime);
+int ext4_fsymlink(const char *target, const char *path);
+
/*********************************DIRECTORY OPERATION***********************/
/**@brief Recursive directory remove.
--- a/lwext4/ext4_dir.c
+++ b/lwext4/ext4_dir.c
@@ -206,6 +206,25 @@
/* Check maximum entry length */
ext4_assert(entry_len <= ext4_sb_get_block_size(sb));
+ /* Set type of entry */
+ switch (ext4_inode_type(sb, child->inode)) {
+ case EXT4_INODE_MODE_DIRECTORY:
+ ext4_dir_entry_ll_set_inode_type(sb, entry,
+ EXT4_DIRECTORY_FILETYPE_DIR);
+ break;
+ case EXT4_INODE_MODE_FILE:
+ ext4_dir_entry_ll_set_inode_type(
+ sb, entry, EXT4_DIRECTORY_FILETYPE_REG_FILE);
+ break;
+ case EXT4_INODE_MODE_SOFTLINK:
+ ext4_dir_entry_ll_set_inode_type(
+ sb, entry, EXT4_DIRECTORY_FILETYPE_SYMLINK);
+ break;
+ default:
+ /* FIXME: right now we only support 3 inode type. */
+ ext4_assert(0);
+ }
+
/* Set basic attributes */
ext4_dir_entry_ll_set_inode(entry, child->index);
ext4_dir_entry_ll_set_entry_length(entry, entry_len);
@@ -213,14 +232,6 @@
/* Write name */
memcpy(entry->name, name, name_len);
-
- /* Set type of entry */
- if (ext4_inode_is_type(sb, child->inode, EXT4_INODE_MODE_DIRECTORY))
- ext4_dir_entry_ll_set_inode_type(sb, entry,
- EXT4_DIRECTORY_FILETYPE_DIR);
- else
- ext4_dir_entry_ll_set_inode_type(
- sb, entry, EXT4_DIRECTORY_FILETYPE_REG_FILE);
}
int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
--- a/lwext4/ext4_errno.h
+++ b/lwext4/ext4_errno.h
@@ -41,41 +41,42 @@
#if !CONFIG_HAVE_OWN_ERRNO
#include <errno.h>
#else
-#define EPERM 1 /* Operation not permitted */
-#define ENOENT 2 /* No such file or directory */
-#define ESRCH 3 /* No such process */
-#define EINTR 4 /* Interrupted system call */
-#define EIO 5 /* I/O error */
-#define ENXIO 6 /* No such device or address */
-#define E2BIG 7 /* Argument list too long */
-#define ENOEXEC 8 /* Exec format error */
-#define EBADF 9 /* Bad file number */
-#define ECHILD 10 /* No child processes */
-#define EAGAIN 11 /* Try again */
-#define ENOMEM 12 /* Out of memory */
-#define EACCES 13 /* Permission denied */
-#define EFAULT 14 /* Bad address */
-#define ENOTBLK 15 /* Block device required */
-#define EBUSY 16 /* Device or resource busy */
-#define EEXIST 17 /* File exists */
-#define EXDEV 18 /* Cross-device link */
-#define ENODEV 19 /* No such device */
-#define ENOTDIR 20 /* Not a directory */
-#define EISDIR 21 /* Is a directory */
-#define EINVAL 22 /* Invalid argument */
-#define ENFILE 23 /* File table overflow */
-#define EMFILE 24 /* Too many open files */
-#define ENOTTY 25 /* Not a typewriter */
-#define ETXTBSY 26 /* Text file busy */
-#define EFBIG 27 /* File too large */
-#define ENOSPC 28 /* No space left on device */
-#define ESPIPE 29 /* Illegal seek */
-#define EROFS 30 /* Read-only file system */
-#define EMLINK 31 /* Too many links */
-#define EPIPE 32 /* Broken pipe */
-#define EDOM 33 /* Math argument out of domain of func */
-#define ERANGE 34 /* Math result not representable */
-#define ENOTSUP 95 /* Not supported */
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ENOTSUP 95 /* Not supported */
#endif
#ifndef ENOTSUP
--- a/lwext4/ext4_fs.c
+++ b/lwext4/ext4_fs.c
@@ -613,14 +613,59 @@
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
+}
+
+static uint32_t ext4_fs_correspond_inode_mode(int filetype)
+{
+ switch (filetype) {
+ case EXT4_DIRECTORY_FILETYPE_DIR:
+ return EXT4_INODE_MODE_DIRECTORY;
+ case EXT4_DIRECTORY_FILETYPE_REG_FILE:
+ return EXT4_INODE_MODE_FILE;
+ case EXT4_DIRECTORY_FILETYPE_SYMLINK:
+ return EXT4_INODE_MODE_SOFTLINK;
+ default:
+ /* FIXME: right now we only support 3 file type. */
+ ext4_assert(0);
+ }
+ return 0;
+}
+
int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
- bool is_directory)
+ int filetype)
{
/* Check if newly allocated i-node will be a directory */
- uint32_t i;
bool is_dir;
- is_dir = is_directory;
+ is_dir = (filetype == EXT4_DIRECTORY_FILETYPE_DIR);
/* Allocate inode by allocation algorithm */
uint32_t index;
@@ -638,7 +683,7 @@
/* Initialize i-node */
struct ext4_inode *inode = inode_ref->inode;
- uint16_t mode;
+ uint32_t mode;
if (is_dir) {
/*
* Default directory permissions to be compatible with other
@@ -648,7 +693,6 @@
mode = 0777;
mode |= EXT4_INODE_MODE_DIRECTORY;
- ext4_inode_set_mode(&fs->sb, inode, mode);
} else {
/*
* Default file permissions to be compatible with other systems
@@ -656,9 +700,9 @@
*/
mode = 0666;
- mode |= EXT4_INODE_MODE_FILE;
- ext4_inode_set_mode(&fs->sb, inode, mode);
+ mode |= ext4_fs_correspond_inode_mode(filetype);
}
+ ext4_inode_set_mode(&fs->sb, inode, mode);
ext4_inode_set_links_count(inode, 0);
ext4_inode_set_uid(inode, 0);
@@ -672,32 +716,15 @@
ext4_inode_set_flags(inode, 0);
ext4_inode_set_generation(inode, 0);
- /* Reset blocks array */
- for (i = 0; i < EXT4_INODE_BLOCKS; i++)
- inode->blocks[i] = 0;
+ /* Reset blocks array. For symbolic link inode, just
+ * fill in blocks with 0 */
+ if (ext4_inode_is_type(&fs->sb, inode, EXT4_INODE_MODE_SOFTLINK)) {
+ for (int 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);
+ } else
+ ext4_fs_inode_blocks_init(fs, inode_ref);
- /* 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
-
inode_ref->dirty = true;
return EOK;
@@ -867,6 +894,18 @@
/* It's not supported to make the larger file by truncate operation */
if (old_size < new_size)
return EINVAL;
+
+ if (ext4_inode_is_type(sb, inode_ref->inode, EXT4_INODE_MODE_SOFTLINK)
+ && old_size < sizeof(inode_ref->inode->blocks)
+ && !ext4_inode_get_blocks_count(sb, inode_ref->inode)) {
+ char *content = (char *)inode_ref->inode->blocks;
+ memset(content + new_size, 0,
+ sizeof(inode_ref->inode->blocks) - new_size);
+ ext4_inode_set_size(inode_ref->inode, new_size);
+ inode_ref->dirty = true;
+
+ return EOK;
+ }
/* Compute how many blocks will be released */
uint64_t size_diff = old_size - new_size;
--- a/lwext4/ext4_fs.h
+++ b/lwext4/ext4_fs.h
@@ -134,6 +134,12 @@
int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
struct ext4_inode_ref *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 Put reference to i-node.
* @param ref Pointer for reference to be put back
* @return Error code
@@ -143,11 +149,11 @@
/**@brief Allocate new i-node in the filesystem.
* @param fs Filesystem to allocated i-node on
* @param inode_ref Output pointer to return reference to allocated i-node
- * @param flags Flags to be set for newly created i-node
+ * @param filetype File type of newly created i-node
* @return Error code
*/
int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
- bool is_directory);
+ int filetype);
/**@brief Release i-node and mark it as free.
* @param inode_ref I-node to be released
--- a/lwext4/ext4_inode.c
+++ b/lwext4/ext4_inode.c
@@ -290,11 +290,15 @@
inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block);
}
+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);
+}
+
bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
uint32_t type)
{
- return (ext4_inode_get_mode(sb, inode) & EXT4_INODE_MODE_TYPE_MASK) ==
- type;
+ return ext4_inode_type(sb, inode) == type;
}
bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f)
@@ -323,7 +327,8 @@
return false;
if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||
- (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))
+ (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)) ||
+ (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_SOFTLINK)))
return true;
return false;
--- a/lwext4/ext4_inode.h
+++ b/lwext4/ext4_inode.h
@@ -245,6 +245,13 @@
void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
uint32_t block);
+/**@brief return the type of i-node
+ * @param sb Superblock
+ * @param inode I-node to return the type of
+ * @return Result of check operation
+ */
+uint32_t ext4_inode_type(struct ext4_sblock *sb, struct ext4_inode *inode);
+
/**@brief Check if i-node has specified type.
* @param sb Superblock
* @param inode I-node to check type of