diff options
| author | root <ngkaho1234@gmail.com> | 2015-09-20 16:51:55 +0000 |
|---|---|---|
| committer | root <ngkaho1234@gmail.com> | 2015-09-20 16:51:55 +0000 |
| commit | ab3010aeb7aff7581d67866819a1ec74ce36916a (patch) | |
| tree | dbcec185adfaec79f83e219769b533712e138ed9 | |
| parent | 400b183c480845e1cd2c2f49f74baade00d2653c (diff) | |
Symbolic link support: ext4_fsymlink proposed.
| -rw-r--r-- | lwext4/ext4.c | 127 | ||||
| -rw-r--r-- | lwext4/ext4.h | 6 | ||||
| -rw-r--r-- | lwext4/ext4_fs.c | 56 | ||||
| -rw-r--r-- | lwext4/ext4_fs.h | 7 |
4 files changed, 171 insertions, 25 deletions
diff --git a/lwext4/ext4.c b/lwext4/ext4.c index 4e47834..acd4c9f 100644 --- a/lwext4/ext4.c +++ b/lwext4/ext4.c @@ -1279,6 +1279,30 @@ int ext4_fread(ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt) 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; @@ -1715,6 +1739,109 @@ int ext4_file_set_ctime(ext4_file *f, uint32_t ctime) 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; +} + /*********************************DIRECTORY OPERATION************************/ int ext4_dir_rm(const char *path) diff --git a/lwext4/ext4.h b/lwext4/ext4.h index 4328c22..59b0501 100644 --- a/lwext4/ext4.h +++ b/lwext4/ext4.h @@ -258,6 +258,12 @@ int ext4_cache_write_back(const char *path, bool on); * @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 diff --git a/lwext4/ext4_fs.c b/lwext4/ext4_fs.c index 28102d1..376b8e6 100644 --- a/lwext4/ext4_fs.c +++ b/lwext4/ext4_fs.c @@ -613,11 +613,40 @@ int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref) 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 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, 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; diff --git a/lwext4/ext4_fs.h b/lwext4/ext4_fs.h index ee63ef4..b7e8496 100644 --- a/lwext4/ext4_fs.h +++ b/lwext4/ext4_fs.h @@ -155,6 +155,13 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref, */ 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) |
