2020-09-08 10:21:39 +08:00
|
|
|
/*
|
2021-03-11 18:43:57 +08:00
|
|
|
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
|
|
|
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
2020-09-08 10:21:39 +08:00
|
|
|
*
|
|
|
|
* 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 "errno.h"
|
|
|
|
#include "stdlib.h"
|
|
|
|
#include "string.h"
|
|
|
|
#include "dirent.h"
|
|
|
|
#include "unistd.h"
|
|
|
|
#include "sys/select.h"
|
2021-07-05 16:03:16 +08:00
|
|
|
#include "sys/mount.h"
|
2020-09-08 10:21:39 +08:00
|
|
|
#include "sys/stat.h"
|
2021-07-05 16:03:16 +08:00
|
|
|
#include "sys/statfs.h"
|
2020-09-08 10:21:39 +08:00
|
|
|
#include "sys/prctl.h"
|
|
|
|
#include "fs/fd_table.h"
|
2021-06-15 20:55:38 +08:00
|
|
|
#include "fs/file.h"
|
2020-09-08 10:21:39 +08:00
|
|
|
#include "linux/spinlock.h"
|
|
|
|
#include "los_process_pri.h"
|
|
|
|
#include "los_task_pri.h"
|
|
|
|
#include "capability_api.h"
|
2021-06-15 20:55:38 +08:00
|
|
|
#include "vnode.h"
|
2020-09-08 10:21:39 +08:00
|
|
|
|
|
|
|
#define MAX_DIR_ENT 1024
|
|
|
|
int fstat(int fd, struct stat *buf)
|
|
|
|
{
|
|
|
|
struct file *filep = NULL;
|
|
|
|
|
|
|
|
int ret = fs_getfilep(fd, &filep);
|
|
|
|
if (ret < 0) {
|
|
|
|
return VFS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat(filep->f_path, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fstat64(int fd, struct stat64 *buf)
|
|
|
|
{
|
|
|
|
struct file *filep = NULL;
|
|
|
|
|
|
|
|
int ret = fs_getfilep(fd, &filep);
|
|
|
|
if (ret < 0) {
|
|
|
|
return VFS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stat64(filep->f_path, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int lstat(const char *path, struct stat *buffer)
|
|
|
|
{
|
|
|
|
return stat(path, buffer);
|
|
|
|
}
|
|
|
|
|
2021-01-14 16:50:10 +08:00
|
|
|
int VfsVnodePermissionCheck(const struct Vnode *node, int accMode)
|
|
|
|
{
|
|
|
|
uint fuid = node->uid;
|
|
|
|
uint fgid = node->gid;
|
|
|
|
uint fileMode = node->mode;
|
|
|
|
return VfsPermissionCheck(fuid, fgid, fileMode, accMode);
|
|
|
|
}
|
2021-11-12 15:32:39 +08:00
|
|
|
|
2021-01-14 16:50:10 +08:00
|
|
|
int VfsPermissionCheck(uint fuid, uint fgid, uint fileMode, int accMode)
|
2020-09-08 10:21:39 +08:00
|
|
|
{
|
|
|
|
uint uid = OsCurrUserGet()->effUserID;
|
|
|
|
mode_t tmpMode = fileMode;
|
|
|
|
|
|
|
|
if (uid == fuid) {
|
|
|
|
tmpMode >>= USER_MODE_SHIFT;
|
|
|
|
} else if (LOS_CheckInGroups(fgid)) {
|
|
|
|
tmpMode >>= GROUP_MODE_SHIFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpMode &= (READ_OP | WRITE_OP | EXEC_OP);
|
|
|
|
|
2021-03-11 18:43:57 +08:00
|
|
|
if (((uint)accMode & tmpMode) == accMode) {
|
2020-09-08 10:21:39 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpMode = 0;
|
|
|
|
if (S_ISDIR(fileMode)) {
|
2021-04-16 17:33:40 +08:00
|
|
|
if (IsCapPermit(CAP_DAC_EXECUTE)
|
|
|
|
|| (!((uint)accMode & WRITE_OP) && IsCapPermit(CAP_DAC_READ_SEARCH))) {
|
2020-09-08 10:21:39 +08:00
|
|
|
tmpMode |= EXEC_OP;
|
|
|
|
}
|
|
|
|
} else {
|
2021-04-16 17:33:40 +08:00
|
|
|
if (IsCapPermit(CAP_DAC_EXECUTE) && (fileMode & MODE_IXUGO)) {
|
2020-09-08 10:21:39 +08:00
|
|
|
tmpMode |= EXEC_OP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-16 17:33:40 +08:00
|
|
|
if (IsCapPermit(CAP_DAC_WRITE)) {
|
2020-09-08 10:21:39 +08:00
|
|
|
tmpMode |= WRITE_OP;
|
|
|
|
}
|
|
|
|
|
2021-04-16 17:33:40 +08:00
|
|
|
if (IsCapPermit(CAP_DAC_READ_SEARCH)) {
|
2020-09-08 10:21:39 +08:00
|
|
|
tmpMode |= READ_OP;
|
|
|
|
}
|
|
|
|
|
2021-03-11 18:43:57 +08:00
|
|
|
if (((uint)accMode & tmpMode) == accMode) {
|
2020-09-08 10:21:39 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VFS_USING_WORKDIR
|
2021-03-11 18:43:57 +08:00
|
|
|
static int SetWorkDir(const char *dir, size_t len)
|
2020-09-08 10:21:39 +08:00
|
|
|
{
|
|
|
|
errno_t ret;
|
|
|
|
uint lock_flags;
|
|
|
|
LosProcessCB *curr = OsCurrProcessGet();
|
|
|
|
|
|
|
|
spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
|
|
|
|
ret = strncpy_s(curr->files->workdir, PATH_MAX, dir, len);
|
|
|
|
curr->files->workdir[PATH_MAX - 1] = '\0';
|
|
|
|
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
|
|
|
|
if (ret != EOK) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int chdir(const char *path)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char *fullpath = NULL;
|
|
|
|
char *fullpath_bak = NULL;
|
|
|
|
struct stat statBuff;
|
|
|
|
|
2021-01-14 16:50:10 +08:00
|
|
|
|
2020-09-08 10:21:39 +08:00
|
|
|
if (!path) {
|
|
|
|
set_errno(EFAULT);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strlen(path)) {
|
|
|
|
set_errno(ENOENT);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen(path) > PATH_MAX) {
|
|
|
|
set_errno(ENAMETOOLONG);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = vfs_normalize_path((const char *)NULL, path, &fullpath);
|
|
|
|
if (ret < 0) {
|
|
|
|
set_errno(-ret);
|
|
|
|
return -1; /* build path failed */
|
|
|
|
}
|
|
|
|
fullpath_bak = fullpath;
|
|
|
|
ret = stat(fullpath, &statBuff);
|
|
|
|
if (ret < 0) {
|
|
|
|
free(fullpath_bak);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!S_ISDIR(statBuff.st_mode)) {
|
|
|
|
set_errno(ENOTDIR);
|
|
|
|
free(fullpath_bak);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VfsPermissionCheck(statBuff.st_uid, statBuff.st_gid, statBuff.st_mode, EXEC_OP)) {
|
|
|
|
set_errno(EACCES);
|
|
|
|
free(fullpath_bak);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VFS_USING_WORKDIR
|
|
|
|
ret = SetWorkDir(fullpath, strlen(fullpath));
|
2021-11-12 15:32:39 +08:00
|
|
|
if (ret != 0) {
|
2020-09-08 10:21:39 +08:00
|
|
|
PRINT_ERR("chdir path error!\n");
|
|
|
|
ret = -1;
|
2021-11-12 15:32:39 +08:00
|
|
|
}
|
2020-09-08 10:21:39 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* release normalize directory path name */
|
|
|
|
|
|
|
|
free(fullpath_bak);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* this function is a POSIX compliant version, which will return current
|
|
|
|
* working directory.
|
|
|
|
*
|
|
|
|
* @param buf the returned current directory.
|
|
|
|
* @param size the buffer size.
|
|
|
|
*
|
|
|
|
* @return the returned current directory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *getcwd(char *buf, size_t n)
|
|
|
|
{
|
|
|
|
#ifdef VFS_USING_WORKDIR
|
|
|
|
int ret;
|
|
|
|
unsigned int len;
|
|
|
|
UINTPTR lock_flags;
|
|
|
|
LosProcessCB *curr = OsCurrProcessGet();
|
|
|
|
#endif
|
|
|
|
if (buf == NULL) {
|
|
|
|
set_errno(EINVAL);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
#ifdef VFS_USING_WORKDIR
|
|
|
|
spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
|
|
|
|
len = strlen(curr->files->workdir);
|
2021-11-12 15:32:39 +08:00
|
|
|
if (n <= len) {
|
2020-09-08 10:21:39 +08:00
|
|
|
set_errno(ERANGE);
|
|
|
|
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
|
|
|
|
return NULL;
|
2021-11-12 15:32:39 +08:00
|
|
|
}
|
2020-09-08 10:21:39 +08:00
|
|
|
ret = memcpy_s(buf, n, curr->files->workdir, len + 1);
|
2021-11-12 15:32:39 +08:00
|
|
|
if (ret != EOK) {
|
2020-09-08 10:21:39 +08:00
|
|
|
set_errno(ENAMETOOLONG);
|
|
|
|
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
|
|
|
|
return NULL;
|
2021-11-12 15:32:39 +08:00
|
|
|
}
|
2020-09-08 10:21:39 +08:00
|
|
|
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
|
|
|
|
#else
|
|
|
|
PRINT_ERR("NO_WORKING_DIR\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
int chmod(const char *path, mode_t mode)
|
|
|
|
{
|
2021-07-05 16:03:16 +08:00
|
|
|
struct IATTR attr = {0};
|
|
|
|
attr.attr_chg_mode = mode;
|
|
|
|
attr.attr_chg_valid = CHG_MODE; /* change mode */
|
|
|
|
int ret;
|
2020-09-08 10:21:39 +08:00
|
|
|
|
2021-07-05 16:03:16 +08:00
|
|
|
ret = chattr(path, &attr);
|
|
|
|
if (ret < 0) {
|
|
|
|
return VFS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int chown(const char *pathname, uid_t owner, gid_t group)
|
|
|
|
{
|
|
|
|
struct IATTR attr = {0};
|
|
|
|
attr.attr_chg_valid = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (owner != (uid_t)-1) {
|
|
|
|
attr.attr_chg_uid = owner;
|
|
|
|
attr.attr_chg_valid |= CHG_UID;
|
|
|
|
}
|
|
|
|
if (group != (gid_t)-1) {
|
|
|
|
attr.attr_chg_gid = group;
|
|
|
|
attr.attr_chg_valid |= CHG_GID;
|
|
|
|
}
|
|
|
|
ret = chattr(pathname, &attr);
|
|
|
|
if (ret < 0) {
|
2020-09-08 10:21:39 +08:00
|
|
|
return VFS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int access(const char *path, int amode)
|
|
|
|
{
|
2021-07-05 16:03:16 +08:00
|
|
|
int ret;
|
2020-09-08 10:21:39 +08:00
|
|
|
struct stat buf;
|
2021-07-05 16:03:16 +08:00
|
|
|
struct statfs fsBuf;
|
|
|
|
|
|
|
|
ret = statfs(path, &fsBuf);
|
|
|
|
if (ret != 0) {
|
|
|
|
if (get_errno() != ENOSYS) {
|
|
|
|
return VFS_ERROR;
|
|
|
|
}
|
|
|
|
/* dev has no statfs ops, need devfs to handle this in feature */
|
|
|
|
}
|
2020-09-08 10:21:39 +08:00
|
|
|
|
2021-07-05 16:03:16 +08:00
|
|
|
if ((fsBuf.f_flags & MS_RDONLY) && ((unsigned int)amode & W_OK)) {
|
|
|
|
set_errno(EROFS);
|
|
|
|
return VFS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = stat(path, &buf);
|
|
|
|
if (ret != 0) {
|
|
|
|
return VFS_ERROR;
|
|
|
|
}
|
2020-09-08 10:21:39 +08:00
|
|
|
|
2021-07-05 16:03:16 +08:00
|
|
|
if (VfsPermissionCheck(buf.st_uid, buf.st_gid, buf.st_mode, amode)) {
|
|
|
|
set_errno(EACCES);
|
2020-09-08 10:21:39 +08:00
|
|
|
return VFS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dirent **scandir_get_file_list(const char *dir, int *num, int(*filter)(const struct dirent *))
|
|
|
|
{
|
|
|
|
DIR *od = NULL;
|
|
|
|
int listSize = MAX_DIR_ENT;
|
2021-03-11 18:43:57 +08:00
|
|
|
int n = 0;
|
2020-09-08 10:21:39 +08:00
|
|
|
struct dirent **list = NULL;
|
|
|
|
struct dirent **newList = NULL;
|
|
|
|
struct dirent *ent = NULL;
|
|
|
|
struct dirent *p = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
od = opendir(dir);
|
|
|
|
if (od == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
list = (struct dirent **)malloc(listSize * sizeof(struct dirent *));
|
|
|
|
if (list == NULL) {
|
|
|
|
(void)closedir(od);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ent = readdir(od); ent != NULL; ent = readdir(od)) {
|
|
|
|
if (filter && !filter(ent)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n == listSize) {
|
|
|
|
listSize += MAX_DIR_ENT;
|
|
|
|
newList = (struct dirent **)malloc(listSize * sizeof(struct dirent *));
|
|
|
|
if (newList == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = memcpy_s(newList, listSize * sizeof(struct dirent *), list, n * sizeof(struct dirent *));
|
|
|
|
if (err != EOK) {
|
|
|
|
free(newList);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(list);
|
|
|
|
list = newList;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = (struct dirent *)malloc(sizeof(struct dirent));
|
|
|
|
if (p == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void)memcpy_s((void *)p, sizeof(struct dirent), (void *)ent, sizeof(struct dirent));
|
|
|
|
list[n] = p;
|
|
|
|
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (closedir(od) < 0) {
|
|
|
|
while (n--) {
|
|
|
|
free(list[n]);
|
|
|
|
}
|
|
|
|
free(list);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*num = n;
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
int scandir(const char *dir, struct dirent ***namelist,
|
|
|
|
int(*filter)(const struct dirent *),
|
2021-11-12 15:32:39 +08:00
|
|
|
int(*compar)(const struct dirent **, const struct dirent **))
|
2020-09-08 10:21:39 +08:00
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
struct dirent **list = NULL;
|
|
|
|
|
|
|
|
if ((dir == NULL) || (namelist == NULL)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
list = scandir_get_file_list(dir, &n, filter);
|
|
|
|
if (list == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Change to return to the array size */
|
|
|
|
*namelist = (struct dirent **)malloc(n * sizeof(struct dirent *));
|
|
|
|
if (*namelist == NULL && n > 0) {
|
|
|
|
*namelist = list;
|
|
|
|
} else if (*namelist != NULL) {
|
|
|
|
(void)memcpy_s(*namelist, n * sizeof(struct dirent *), list, n * sizeof(struct dirent *));
|
|
|
|
free(list);
|
|
|
|
} else {
|
|
|
|
free(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sort array */
|
|
|
|
|
|
|
|
if (compar && *namelist) {
|
|
|
|
qsort((void *)*namelist, (size_t)n, sizeof(struct dirent *), (int (*)(const void *, const void *))*compar);
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
int alphasort(const struct dirent **a, const struct dirent **b)
|
|
|
|
{
|
|
|
|
return strcoll((*a)->d_name, (*b)->d_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *rindex(const char *s, int c)
|
|
|
|
{
|
|
|
|
if (s == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't bother tracing - strrchr can do that */
|
|
|
|
return (char *)strrchr(s, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *ls_get_fullpath(const char *path, struct dirent *pdirent)
|
|
|
|
{
|
|
|
|
char *fullpath = NULL;
|
2021-11-12 15:32:39 +08:00
|
|
|
int ret;
|
2020-09-08 10:21:39 +08:00
|
|
|
|
|
|
|
if (path[1] != '\0') {
|
2021-11-12 15:32:39 +08:00
|
|
|
/* 2, The position of the path character: / and the end character '/0' */
|
2020-09-08 10:21:39 +08:00
|
|
|
fullpath = (char *)malloc(strlen(path) + strlen(pdirent->d_name) + 2);
|
|
|
|
if (fullpath == NULL) {
|
|
|
|
goto exit_with_nomem;
|
|
|
|
}
|
|
|
|
|
2021-11-12 15:32:39 +08:00
|
|
|
/* 2, The position of the path character: / and the end character '/0' */
|
2020-09-08 10:21:39 +08:00
|
|
|
ret = snprintf_s(fullpath, strlen(path) + strlen(pdirent->d_name) + 2,
|
|
|
|
strlen(path) + strlen(pdirent->d_name) + 1, "%s/%s", path, pdirent->d_name);
|
|
|
|
if (ret < 0) {
|
|
|
|
free(fullpath);
|
|
|
|
set_errno(ENAMETOOLONG);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
2021-11-12 15:32:39 +08:00
|
|
|
/* 2, The position of the path character: / and the end character '/0' */
|
2020-09-08 10:21:39 +08:00
|
|
|
fullpath = (char *)malloc(strlen(pdirent->d_name) + 2);
|
|
|
|
if (fullpath == NULL) {
|
|
|
|
goto exit_with_nomem;
|
|
|
|
}
|
|
|
|
|
2021-11-12 15:32:39 +08:00
|
|
|
/* 2, The position of the path character: / and the end character '/0' */
|
2020-09-08 10:21:39 +08:00
|
|
|
ret = snprintf_s(fullpath, strlen(pdirent->d_name) + 2, strlen(pdirent->d_name) + 1,
|
|
|
|
"/%s", pdirent->d_name);
|
|
|
|
if (ret < 0) {
|
|
|
|
free(fullpath);
|
|
|
|
set_errno(ENAMETOOLONG);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fullpath;
|
|
|
|
|
|
|
|
exit_with_nomem:
|
|
|
|
set_errno(ENOSPC);
|
|
|
|
return (char *)NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PrintFileInfo64(const struct stat64 *stat64Info, const char *name)
|
|
|
|
{
|
|
|
|
mode_t mode;
|
|
|
|
char str[UGO_NUMS][UGO_NUMS + 1] = {0};
|
|
|
|
char dirFlag;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UGO_NUMS; i++) {
|
2021-03-11 18:43:57 +08:00
|
|
|
mode = stat64Info->st_mode >> (uint)(USER_MODE_SHIFT - i * UGO_NUMS);
|
2020-09-08 10:21:39 +08:00
|
|
|
str[i][0] = (mode & READ_OP) ? 'r' : '-';
|
|
|
|
str[i][1] = (mode & WRITE_OP) ? 'w' : '-';
|
|
|
|
str[i][UGO_NUMS - 1] = (mode & EXEC_OP) ? 'x' : '-';
|
|
|
|
}
|
|
|
|
|
feat: support link/symlink/readlink
新增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 <chenjing139@huawei.com>
2021-06-04 10:30:12 +08:00
|
|
|
if (S_ISDIR(stat64Info->st_mode)) {
|
|
|
|
dirFlag = 'd';
|
|
|
|
} else if (S_ISLNK(stat64Info->st_mode)) {
|
|
|
|
dirFlag = 'l';
|
|
|
|
} else {
|
|
|
|
dirFlag = '-';
|
|
|
|
}
|
2020-09-08 10:21:39 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PrintFileInfo(const struct stat *statInfo, const char *name)
|
|
|
|
{
|
|
|
|
mode_t mode;
|
|
|
|
char str[UGO_NUMS][UGO_NUMS + 1] = {0};
|
|
|
|
char dirFlag;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UGO_NUMS; i++) {
|
2021-03-11 18:43:57 +08:00
|
|
|
mode = statInfo->st_mode >> (uint)(USER_MODE_SHIFT - i * UGO_NUMS);
|
2020-09-08 10:21:39 +08:00
|
|
|
str[i][0] = (mode & READ_OP) ? 'r' : '-';
|
|
|
|
str[i][1] = (mode & WRITE_OP) ? 'w' : '-';
|
|
|
|
str[i][UGO_NUMS - 1] = (mode & EXEC_OP) ? 'x' : '-';
|
|
|
|
}
|
|
|
|
|
feat: support link/symlink/readlink
新增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 <chenjing139@huawei.com>
2021-06-04 10:30:12 +08:00
|
|
|
if (S_ISDIR(statInfo->st_mode)) {
|
|
|
|
dirFlag = 'd';
|
|
|
|
} else if (S_ISLNK(statInfo->st_mode)) {
|
|
|
|
dirFlag = 'l';
|
|
|
|
} else {
|
|
|
|
dirFlag = '-';
|
|
|
|
}
|
2020-09-08 10:21:39 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2021-03-30 19:41:57 +08:00
|
|
|
|
|
|
|
int LsFile(const char *path)
|
2020-09-08 10:21:39 +08:00
|
|
|
{
|
2021-03-30 19:41:57 +08:00
|
|
|
struct stat64 stat64Info;
|
|
|
|
struct stat statInfo;
|
|
|
|
|
|
|
|
if (stat64(path, &stat64Info) == 0) {
|
|
|
|
PrintFileInfo64(&stat64Info, path);
|
|
|
|
} else if (stat(path, &statInfo) == 0) {
|
|
|
|
PrintFileInfo(&statInfo, path);
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int LsDir(const char *path)
|
|
|
|
{
|
|
|
|
struct stat statInfo = { 0 };
|
|
|
|
struct stat64 stat64Info = { 0 };
|
|
|
|
DIR *d = NULL;
|
2020-09-08 10:21:39 +08:00
|
|
|
char *fullpath = NULL;
|
|
|
|
char *fullpath_bak = NULL;
|
2021-03-30 19:41:57 +08:00
|
|
|
struct dirent *pdirent = NULL;
|
|
|
|
|
|
|
|
d = opendir(path);
|
|
|
|
if (d == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRINTK("Directory %s:\n", path);
|
|
|
|
do {
|
|
|
|
pdirent = readdir(d);
|
|
|
|
if (pdirent == NULL) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (!strcmp(pdirent->d_name, ".") || !strcmp(pdirent->d_name, "..")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(void)memset_s(&statInfo, sizeof(struct stat), 0, sizeof(struct stat));
|
|
|
|
(void)memset_s(&stat64Info, sizeof(struct stat), 0, sizeof(struct stat));
|
|
|
|
fullpath = ls_get_fullpath(path, pdirent);
|
|
|
|
if (fullpath == NULL) {
|
|
|
|
(void)closedir(d);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fullpath_bak = fullpath;
|
|
|
|
if (stat64(fullpath, &stat64Info) == 0) {
|
|
|
|
PrintFileInfo64(&stat64Info, pdirent->d_name);
|
|
|
|
} else if (stat(fullpath, &statInfo) == 0) {
|
|
|
|
PrintFileInfo(&statInfo, pdirent->d_name);
|
|
|
|
} else {
|
|
|
|
PRINTK("BAD file: %s\n", pdirent->d_name);
|
|
|
|
}
|
|
|
|
free(fullpath_bak);
|
|
|
|
}
|
|
|
|
} while (1);
|
|
|
|
(void)closedir(d);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ls(const char *pathname)
|
|
|
|
{
|
|
|
|
struct stat statInfo = { 0 };
|
|
|
|
char *path = NULL;
|
2020-09-08 10:21:39 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (pathname == NULL) {
|
|
|
|
#ifdef VFS_USING_WORKDIR
|
|
|
|
UINTPTR lock_flags;
|
|
|
|
LosProcessCB *curr = OsCurrProcessGet();
|
|
|
|
|
|
|
|
/* open current working directory */
|
|
|
|
|
|
|
|
spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
|
|
|
|
path = strdup(curr->files->workdir);
|
|
|
|
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
|
|
|
|
#else
|
|
|
|
path = strdup("/");
|
|
|
|
#endif
|
|
|
|
if (path == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = vfs_normalize_path(NULL, pathname, &path);
|
|
|
|
if (ret < 0) {
|
|
|
|
set_errno(-ret);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-30 19:41:57 +08:00
|
|
|
ret = stat(path, &statInfo);
|
|
|
|
if (ret < 0) {
|
2020-09-08 10:21:39 +08:00
|
|
|
perror("ls error");
|
2021-03-30 19:41:57 +08:00
|
|
|
free(path);
|
|
|
|
return;
|
|
|
|
}
|
2020-09-08 10:21:39 +08:00
|
|
|
|
2021-03-30 19:41:57 +08:00
|
|
|
if (statInfo.st_mode & S_IFDIR) { /* list all directory and file */
|
|
|
|
ret = LsDir((pathname == NULL) ? path : pathname);
|
|
|
|
} else { /* show the file infomation */
|
|
|
|
ret = LsFile(path);
|
|
|
|
}
|
|
|
|
if (ret < 0) {
|
|
|
|
perror("ls error");
|
2020-09-08 10:21:39 +08:00
|
|
|
}
|
|
|
|
|
2021-03-30 19:41:57 +08:00
|
|
|
free(path);
|
2020-09-08 10:21:39 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *realpath(const char *path, char *resolved_path)
|
|
|
|
{
|
|
|
|
int ret, result;
|
|
|
|
char *new_path = NULL;
|
|
|
|
struct stat buf;
|
|
|
|
|
|
|
|
ret = vfs_normalize_path(NULL, path, &new_path);
|
|
|
|
if (ret < 0) {
|
|
|
|
ret = -ret;
|
|
|
|
set_errno(ret);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = stat(new_path, &buf);
|
|
|
|
|
|
|
|
if (resolved_path == NULL) {
|
|
|
|
if (result != ENOERR) {
|
|
|
|
free(new_path);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return new_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = strcpy_s(resolved_path, PATH_MAX, new_path);
|
|
|
|
if (ret != EOK) {
|
|
|
|
ret = -ret;
|
|
|
|
set_errno(ret);
|
|
|
|
free(new_path);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(new_path);
|
|
|
|
if (result != ENOERR) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return resolved_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
void lsfd(void)
|
|
|
|
{
|
2021-01-14 16:50:10 +08:00
|
|
|
struct filelist *f_list = NULL;
|
2020-09-08 10:21:39 +08:00
|
|
|
unsigned int i = 3; /* file start fd */
|
|
|
|
int ret;
|
2021-01-14 16:50:10 +08:00
|
|
|
struct Vnode *node = NULL;
|
2020-09-08 10:21:39 +08:00
|
|
|
|
|
|
|
f_list = &tg_filelist;
|
|
|
|
|
|
|
|
PRINTK(" fd filename\n");
|
|
|
|
ret = sem_wait(&f_list->fl_sem);
|
|
|
|
if (ret < 0) {
|
|
|
|
PRINTK("sem_wait error, ret=%d\n", ret);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (i < CONFIG_NFILE_DESCRIPTORS) {
|
|
|
|
node = files_get_openfile(i);
|
|
|
|
if (node) {
|
|
|
|
PRINTK("%5d %s\n", i, f_list->fl_files[i].f_path);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
(void)sem_post(&f_list->fl_sem);
|
|
|
|
}
|
|
|
|
|
|
|
|
mode_t GetUmask(void)
|
|
|
|
{
|
|
|
|
return OsCurrProcessGet()->umask;
|
|
|
|
}
|
|
|
|
|
|
|
|
mode_t SysUmask(mode_t mask)
|
|
|
|
{
|
|
|
|
UINT32 intSave;
|
|
|
|
mode_t umask;
|
|
|
|
mode_t oldUmask;
|
|
|
|
umask = mask & UMASK_FULL;
|
|
|
|
SCHEDULER_LOCK(intSave);
|
|
|
|
oldUmask = OsCurrProcessGet()->umask;
|
|
|
|
OsCurrProcessGet()->umask = umask;
|
|
|
|
SCHEDULER_UNLOCK(intSave);
|
|
|
|
return oldUmask;
|
|
|
|
}
|
|
|
|
|