ext4: fix ext4_fsymlink creation
[lwext4.git] / src / ext4.c
index e877f13703fccea5a3d5106fb7ef414fae070778..b270361d331783ca580555d138591caa741f44ae 100644 (file)
  * @brief Ext4 high level operations (file, directory, mountpoints...)
  */
 
-#include "ext4_config.h"
-#include "ext4_types.h"
-#include "ext4_misc.h"
-#include "ext4_errno.h"
-#include "ext4_oflags.h"
-#include "ext4_debug.h"
-
-#include "ext4.h"
-#include "ext4_trans.h"
-#include "ext4_blockdev.h"
-#include "ext4_fs.h"
-#include "ext4_dir.h"
-#include "ext4_inode.h"
-#include "ext4_super.h"
-#include "ext4_block_group.h"
-#include "ext4_dir_idx.h"
-#include "ext4_xattr.h"
-#include "ext4_journal.h"
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_misc.h>
+#include <ext4_errno.h>
+#include <ext4_oflags.h>
+#include <ext4_debug.h>
+
+#include <ext4.h>
+#include <ext4_trans.h>
+#include <ext4_blockdev.h>
+#include <ext4_fs.h>
+#include <ext4_dir.h>
+#include <ext4_inode.h>
+#include <ext4_super.h>
+#include <ext4_block_group.h>
+#include <ext4_dir_idx.h>
+#include <ext4_xattr.h>
+#include <ext4_journal.h>
 
 
 #include <stdlib.h>
@@ -379,11 +379,9 @@ int ext4_mount(const char *dev_name, const char *mount_point,
                return ENOTSUP;
 
        for (size_t i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
-               if (s_bdevices[i].name) {
-                       if (!strcmp(dev_name, s_bdevices[i].name)) {
-                               bd = s_bdevices[i].bd;
-                               break;
-                       }
+               if (!strcmp(dev_name, s_bdevices[i].name)) {
+                       bd = s_bdevices[i].bd;
+                       break;
                }
        }
 
@@ -966,9 +964,6 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
        if (parent_inode)
                *parent_inode = ref.index;
 
-       if (flags & O_CREAT)
-               ext4_trans_start(mp);
-
        len = ext4_path_check(path, &is_goal);
        while (1) {
 
@@ -998,9 +993,11 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
                        struct ext4_inode_ref child_ref;
                        r = ext4_fs_alloc_inode(fs, &child_ref,
                                        is_goal ? ftype : EXT4_DE_DIR);
+
                        if (r != EOK)
                                break;
 
+                       ext4_fs_inode_blocks_init(fs, &child_ref);
 
                        /*Link with root dir.*/
                        r = ext4_link(mp, &ref, &child_ref, path, len, false);
@@ -1068,7 +1065,7 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
 
                if (name_off)
                        *name_off += len + 1;
-       };
+       }
 
        if (r != EOK) {
                ext4_fs_put_inode_ref(&ref);
@@ -1092,19 +1089,9 @@ 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);
-       if (flags & O_CREAT) {
-               if (r == EOK)
-                       ext4_trans_stop(mp);
-               else
-                       ext4_trans_abort(mp);
-
-       }
-
-       return r;
+       return ext4_fs_put_inode_ref(&ref);
 }
 
 /****************************************************************************/
