X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=lwext4%2Fext4.c;h=e3c8154222f99d57cea6af1474cf7d2a9d906d6d;hb=a4ec81fd03739007d083a7cc3bfaf5e548cefc8e;hp=7ce8786f10f3ac8caced0e8de7bfdc878e67f1ad;hpb=5231ccdd1c9fdc7944118d8adb397ff87966e280;p=lwext4.git diff --git a/lwext4/ext4.c b/lwext4/ext4.c index 7ce8786..e3c8154 100644 --- a/lwext4/ext4.c +++ b/lwext4/ext4.c @@ -44,6 +44,7 @@ #include "ext4_inode.h" #include "ext4_super.h" #include "ext4_dir_idx.h" +#include "ext4_xattr.h" #include "ext4.h" #include @@ -180,7 +181,7 @@ static int ext4_has_children(bool *has_children, struct ext4_inode_ref *enode) static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, struct ext4_inode_ref *child, const char *name, - uint32_t name_len) + uint32_t name_len, bool rename) { /* Check maximum name length */ if (name_len > EXT4_DIRECTORY_FILENAME_LEN) @@ -196,7 +197,7 @@ static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, */ if (ext4_inode_is_type(&mp->fs.sb, child->inode, EXT4_INODE_MODE_DIRECTORY) && - ext4_inode_get_links_count(child->inode) == 0) { + !rename) { rc = ext4_dir_add_entry(child, ".", strlen("."), child); if (rc != EOK) { ext4_dir_remove_entry(parent, name, strlen(name)); @@ -231,6 +232,10 @@ static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, child->dirty = true; parent->dirty = true; } else { + /* + * In case we want to rename a directory, + * we reset the original '..' pointer. + */ if (ext4_inode_is_type(&mp->fs.sb, child->inode, EXT4_INODE_MODE_DIRECTORY)) { int has_flag_index = @@ -253,7 +258,7 @@ static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, } else { #if CONFIG_DIR_INDEX_ENABLE - rc = ext4_dir_dx_reset_parent_inode(parent, + rc = ext4_dir_dx_reset_parent_inode(child, parent->index); if (rc != EOK) return rc; @@ -263,7 +268,8 @@ static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent, ext4_fs_inode_links_count_inc(parent); parent->dirty = true; - } else { + } + if (!rename) { ext4_fs_inode_links_count_inc(child); child->dirty = true; } @@ -284,7 +290,7 @@ static int ext4_unlink(struct ext4_mountpoint *mp, /* 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); @@ -445,18 +451,25 @@ int ext4_umount(const char *mount_point) return ext4_block_fini(mp->fs.bdev); } +static struct ext4_mountpoint *ext4_get_mount(const char *path) +{ + int i; + for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { + + if (!_mp[i].mounted) + continue; + + if (!strncmp(_mp[i].name, path, strlen(_mp[i].name))) + return &_mp[i]; + } + return 0; +} + int ext4_mount_point_stats(const char *mount_point, struct ext4_mount_stats *stats) { - uint32_t i; - struct ext4_mountpoint *mp = 0; + struct ext4_mountpoint *mp = ext4_get_mount(mount_point); - for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { - if (!strcmp(_mp[i].name, mount_point)) { - mp = &_mp[i]; - break; - } - } if (!mp) return ENOENT; @@ -498,20 +511,6 @@ int ext4_mount_setup_locks(const char *mount_point, /********************************FILE OPERATIONS*****************************/ -static struct ext4_mountpoint *ext4_get_mount(const char *path) -{ - int i; - for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) { - - if (!_mp[i].mounted) - continue; - - if (!strncmp(_mp[i].name, path, strlen(_mp[i].name))) - return &_mp[i]; - } - return 0; -} - static int ext4_path_check(const char *path, bool *is_goal) { int i; @@ -574,7 +573,7 @@ static bool ext4_parse_flags(const char *flags, uint32_t *file_flags) } /* - * NOTICE: if filetype is equal to EXT4_DIRECTORY_FILETYPE_UNKNOWN, + * NOTICE: if filetype is equal to EXT4_DIRENTRY_UNKNOWN, * any filetype of the target dir entry will be accepted. */ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, @@ -582,7 +581,7 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, uint32_t *name_off) { bool is_goal = false; - uint8_t inode_type = EXT4_DIRECTORY_FILETYPE_DIR; + uint8_t inode_type = EXT4_DIRENTRY_UNKNOWN; uint32_t next_inode; int r; @@ -621,8 +620,8 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, if (!len) { /*If root open was request.*/ if (is_goal && - ((filetype == EXT4_DIRECTORY_FILETYPE_DIR) || - (filetype == EXT4_DIRECTORY_FILETYPE_UNKNOWN))) + ((filetype == EXT4_DIRENTRY_DIR) || + (filetype == EXT4_DIRENTRY_UNKNOWN))) break; r = ENOENT; @@ -632,6 +631,9 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, r = ext4_dir_find_entry(&result, &ref, path, len); if (r != EOK) { + /*Destroy last result*/ + ext4_dir_destroy_result(&ref, &result); + if (r != ENOENT) break; @@ -642,16 +644,14 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, 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_DIRENTRY_DIR); if (r != EOK) break; - /*Destroy last result*/ - ext4_dir_destroy_result(&ref, &result); /*Link with root dir.*/ - r = ext4_link(mp, &ref, &child_ref, path, len); + r = ext4_link(mp, &ref, &child_ref, path, len, false); if (r != EOK) { /*Fail. Free new inode.*/ ext4_fs_free_inode(&child_ref); @@ -679,11 +679,11 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, break; /*If expected file error*/ - if (inode_type != EXT4_DIRECTORY_FILETYPE_DIR && !is_goal) { + if (inode_type != EXT4_DIRENTRY_DIR && !is_goal) { r = ENOENT; break; } - if (filetype != EXT4_DIRECTORY_FILETYPE_UNKNOWN) { + if (filetype != EXT4_DIRENTRY_UNKNOWN) { if ((inode_type != filetype) && is_goal) { r = ENOENT; break; @@ -715,7 +715,7 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, if (is_goal) { if ((f->flags & O_TRUNC) && - (inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE)) { + (inode_type == EXT4_DIRENTRY_REG_FILE)) { r = ext4_fs_truncate_inode(&ref, 0); if (r != EOK) { @@ -731,6 +731,7 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags, if (f->flags & O_APPEND) f->fpos = f->fsize; + } r = ext4_fs_put_inode_ref(&ref); @@ -749,19 +750,20 @@ static int ext4_generic_open(ext4_file *f, const char *path, const char *flags, return EINVAL; if (file_expect == true) - filetype = EXT4_DIRECTORY_FILETYPE_REG_FILE; + filetype = EXT4_DIRENTRY_REG_FILE; else - filetype = EXT4_DIRECTORY_FILETYPE_DIR; + filetype = EXT4_DIRENTRY_DIR; return ext4_generic_open2(f, path, iflags, filetype, parent_inode, name_off); } static int __ext4_create_hardlink(const char *path, - struct ext4_inode_ref *child_ref) + struct ext4_inode_ref *child_ref, + bool rename) { bool is_goal = false; - uint8_t inode_type = EXT4_DIRECTORY_FILETYPE_DIR; + uint8_t inode_type = EXT4_DIRENTRY_DIR; uint32_t next_inode; int r; @@ -799,14 +801,19 @@ static int __ext4_create_hardlink(const char *path, r = ext4_dir_find_entry(&result, &ref, path, len); if (r != EOK) { + /*Destroy last result*/ + ext4_dir_destroy_result(&ref, &result); + if (r != ENOENT || !is_goal) break; + /*Link with root dir.*/ + r = ext4_link(mp, &ref, child_ref, path, len, rename); + break; + } else if (r == EOK && is_goal) { /*Destroy last result*/ ext4_dir_destroy_result(&ref, &result); - - /*Link with root dir.*/ - r = ext4_link(mp, &ref, child_ref, path, len); + r = EEXIST; break; } @@ -818,7 +825,7 @@ static int __ext4_create_hardlink(const char *path, if (r != EOK) break; - if (inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE) { + if (inode_type == EXT4_DIRENTRY_REG_FILE) { if (is_goal) r = EEXIST; else @@ -850,10 +857,10 @@ static int __ext4_create_hardlink(const char *path, return r; } -static int __ext4_remove_hardlink(const char *path, - uint32_t name_off, - struct ext4_inode_ref *parent_ref, - struct ext4_inode_ref *child_ref) +static int ext4_remove_orig_reference(const char *path, + uint32_t name_off, + struct ext4_inode_ref *parent_ref, + struct ext4_inode_ref *child_ref) { bool is_goal; int r; @@ -868,16 +875,17 @@ static int __ext4_remove_hardlink(const char *path, len = ext4_path_check(path, &is_goal); - /*Unlink from parent*/ - r = ext4_unlink(mp, parent_ref, child_ref, path, len); + /* Remove entry from parent directory */ + r = ext4_dir_remove_entry(parent_ref, path, len); if (r != EOK) goto Finish; + if (ext4_inode_is_type(&mp->fs.sb, child_ref->inode, + EXT4_INODE_MODE_DIRECTORY)) { + ext4_fs_inode_links_count_dec(parent_ref); + parent_ref->dirty = true; + } Finish: - if (r != EOK) - ext4_fs_put_inode_ref(child_ref); - - ext4_fs_put_inode_ref(parent_ref); return r; } @@ -902,7 +910,7 @@ int ext4_flink(const char *path, const char *hardlink_path) EXT4_MP_LOCK(mp); r = ext4_generic_open2(&f, path, O_RDONLY, - EXT4_DIRECTORY_FILETYPE_UNKNOWN, + EXT4_DIRENTRY_UNKNOWN, &parent_inode, &name_off); if (r != EOK) goto Finish; @@ -917,7 +925,14 @@ int ext4_flink(const char *path, const char *hardlink_path) child_loaded = true; - r = __ext4_create_hardlink(hardlink_path, &child_ref); + /* Creating hardlink for directory is not allowed. */ + if (ext4_inode_is_type(&mp->fs.sb, child_ref.inode, + EXT4_INODE_MODE_DIRECTORY)) { + r = EINVAL; + goto Finish; + } + + r = __ext4_create_hardlink(hardlink_path, &child_ref, false); Finish: if (child_loaded) @@ -944,7 +959,7 @@ int ext4_frename(const char *path, const char *new_path) EXT4_MP_LOCK(mp); r = ext4_generic_open2(&f, path, O_RDONLY, - EXT4_DIRECTORY_FILETYPE_UNKNOWN, + EXT4_DIRENTRY_UNKNOWN, &parent_inode, &name_off); if (r != EOK) goto Finish; @@ -966,11 +981,12 @@ int ext4_frename(const char *path, const char *new_path) child_loaded = true; - r = __ext4_create_hardlink(new_path, &child_ref); + r = __ext4_create_hardlink(new_path, &child_ref, true); if (r != EOK) goto Finish; - r = __ext4_remove_hardlink(path, name_off, &parent_ref, &child_ref); + r = ext4_remove_orig_reference(path, name_off, + &parent_ref, &child_ref); if (r != EOK) goto Finish; @@ -1028,7 +1044,9 @@ int ext4_fremove(const char *path) 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_DIRENTRY_UNKNOWN, + &parent_inode, &name_off); if (r != EOK) { EXT4_MP_UNLOCK(mp); return r; @@ -1083,18 +1101,32 @@ Finish: return r; } -int ext4_fill_raw_inode(const char *mount_point, uint32_t ino, +int ext4_fill_raw_inode(const char *path, + uint32_t *ret_ino, struct ext4_inode *inode) { int r; + ext4_file f; struct ext4_inode_ref inode_ref; - struct ext4_mountpoint *mp = ext4_get_mount(mount_point); + struct ext4_mountpoint *mp = ext4_get_mount(path); + uint32_t ino; if (!mp) return ENOENT; EXT4_MP_LOCK(mp); + r = ext4_generic_open2(&f, path, O_RDONLY, + EXT4_DIRENTRY_UNKNOWN, + NULL, NULL); + if (r != EOK) { + EXT4_MP_UNLOCK(mp); + return r; + } + + ino = f.inode; + ext4_fclose(&f); + /*Load parent*/ r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref); if (r != EOK) { @@ -1106,6 +1138,10 @@ int ext4_fill_raw_inode(const char *mount_point, uint32_t ino, ext4_fs_put_inode_ref(&inode_ref); EXT4_MP_UNLOCK(mp); + + if (ret_ino) + *ret_ino = ino; + return r; } @@ -1125,7 +1161,7 @@ int ext4_fopen(ext4_file *f, const char *path, const char *flags) return r; } -int ext4_fopen2(ext4_file *f, const char *path, int flags, bool file_expect) +int ext4_fopen2(ext4_file *f, const char *path, int flags) { struct ext4_mountpoint *mp = ext4_get_mount(path); int r; @@ -1134,10 +1170,7 @@ int ext4_fopen2(ext4_file *f, const char *path, int flags, bool file_expect) if (!mp) return ENOENT; - if (file_expect == true) - filetype = EXT4_DIRECTORY_FILETYPE_REG_FILE; - else - filetype = EXT4_DIRECTORY_FILETYPE_DIR; + filetype = EXT4_DIRENTRY_REG_FILE; EXT4_MP_LOCK(mp); ext4_block_cache_write_back(mp->fs.bdev, 1); @@ -1178,23 +1211,6 @@ static int ext4_ftruncate_no_lock(ext4_file *f, uint64_t size) 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) @@ -1236,7 +1252,7 @@ int ext4_ftruncate(ext4_file *f, uint64_t size) return r; } -int ext4_fread(ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt) +int ext4_fread(ext4_file *f, void *buf, size_t size, size_t *rcnt) { uint32_t u; uint32_t fblock; @@ -1278,6 +1294,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_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; @@ -1370,7 +1410,7 @@ Finish: return r; } -int ext4_fwrite(ext4_file *f, const void *buf, uint32_t size, uint32_t *wcnt) +int ext4_fwrite(ext4_file *f, const void *buf, size_t size, size_t *wcnt) { uint32_t u; uint32_t fblock; @@ -1576,27 +1616,34 @@ uint64_t ext4_ftell(ext4_file *f) { return f->fpos; } uint64_t ext4_fsize(ext4_file *f) { return f->fsize; } -int ext4_fchmod(ext4_file *f, uint32_t mode) +int ext4_chmod(const char *path, uint32_t mode) { int r; uint32_t ino; + ext4_file f; struct ext4_sblock *sb; struct ext4_inode_ref inode_ref; - struct ext4_mountpoint *mp = f->mp; + struct ext4_mountpoint *mp = ext4_get_mount(path); if (!mp) return ENOENT; EXT4_MP_LOCK(mp); - ino = f->inode; + r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) { + EXT4_MP_UNLOCK(mp); + return r; + } + ino = f.inode; + sb = &mp->fs.sb; + ext4_fclose(&f); r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref); if (r != EOK) { EXT4_MP_UNLOCK(mp); return r; } - sb = &f->mp->fs.sb; ext4_inode_set_mode(sb, inode_ref.inode, mode); inode_ref.dirty = true; @@ -1605,19 +1652,26 @@ int ext4_fchmod(ext4_file *f, uint32_t mode) return r; } -int ext4_fchown(ext4_file *f, uint32_t uid, uint32_t gid) +int ext4_chown(const char *path, uint32_t uid, uint32_t gid) { int r; + ext4_file f; uint32_t ino; struct ext4_inode_ref inode_ref; - struct ext4_mountpoint *mp = f->mp; + struct ext4_mountpoint *mp = ext4_get_mount(path); if (!mp) return ENOENT; EXT4_MP_LOCK(mp); - ino = f->inode; + r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) { + EXT4_MP_UNLOCK(mp); + return r; + } + ino = f.inode; + ext4_fclose(&f); r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref); if (r != EOK) { EXT4_MP_UNLOCK(mp); @@ -1633,19 +1687,26 @@ int ext4_fchown(ext4_file *f, uint32_t uid, uint32_t gid) return r; } -int ext4_file_set_atime(ext4_file *f, uint32_t atime) +int ext4_file_set_atime(const char *path, uint32_t atime) { int r; + ext4_file f; uint32_t ino; struct ext4_inode_ref inode_ref; - struct ext4_mountpoint *mp = f->mp; + struct ext4_mountpoint *mp = ext4_get_mount(path); if (!mp) return ENOENT; EXT4_MP_LOCK(mp); - ino = f->inode; + r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) { + EXT4_MP_UNLOCK(mp); + return r; + } + ino = f.inode; + ext4_fclose(&f); r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref); if (r != EOK) { EXT4_MP_UNLOCK(mp); @@ -1660,19 +1721,26 @@ int ext4_file_set_atime(ext4_file *f, uint32_t atime) return r; } -int ext4_file_set_mtime(ext4_file *f, uint32_t mtime) +int ext4_file_set_mtime(const char *path, uint32_t mtime) { int r; + ext4_file f; uint32_t ino; struct ext4_inode_ref inode_ref; - struct ext4_mountpoint *mp = f->mp; + struct ext4_mountpoint *mp = ext4_get_mount(path); if (!mp) return ENOENT; EXT4_MP_LOCK(mp); - ino = f->inode; + r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) { + EXT4_MP_UNLOCK(mp); + return r; + } + ino = f.inode; + ext4_fclose(&f); r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref); if (r != EOK) { EXT4_MP_UNLOCK(mp); @@ -1687,19 +1755,26 @@ int ext4_file_set_mtime(ext4_file *f, uint32_t mtime) return r; } -int ext4_file_set_ctime(ext4_file *f, uint32_t ctime) +int ext4_file_set_ctime(const char *path, uint32_t ctime) { int r; + ext4_file f; uint32_t ino; struct ext4_inode_ref inode_ref; - struct ext4_mountpoint *mp = f->mp; + struct ext4_mountpoint *mp = ext4_get_mount(path); if (!mp) return ENOENT; EXT4_MP_LOCK(mp); - ino = f->inode; + r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) { + EXT4_MP_UNLOCK(mp); + return r; + } + ino = f.inode; + ext4_fclose(&f); r = ext4_fs_get_inode_ref(&mp->fs, ino, &inode_ref); if (r != EOK) { EXT4_MP_UNLOCK(mp); @@ -1714,6 +1789,385 @@ 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); + 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_DIRENTRY_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; +} + +int ext4_readlink(const char *path, char *buf, size_t bufsize, size_t *rcnt) +{ + struct ext4_mountpoint *mp = ext4_get_mount(path); + int r; + ext4_file f; + int filetype; + + if (!mp) + return ENOENT; + + if (!buf) + return EINVAL; + + memset(buf, 0, sizeof(bufsize)); + + filetype = EXT4_DIRENTRY_SYMLINK; + + EXT4_MP_LOCK(mp); + ext4_block_cache_write_back(mp->fs.bdev, 1); + r = ext4_generic_open2(&f, path, O_RDONLY, filetype, 0, 0); + if (r == EOK) + r = ext4_fread(&f, buf, bufsize, rcnt); + else + goto Finish; + + ext4_fclose(&f); + +Finish: + ext4_block_cache_write_back(mp->fs.bdev, 0); + EXT4_MP_UNLOCK(mp); + return r; +} + +int ext4_setxattr(const char *path, const char *name, size_t name_len, + const void *data, size_t data_size, bool replace) +{ + int r = EOK; + ext4_file f; + uint32_t inode; + uint8_t name_index; + const char *dissected_name = NULL; + size_t dissected_len = 0; + struct ext4_xattr_ref xattr_ref; + struct ext4_inode_ref inode_ref; + struct ext4_mountpoint *mp = ext4_get_mount(path); + if (!mp) + return ENOENT; + + dissected_name = ext4_extract_xattr_name(name, name_len, + &name_index, &dissected_len); + if (!dissected_len) + return EINVAL; + + EXT4_MP_LOCK(mp); + r = ext4_generic_open2(&f, path, O_RDWR, + EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) + goto Finish; + inode = f.inode; + ext4_fclose(&f); + + r = ext4_fs_get_inode_ref(&mp->fs, inode, &inode_ref); + if (r != EOK) + goto Finish; + + r = ext4_fs_get_xattr_ref(&mp->fs, &inode_ref, + &xattr_ref); + if (r != EOK) { + ext4_fs_put_inode_ref(&inode_ref); + goto Finish; + } + + r = ext4_fs_set_xattr(&xattr_ref, name_index, dissected_name, + dissected_len, data, data_size, replace); + + ext4_fs_put_xattr_ref(&xattr_ref); + ext4_fs_put_inode_ref(&inode_ref); +Finish: + EXT4_MP_UNLOCK(mp); + return r; +} + +int ext4_getxattr(const char *path, const char *name, size_t name_len, + void *buf, size_t buf_size, size_t *data_size) +{ + int r = EOK; + ext4_file f; + uint32_t inode; + uint8_t name_index; + const char *dissected_name = NULL; + size_t dissected_len = 0; + struct ext4_xattr_ref xattr_ref; + struct ext4_inode_ref inode_ref; + struct ext4_mountpoint *mp = ext4_get_mount(path); + if (!mp) + return ENOENT; + + dissected_name = ext4_extract_xattr_name(name, name_len, + &name_index, &dissected_len); + if (!dissected_len) + return EINVAL; + + EXT4_MP_LOCK(mp); + r = ext4_generic_open2(&f, path, O_RDWR, + EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) + goto Finish; + inode = f.inode; + ext4_fclose(&f); + + r = ext4_fs_get_inode_ref(&mp->fs, inode, &inode_ref); + if (r != EOK) + goto Finish; + + r = ext4_fs_get_xattr_ref(&mp->fs, &inode_ref, + &xattr_ref); + if (r != EOK) { + ext4_fs_put_inode_ref(&inode_ref); + goto Finish; + } + + r = ext4_fs_get_xattr(&xattr_ref, name_index, + dissected_name, dissected_len, + buf, buf_size, data_size); + + ext4_fs_put_xattr_ref(&xattr_ref); + ext4_fs_put_inode_ref(&inode_ref); +Finish: + EXT4_MP_UNLOCK(mp); + return r; +} + +struct ext4_listxattr_iterator { + char *list; + char *list_ptr; + size_t size; + size_t ret_size; + bool list_too_small; + bool get_required_size; +}; + +static int ext4_iterate_ea_list(struct ext4_xattr_ref *ref, + struct ext4_xattr_item *item) +{ + struct ext4_listxattr_iterator *lxi; + lxi = ref->iter_arg; + if (!lxi->get_required_size) { + size_t prefix_len; + const char *prefix; + prefix = ext4_get_xattr_name_prefix(item->name_index, + &prefix_len); + if (lxi->ret_size + + prefix_len + item->name_len + 1 > + lxi->size) { + + lxi->list_too_small = 1; + return EXT4_XATTR_ITERATE_STOP; + } + if (prefix) { + memcpy(lxi->list_ptr, prefix, prefix_len); + lxi->list_ptr += prefix_len; + lxi->ret_size += prefix_len; + } + memcpy(lxi->list_ptr, item->name, item->name_len); + lxi->list_ptr[item->name_len] = 0; + lxi->list_ptr += item->name_len + 1; + } + lxi->ret_size += item->name_len + 1; + return EXT4_XATTR_ITERATE_CONT; +} + +int ext4_listxattr(const char *path, char *list, size_t size, size_t *ret_size) +{ + int r = EOK; + ext4_file f; + uint32_t inode; + struct ext4_xattr_ref xattr_ref; + struct ext4_inode_ref inode_ref; + struct ext4_listxattr_iterator lxi; + struct ext4_mountpoint *mp = ext4_get_mount(path); + if (!mp) + return ENOENT; + + lxi.list = list; + lxi.list_ptr = list; + lxi.size = size; + lxi.ret_size = 0; + lxi.list_too_small = false; + lxi.get_required_size = (!size) ? true : false; + + EXT4_MP_LOCK(mp); + r = ext4_generic_open2(&f, path, O_RDWR, + EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) + goto Finish; + inode = f.inode; + ext4_fclose(&f); + + r = ext4_fs_get_inode_ref(&mp->fs, inode, &inode_ref); + if (r != EOK) + goto Finish; + + r = ext4_fs_get_xattr_ref(&mp->fs, &inode_ref, + &xattr_ref); + if (r != EOK) { + ext4_fs_put_inode_ref(&inode_ref); + goto Finish; + } + + xattr_ref.iter_arg = &lxi; + ext4_fs_xattr_iterate(&xattr_ref, ext4_iterate_ea_list); + if (lxi.list_too_small) + r = ERANGE; + + if (r == EOK) { + if (ret_size) + *ret_size = lxi.ret_size; + + } + ext4_fs_put_xattr_ref(&xattr_ref); + ext4_fs_put_inode_ref(&inode_ref); +Finish: + EXT4_MP_UNLOCK(mp); + return r; + +} + +int ext4_removexattr(const char *path, const char *name, size_t name_len) +{ + int r = EOK; + ext4_file f; + uint32_t inode; + uint8_t name_index; + const char *dissected_name = NULL; + size_t dissected_len = 0; + struct ext4_xattr_ref xattr_ref; + struct ext4_inode_ref inode_ref; + struct ext4_mountpoint *mp = ext4_get_mount(path); + if (!mp) + return ENOENT; + + dissected_name = ext4_extract_xattr_name(name, name_len, + &name_index, &dissected_len); + if (!dissected_len) + return EINVAL; + + EXT4_MP_LOCK(mp); + r = ext4_generic_open2(&f, path, O_RDWR, + EXT4_DIRENTRY_UNKNOWN, 0, 0); + if (r != EOK) + goto Finish; + inode = f.inode; + ext4_fclose(&f); + + r = ext4_fs_get_inode_ref(&mp->fs, inode, &inode_ref); + if (r != EOK) + goto Finish; + + r = ext4_fs_get_xattr_ref(&mp->fs, &inode_ref, + &xattr_ref); + if (r != EOK) { + ext4_fs_put_inode_ref(&inode_ref); + goto Finish; + } + + r = ext4_fs_remove_xattr(&xattr_ref, name_index, dissected_name, + dissected_len); + + ext4_fs_put_xattr_ref(&xattr_ref); + ext4_fs_put_inode_ref(&inode_ref); +Finish: + EXT4_MP_UNLOCK(mp); + return r; + +} + /*********************************DIRECTORY OPERATION************************/ int ext4_dir_rm(const char *path) @@ -1964,7 +2418,10 @@ int ext4_dir_open(ext4_dir *d, const char *path) return r; } -int ext4_dir_close(ext4_dir *d) { return ext4_fclose(&d->f); } +int ext4_dir_close(ext4_dir *d) +{ + return ext4_fclose(&d->f); +} const ext4_direntry *ext4_dir_entry_next(ext4_dir *d) { @@ -2009,6 +2466,11 @@ Finish: return de; } +void ext4_dir_entry_rewind(ext4_dir *d) +{ + d->next_off = 0; +} + /** * @} */