Initial Symbolic support.
authorroot <ngkaho1234@gmail.com>
Mon, 21 Sep 2015 16:22:23 +0000 (16:22 +0000)
committerroot <ngkaho1234@gmail.com>
Mon, 21 Sep 2015 16:22:23 +0000 (16:22 +0000)
lwext4/ext4.c
lwext4/ext4.h
lwext4/ext4_dir.c
lwext4/ext4_errno.h
lwext4/ext4_fs.c
lwext4/ext4_fs.h
lwext4/ext4_inode.c
lwext4/ext4_inode.h

index b497ffadc8fa7e68a9f9a706ab8a259838ca2241..3c701eb04775eaba80635a20a23e93a0d699646f 100644 (file)
@@ -284,7 +284,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);
@@ -582,7 +582,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;
        uint32_t next_inode;
 
        int r;
@@ -642,8 +642,8 @@ 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_DIRECTORY_FILETYPE_DIR);
                        if (r != EOK)
                                break;
 
@@ -1028,7 +1028,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_DIRECTORY_FILETYPE_UNKNOWN,
+                              &parent_inode, &name_off);
        if (r != EOK) {
                EXT4_MP_UNLOCK(mp);
                return r;
@@ -1147,6 +1149,28 @@ int ext4_fopen2(ext4_file *f, const char *path, int flags, bool file_expect)
        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,8 +1202,7 @@ 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
+       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;
@@ -1278,6 +1301,30 @@ int ext4_fread(ext4_file *f, void *buf, size_t size, size_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;
@@ -1714,6 +1761,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);
+       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;
+}
+
 /*********************************DIRECTORY OPERATION************************/
 
 int ext4_dir_rm(const char *path)
index 6bd33902c49f610dfc323f6d404c69cf8e1c9ca6..6b76d053b692f153ffee664a39a2c06c58207248 100644 (file)
@@ -360,6 +360,8 @@ int ext4_file_set_atime(ext4_file *f, uint32_t atime);
 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.
index db4ca6414fe4d72b7d2bb5ac4cbee4b7a8bc3e83..81cde300e9e73af5528190b903402b8225853d35 100644 (file)
@@ -206,6 +206,25 @@ void ext4_dir_write_entry(struct ext4_sblock *sb,
        /* 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 @@ void ext4_dir_write_entry(struct ext4_sblock *sb,
 
        /* 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,
index a03e997c0728de7165df82c9459558eb4808aed6..ab41de5e78386afe3dbad2847ba3c4403f73754a 100644 (file)
 #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
index 28102d1075a9540cedf63deac83f13d3605de327..e48f31c1e681230728a0d86c7418b337ae265814 100644 (file)
@@ -613,14 +613,59 @@ 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
+}
+
+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 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
        /* 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 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
 
                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 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
                 */
 
                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,31 +716,14 @@ int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
        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;
-
-#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);
+       /* 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;
 
-               /* 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
+       } else
+               ext4_fs_inode_blocks_init(fs, inode_ref);
 
        inode_ref->dirty = true;
 
index ee63ef44af45e0a7da25e971f011b5bc08d07bfa..d05b962e755b840ccb87dca3200dd3b2427a3453 100644 (file)
@@ -134,6 +134,12 @@ int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref);
 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 @@ int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref);
 /**@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
index b996df5cb3ddcf9aa86761809abf9af80258d094..3bf20e08f879a616869662cec5aeb13f9f336183 100644 (file)
@@ -290,11 +290,15 @@ void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
        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)
index c06c6092d1edeeb68bd7ac6302b9f2bc2ae74d43..c86bdb6feab639cc757196973f07a02ea39749f1 100644 (file)
@@ -245,6 +245,13 @@ uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx);
 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