@@ -1115,6 +1102,9 @@ static int ext4_generic_open(ext4_file *f, const char *path, const char *flags,
 {
        uint32_t iflags;
        int filetype;
+       int r;
+       struct ext4_mountpoint *mp = ext4_get_mount(path);
+
        if (ext4_parse_flags(flags, &iflags) == false)
                return EINVAL;
 
@@ -1123,8 +1113,20 @@ static int ext4_generic_open(ext4_file *f, const char *path, const char *flags,
        else
                filetype = EXT4_DE_DIR;
 
-       return ext4_generic_open2(f, path, iflags, filetype, parent_inode,
-                                 name_off);
+       if (iflags & O_CREAT)
+               ext4_trans_start(mp);
+
+       r = ext4_generic_open2(f, path, iflags, filetype, parent_inode,
+                               name_off);
+
+       if (iflags & O_CREAT) {
+               if (r == EOK)
+                       ext4_trans_stop(mp);
+               else
+                       ext4_trans_abort(mp);
+       }
+
+       return r;
 }
 
 static int ext4_create_hardlink(const char *path,
@@ -1283,15 +1285,16 @@ int ext4_flink(const char *path, const char *hardlink_path)
                return EINVAL;
 
        EXT4_MP_LOCK(mp);
-       ext4_trans_start(mp);
-
        r = ext4_generic_open2(&f, path, O_RDONLY, EXT4_DE_UNKNOWN,
                               &parent_inode, &name_off);
-       if (r != EOK)
-               goto Finish;
+       if (r != EOK) {
+               EXT4_MP_UNLOCK(mp);
+               return r;
+       }
 
        child_inode = f.inode;
        ext4_fclose(&f);
+       ext4_trans_start(mp);
 
        /*We have file to unlink. Load it.*/
        r = ext4_fs_get_inode_ref(&mp->fs, child_inode, &child_ref);
@@ -1340,15 +1343,17 @@ int ext4_frename(const char *path, const char *new_path)
                return EROFS;
 
        EXT4_MP_LOCK(mp);
-       ext4_trans_start(mp);
 
        r = ext4_generic_open2(&f, path, O_RDONLY, EXT4_DE_UNKNOWN,
                                &parent_inode, &name_off);
-       if (r != EOK)
-               goto Finish;
+       if (r != EOK) {
+               EXT4_MP_UNLOCK(mp);
+               return r;
+       }
 
        child_inode = f.inode;
        ext4_fclose(&f);
+       ext4_trans_start(mp);
 
        /*Load parent*/
        r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent_ref);
@@ -1434,6 +1439,7 @@ int ext4_fremove(const char *path)
 {
        ext4_file f;
        uint32_t parent_inode;
+       uint32_t child_inode;
        uint32_t name_off;
        bool is_goal;
        int r;
@@ -1449,16 +1455,17 @@ int ext4_fremove(const char *path)
                return EROFS;
 
        EXT4_MP_LOCK(mp);
-       ext4_trans_start(mp);
-
-       r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DE_UNKNOWN,
+       r = ext4_generic_open2(&f, path, O_RDONLY, EXT4_DE_UNKNOWN,
                               &parent_inode, &name_off);
        if (r != EOK) {
-               ext4_trans_abort(mp);
                EXT4_MP_UNLOCK(mp);
                return r;
        }
 
+       child_inode = f.inode;
+       ext4_fclose(&f);
+       ext4_trans_start(mp);
+
        /*Load parent*/
        r = ext4_fs_get_inode_ref(&mp->fs, parent_inode, &parent);
        if (r != EOK) {
@@ -1468,7 +1475,7 @@ int ext4_fremove(const char *path)
        }
 
        /*We have file to delete. Load it.*/
-       r = ext4_fs_get_inode_ref(&mp->fs, f.inode, &child);
+       r = ext4_fs_get_inode_ref(&mp->fs, child_inode, &child);
        if (r != EOK) {
                ext4_fs_put_inode_ref(&parent);
                ext4_trans_abort(mp);
@@ -1561,12 +1568,23 @@ int ext4_fopen2(ext4_file *file, const char *path, int flags)
         filetype = EXT4_DE_REG_FILE;
 
        EXT4_MP_LOCK(mp);
-
        ext4_block_cache_write_back(mp->fs.bdev, 1);
+
+       if (flags & O_CREAT)
+               ext4_trans_start(mp);
+
        r = ext4_generic_open2(file, path, flags, filetype, NULL, NULL);
-       ext4_block_cache_write_back(mp->fs.bdev, 0);
 
+       if (flags & O_CREAT) {
+               if (r == EOK)
+                       ext4_trans_stop(mp);
+               else
+                       ext4_trans_abort(mp);
+       }
+
+       ext4_block_cache_write_back(mp->fs.bdev, 0);
        EXT4_MP_UNLOCK(mp);
+
        return r;
 }
 
@@ -1998,23 +2016,25 @@ Finish:
        return r;
 }
 
-int ext4_fseek(ext4_file *file, uint64_t offset, uint32_t origin)
+int ext4_fseek(ext4_file *file, int64_t offset, uint32_t origin)
 {
        switch (origin) {
        case SEEK_SET:
-               if (offset > file->fsize)
+               if (offset < 0 || (uint64_t)offset > file->fsize)
                        return EINVAL;
 
                file->fpos = offset;
                return EOK;
        case SEEK_CUR:
-               if ((offset + file->fpos) > file->fsize)
+               if ((offset < 0 && (uint64_t)(-offset) > file->fpos) ||
+                   (offset > 0 &&
+                    (uint64_t)offset > (file->fsize - file->fpos)))
                        return EINVAL;
 
                file->fpos += offset;
                return EOK;
        case SEEK_END:
-               if (offset > file->fsize)
+               if (offset < 0 || (uint64_t)offset > file->fsize)
                        return EINVAL;
 
                file->fpos = file->fsize - offset;
@@ -2041,12 +2061,11 @@ static int ext4_trans_get_inode_ref(const char *path,
        int r;
        ext4_file f;
 
-       ext4_trans_start(mp);
-       r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DE_UNKNOWN, NULL, NULL);
-       if (r != EOK) {
-               ext4_trans_abort(mp);
+       r = ext4_generic_open2(&f, path, O_RDONLY, EXT4_DE_UNKNOWN, NULL, NULL);
+       if (r != EOK)
                return r;
-       }
+
+       ext4_trans_start(mp);
 
        r = ext4_fs_get_inode_ref(&mp->fs, f.inode, inode_ref);
        if (r != EOK) {
@@ -2108,6 +2127,22 @@ int ext4_raw_inode_fill(const char *path, uint32_t *ret_ino,
        return r;
 }
 
+int ext4_inode_exist(const char *path, int type)
+{
+       int r;
+       ext4_file f;
+       struct ext4_mountpoint *mp = ext4_get_mount(path);
+
+       if (!mp)
+               return ENOENT;
+
+       EXT4_MP_LOCK(mp);
+       r = ext4_generic_open2(&f, path, O_RDONLY, type, NULL, NULL);
+       EXT4_MP_UNLOCK(mp);
+
+       return r;
+}
+
 int ext4_mode_set(const char *path, uint32_t mode)
 {
        int r;
@@ -2439,15 +2474,16 @@ static int ext4_fsymlink_set(ext4_file *f, const void *buf, uint32_t size)
                memcpy(ref.inode->blocks, buf, size);
                ext4_inode_clear_flag(ref.inode, EXT4_INODE_FLAG_EXTENTS);
        } else {
+               uint64_t off;
                ext4_fs_inode_blocks_init(&f->mp->fs, &ref);
                r = ext4_fs_append_inode_dblk(&ref, &fblock, &sblock);
                if (r != EOK)
                        goto Finish;
 
-               r = ext4_block_writebytes(f->mp->fs.bdev, 0, buf, size);
+               off = fblock * block_size;
+               r = ext4_block_writebytes(f->mp->fs.bdev, off, buf, size);
                if (r != EOK)
                        goto Finish;
-
        }
 
        /*Stop write back cache mode*/
@@ -2484,10 +2520,10 @@ int ext4_fsymlink(const char *target, const char *path)
        filetype = EXT4_DE_SYMLINK;
 
        EXT4_MP_LOCK(mp);
+       ext4_block_cache_write_back(mp->fs.bdev, 1);
        ext4_trans_start(mp);
 
-       ext4_block_cache_write_back(mp->fs.bdev, 1);
-       r = ext4_generic_open2(&f, path, O_RDWR|O_CREAT, filetype, NULL, NULL);
+       r = ext4_generic_open2(&f, path, O_RDWR | O_CREAT, filetype, NULL, NULL);
        if (r == EOK)
                r = ext4_fsymlink_set(&f, target, strlen(target));
        else
@@ -2496,13 +2532,12 @@ int ext4_fsymlink(const char *target, const char *path)
        ext4_fclose(&f);
 
 Finish:
-       ext4_block_cache_write_back(mp->fs.bdev, 0);
-
        if (r != EOK)
                ext4_trans_abort(mp);
        else
                ext4_trans_stop(mp);
 
+       ext4_block_cache_write_back(mp->fs.bdev, 0);
        EXT4_MP_UNLOCK(mp);
        return r;
 }
@@ -2534,11 +2569,6 @@ int ext4_readlink(const char *path, char *buf, size_t bufsize, size_t *rcnt)
 
 Finish:
        ext4_block_cache_write_back(mp->fs.bdev, 0);
-       if (r != EOK)
-               ext4_trans_abort(mp);
-       else
-               ext4_trans_stop(mp);
-
        EXT4_MP_UNLOCK(mp);
        return r;
 }
@@ -2598,27 +2628,27 @@ int ext4_mknod(const char *path, int filetype, uint32_t dev)
                return EINVAL;
 
        EXT4_MP_LOCK(mp);
+       ext4_block_cache_write_back(mp->fs.bdev, 1);
        ext4_trans_start(mp);
 
-       ext4_block_cache_write_back(mp->fs.bdev, 1);
-       r = ext4_generic_open2(&f, path, O_RDWR|O_CREAT, filetype, NULL, NULL);
+       r = ext4_generic_open2(&f, path, O_RDWR | O_CREAT, filetype, NULL, NULL);
        if (r == EOK) {
                if (filetype == EXT4_DE_CHRDEV ||
                    filetype == EXT4_DE_BLKDEV)
                        r = ext4_mknod_set(&f, dev);
-       } else
+       } else {
                goto Finish;
+       }
 
        ext4_fclose(&f);
 
 Finish:
-       ext4_block_cache_write_back(mp->fs.bdev, 0);
-
        if (r != EOK)
                ext4_trans_abort(mp);
        else
                ext4_trans_stop(mp);
 
+       ext4_block_cache_write_back(mp->fs.bdev, 0);
        EXT4_MP_UNLOCK(mp);
        return r;
 }
@@ -2648,13 +2678,15 @@ int ext4_setxattr(const char *path, const char *name, size_t name_len,
                return EINVAL;
 
        EXT4_MP_LOCK(mp);
-       ext4_trans_start(mp);
+       r = ext4_generic_open2(&f, path, O_RDONLY, EXT4_DE_UNKNOWN, NULL, NULL);
+       if (r != EOK) {
+               EXT4_MP_UNLOCK(mp);
+               return r;
+       }
 
-       r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DE_UNKNOWN, NULL, NULL);
-       if (r != EOK)
-               goto Finish;
        inode = f.inode;
        ext4_fclose(&f);
+       ext4_trans_start(mp);
 
        r = ext4_fs_get_inode_ref(&mp->fs, inode, &inode_ref);
        if (r != EOK)
@@ -2696,9 +2728,10 @@ int ext4_getxattr(const char *path, const char *name, size_t name_len,
                return EINVAL;
 
        EXT4_MP_LOCK(mp);
-       r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DE_UNKNOWN, NULL, NULL);
+       r = ext4_generic_open2(&f, path, O_RDONLY, EXT4_DE_UNKNOWN, NULL, NULL);
        if (r != EOK)
                goto Finish;
+
        inode = f.inode;
        ext4_fclose(&f);
 
@@ -2729,7 +2762,7 @@ int ext4_listxattr(const char *path, char *list, size_t size, size_t *ret_size)
                return ENOENT;
 
        EXT4_MP_LOCK(mp);
-       r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DE_UNKNOWN, NULL, NULL);
+       r = ext4_generic_open2(&f, path, O_RDONLY, EXT4_DE_UNKNOWN, NULL, NULL);
        if (r != EOK)
                goto Finish;
        inode = f.inode;
