feat(dfs_v2/cromfs): add symlink support (#8132)

This commit is contained in:
xqyjlj 2023-10-17 09:55:28 +08:00 committed by GitHub
parent 61f7d483e2
commit 1e0f406b4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 143 additions and 26 deletions

View File

@ -50,8 +50,12 @@ typedef struct
uint8_t padding[CROMFS_PATITION_HEAD_SIZE - sizeof(partition_head_data)]; uint8_t padding[CROMFS_PATITION_HEAD_SIZE - sizeof(partition_head_data)];
} partition_head; } partition_head;
#define CROMFS_DIRENT_ATTR_DIR 0x1UL enum
#define CROMFS_DIRENT_ATTR_FILE 0x0UL {
CROMFS_DIRENT_ATTR_FILE = 0x0UL,
CROMFS_DIRENT_ATTR_DIR = 0x1UL,
CROMFS_DIRENT_ATTR_SYMLINK = 0x2UL,
};
typedef struct typedef struct
{ {
@ -607,12 +611,12 @@ static int dfs_cromfs_unmount(struct dfs_mnt *mnt)
return RT_EOK; return RT_EOK;
} }
static uint32_t cromfs_lookup(cromfs_info *ci, const char *path, int* is_dir, uint32_t *size, uint32_t *osize) static uint32_t cromfs_lookup(cromfs_info *ci, const char *path, int* file_type, uint32_t *size, uint32_t *osize)
{ {
uint32_t cur_size = 0, cur_pos = 0, cur_osize = 0; uint32_t cur_size = 0, cur_pos = 0, cur_osize = 0;
const char *subpath = NULL, *subpath_end = NULL; const char *subpath = NULL, *subpath_end = NULL;
void *di_mem = NULL; void *di_mem = NULL;
int isdir = 0; int _file_type = 0;
if (path[0] == '\0') if (path[0] == '\0')
{ {
@ -622,7 +626,7 @@ static uint32_t cromfs_lookup(cromfs_info *ci, const char *path, int* is_dir, ui
cur_size = ci->part_info.root_dir_size; cur_size = ci->part_info.root_dir_size;
cur_osize = 0; cur_osize = 0;
cur_pos = ci->part_info.root_dir_pos; cur_pos = ci->part_info.root_dir_pos;
isdir = 1; _file_type = CROMFS_DIRENT_ATTR_DIR;
subpath_end = path; subpath_end = path;
while (1) while (1)
@ -646,7 +650,7 @@ static uint32_t cromfs_lookup(cromfs_info *ci, const char *path, int* is_dir, ui
} }
/* if not dir or empty dir, error */ /* if not dir or empty dir, error */
if (!isdir || !cur_size) if (_file_type != CROMFS_DIRENT_ATTR_DIR || !cur_size)
{ {
return CROMFS_POS_ERROR; return CROMFS_POS_ERROR;
} }
@ -673,13 +677,21 @@ static uint32_t cromfs_lookup(cromfs_info *ci, const char *path, int* is_dir, ui
cur_size = di_iter->dirent.file_size; cur_size = di_iter->dirent.file_size;
cur_osize = di_iter->dirent.file_origin_size; cur_osize = di_iter->dirent.file_origin_size;
cur_pos = di_iter->dirent.parition_pos; cur_pos = di_iter->dirent.parition_pos;
if (di_iter->dirent.attr == CROMFS_DIRENT_ATTR_DIR) if (di_iter->dirent.attr == CROMFS_DIRENT_ATTR_FILE)
{ {
isdir = 1; _file_type = CROMFS_DIRENT_ATTR_FILE;
}
else if (di_iter->dirent.attr == CROMFS_DIRENT_ATTR_DIR)
{
_file_type = CROMFS_DIRENT_ATTR_DIR;
}
else if (di_iter->dirent.attr == CROMFS_DIRENT_ATTR_SYMLINK)
{
_file_type = CROMFS_DIRENT_ATTR_SYMLINK;
} }
else else
{ {
isdir = 0; RT_ASSERT(0);
} }
break; break;
} }
@ -698,11 +710,11 @@ static uint32_t cromfs_lookup(cromfs_info *ci, const char *path, int* is_dir, ui
} }
*size = cur_size; *size = cur_size;
*osize = cur_osize; *osize = cur_osize;
*is_dir = isdir; *file_type = _file_type;
return cur_pos; return cur_pos;
} }
static uint32_t __dfs_cromfs_lookup(cromfs_info *ci, const char *path, int* is_dir, uint32_t *size, uint32_t *osize) static uint32_t __dfs_cromfs_lookup(cromfs_info *ci, const char *path, int* file_type, uint32_t *size, uint32_t *osize)
{ {
rt_err_t result = RT_EOK; rt_err_t result = RT_EOK;
uint32_t ret = 0; uint32_t ret = 0;
@ -712,7 +724,7 @@ static uint32_t __dfs_cromfs_lookup(cromfs_info *ci, const char *path, int* is_d
{ {
return CROMFS_POS_ERROR; return CROMFS_POS_ERROR;
} }
ret = cromfs_lookup(ci, path, is_dir, size, osize); ret = cromfs_lookup(ci, path, file_type, size, osize);
rt_mutex_release(&ci->lock); rt_mutex_release(&ci->lock);
return ret; return ret;
} }
@ -839,7 +851,7 @@ static file_info *get_file_info(cromfs_info *ci, uint32_t partition_pos, int inc
return NULL; return NULL;
} }
static file_info *inset_file_info(cromfs_info *ci, uint32_t partition_pos, int is_dir, uint32_t size, uint32_t osize) static file_info *inset_file_info(cromfs_info *ci, uint32_t partition_pos, int file_type, uint32_t size, uint32_t osize)
{ {
file_info *fi = NULL; file_info *fi = NULL;
void *file_buff = NULL; void *file_buff = NULL;
@ -852,7 +864,7 @@ static file_info *inset_file_info(cromfs_info *ci, uint32_t partition_pos, int i
} }
fi->partition_pos = partition_pos; fi->partition_pos = partition_pos;
fi->ci = ci; fi->ci = ci;
if (is_dir) if (file_type == CROMFS_DIRENT_ATTR_DIR)
{ {
fi->size = size; fi->size = size;
} }
@ -949,7 +961,7 @@ static int dfs_cromfs_open(struct dfs_file *file)
cromfs_info *ci = NULL; cromfs_info *ci = NULL;
uint32_t file_pos = 0; uint32_t file_pos = 0;
uint32_t size = 0, osize = 0; uint32_t size = 0, osize = 0;
int is_dir = 0; int file_type = 0;
rt_err_t result = RT_EOK; rt_err_t result = RT_EOK;
if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR)) if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
@ -971,7 +983,7 @@ static int dfs_cromfs_open(struct dfs_file *file)
ci = (cromfs_info *)file->dentry->mnt->data; ci = (cromfs_info *)file->dentry->mnt->data;
file_pos = __dfs_cromfs_lookup(ci, file->dentry->pathname, &is_dir, &size, &osize); file_pos = __dfs_cromfs_lookup(ci, file->dentry->pathname, &file_type, &size, &osize);
if (file_pos == CROMFS_POS_ERROR) if (file_pos == CROMFS_POS_ERROR)
{ {
ret = -ENOENT; ret = -ENOENT;
@ -979,7 +991,7 @@ static int dfs_cromfs_open(struct dfs_file *file)
} }
/* entry is a directory file type */ /* entry is a directory file type */
if (is_dir) if (file_type == CROMFS_DIRENT_ATTR_DIR)
{ {
if (!(file->flags & O_DIRECTORY)) if (!(file->flags & O_DIRECTORY))
{ {
@ -988,6 +1000,10 @@ static int dfs_cromfs_open(struct dfs_file *file)
} }
file->vnode->type = FT_DIRECTORY; file->vnode->type = FT_DIRECTORY;
} }
else if (file_type == CROMFS_DIRENT_ATTR_SYMLINK)
{
file->vnode->type = FT_SYMLINK;
}
else else
{ {
/* entry is a file, but open it as a directory */ /* entry is a file, but open it as a directory */
@ -1009,7 +1025,7 @@ static int dfs_cromfs_open(struct dfs_file *file)
fi = get_file_info(ci, file_pos, 1); fi = get_file_info(ci, file_pos, 1);
if (!fi) if (!fi)
{ {
fi = inset_file_info(ci, file_pos, is_dir, size, osize); fi = inset_file_info(ci, file_pos, file_type, size, osize);
} }
rt_mutex_release(&ci->lock); rt_mutex_release(&ci->lock);
if (!fi) if (!fi)
@ -1019,7 +1035,7 @@ static int dfs_cromfs_open(struct dfs_file *file)
} }
file->vnode->data = fi; file->vnode->data = fi;
if (is_dir) if (file_type)
{ {
file->vnode->size = size; file->vnode->size = size;
} }
@ -1037,13 +1053,13 @@ end:
static int dfs_cromfs_stat(struct dfs_dentry *dentry, struct stat *st) static int dfs_cromfs_stat(struct dfs_dentry *dentry, struct stat *st)
{ {
uint32_t size = 0, osize = 0; uint32_t size = 0, osize = 0;
int is_dir = 0; int file_type = 0;
cromfs_info *ci = NULL; cromfs_info *ci = NULL;
uint32_t file_pos = 0; uint32_t file_pos = 0;
ci = (cromfs_info *)dentry->mnt->data; ci = (cromfs_info *)dentry->mnt->data;
file_pos = __dfs_cromfs_lookup(ci, dentry->pathname, &is_dir, &size, &osize); file_pos = __dfs_cromfs_lookup(ci, dentry->pathname, &file_type, &size, &osize);
if (file_pos == CROMFS_POS_ERROR) if (file_pos == CROMFS_POS_ERROR)
{ {
return -ENOENT; return -ENOENT;
@ -1053,12 +1069,18 @@ static int dfs_cromfs_stat(struct dfs_dentry *dentry, struct stat *st)
st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH; S_IWUSR | S_IWGRP | S_IWOTH;
if (is_dir) if (file_type == CROMFS_DIRENT_ATTR_DIR)
{ {
st->st_mode &= ~S_IFREG; st->st_mode &= ~S_IFREG;
st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
st->st_size = size; st->st_size = size;
} }
else if(file_type == CROMFS_DIRENT_ATTR_SYMLINK)
{
st->st_mode &= ~S_IFREG;
st->st_mode |= S_IFLNK | S_IXUSR | S_IXGRP | S_IXOTH;
st->st_size = osize;
}
else else
{ {
st->st_size = osize; st->st_size = osize;
@ -1167,8 +1189,8 @@ static struct dfs_vnode *dfs_cromfs_lookup (struct dfs_dentry *dentry)
if (ci) if (ci)
{ {
uint32_t size = 0, osize = 0; uint32_t size = 0, osize = 0;
int is_dir = 0; int file_type = 0;
uint32_t file_pos = __dfs_cromfs_lookup(ci, dentry->pathname, &is_dir, &size, &osize); uint32_t file_pos = __dfs_cromfs_lookup(ci, dentry->pathname, &file_type, &size, &osize);
if (file_pos != CROMFS_POS_ERROR) if (file_pos != CROMFS_POS_ERROR)
{ {
@ -1177,12 +1199,18 @@ static struct dfs_vnode *dfs_cromfs_lookup (struct dfs_dentry *dentry)
{ {
vnode->nlink = 1; vnode->nlink = 1;
if (is_dir) if (file_type == CROMFS_DIRENT_ATTR_DIR)
{ {
vnode->mode = S_IFDIR | (0555); vnode->mode = S_IFDIR | (0555);
vnode->type = FT_DIRECTORY; vnode->type = FT_DIRECTORY;
vnode->size = size; vnode->size = size;
} }
else if (file_type == CROMFS_DIRENT_ATTR_SYMLINK)
{
vnode->mode = S_IFLNK | (0555);
vnode->type = FT_SYMLINK;
vnode->size = osize;
}
else else
{ {
vnode->mode = S_IFREG | (0555); vnode->mode = S_IFREG | (0555);
@ -1203,6 +1231,85 @@ static int dfs_cromfs_free_vnode(struct dfs_vnode *vnode)
return 0; return 0;
} }
static int cromfs_readlink(cromfs_info *ci, char *path, char *buf, int len)
{
int ret = 0;
file_info *fi = NULL;
uint32_t file_pos = 0;
int file_type = 0;
uint32_t size = 0, osize = 0;
rt_err_t result = RT_EOK;
file_pos = __dfs_cromfs_lookup(ci, path, &file_type, &size, &osize);
if (file_pos == CROMFS_POS_ERROR)
{
ret = -ENOENT;
goto end1;
}
result = rt_mutex_take(&ci->lock, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
ret = -EINTR;
goto end;
}
fi = get_file_info(ci, file_pos, 1);
if (!fi)
{
fi = inset_file_info(ci, file_pos, file_type, size, osize);
}
rt_mutex_release(&ci->lock);
if (!fi)
{
ret = -ENOENT;
goto end;
}
if (len > 0)
{
RT_ASSERT(fi->size != 0);
RT_ASSERT(fi->buff);
int fill_ret = 0;
fill_ret = fill_file_data(fi);
if (fill_ret < 0)
{
ret = -ENOENT;
deref_file_info(ci, fi->partition_pos);
goto end;
}
len = len - 1;
osize = osize < len ? osize : len;
memcpy(buf, fi->buff, osize);
}
if (ret == 0)
{
buf[osize] = '\0';
ret = osize;
}
deref_file_info(ci, fi->partition_pos);
end:
rt_mutex_release(&ci->lock);
end1:
return ret;
}
static int dfs_cromfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
{
cromfs_info *ci = NULL;
if (dentry && buf)
{
ci = (cromfs_info *)dentry->mnt->data;
return cromfs_readlink(ci, dentry->pathname, buf, len);
}
return -EBADF;
}
static const struct dfs_file_ops _crom_fops = static const struct dfs_file_ops _crom_fops =
{ {
.open = dfs_cromfs_open, .open = dfs_cromfs_open,
@ -1219,6 +1326,9 @@ static const struct dfs_filesystem_ops _cromfs_ops =
.default_fops = &_crom_fops, .default_fops = &_crom_fops,
.mount = dfs_cromfs_mount, .mount = dfs_cromfs_mount,
.umount = dfs_cromfs_unmount, .umount = dfs_cromfs_unmount,
.readlink = dfs_cromfs_readlink,
.stat = dfs_cromfs_stat, .stat = dfs_cromfs_stat,
.lookup = dfs_cromfs_lookup, .lookup = dfs_cromfs_lookup,
.free_vnode = dfs_cromfs_free_vnode .free_vnode = dfs_cromfs_free_vnode

View File

@ -210,7 +210,7 @@ static char *dfs_nolink_path(struct dfs_mnt **mnt, char *fullpath, int mode)
char link_fn[DFS_PATH_MAX] = {0}; char link_fn[DFS_PATH_MAX] = {0};
struct dfs_dentry *dentry = RT_NULL; struct dfs_dentry *dentry = RT_NULL;
path = (char *)rt_malloc(DFS_PATH_MAX); path = (char *)rt_malloc((DFS_PATH_MAX * 2) + 1); // path + syslink + \0
if (!path) if (!path)
{ {
return path; return path;
@ -317,6 +317,13 @@ static char *dfs_nolink_path(struct dfs_mnt **mnt, char *fullpath, int mode)
{ {
rt_kprintf("link error: %s\n", path); rt_kprintf("link error: %s\n", path);
} }
char *_fullpath = dfs_normalize_path(RT_NULL, path);
if (_fullpath)
{
strncpy(path, _fullpath, DFS_PATH_MAX);
rt_free(_fullpath);
}
} }
dfs_dentry_unref(dentry); dfs_dentry_unref(dentry);
} }