From: root Date: Mon, 21 Sep 2015 16:22:23 +0000 (+0000) Subject: Initial Symbolic support. X-Git-Tag: v1.0.0~433^2~3 X-Git-Url: https://git.carlh.net/gitweb/?a=commitdiff_plain;h=0505aa925586074109efe77089303341025f9b51;p=lwext4.git Initial Symbolic support. --- diff --git a/lwext4/ext4.c b/lwext4/ext4.c index b497ffa..3c701eb 100644 --- a/lwext4/ext4.c +++ b/lwext4/ext4.c @@ -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) diff --git a/lwext4/ext4.h b/lwext4/ext4.h index 6bd3390..6b76d05 100644 --- a/lwext4/ext4.h +++ b/lwext4/ext4.h @@ -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. diff --git a/lwext4/ext4_dir.c b/lwext4/ext4_dir.c index db4ca64..81cde30 100644 --- a/lwext4/ext4_dir.c +++ b/lwext4/ext4_dir.c @@ -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, diff --git a/lwext4/ext4_errno.h b/lwext4/ext4_errno.h index a03e997..ab41de5 100644 --- a/lwext4/ext4_errno.h +++ b/lwext4/ext4_errno.h @@ -41,41 +41,42 @@ #if !CONFIG_HAVE_OWN_ERRNO #include #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 diff --git a/lwext4/ext4_fs.c b/lwext4/ext4_fs.c index 28102d1..e48f31c 100644 --- a/lwext4/ext4_fs.c +++ b/lwext4/ext4_fs.c @@ -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; diff --git a/lwext4/ext4_fs.h b/lwext4/ext4_fs.h index ee63ef4..d05b962 100644 --- a/lwext4/ext4_fs.h +++ b/lwext4/ext4_fs.h @@ -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 diff --git a/lwext4/ext4_inode.c b/lwext4/ext4_inode.c index b996df5..3bf20e0 100644 --- a/lwext4/ext4_inode.c +++ b/lwext4/ext4_inode.c @@ -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) diff --git a/lwext4/ext4_inode.h b/lwext4/ext4_inode.h index c06c609..c86bdb6 100644 --- a/lwext4/ext4_inode.h +++ b/lwext4/ext4_inode.h @@ -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