@@ -2818,13 +2851,15 @@ int ext4_removexattr(const char *path, const char *name, size_t name_len)
                return EINVAL;
 
        EXT4_MP_LOCK(mp);
-       ext4_trans_start(mp);
+       r = ext4_generic_open2(&f, path, O_RDONLY, EXT4_DE_UNKNOWN, NULL, NULL);
+       if (r != EOK) {
+               EXT4_MP_LOCK(mp);
+               return r;
+       }
 
-       r = ext4_generic_open2(&f, path, O_RDWR, EXT4_DE_UNKNOWN, NULL, NULL);
-       if (r != EOK)
-               goto Finish;
        inode = f.inode;
        ext4_fclose(&f);
+       ext4_trans_start(mp);
 
        r = ext4_fs_get_inode_ref(&mp->fs, inode, &inode_ref);
        if (r != EOK)
@@ -2880,14 +2915,12 @@ int ext4_dir_rm(const char *path)
        /*Check if exist.*/
        r = ext4_generic_open(&f, path, "r", false, &inode_up, &name_off);
        if (r != EOK) {
-               ext4_trans_abort(mp);
                EXT4_MP_UNLOCK(mp);
                return r;
        }
 
        path += name_off;
        len = ext4_path_check(path, &is_goal);
-
        inode_current = f.inode;
 
        ext4_block_cache_write_back(mp->fs.bdev, 1);
@@ -3100,7 +3133,6 @@ int ext4_dir_mk(const char *path)
 {
        int r;
        ext4_file f;
-
        struct ext4_mountpoint *mp = ext4_get_mount(path);
 
        if (!mp)
@@ -3110,26 +3142,16 @@ int ext4_dir_mk(const char *path)
                return EROFS;
 
        EXT4_MP_LOCK(mp);
-       ext4_trans_start(mp);
 
        /*Check if exist.*/
        r = ext4_generic_open(&f, path, "r", false, 0, 0);
-       if (r == EOK) {
-               /*Directory already created*/
-               ext4_trans_stop(mp);
-               EXT4_MP_UNLOCK(mp);
-               return r;
-       }
+       if (r == EOK)
+               goto Finish;
 
-       /*Create new dir*/
+       /*Create new directory.*/
        r = ext4_generic_open(&f, path, "w", false, 0, 0);
-       if (r != EOK) {
-               ext4_trans_abort(mp);
-               EXT4_MP_UNLOCK(mp);
-               return r;
-       }
 
-       ext4_trans_stop(mp);
+Finish:
        EXT4_MP_UNLOCK(mp);
        return r;
 }