From 6eddc869d349be59860bfd84ff10b7579a9b00a9 Mon Sep 17 00:00:00 2001 From: chenjing Date: Fri, 4 Jun 2021 10:30:12 +0800 Subject: [PATCH] feat: support link/symlink/readlink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增link/symlink/readlink接口的系统调用及内核实现,当前仅支持jffs2文件系统。具体接口说明如下: 一、hard link 接口原型: int link(const char *oldpath, const char *newpath); int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags); 作用: 创建oldpath的硬链接,名为newpath。 功能说明: 1、newpath与oldpath必须在同一挂载分区内。 2、若newpath已存在,不会覆盖,错误码EEXIST。 3、oldpath必须为普通文件或者软链接文件。 4、如果oldpath是一个软链接文件,那么: 若调用link接口或者linkat(flags=0),创建出软链接文件的硬链接; 若调用linkat(flags = AT_SYMLINK_FOLLOW),创建出软链接所指向源文件的硬链接。 5、oldpath与newpath对应同一个文件,对oldpath与newpath任一名字的操作都是直接操作文件,没有“原始文件”的说法。 6、使用cp命令拷贝一个硬链接文件,生成文件的拷贝,新文件的nlink数为1。 7、删除oldpath或newpath,底层文件仍存在,可以通过另一个path访问。只有当两个path都删除之后,才会真正将文件删除,空间释放。 二、symbol link 接口原型: int symlink(const char *target, const char *linkpath); int symlinkat(const char *target, int newdirfd, const char *linkpath); 作用: 创建一个软链接文件linkpath,存储字符串target。 功能说明: 1、target可以为任意字符串(长度小于PATH_MAX)。 2、若linkpath文件名已存在,不会覆盖,错误码EEXIST。 3、用readlink函数可读取软链接的target内容。 4、软链接文件本身大小为target长度。 5、ls时软链接文件类型显示为 'l'。 6、symlink最大循环次数为CONFIG_FS_MAX_LNK_CNT(目前为40),超出则返回错误,错误码ELOOP。 7、使用cp命令拷贝一个软链接文件: 若target是一个文件:创建一个源文件的拷贝,类型为普通文件; 若target非文件:拷贝失败。 三、readlink 接口原型: ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz); 作用: 读取软链接文件存放的的target内容。 功能说明: 1、pathname必须为软链接文件,否则错误码EINVAL。 2、如果bufsiz小于target长度,则截断target。 close #I3Q0OD Change-Id: I3864d6069b627b705a369e8e32dc1eb922dc0157 Signed-off-by: chenjing --- fs/include/fs/vnode.h | 3 + fs/include/vfs_config.h | 2 + fs/jffs2/src/vfs_jffs2.c | 187 +++++++++++----- fs/vfs/Makefile | 3 + fs/vfs/operation/fs_other.c | 16 +- fs/vfs/vfs_cmd/vfs_shellcmd.c | 10 +- syscall/fs_syscall.c | 204 +++++++++++++++++ syscall/los_syscall.h | 6 + syscall/syscall_lookup.h | 6 + testsuites/unittest/fs/BUILD.gn | 11 + testsuites/unittest/fs/jffs/It_vfs_jffs.h | 14 ++ .../fs/jffs/full/It_vfs_test_link_001.cpp | 116 ++++++++++ .../fs/jffs/full/It_vfs_test_link_002.cpp | 97 +++++++++ .../fs/jffs/full/It_vfs_test_link_003.cpp | 110 ++++++++++ .../fs/jffs/full/It_vfs_test_linkat_001.cpp | 134 ++++++++++++ .../fs/jffs/full/It_vfs_test_linkat_002.cpp | 205 ++++++++++++++++++ .../fs/jffs/full/It_vfs_test_linkat_003.cpp | 183 ++++++++++++++++ .../fs/jffs/full/It_vfs_test_readlink_001.cpp | 101 +++++++++ .../fs/jffs/full/It_vfs_test_symlink_001.cpp | 103 +++++++++ .../fs/jffs/full/It_vfs_test_symlink_002.cpp | 81 +++++++ .../fs/jffs/full/It_vfs_test_symlink_003.cpp | 128 +++++++++++ .../jffs/full/It_vfs_test_symlinkat_001.cpp | 143 ++++++++++++ testsuites/unittest/fs/jffs/vfs_jffs_test.cpp | 57 ++++- 23 files changed, 1861 insertions(+), 59 deletions(-) create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_link_001.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_link_002.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_link_003.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_001.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_002.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_003.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_readlink_001.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_001.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_002.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_003.cpp create mode 100644 testsuites/unittest/fs/jffs/full/It_vfs_test_symlinkat_001.cpp diff --git a/fs/include/fs/vnode.h b/fs/include/fs/vnode.h index 677d61cd..813a536b 100644 --- a/fs/include/fs/vnode.h +++ b/fs/include/fs/vnode.h @@ -99,6 +99,9 @@ struct VnodeOps { int (*Truncate)(struct Vnode *vnode, off_t len); int (*Truncate64)(struct Vnode *vnode, off64_t len); int (*Fscheck)(struct Vnode *vnode, struct fs_dirent_s *dir); + int (*Link)(struct Vnode *src, struct Vnode *dstParent, struct Vnode **dst, const char *dstName); + int (*Symlink)(struct Vnode *parentVnode, struct Vnode **newVnode, const char *path, const char *target); + ssize_t (*Readlink)(struct Vnode *vnode, char *buffer, size_t bufLen); }; typedef int VfsHashCmp(struct Vnode *vnode, void *arg); diff --git a/fs/include/vfs_config.h b/fs/include/vfs_config.h index 670f602d..835e94d1 100644 --- a/fs/include/vfs_config.h +++ b/fs/include/vfs_config.h @@ -75,6 +75,8 @@ extern "C" { #define CONFIG_FS_FLASH_BLOCK_NUM 1 +#define CONFIG_FS_MAX_LNK_CNT 40 + /* nfs configure */ #define CONFIG_NFS_MACHINE_NAME "IPC" // nfs device name is IPC diff --git a/fs/jffs2/src/vfs_jffs2.c b/fs/jffs2/src/vfs_jffs2.c index cb651a2b..1f85cf75 100644 --- a/fs/jffs2/src/vfs_jffs2.c +++ b/fs/jffs2/src/vfs_jffs2.c @@ -74,6 +74,9 @@ static void Jffs2SetVtype(struct jffs2_inode *node, struct Vnode *pVnode) case S_IFDIR: pVnode->type = VNODE_TYPE_DIR; break; + case S_IFLNK: + pVnode->type = VNODE_TYPE_LNK; + break; default: pVnode->type = VNODE_TYPE_UNKNOWN; break; @@ -130,7 +133,6 @@ int VfsJffs2Bind(struct Mount *mnt, struct Vnode *blkDriver, const void *data) LOS_MuxUnlock(&g_jffs2FsLock); goto ERROR_WITH_VNODE; } - rootNode->i_vnode = pv; pv->type = VNODE_TYPE_DIR; pv->data = (void *)rootNode; pv->originMount = mnt; @@ -197,18 +199,15 @@ int VfsJffs2Lookup(struct Vnode *parentVnode, const char *path, int len, struct return -ENOENT; } - if (node->i_vnode) { - *ppVnode = node->i_vnode; - (void)VfsHashGet(parentVnode->originMount, node->i_ino, &newVnode, NULL, NULL); - LOS_MuxUnlock(&g_jffs2FsLock); - if (newVnode) { - if (newVnode->data == NULL) { - LOS_Panic("#####VfsHashGet error#####\n"); - } - newVnode->parent = parentVnode; - *ppVnode = newVnode; - return 0; - } + (void)VfsHashGet(parentVnode->originMount, node->i_ino, &newVnode, NULL, NULL); + LOS_MuxUnlock(&g_jffs2FsLock); + if (newVnode) { + if (newVnode->data == NULL) { + LOS_Panic("#####VfsHashGet error#####\n"); + } + newVnode->parent = parentVnode; + *ppVnode = newVnode; + return 0; } ret = VnodeAlloc(&g_jffs2Vops, &newVnode); if (ret != 0) { @@ -219,11 +218,6 @@ int VfsJffs2Lookup(struct Vnode *parentVnode, const char *path, int len, struct } Jffs2SetVtype(node, newVnode); - node->i_vnode = newVnode; - if (&g_jffs2Vops != parentVnode->vop) { - LOS_Panic("jffs2 vop failed"); - } - newVnode->vop = parentVnode->vop; newVnode->fop = parentVnode->fop; newVnode->data = node; newVnode->parent = parentVnode; @@ -260,11 +254,6 @@ int VfsJffs2Create(struct Vnode *parentVnode, const char *path, int mode, struct } newVnode->type = VNODE_TYPE_REG; - newNode->i_vnode = newVnode; - newVnode->vop = parentVnode->vop; - if (&g_jffs2Vops != parentVnode->vop) { - LOS_Panic("jffs2 vop failed"); - } newVnode->fop = parentVnode->fop; newVnode->data = newNode; newVnode->parent = parentVnode; @@ -527,17 +516,12 @@ int VfsJffs2Mkdir(struct Vnode *parentNode, const char *dirName, mode_t mode, st ret = jffs2_mkdir((struct jffs2_inode *)parentNode->data, (const unsigned char *)dirName, mode, &node); if (ret != 0) { - VnodeFree(newVnode); LOS_MuxUnlock(&g_jffs2FsLock); + VnodeFree(newVnode); return ret; } newVnode->type = VNODE_TYPE_DIR; - node->i_vnode = newVnode; - newVnode->vop = parentNode->vop; - if (&g_jffs2Vops != parentNode->vop) { - LOS_Panic("jffs2 vop failed"); - } newVnode->fop = parentNode->fop; newVnode->data = node; newVnode->parent = parentNode; @@ -606,6 +590,8 @@ int VfsJffs2Chattr(struct Vnode *pVnode, struct IATTR *attr) int VfsJffs2Rmdir(struct Vnode *parentVnode, struct Vnode *targetVnode, const char *path) { int ret; + struct jffs2_inode *parentInode = (struct jffs2_inode *)parentVnode->data; + struct jffs2_inode *targetInode = (struct jffs2_inode *)targetVnode->data; if (!parentVnode || !targetVnode) { return -EINVAL; @@ -613,16 +599,125 @@ int VfsJffs2Rmdir(struct Vnode *parentVnode, struct Vnode *targetVnode, const ch LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER); - ret = jffs2_rmdir((struct jffs2_inode *)parentVnode->data, (struct jffs2_inode *)targetVnode->data, - (const unsigned char *)path); + ret = jffs2_rmdir(parentInode, targetInode, (const unsigned char *)path); + + if (ret == 0) { + (void)jffs2_iput(targetInode); + } LOS_MuxUnlock(&g_jffs2FsLock); return ret; } +int VfsJffs2Link(struct Vnode *oldVnode, struct Vnode *newParentVnode, struct Vnode **newVnode, const char *newName) +{ + int ret; + struct jffs2_inode *oldInode = oldVnode->data; + struct jffs2_inode *newParentInode = newParentVnode->data; + struct Vnode *pVnode = NULL; + + ret = VnodeAlloc(&g_jffs2Vops, &pVnode); + if (ret != 0) { + return -ENOMEM; + } + + LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER); + ret = jffs2_link(oldInode, newParentInode, (const unsigned char *)newName); + if (ret != 0) { + LOS_MuxUnlock(&g_jffs2FsLock); + VnodeFree(pVnode); + return ret; + } + + pVnode->type = VNODE_TYPE_REG; + pVnode->fop = &g_jffs2Fops; + pVnode->parent = newParentVnode; + pVnode->originMount = newParentVnode->originMount; + pVnode->data = oldInode; + pVnode->uid = oldVnode->uid; + pVnode->gid = oldVnode->gid; + pVnode->mode = oldVnode->mode; + + *newVnode = pVnode; + (void)VfsHashInsert(*newVnode, oldInode->i_ino); + + LOS_MuxUnlock(&g_jffs2FsLock); + return ret; +} + +int VfsJffs2Symlink(struct Vnode *parentVnode, struct Vnode **newVnode, const char *path, const char *target) +{ + int ret; + struct jffs2_inode *inode = NULL; + struct Vnode *pVnode = NULL; + + ret = VnodeAlloc(&g_jffs2Vops, &pVnode); + if (ret != 0) { + return -ENOMEM; + } + + LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER); + ret = jffs2_symlink((struct jffs2_inode *)parentVnode->data, &inode, (const unsigned char *)path, target); + if (ret != 0) { + LOS_MuxUnlock(&g_jffs2FsLock); + VnodeFree(pVnode); + return ret; + } + + pVnode->type = VNODE_TYPE_LNK; + pVnode->fop = &g_jffs2Fops; + pVnode->parent = parentVnode; + pVnode->originMount = parentVnode->originMount; + pVnode->data = inode; + pVnode->uid = inode->i_uid; + pVnode->gid = inode->i_gid; + pVnode->mode = inode->i_mode; + + *newVnode = pVnode; + (void)VfsHashInsert(*newVnode, inode->i_ino); + + LOS_MuxUnlock(&g_jffs2FsLock); + return ret; +} + +ssize_t VfsJffs2Readlink(struct Vnode *vnode, char *buffer, size_t bufLen) +{ + ssize_t ret = 0; + struct jffs2_inode *inode = NULL; + struct jffs2_inode_info *f = NULL; + ssize_t targetLen; + ssize_t cnt; + + LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER); + + inode = (struct jffs2_inode *)vnode->data; + f = JFFS2_INODE_INFO(inode); + targetLen = strlen((const char *)f->target); + if (bufLen == 0) { + LOS_MuxUnlock(&g_jffs2FsLock); + return 0; + } + + cnt = (bufLen - 1) < targetLen ? (bufLen - 1) : targetLen; + if (LOS_CopyFromKernel(buffer, bufLen, (const char *)f->target, cnt) != 0) { + cnt = 0; + ret = -EFAULT; + } + buffer[cnt] = '\0'; + + LOS_MuxUnlock(&g_jffs2FsLock); + if (ret < 0) { + return ret; + } + + return cnt; +} + int VfsJffs2Unlink(struct Vnode *parentVnode, struct Vnode *targetVnode, const char *path) { int ret; + struct jffs2_inode *parentInode = (struct jffs2_inode *)parentVnode->data; + struct jffs2_inode *targetInode = (struct jffs2_inode *)targetVnode->data; if (!parentVnode || !targetVnode) { PRINTK("%s-%d parentVnode=%x, targetVnode=%x\n", __FUNCTION__, __LINE__, parentVnode, targetVnode); @@ -631,8 +726,11 @@ int VfsJffs2Unlink(struct Vnode *parentVnode, struct Vnode *targetVnode, const c LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER); - ret = jffs2_unlink((struct jffs2_inode *)parentVnode->data, (struct jffs2_inode *)targetVnode->data, - (const unsigned char *)path); + ret = jffs2_unlink(parentInode, targetInode, (const unsigned char *)path); + + if (ret == 0) { + (void)jffs2_iput(targetInode); + } LOS_MuxUnlock(&g_jffs2FsLock); return ret; @@ -664,8 +762,6 @@ int VfsJffs2Rename(struct Vnode *fromVnode, struct Vnode *toParentVnode, const c fromNode = (struct jffs2_inode *)fromVnode->data; ret = jffs2_rename((struct jffs2_inode *)fromParentVnode->data, fromNode, (const unsigned char *)fromName, (struct jffs2_inode *)toParentVnode->data, (const unsigned char *)toName); - /* Careful with this: we can safely free the fromVnode AND toVnode but not fromNode, so reset the i_vnode field OR - it will be a jungle field. With a new lookup process, we'll allocate a new vnode for it. */ fromVnode->parent = toParentVnode; LOS_MuxUnlock(&g_jffs2FsLock); @@ -686,6 +782,7 @@ int VfsJffs2Stat(struct Vnode *pVnode, struct stat *buf) switch (node->i_mode & S_IFMT) { case S_IFREG: case S_IFDIR: + case S_IFLNK: buf->st_mode = node->i_mode; break; @@ -713,22 +810,7 @@ int VfsJffs2Stat(struct Vnode *pVnode, struct stat *buf) int VfsJffs2Reclaim(struct Vnode *pVnode) { - int ret; - struct jffs2_inode *node = NULL; - - LOS_MuxLock(&g_jffs2FsLock, (uint32_t)JFFS2_WAITING_FOREVER); - - node = pVnode->data; - if (node == NULL) { - return LOS_OK; - } - - node->i_vnode = NULL; - ret = jffs2_iput(node); - - LOS_MuxUnlock(&g_jffs2FsLock); - - return ret; + return 0; } int VfsJffs2Statfs(struct Mount *mnt, struct statfs *buf) @@ -797,6 +879,9 @@ struct VnodeOps g_jffs2Vops = { .Reclaim = VfsJffs2Reclaim, .Truncate = VfsJffs2Truncate, .Truncate64 = VfsJffs2Truncate64, + .Link = VfsJffs2Link, + .Symlink = VfsJffs2Symlink, + .Readlink = VfsJffs2Readlink, }; struct file_operations_vfs g_jffs2Fops = { diff --git a/fs/vfs/Makefile b/fs/vfs/Makefile index c2758a89..d779909e 100644 --- a/fs/vfs/Makefile +++ b/fs/vfs/Makefile @@ -64,6 +64,9 @@ $(LITEOSTHIRDPARTY)/NuttX/fs/vfs/fs_statfs.c \ $(LITEOSTHIRDPARTY)/NuttX/fs/vfs/fs_truncate.c \ $(LITEOSTHIRDPARTY)/NuttX/fs/vfs/fs_truncate64.c \ $(LITEOSTHIRDPARTY)/NuttX/fs/vfs/fs_unlink.c \ +$(LITEOSTHIRDPARTY)/NuttX/fs/vfs/fs_link.c \ +$(LITEOSTHIRDPARTY)/NuttX/fs/vfs/fs_readlink.c \ +$(LITEOSTHIRDPARTY)/NuttX/fs/vfs/fs_symlink.c \ $(LITEOSTHIRDPARTY)/NuttX/fs/vfs/fs_write.c \ $(wildcard operation/*.c) \ \ diff --git a/fs/vfs/operation/fs_other.c b/fs/vfs/operation/fs_other.c index 65196bb3..0d831968 100644 --- a/fs/vfs/operation/fs_other.c +++ b/fs/vfs/operation/fs_other.c @@ -484,7 +484,13 @@ static void PrintFileInfo64(const struct stat64 *stat64Info, const char *name) str[i][UGO_NUMS - 1] = (mode & EXEC_OP) ? 'x' : '-'; } - dirFlag = (S_ISDIR(stat64Info->st_mode)) ? 'd' : '-'; + if (S_ISDIR(stat64Info->st_mode)) { + dirFlag = 'd'; + } else if (S_ISLNK(stat64Info->st_mode)) { + dirFlag = 'l'; + } else { + dirFlag = '-'; + } PRINTK("%c%s%s%s %-8lld u:%-5d g:%-5d %-10s\n", dirFlag, str[0], str[1], str[UGO_NUMS - 1], stat64Info->st_size, stat64Info->st_uid, stat64Info->st_gid, name); @@ -504,7 +510,13 @@ static void PrintFileInfo(const struct stat *statInfo, const char *name) str[i][UGO_NUMS - 1] = (mode & EXEC_OP) ? 'x' : '-'; } - dirFlag = (S_ISDIR(statInfo->st_mode)) ? 'd' : '-'; + if (S_ISDIR(statInfo->st_mode)) { + dirFlag = 'd'; + } else if (S_ISLNK(statInfo->st_mode)) { + dirFlag = 'l'; + } else { + dirFlag = '-'; + } PRINTK("%c%s%s%s %-8lld u:%-5d g:%-5d %-10s\n", dirFlag, str[0], str[1], str[UGO_NUMS - 1], statInfo->st_size, statInfo->st_uid, statInfo->st_gid, name); diff --git a/fs/vfs/vfs_cmd/vfs_shellcmd.c b/fs/vfs/vfs_cmd/vfs_shellcmd.c index 29aa4bd0..49f59ed6 100644 --- a/fs/vfs/vfs_cmd/vfs_shellcmd.c +++ b/fs/vfs/vfs_cmd/vfs_shellcmd.c @@ -832,7 +832,7 @@ static int os_shell_cmd_do_rmdir(const char *pathname) return -1; } - if (S_ISREG(stat_info.st_mode)) + if (S_ISREG(stat_info.st_mode) || S_ISLNK(stat_info.st_mode)) { return remove(pathname); } @@ -1050,7 +1050,7 @@ static int os_wildcard_extract_directory(char *fullpath, void *dst, wildcard_typ else if (mark == CP_COUNT) { ret = stat(fullpath, &stat_buf); - if (ret == 0 && S_ISREG(stat_buf.st_mode)) + if (ret == 0 && (S_ISREG(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode))) { (*(int *)dst)++; } @@ -1106,7 +1106,7 @@ static int os_wildcard_extract_directory(char *fullpath, void *dst, wildcard_typ else if (mark == CP_COUNT) { ret = stat(src, &stat_buf); - if (ret == 0 && S_ISREG(stat_buf.st_mode)) + if (ret == 0 && (S_ISREG(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode))) { (*(int *)dst)++; if ((*(int *)dst) > 1) @@ -1216,7 +1216,7 @@ int osShellCmdCp(int argc, const char **argv) } else { - if (S_ISREG(stat_buf.st_mode) && dst[strlen(dst) - 1] == '/') + if ((S_ISREG(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode)) && dst[strlen(dst) - 1] == '/') { PRINTK("cp error: %s is not a directory.\n", dst_fullpath); goto errout_with_path; @@ -1225,7 +1225,7 @@ int osShellCmdCp(int argc, const char **argv) if (os_is_containers_wildcard(src_fullpath)) { - if (ret < 0 || S_ISREG(stat_buf.st_mode)) + if (ret < 0 || S_ISREG(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode)) { char *src_copy = strdup(src_fullpath); if (src_copy == NULL) diff --git a/syscall/fs_syscall.c b/syscall/fs_syscall.c index cd255b66..dbd5a6ee 100644 --- a/syscall/fs_syscall.c +++ b/syscall/fs_syscall.c @@ -356,6 +356,98 @@ OUT: return ret; } +int SysLink(const char *oldpath, const char *newpath) +{ + int ret; + char *oldpathRet = NULL; + char *newpathRet = NULL; + + if (oldpath != NULL) { + ret = UserPathCopy(oldpath, &oldpathRet); + if (ret != 0) { + goto OUT; + } + } + + if (newpath != NULL) { + ret = UserPathCopy(newpath, &newpathRet); + if (ret != 0) { + goto OUT; + } + } + + ret = link(oldpathRet, newpathRet); + if (ret < 0) { + ret = -get_errno(); + } + +OUT: + if (oldpathRet != NULL) { + (void)LOS_MemFree(OS_SYS_MEM_ADDR, oldpathRet); + } + if (newpathRet != NULL) { + (void)LOS_MemFree(OS_SYS_MEM_ADDR, newpathRet); + } + return ret; +} + +ssize_t SysReadlink(const char *pathname, char *buf, size_t bufsize) +{ + ssize_t ret; + char *pathRet = NULL; + + if (bufsize == 0) { + return -EINVAL; + } + + if (pathname != NULL) { + ret = UserPathCopy(pathname, &pathRet); + if (ret != 0) { + goto OUT; + } + } + + if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buf, bufsize)) { + ret = -EFAULT; + goto OUT; + } + + ret = readlink(pathRet, buf, bufsize); + if (ret < 0) { + ret = -get_errno(); + } + +OUT: + if (pathRet != NULL) { + (void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet); + } + return ret; +} + +int SysSymlink(const char *target, const char *linkpath) +{ + int ret; + char *pathRet = NULL; + + if (linkpath != NULL) { + ret = UserPathCopy(linkpath, &pathRet); + if (ret != 0) { + goto OUT; + } + } + + ret = symlink(target, pathRet); + if (ret < 0) { + ret = -get_errno(); + } + +OUT: + if (pathRet != NULL) { + (void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet); + } + return ret; +} + int SysUnlink(const char *pathname) { int ret; @@ -1638,6 +1730,118 @@ OUT: return ret; } +int SysLinkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) +{ + int ret; + char *oldpathRet = NULL; + char *newpathRet = NULL; + + if (oldpath != NULL) { + ret = UserPathCopy(oldpath, &oldpathRet); + if (ret != 0) { + goto OUT; + } + } + + if (newpath != NULL) { + ret = UserPathCopy(newpath, &newpathRet); + if (ret != 0) { + goto OUT; + } + } + + if (olddirfd != AT_FDCWD) { + /* Process fd convert to system global fd */ + olddirfd = GetAssociatedSystemFd(olddirfd); + } + + if (newdirfd != AT_FDCWD) { + /* Process fd convert to system global fd */ + newdirfd = GetAssociatedSystemFd(newdirfd); + } + + ret = linkat(olddirfd, oldpathRet, newdirfd, newpathRet, flags); + if (ret < 0) { + ret = -get_errno(); + } + +OUT: + if (oldpathRet != NULL) { + (void)LOS_MemFree(OS_SYS_MEM_ADDR, oldpathRet); + } + if (newpathRet != NULL) { + (void)LOS_MemFree(OS_SYS_MEM_ADDR, newpathRet); + } + return ret; +} + +int SysSymlinkat(const char *target, int dirfd, const char *linkpath) +{ + int ret; + char *pathRet = NULL; + + if (linkpath != NULL) { + ret = UserPathCopy(linkpath, &pathRet); + if (ret != 0) { + goto OUT; + } + } + + if (dirfd != AT_FDCWD) { + /* Process fd convert to system global fd */ + dirfd = GetAssociatedSystemFd(dirfd); + } + + ret = symlinkat(target, dirfd, pathRet); + if (ret < 0) { + ret = -get_errno(); + } + +OUT: + if (pathRet != NULL) { + (void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet); + } + return ret; +} + +ssize_t SysReadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize) +{ + ssize_t ret; + char *pathRet = NULL; + + if (bufsize == 0) { + return -EINVAL; + } + + if (pathname != NULL) { + ret = UserPathCopy(pathname, &pathRet); + if (ret != 0) { + goto OUT; + } + } + + if (dirfd != AT_FDCWD) { + /* Process fd convert to system global fd */ + dirfd = GetAssociatedSystemFd(dirfd); + } + + if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buf, bufsize)) { + ret = -EFAULT; + goto OUT; + } + + ret = readlinkat(dirfd, pathRet, buf, bufsize); + if (ret < 0) { + ret = -get_errno(); + } + +OUT: + if (pathRet != NULL) { + (void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet); + } + return ret; +} + int SysUnlinkat(int dirfd, const char *pathname, int flag) { int ret; diff --git a/syscall/los_syscall.h b/syscall/los_syscall.h index 68281167..ca453e3e 100644 --- a/syscall/los_syscall.h +++ b/syscall/los_syscall.h @@ -220,6 +220,12 @@ extern ssize_t SysRead(int fd, void *buf, size_t nbytes); extern ssize_t SysWrite(int fd, const void *buf, size_t nbytes); extern int SysOpen(const char *path, int oflags, ...); extern int SysCreat(const char *pathname, mode_t mode); +extern int SysLink(const char *path1, const char *path2); +extern ssize_t SysReadlink(const char *pathname, char *buf, size_t bufsize); +extern int SysSymlink(const char *target, const char *linkpath); +extern int SysLinkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags); +extern int SysSymlinkat(const char *target, int dirfd, const char *linkpath); +extern ssize_t SysReadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize); extern int SysUnlink( const char *pathname); extern int SysExecve(const char *fileName, char *const *argv, char *const *envp); extern int SysChdir(const char *path); diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index 9f64594a..236f7a25 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -37,6 +37,9 @@ SYSCALL_HAND_DEF(__NR_write, SysWrite, ssize_t, ARG_NUM_3) SYSCALL_HAND_DEF(__NR_open, SysOpen, int, ARG_NUM_7) SYSCALL_HAND_DEF(__NR_close, SysClose, int, ARG_NUM_1) SYSCALL_HAND_DEF(__NR_creat, SysCreat, int, ARG_NUM_2) +SYSCALL_HAND_DEF(__NR_link, SysLink, int, ARG_NUM_2) +SYSCALL_HAND_DEF(__NR_readlink, SysReadlink, ssize_t, ARG_NUM_3) +SYSCALL_HAND_DEF(__NR_symlink, SysSymlink, int, ARG_NUM_2) SYSCALL_HAND_DEF(__NR_unlink, SysUnlink, int, ARG_NUM_1) #ifdef LOSCFG_KERNEL_DYNLOAD @@ -96,6 +99,9 @@ SYSCALL_HAND_DEF(__NR_getdents64, SysGetdents64, int, ARG_NUM_3) SYSCALL_HAND_DEF(__NR_format, SysFormat, int, ARG_NUM_3) #endif +SYSCALL_HAND_DEF(__NR_linkat, SysLinkat, int, ARG_NUM_5) +SYSCALL_HAND_DEF(__NR_symlinkat, SysSymlinkat, int, ARG_NUM_3) +SYSCALL_HAND_DEF(__NR_readlinkat, SysReadlinkat, ssize_t, ARG_NUM_4) SYSCALL_HAND_DEF(__NR_unlinkat, SysUnlinkat, int, ARG_NUM_3) SYSCALL_HAND_DEF(__NR_renameat, SysRenameat, int, ARG_NUM_4) SYSCALL_HAND_DEF(__NR_openat, SysOpenat, int, ARG_NUM_7) diff --git a/testsuites/unittest/fs/BUILD.gn b/testsuites/unittest/fs/BUILD.gn index 5912e8f0..7fc066b3 100644 --- a/testsuites/unittest/fs/BUILD.gn +++ b/testsuites/unittest/fs/BUILD.gn @@ -779,6 +779,17 @@ sources_full = [ "jffs/full/It_vfs_jffs_701.cpp", "jffs/full/It_vfs_jffs_807.cpp", "jffs/full/It_vfs_jffs_808.cpp", + "jffs/full/It_vfs_test_link_001.cpp", + "jffs/full/It_vfs_test_link_002.cpp", + "jffs/full/It_vfs_test_link_003.cpp", + "jffs/full/It_vfs_test_linkat_001.cpp", + "jffs/full/It_vfs_test_linkat_002.cpp", + "jffs/full/It_vfs_test_linkat_003.cpp", + "jffs/full/It_vfs_test_readlink_001.cpp", + "jffs/full/It_vfs_test_symlink_001.cpp", + "jffs/full/It_vfs_test_symlink_002.cpp", + "jffs/full/It_vfs_test_symlink_003.cpp", + "jffs/full/It_vfs_test_symlinkat_001.cpp", ] if (LOSCFG_USER_TEST_LEVEL >= TEST_LEVEL_LOW) { diff --git a/testsuites/unittest/fs/jffs/It_vfs_jffs.h b/testsuites/unittest/fs/jffs/It_vfs_jffs.h index 7d5ac522..f1fd0b30 100644 --- a/testsuites/unittest/fs/jffs/It_vfs_jffs.h +++ b/testsuites/unittest/fs/jffs/It_vfs_jffs.h @@ -102,6 +102,8 @@ constexpr const char* JFFS_BASE_DIR = "/"; #define JFFS_PATH_NAME0 "/storage/test" #define JFFS_PATH_NAME01 "/storage/test1" #define JFFS_PATH_NAME02 "/storage/test2" +#define JFFS_PATH_NAME03 "/storage/test3" +#define JFFS_PATH_NAME04 "/storage/test4" #define JFFS_PATH_NAME00 "/storage/test/test00" #define JFFS_PATH_NAME11 "/storage/test1/test11" #define JFFS_PATH_NAME22 "/storage/test2/test22" @@ -948,6 +950,18 @@ VOID ItFsJffsLSFD_004(VOID); VOID ItFsJffsLSFD_005(VOID); VOID ItFsJffsLSFD_006(VOID); VOID ItFsJffsLSFD_007(VOID); + +VOID ItFsTestLink001(VOID); +VOID ItFsTestLink002(VOID); +VOID ItFsTestLink003(VOID); +VOID ItFsTestLinkat001(VOID); +VOID ItFsTestLinkat002(VOID); +VOID ItFsTestLinkat003(VOID); +VOID ItFsTestReadlink001(VOID); +VOID ItFsTestSymlink001(VOID); +VOID ItFsTestSymlink002(VOID); +VOID ItFsTestSymlink003(VOID); +VOID ItFsTestSymlinkat001(VOID); #endif #if defined(LOSCFG_USER_TESTSUIT_SHELL) diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_link_001.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_link_001.cpp new file mode 100644 index 00000000..f7b70a18 --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_link_001.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 fd1 = -1; + INT32 len, ret; + struct stat statBuf1 = {0}; + struct stat statBuf2 = {0}; + CHAR filebuf[JFFS_STANDARD_NAME_LENGTH] = "1234567890abcde&"; + CHAR readbuf[JFFS_STANDARD_NAME_LENGTH] = {0}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + + ret = link("/lib/libc.so", pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT1); + ICUNIT_GOTO_EQUAL(errno, EXDEV, errno, EXIT1); + + fd = open(pathname1, O_NONBLOCK | O_CREAT | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT); + + len = write(fd, filebuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT3); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = link(pathname1, pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + ret = stat(pathname1, &statBuf1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf1.st_nlink, 2, statBuf1.st_nlink, EXIT2); + + ret = stat(pathname2, &statBuf2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf2.st_ino, statBuf1.st_ino, statBuf2.st_ino, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf2.st_mode, statBuf1.st_mode, statBuf2.st_mode, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf2.st_nlink, statBuf1.st_nlink, statBuf2.st_nlink, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf2.st_uid, statBuf1.st_uid, statBuf2.st_uid, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf2.st_gid, statBuf1.st_gid, statBuf2.st_gid, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf2.st_size, statBuf1.st_size, statBuf2.st_size, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf2.st_blksize, statBuf1.st_blksize, statBuf2.st_blksize, EXIT2); + + fd1 = open(pathname2, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT2); + + len = read(fd1, readbuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT4); + ICUNIT_GOTO_STRING_EQUAL(readbuf, filebuf, readbuf, EXIT4); + + ret = close(fd1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = unlink(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + memset(&statBuf1, 0, sizeof(struct stat)); + ret = stat(pathname1, &statBuf1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf1.st_nlink, 1, statBuf1.st_nlink, EXIT2); + + ret = unlink(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT4: + close(fd1); + goto EXIT2; +EXIT3: + close(fd); + goto EXIT1; +EXIT2: + unlink(pathname2); +EXIT1: + unlink(pathname1); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestLink001(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_LINK_001", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_link_002.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_link_002.cpp new file mode 100644 index 00000000..135c4d9f --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_link_002.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 fd1 = -1; + INT32 len, ret; + CHAR filebuf[JFFS_STANDARD_NAME_LENGTH] = "1234567890abcde&"; + CHAR readbuf[JFFS_STANDARD_NAME_LENGTH] = {0}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + + fd = open(pathname1, O_NONBLOCK | O_CREAT | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = link(pathname1, pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + fd1 = open(pathname2, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT2); + + len = write(fd1, filebuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT4); + + ret = close(fd1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = unlink(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + fd = open(pathname1, O_NONBLOCK | O_CREAT | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT1); + + len = read(fd, readbuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT3); + ICUNIT_GOTO_STRING_EQUAL(readbuf, filebuf, readbuf, EXIT3); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = unlink(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT4: + close(fd1); + goto EXIT2; +EXIT3: + close(fd); + goto EXIT1; +EXIT2: + unlink(pathname2); +EXIT1: + unlink(pathname1); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestLink002(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_LINK_002", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_link_003.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_link_003.cpp new file mode 100644 index 00000000..002ce30e --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_link_003.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 ret; + CHAR filebuf[PATH_MAX + 2] = {""}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + CHAR pathname3[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME02 }; + CHAR pathname4[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME03 }; + CHAR pathname5[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME04 }; + + for (int i = 0; i < PATH_MAX + 1; i++) { + strcat(filebuf, "d"); + } + filebuf[PATH_MAX + 1] = '\0'; + ret = link(filebuf, pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT); + ICUNIT_GOTO_EQUAL(errno, ENAMETOOLONG, errno, EXIT); + + ret = link("dddddddddddddd", pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT); + ICUNIT_GOTO_EQUAL(errno, ENOENT, errno, EXIT); + + ret = link(JFFS_MAIN_DIR0, pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT); + ICUNIT_GOTO_EQUAL(errno, EPERM, errno, EXIT); + + fd = creat(pathname2, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = link(pathname2, pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + fd = creat(pathname3, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT3); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT5); + + ret = link(pathname3, pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT4); + ICUNIT_GOTO_EQUAL(errno, EEXIST, errno, EXIT4); + + ret = unlink(pathname3); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = unlink(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = unlink(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT5: + close(fd); +EXIT4: + unlink(pathname3); +EXIT3: + unlink(pathname1); + goto EXIT1; +EXIT2: + close(fd); +EXIT1: + unlink(pathname2); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestLink003(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_LINK_003", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} + diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_001.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_001.cpp new file mode 100644 index 00000000..d649f6a3 --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_001.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 fd1 = -1; + INT32 len, ret; + CHAR filebuf[JFFS_STANDARD_NAME_LENGTH] = "1234567890abcde&"; + CHAR readbuf[JFFS_STANDARD_NAME_LENGTH] = {0}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + CHAR pathname3[JFFS_STANDARD_NAME_LENGTH] = "originfile"; + CHAR pathname4[JFFS_STANDARD_NAME_LENGTH] = "linkfile"; + INT32 olddirFd = -1; + INT32 newdirFd = -1; + DIR *olddir = NULL; + DIR *newdir = NULL; + + ret = mkdir(pathname1, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT); + + olddir = opendir(pathname1); + ICUNIT_GOTO_NOT_EQUAL(olddir, NULL, olddir, EXIT1); + + olddirFd = dirfd(olddir); + ICUNIT_GOTO_NOT_EQUAL(olddirFd, JFFS_IS_ERROR, olddirFd, EXIT2); + + ret = mkdir(pathname2, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + newdir = opendir(pathname2); + ICUNIT_GOTO_NOT_EQUAL(newdir, NULL, newdir, EXIT3); + + newdirFd = dirfd(newdir); + ICUNIT_GOTO_NOT_EQUAL(newdirFd, JFFS_IS_ERROR, newdirFd, EXIT4); + + fd = openat(olddirFd, pathname3, O_NONBLOCK | O_CREAT | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT4); + + len = write(fd, filebuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT6); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT6); + + ret = linkat(olddirFd, pathname3, newdirFd, pathname4, 0); + ICUNIT_GOTO_NOT_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT5); + + ret = unlinkat(olddirFd, pathname3, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT5); + + fd1 = openat(newdirFd, pathname4, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT5); + + len = read(fd1, readbuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT8); + ICUNIT_GOTO_STRING_EQUAL(readbuf, filebuf, readbuf, EXIT8); + + ret = close(fd1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT8); + + ret = unlinkat(newdirFd, pathname4, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT7); + + ret = closedir(newdir); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = rmdir(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = closedir(olddir); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = rmdir(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT8: + close(fd1); +EXIT7: + unlinkat(newdirFd, pathname4, 0); + goto EXIT5; +EXIT6: + close(fd); +EXIT5: + unlinkat(olddirFd, pathname3, 0); +EXIT4: + closedir(newdir); +EXIT3: + rmdir(pathname2); +EXIT2: + closedir(olddir); +EXIT1: + rmdir(pathname1); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestLinkat001(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_LINKAT_001", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_002.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_002.cpp new file mode 100644 index 00000000..35759850 --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_002.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 fd1 = -1; + INT32 len, ret; + struct stat statBuf = {0}; + CHAR filebuf[JFFS_STANDARD_NAME_LENGTH] = "1234567890abcde&"; + CHAR readbuf[JFFS_STANDARD_NAME_LENGTH] = {0}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + CHAR pathname3[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME02 }; + CHAR pathname4[JFFS_STANDARD_NAME_LENGTH] = "originfile"; + CHAR pathname5[JFFS_STANDARD_NAME_LENGTH] = "symlinkfile"; + CHAR pathname6[JFFS_STANDARD_NAME_LENGTH] = "linkfile"; + CHAR pathname7[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname8[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + CHAR pathname9[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME02 }; + INT32 dirFd0 = -1; + INT32 dirFd1 = -1; + INT32 dirFd2 = -1; + DIR *dir0 = NULL; + DIR *dir1 = NULL; + DIR *dir2 = NULL; + + /* get dirfd0 */ + ret = mkdir(pathname1, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT); + + dir0 = opendir(pathname1); + ICUNIT_GOTO_NOT_EQUAL(dir0, NULL, dir0, EXIT1); + + dirFd0 = dirfd(dir0); + ICUNIT_GOTO_NOT_EQUAL(dirFd0, JFFS_IS_ERROR, dirFd0, EXIT2); + + /* get dirfd1 */ + ret = mkdir(pathname2, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + dir1 = opendir(pathname2); + ICUNIT_GOTO_NOT_EQUAL(dir1, NULL, dir1, EXIT3); + + dirFd1 = dirfd(dir1); + ICUNIT_GOTO_NOT_EQUAL(dirFd1, JFFS_IS_ERROR, dirFd1, EXIT4); + + /* get dirfd2 */ + ret = mkdir(pathname3, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + dir2 = opendir(pathname3); + ICUNIT_GOTO_NOT_EQUAL(dir2, NULL, dir2, EXIT5); + + dirFd2 = dirfd(dir2); + ICUNIT_GOTO_NOT_EQUAL(dirFd2, JFFS_IS_ERROR, dirFd2, EXIT6); + + /* creat original file */ + fd = openat(dirFd0, pathname4, O_NONBLOCK | O_CREAT | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT6); + + len = write(fd, filebuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT8); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT7); + + /* creat a symbol link to the original file */ + strcat(pathname7, "/"); + strcat(pathname7, pathname4); + ret = symlinkat(pathname7, dirFd1, pathname5); + ICUNIT_GOTO_NOT_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT7); + + len = readlinkat(dirFd1, pathname5, readbuf, sizeof(readbuf)); + ICUNIT_GOTO_EQUAL(len, strlen(pathname7), len, EXIT9); + ICUNIT_GOTO_STRING_EQUAL(readbuf, pathname7, readbuf, EXIT9); + + /* creat a hard link to the symlink file */ + ret = linkat(dirFd1, pathname5, dirFd2, pathname6, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT9); + + strcat(pathname9, "/"); + strcat(pathname9, pathname6); + ret = stat(pathname9, &statBuf); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT10); + ICUNIT_GOTO_EQUAL(statBuf.st_mode & S_IFMT, S_IFLNK, statBuf.st_mode & S_IFMT, EXIT10); + ICUNIT_GOTO_EQUAL(statBuf.st_size, strlen(pathname7), statBuf.st_size, EXIT10); + + len = readlink(pathname9, readbuf, sizeof(readbuf)); + ICUNIT_GOTO_EQUAL(len, JFFS_IS_ERROR, len, EXIT10); + ICUNIT_GOTO_EQUAL(errno, EINVAL, errno, EXIT10); + + ret = unlink(pathname9); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT10); + + /* creat a hard link to the original file by linking to the symlink file */ + ret = linkat(dirFd1, pathname5, dirFd2, pathname6, AT_SYMLINK_FOLLOW); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT9); + + memset(&statBuf, 0, sizeof(struct stat)); + ret = stat(pathname9, &statBuf); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT10); + ICUNIT_GOTO_EQUAL(statBuf.st_mode & S_IFMT, S_IFREG, statBuf.st_mode & S_IFMT, EXIT10); + + fd1 = openat(dirFd2, pathname6, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT10); + + memset(readbuf, 0, JFFS_STANDARD_NAME_LENGTH); + len = read(fd1, readbuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT11); + ICUNIT_GOTO_STRING_EQUAL(readbuf, filebuf, readbuf, EXIT11); + + ret = close(fd1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT11); + + ret = unlinkat(dirFd2, pathname6, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT10); + + ret = unlinkat(dirFd1, pathname5, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT9); + + ret = unlinkat(dirFd0, pathname4, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT7); + + ret = closedir(dir2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT6); + + ret = rmdir(pathname3); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT5); + + ret = closedir(dir1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = rmdir(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = closedir(dir0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = rmdir(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT11: + close(fd1); +EXIT10: + unlinkat(dirFd2, pathname6, 0); +EXIT9: + unlinkat(dirFd1, pathname5, 0); + goto EXIT7; +EXIT8: + close(fd); +EXIT7: + unlinkat(dirFd0, pathname4, 0); +EXIT6: + closedir(dir2); +EXIT5: + rmdir(pathname3); +EXIT4: + closedir(dir1); +EXIT3: + rmdir(pathname2); +EXIT2: + closedir(dir0); +EXIT1: + rmdir(pathname1); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestLinkat002(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_LINKAT_002", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_003.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_003.cpp new file mode 100644 index 00000000..83190062 --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_linkat_003.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 ret; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + CHAR pathname3[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME02 }; + CHAR pathname4[JFFS_STANDARD_NAME_LENGTH] = "symlinkfile1"; + CHAR pathname5[JFFS_STANDARD_NAME_LENGTH] = "symlinkfile2"; + CHAR pathname6[JFFS_STANDARD_NAME_LENGTH] = "linkfile"; + CHAR pathname7[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname8[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + CHAR pathname9[JFFS_STANDARD_NAME_LENGTH] = { JFFS_MAIN_DIR0 }; + INT32 dirFd0 = -1; + INT32 dirFd1 = -1; + INT32 dirFd2 = -1; + DIR *dir0 = NULL; + DIR *dir1 = NULL; + DIR *dir2 = NULL; + + /* get dirfd0 */ + ret = mkdir(pathname1, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT); + + dir0 = opendir(pathname1); + ICUNIT_GOTO_NOT_EQUAL(dir0, NULL, dir0, EXIT1); + + dirFd0 = dirfd(dir0); + ICUNIT_GOTO_NOT_EQUAL(dirFd0, JFFS_IS_ERROR, dirFd0, EXIT2); + + /* get dirfd1 */ + ret = mkdir(pathname2, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + dir1 = opendir(pathname2); + ICUNIT_GOTO_NOT_EQUAL(dir1, NULL, dir1, EXIT3); + + dirFd1 = dirfd(dir1); + ICUNIT_GOTO_NOT_EQUAL(dirFd1, JFFS_IS_ERROR, dirFd1, EXIT4); + + /* get dirfd2 */ + ret = mkdir(pathname3, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + dir2 = opendir(pathname3); + ICUNIT_GOTO_NOT_EQUAL(dir2, NULL, dir2, EXIT5); + + dirFd2 = dirfd(dir2); + ICUNIT_GOTO_NOT_EQUAL(dirFd2, JFFS_IS_ERROR, dirFd2, EXIT6); + + /* creat a dangling symbolic link */ + strcat(pathname9, "/not_exist"); + ret = symlinkat(pathname9, dirFd1, pathname5); + ICUNIT_GOTO_NOT_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT6); + + /* creat a hard link to the dangling symlink file */ + ret = linkat(dirFd1, pathname5, dirFd2, pathname6, 1); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT7); + ICUNIT_GOTO_EQUAL(errno, EINVAL, errno, EXIT7); + + ret = linkat(dirFd1, pathname5, dirFd2, pathname6, AT_SYMLINK_FOLLOW); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT7); + ICUNIT_GOTO_EQUAL(errno, ENOENT, errno, EXIT7); + + ret = linkat(dirFd1, pathname5, dirFd2, pathname6, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT7); + + ret = unlinkat(dirFd1, pathname5, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT7); + + ret = unlinkat(dirFd2, pathname6, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT8); + + /* creat two looped symbolic link */ + strcat(pathname7, "/"); + strcat(pathname7, pathname4); + ret = symlinkat(pathname7, dirFd1, pathname5); + ICUNIT_GOTO_NOT_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT6); + + strcat(pathname8, "/"); + strcat(pathname8, pathname5); + ret = symlinkat(pathname8, dirFd0, pathname4); + ICUNIT_GOTO_NOT_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT7); + + /* creat a hard link to the looped symlink file */ + ret = linkat(dirFd1, pathname5, dirFd2, pathname6, AT_SYMLINK_FOLLOW); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT9); + ICUNIT_GOTO_EQUAL(errno, ELOOP, errno, EXIT9); + + ret = linkat(dirFd1, pathname5, dirFd2, pathname6, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT9); + + /* remove all */ + ret = unlinkat(dirFd2, pathname6, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT10); + + ret = unlinkat(dirFd0, pathname4, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT9); + + ret = unlinkat(dirFd1, pathname5, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT7); + + ret = closedir(dir2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT6); + + ret = rmdir(pathname3); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT5); + + ret = closedir(dir1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = rmdir(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = closedir(dir0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = rmdir(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT10: + unlinkat(dirFd2, pathname6, 0); +EXIT9: + unlinkat(dirFd0, pathname4, 0); + goto EXIT7; +EXIT8: + unlinkat(dirFd2, pathname6, 0); +EXIT7: + unlinkat(dirFd1, pathname5, 0); +EXIT6: + closedir(dir2); +EXIT5: + rmdir(pathname3); +EXIT4: + closedir(dir1); +EXIT3: + rmdir(pathname2); +EXIT2: + closedir(dir0); +EXIT1: + rmdir(pathname1); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestLinkat003(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_LINKAT_003", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_readlink_001.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_readlink_001.cpp new file mode 100644 index 00000000..e80aa975 --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_readlink_001.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 ret; + size_t readSize = 3; + CHAR filebuf[PATH_MAX + 2] = {""}; + CHAR readbuf[JFFS_STANDARD_NAME_LENGTH] = {0}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + + for (int i = 0; i < PATH_MAX + 1; i++) { + strcat(filebuf, "d"); + } + filebuf[PATH_MAX + 1] = '\0'; + + fd = creat(pathname1, 0777); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = symlink(pathname1, pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + ret = readlink(pathname1, readbuf, JFFS_STANDARD_NAME_LENGTH); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT3); + ICUNIT_GOTO_EQUAL(errno, EINVAL, errno, EXIT3); + + ret = readlink(pathname2, readbuf, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT3); + ICUNIT_GOTO_EQUAL(errno, EINVAL, errno, EXIT3); + + ret = readlink(filebuf, readbuf, JFFS_STANDARD_NAME_LENGTH); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT3); + ICUNIT_GOTO_EQUAL(errno, ENAMETOOLONG, errno, EXIT3); + + ret = readlink(pathname2, readbuf, JFFS_STANDARD_NAME_LENGTH); + ICUNIT_GOTO_EQUAL(ret, strlen(pathname1), ret, EXIT3); + ICUNIT_GOTO_STRING_EQUAL(readbuf, pathname1, readbuf, EXIT3); + + ret = readlink(pathname2, readbuf, readSize); + ICUNIT_GOTO_EQUAL(ret, readSize - 1, ret, EXIT3); + ICUNIT_GOTO_STRING_EQUAL(readbuf, "/s", readbuf, EXIT3); + + ret = unlink(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = unlink(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + return JFFS_NO_ERROR; + +EXIT3: + unlink(pathname2); + goto EXIT1; +EXIT2: + close(fd); +EXIT1: + unlink(pathname1); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestReadlink001(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_READLINK_001", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} + diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_001.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_001.cpp new file mode 100644 index 00000000..ceabe1c3 --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_001.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 fd1 = -1; + INT32 len, ret; + struct stat statBuf1 = {0}; + CHAR filebuf[JFFS_STANDARD_NAME_LENGTH] = "1234567890abcde&"; + CHAR readbuf[JFFS_STANDARD_NAME_LENGTH] = {0}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + + fd = open(pathname1, O_NONBLOCK | O_CREAT | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT); + + len = write(fd, filebuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT3); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = symlink(pathname1, pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + ret = stat(pathname2, &statBuf1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf1.st_mode & S_IFMT, S_IFLNK, statBuf1.st_mode & S_IFMT, EXIT2); + ICUNIT_GOTO_EQUAL(statBuf1.st_size, strlen(pathname1), statBuf1.st_size, EXIT2); + + len = readlink(pathname2, readbuf, sizeof(readbuf)); + ICUNIT_GOTO_EQUAL(len, strlen(pathname1), len, EXIT1); + ICUNIT_GOTO_STRING_EQUAL(readbuf, pathname1, readbuf, EXIT2); + + fd1 = open(pathname2, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT2); + + memset(readbuf, 0, JFFS_STANDARD_NAME_LENGTH); + len = read(fd1, readbuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT4); + ICUNIT_GOTO_STRING_EQUAL(readbuf, filebuf, readbuf, EXIT4); + + ret = close(fd1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = unlink(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = unlink(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT4: + close(fd1); + goto EXIT2; +EXIT3: + close(fd); + goto EXIT1; +EXIT2: + unlink(pathname2); +EXIT1: + unlink(pathname1); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestSymlink001(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_SYMLINK_001", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} + diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_002.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_002.cpp new file mode 100644 index 00000000..fb647dba --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_002.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 len, ret; + CHAR readbuf[JFFS_STANDARD_NAME_LENGTH] = {0}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + + ret = symlink(pathname1, pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT); + + len = readlink(pathname2, readbuf, sizeof(readbuf)); + ICUNIT_GOTO_EQUAL(len, strlen(pathname1), len, EXIT1); + ICUNIT_GOTO_STRING_EQUAL(readbuf, pathname1, readbuf, EXIT1); + + ret = symlink(pathname2, pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + memset(readbuf, 0, sizeof(readbuf)); + len = readlink(pathname1, readbuf, sizeof(readbuf)); + ICUNIT_GOTO_EQUAL(len, strlen(pathname2), len, EXIT2); + ICUNIT_GOTO_STRING_EQUAL(readbuf, pathname2, readbuf, EXIT2); + + fd = open(pathname2, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT2); + ICUNIT_GOTO_EQUAL(errno, ELOOP, errno, EXIT2); + + ret = unlink(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = unlink(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT2: + unlink(pathname1); +EXIT1: + unlink(pathname2); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestSymlink002(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_SYMLINK_002", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} + diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_003.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_003.cpp new file mode 100644 index 00000000..463f3afb --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_symlink_003.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 ret; + CHAR filebuf[PATH_MAX + 2] = {""}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + CHAR pathname3[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME02 }; + CHAR pathname4[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME03 }; + CHAR pathname5[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME04 }; + + for (int i = 0; i < PATH_MAX + 1; i++) { + strcat(filebuf, "d"); + } + filebuf[PATH_MAX + 1] = '\0'; + ret = symlink(filebuf, pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT); + ICUNIT_GOTO_EQUAL(errno, ENAMETOOLONG, errno, EXIT); + + ret = symlink("dddddddddddddd", pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + fd = open(pathname2, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT1); + ICUNIT_GOTO_EQUAL(errno, ENOENT, errno, EXIT1); + + ret = symlink("aaaaaaaaaaaaaaa", pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT1); + ICUNIT_GOTO_EQUAL(errno, EEXIST, errno, EXIT1); + + ret = symlink("", pathname3); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + fd = open(pathname3, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT2); + ICUNIT_GOTO_EQUAL(errno, EINVAL, errno, EXIT2); + + fd = creat(pathname4, 0777); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT2); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = symlink(pathname4, pathname5); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + fd = open(pathname5, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT5); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT6); + + ret = unlink(pathname4); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT5); + + fd = open(pathname5, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT7); + ICUNIT_GOTO_EQUAL(errno, ENOENT, errno, EXIT7); + + ret = unlink(pathname5); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT7); + + ret = unlink(pathname3); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = unlink(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT7: + unlink(pathname5); + goto EXIT2; +EXIT6: + close(fd); +EXIT5: + unlink(pathname5); + goto EXIT3; +EXIT4: + close(fd); +EXIT3: + unlink(pathname4); +EXIT2: + unlink(pathname3); +EXIT1: + unlink(pathname2); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestSymlink003(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_SYMLINK_003", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} + diff --git a/testsuites/unittest/fs/jffs/full/It_vfs_test_symlinkat_001.cpp b/testsuites/unittest/fs/jffs/full/It_vfs_test_symlinkat_001.cpp new file mode 100644 index 00000000..2124ab0c --- /dev/null +++ b/testsuites/unittest/fs/jffs/full/It_vfs_test_symlinkat_001.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "It_vfs_jffs.h" + +static UINT32 testcase(VOID) +{ + INT32 fd = -1; + INT32 fd1 = -1; + INT32 len, ret; + CHAR filebuf[JFFS_STANDARD_NAME_LENGTH] = "1234567890abcde&"; + CHAR readbuf[JFFS_STANDARD_NAME_LENGTH] = {0}; + CHAR pathname1[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname2[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + CHAR pathname3[JFFS_STANDARD_NAME_LENGTH] = "originfile"; + CHAR pathname4[JFFS_STANDARD_NAME_LENGTH] = "linkfile"; + CHAR pathname5[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME0 }; + CHAR pathname6[JFFS_STANDARD_NAME_LENGTH] = { JFFS_PATH_NAME01 }; + INT32 olddirFd = -1; + INT32 newdirFd = -1; + DIR *olddir = NULL; + DIR *newdir = NULL; + + ret = mkdir(pathname1, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT); + + olddir = opendir(pathname1); + ICUNIT_GOTO_NOT_EQUAL(olddir, NULL, olddir, EXIT1); + + olddirFd = dirfd(olddir); + ICUNIT_GOTO_NOT_EQUAL(olddirFd, JFFS_IS_ERROR, olddirFd, EXIT2); + + ret = mkdir(pathname2, 0777); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + newdir = opendir(pathname2); + ICUNIT_GOTO_NOT_EQUAL(newdir, NULL, newdir, EXIT3); + + newdirFd = dirfd(newdir); + ICUNIT_GOTO_NOT_EQUAL(newdirFd, JFFS_IS_ERROR, newdirFd, EXIT4); + + fd = openat(olddirFd, pathname3, O_NONBLOCK | O_CREAT | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd, JFFS_IS_ERROR, fd, EXIT4); + + len = write(fd, filebuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT6); + + ret = close(fd); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT6); + + strcat(pathname5, "/"); + strcat(pathname5, pathname3); + ret = symlinkat(pathname5, newdirFd, pathname4); + ICUNIT_GOTO_NOT_EQUAL(ret, JFFS_IS_ERROR, ret, EXIT5); + + len = readlinkat(newdirFd, pathname4, readbuf, sizeof(readbuf)); + ICUNIT_GOTO_EQUAL(len, strlen(pathname5), len, EXIT1); + ICUNIT_GOTO_STRING_EQUAL(readbuf, pathname5, readbuf, EXIT2); + + fd1 = openat(newdirFd, pathname4, O_NONBLOCK | O_RDWR, HIGHEST_AUTHORITY); + ICUNIT_GOTO_NOT_EQUAL(fd1, JFFS_IS_ERROR, fd1, EXIT5); + + memset(readbuf, 0, JFFS_STANDARD_NAME_LENGTH); + len = read(fd1, readbuf, strlen(filebuf)); + ICUNIT_GOTO_EQUAL(len, strlen(filebuf), len, EXIT8); + ICUNIT_GOTO_STRING_EQUAL(readbuf, filebuf, readbuf, EXIT8); + + ret = close(fd1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT8); + + ret = unlinkat(newdirFd, pathname4, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT7); + + ret = unlinkat(olddirFd, pathname3, 0); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT5); + + ret = closedir(newdir); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT4); + + ret = rmdir(pathname2); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT3); + + ret = closedir(olddir); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT2); + + ret = rmdir(pathname1); + ICUNIT_GOTO_EQUAL(ret, JFFS_NO_ERROR, ret, EXIT1); + + return JFFS_NO_ERROR; + +EXIT8: + close(fd1); +EXIT7: + unlinkat(newdirFd, pathname4, 0); + goto EXIT5; +EXIT6: + close(fd); +EXIT5: + unlinkat(olddirFd, pathname3, 0); +EXIT4: + closedir(newdir); +EXIT3: + rmdir(pathname2); +EXIT2: + closedir(olddir); +EXIT1: + rmdir(pathname1); +EXIT: + return JFFS_NO_ERROR; +} + +VOID ItFsTestSymlinkat001(VOID) +{ + TEST_ADD_CASE("IT_FS_TEST_SYMLINKAT_001", testcase, TEST_VFS, TEST_JFFS, TEST_LEVEL0, TEST_FUNCTION); +} diff --git a/testsuites/unittest/fs/jffs/vfs_jffs_test.cpp b/testsuites/unittest/fs/jffs/vfs_jffs_test.cpp index 2b12f2be..531fed81 100644 --- a/testsuites/unittest/fs/jffs/vfs_jffs_test.cpp +++ b/testsuites/unittest/fs/jffs/vfs_jffs_test.cpp @@ -353,7 +353,7 @@ INT32 JffsFixWrite(CHAR *path, INT64 fileSize, INT32 writeSize, INT32 interfaceT gettimeofday(&testTime2, 0); perTime = (testTime2.tv_sec - testTime1.tv_sec) * USECS_PER_SEC + (testTime2.tv_usec - testTime1.tv_usec); - printf("fix_Write TaskID:%3d,sucess to fclose the %s ,task:%lld ms,\n", taskId, path, MSECS_PER_SEC / MSECS_PER_SEC); + printf("fix_Write TaskID:%3d,sucess to fclose the %s ,task:%d ms,\n", taskId, path, MSECS_PER_SEC / MSECS_PER_SEC); free(writeBuf); @@ -6820,6 +6820,61 @@ HWTEST_F(VfsJffsTest, ItFsJffs808, TestSize.Level0) ItFsJffs808(); } +HWTEST_F(VfsJffsTest, ItFsTestLink001, TestSize.Level0) +{ + ItFsTestLink001(); +} + +HWTEST_F(VfsJffsTest, ItFsTestLink002, TestSize.Level0) +{ + ItFsTestLink002(); +} + +HWTEST_F(VfsJffsTest, ItFsTestLink003, TestSize.Level0) +{ + ItFsTestLink003(); +} + +HWTEST_F(VfsJffsTest, ItFsTestLinkat001, TestSize.Level0) +{ + ItFsTestLinkat001(); +} + +HWTEST_F(VfsJffsTest, ItFsTestLinkat002, TestSize.Level0) +{ + ItFsTestLinkat002(); +} + +HWTEST_F(VfsJffsTest, ItFsTestLinkat003, TestSize.Level0) +{ + ItFsTestLinkat003(); +} + +HWTEST_F(VfsJffsTest, ItFsTestReadlink001, TestSize.Level0) +{ + ItFsTestReadlink001(); +} + +HWTEST_F(VfsJffsTest, ItFsTestSymlink001, TestSize.Level0) +{ + ItFsTestSymlink001(); +} + +HWTEST_F(VfsJffsTest, ItFsTestSymlink002, TestSize.Level0) +{ + ItFsTestSymlink002(); +} + +HWTEST_F(VfsJffsTest, ItFsTestSymlink003, TestSize.Level0) +{ + ItFsTestSymlink003(); +} + +HWTEST_F(VfsJffsTest, ItFsTestSymlinkat001, TestSize.Level0) +{ + ItFsTestSymlinkat001(); +} + #endif #if defined(LOSCFG_USER_TEST_SMOKE) /* *