Browse Source

Symbolic link support: ext4_fsymlink proposed.

pull/3/head
root 9 years ago
parent
commit
ab3010aeb7
  1. 127
      lwext4/ext4.c
  2. 6
      lwext4/ext4.h
  3. 56
      lwext4/ext4_fs.c
  4. 7
      lwext4/ext4_fs.h

127
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)

6
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

56
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;

7
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)

Loading…
Cancel
Save