2012-01-01 21:37:21 +08:00
|
|
|
/*
|
2021-03-08 18:19:04 +08:00
|
|
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
2012-01-01 21:37:21 +08:00
|
|
|
*
|
2018-10-15 01:46:07 +08:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2012-01-01 21:37:21 +08:00
|
|
|
*
|
|
|
|
* Change Logs:
|
|
|
|
* Date Author Notes
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <rtthread.h>
|
|
|
|
#include <dfs.h>
|
|
|
|
#include <dfs_fs.h>
|
2017-10-25 14:21:49 +08:00
|
|
|
#include <dfs_file.h>
|
|
|
|
|
2012-01-01 21:37:21 +08:00
|
|
|
#include "dfs_romfs.h"
|
|
|
|
|
|
|
|
int dfs_romfs_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
|
|
|
|
{
|
2022-04-06 21:13:12 +08:00
|
|
|
struct root_data *root_data;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
if (data == NULL)
|
|
|
|
return -EIO;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
root_data = (struct root_data *)rt_malloc(sizeof(struct root_data));
|
|
|
|
if (root_data)
|
|
|
|
{
|
|
|
|
long long size = sizeof(struct romfs_dirent);
|
|
|
|
root_data->dirent = (struct romfs_dirent *)data;
|
|
|
|
if ((const char *)root_data->dirent->data - root_data->dirent->name != 0x04)
|
|
|
|
root_data->offset = 0;
|
|
|
|
else
|
|
|
|
root_data->offset = (long long)root_data->dirent->name != size ? ((long long)data - (long long)root_data->dirent->name + size) : (long long)data;
|
|
|
|
fs->data = root_data;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -RT_ENOMEM;
|
|
|
|
}
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
return RT_EOK;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int dfs_romfs_unmount(struct dfs_filesystem *fs)
|
|
|
|
{
|
2022-04-06 21:13:12 +08:00
|
|
|
if (fs->data)
|
|
|
|
{
|
|
|
|
rt_free(fs->data);
|
|
|
|
}
|
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
return RT_EOK;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int dfs_romfs_ioctl(struct dfs_fd *file, int cmd, void *args)
|
|
|
|
{
|
2017-10-15 22:44:53 +08:00
|
|
|
return -EIO;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
2014-11-03 12:10:25 +08:00
|
|
|
rt_inline int check_dirent(struct romfs_dirent *dirent)
|
|
|
|
{
|
2014-11-03 17:32:50 +08:00
|
|
|
if ((dirent->type != ROMFS_DIRENT_FILE && dirent->type != ROMFS_DIRENT_DIR)
|
|
|
|
|| dirent->size == ~0)
|
2014-11-03 12:10:25 +08:00
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
struct romfs_dirent *dfs_romfs_lookup(struct root_data *root_data, const char *path, rt_size_t *size)
|
2012-01-01 21:37:21 +08:00
|
|
|
{
|
2017-10-15 22:44:53 +08:00
|
|
|
rt_size_t index, found;
|
|
|
|
const char *subpath, *subpath_end;
|
|
|
|
struct romfs_dirent *dirent;
|
|
|
|
rt_size_t dirent_size;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2014-11-03 12:10:25 +08:00
|
|
|
/* Check the root_dirent. */
|
2022-04-06 21:13:12 +08:00
|
|
|
if (check_dirent(root_data->dirent) != 0)
|
2017-10-15 22:44:53 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (path[0] == '/' && path[1] == '\0')
|
|
|
|
{
|
2022-04-06 21:13:12 +08:00
|
|
|
*size = root_data->dirent->size;
|
|
|
|
return root_data->dirent;
|
2017-10-15 22:44:53 +08:00
|
|
|
}
|
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
/* goto root directy entries */
|
|
|
|
dirent = (struct romfs_dirent *)(root_data->dirent->data + root_data->offset);
|
|
|
|
dirent_size = root_data->dirent->size;
|
2017-10-15 22:44:53 +08:00
|
|
|
|
|
|
|
/* get the end position of this subpath */
|
|
|
|
subpath_end = path;
|
|
|
|
/* skip /// */
|
|
|
|
while (*subpath_end && *subpath_end == '/')
|
|
|
|
subpath_end ++;
|
|
|
|
subpath = subpath_end;
|
|
|
|
while ((*subpath_end != '/') && *subpath_end)
|
|
|
|
subpath_end ++;
|
|
|
|
|
|
|
|
while (dirent != NULL)
|
|
|
|
{
|
|
|
|
found = 0;
|
|
|
|
|
|
|
|
/* search in folder */
|
|
|
|
for (index = 0; index < dirent_size; index ++)
|
|
|
|
{
|
2014-11-03 12:10:25 +08:00
|
|
|
if (check_dirent(&dirent[index]) != 0)
|
2017-10-15 22:44:53 +08:00
|
|
|
return NULL;
|
2022-04-06 21:13:12 +08:00
|
|
|
if (rt_strlen(dirent[index].name + root_data->offset) == (subpath_end - subpath) &&
|
|
|
|
rt_strncmp(dirent[index].name + root_data->offset, subpath, (subpath_end - subpath)) == 0)
|
2017-10-15 22:44:53 +08:00
|
|
|
{
|
|
|
|
dirent_size = dirent[index].size;
|
|
|
|
|
|
|
|
/* skip /// */
|
|
|
|
while (*subpath_end && *subpath_end == '/')
|
|
|
|
subpath_end ++;
|
|
|
|
subpath = subpath_end;
|
|
|
|
while ((*subpath_end != '/') && *subpath_end)
|
|
|
|
subpath_end ++;
|
|
|
|
|
|
|
|
if (!(*subpath))
|
|
|
|
{
|
|
|
|
*size = dirent_size;
|
|
|
|
return &dirent[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirent[index].type == ROMFS_DIRENT_DIR)
|
|
|
|
{
|
|
|
|
/* enter directory */
|
2022-04-06 21:13:12 +08:00
|
|
|
dirent = (struct romfs_dirent *)(dirent[index].data + root_data->offset);
|
2017-10-15 22:44:53 +08:00
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* return file dirent */
|
|
|
|
if (subpath != NULL)
|
|
|
|
break; /* not the end of path */
|
|
|
|
|
|
|
|
return &dirent[index];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
break; /* not found */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* not found */
|
|
|
|
return NULL;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
int dfs_romfs_read(struct dfs_fd *file, void *buf, size_t count)
|
2012-01-01 21:37:21 +08:00
|
|
|
{
|
2017-10-15 22:44:53 +08:00
|
|
|
rt_size_t length;
|
|
|
|
struct romfs_dirent *dirent;
|
2022-04-06 21:13:12 +08:00
|
|
|
struct root_data *root_data;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
root_data = (struct root_data *)file->fs->data;
|
2017-10-15 22:44:53 +08:00
|
|
|
dirent = (struct romfs_dirent *)file->data;
|
|
|
|
RT_ASSERT(dirent != NULL);
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2014-11-03 12:10:25 +08:00
|
|
|
if (check_dirent(dirent) != 0)
|
|
|
|
{
|
2017-10-15 22:44:53 +08:00
|
|
|
return -EIO;
|
2014-11-03 12:10:25 +08:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
if (count < file->size - file->pos)
|
|
|
|
length = count;
|
|
|
|
else
|
|
|
|
length = file->size - file->pos;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
if (length > 0)
|
2022-04-06 21:13:12 +08:00
|
|
|
memcpy(buf, &(dirent->data[file->pos]) + root_data->offset, length);
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
/* update file current position */
|
|
|
|
file->pos += length;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
return length;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
int dfs_romfs_lseek(struct dfs_fd *file, off_t offset)
|
2012-01-01 21:37:21 +08:00
|
|
|
{
|
2022-04-06 21:13:12 +08:00
|
|
|
if (offset <= (off_t)file->size)
|
2017-10-15 22:44:53 +08:00
|
|
|
{
|
|
|
|
file->pos = offset;
|
|
|
|
return file->pos;
|
|
|
|
}
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
return -EIO;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int dfs_romfs_close(struct dfs_fd *file)
|
|
|
|
{
|
2017-10-15 22:44:53 +08:00
|
|
|
file->data = NULL;
|
|
|
|
return RT_EOK;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int dfs_romfs_open(struct dfs_fd *file)
|
|
|
|
{
|
2017-10-15 22:44:53 +08:00
|
|
|
rt_size_t size;
|
|
|
|
struct romfs_dirent *dirent;
|
2022-04-06 21:13:12 +08:00
|
|
|
struct root_data *root_data;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
root_data = (struct root_data *)file->fs->data;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
if (check_dirent(root_data->dirent) != 0)
|
2017-10-15 22:44:53 +08:00
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
dirent = dfs_romfs_lookup(root_data, file->path, &size);
|
2017-10-15 22:44:53 +08:00
|
|
|
if (dirent == NULL)
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
/* entry is a directory file type */
|
|
|
|
if (dirent->type == ROMFS_DIRENT_DIR)
|
|
|
|
{
|
|
|
|
if (!(file->flags & O_DIRECTORY))
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* entry is a file, but open it as a directory */
|
|
|
|
if (file->flags & O_DIRECTORY)
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
file->data = dirent;
|
|
|
|
file->size = size;
|
|
|
|
file->pos = 0;
|
|
|
|
|
|
|
|
return RT_EOK;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int dfs_romfs_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
|
|
|
|
{
|
2017-10-15 22:44:53 +08:00
|
|
|
rt_size_t size;
|
|
|
|
struct romfs_dirent *dirent;
|
2022-04-06 21:13:12 +08:00
|
|
|
struct root_data *root_data;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
root_data = (struct root_data *)fs->data;
|
|
|
|
dirent = dfs_romfs_lookup(root_data, path, &size);
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
if (dirent == NULL)
|
|
|
|
return -ENOENT;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
st->st_dev = 0;
|
|
|
|
st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
|
2019-04-03 18:09:52 +08:00
|
|
|
S_IWUSR | S_IWGRP | S_IWOTH;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
if (dirent->type == ROMFS_DIRENT_DIR)
|
|
|
|
{
|
|
|
|
st->st_mode &= ~S_IFREG;
|
|
|
|
st->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
|
|
|
|
}
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
st->st_size = dirent->size;
|
|
|
|
st->st_mtime = 0;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
return RT_EOK;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
int dfs_romfs_getdents(struct dfs_fd *file, struct dirent *dirp, uint32_t count)
|
2012-01-01 21:37:21 +08:00
|
|
|
{
|
2022-04-06 21:13:12 +08:00
|
|
|
uint32_t index;
|
2017-10-15 22:44:53 +08:00
|
|
|
const char *name;
|
|
|
|
struct dirent *d;
|
|
|
|
struct romfs_dirent *dirent, *sub_dirent;
|
2022-04-06 21:13:12 +08:00
|
|
|
struct root_data *root_data;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2022-04-06 21:13:12 +08:00
|
|
|
root_data = (struct root_data *)file->fs->data;
|
2017-10-15 22:44:53 +08:00
|
|
|
dirent = (struct romfs_dirent *)file->data;
|
2014-11-03 12:10:25 +08:00
|
|
|
if (check_dirent(dirent) != 0)
|
2017-10-15 22:44:53 +08:00
|
|
|
return -EIO;
|
|
|
|
RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
/* enter directory */
|
2022-04-06 21:13:12 +08:00
|
|
|
dirent = (struct romfs_dirent *)(dirent->data + root_data->offset);
|
2014-11-03 12:10:25 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
/* make integer count */
|
|
|
|
count = (count / sizeof(struct dirent));
|
|
|
|
if (count == 0)
|
|
|
|
return -EINVAL;
|
2014-11-03 12:10:25 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
index = 0;
|
2022-04-06 21:13:12 +08:00
|
|
|
for (index = 0; index < count && (size_t)file->pos < file->size; index ++)
|
2017-10-15 22:44:53 +08:00
|
|
|
{
|
|
|
|
d = dirp + index;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
sub_dirent = &dirent[file->pos];
|
2022-04-06 21:13:12 +08:00
|
|
|
name = sub_dirent->name + root_data->offset;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
/* fill dirent */
|
|
|
|
if (sub_dirent->type == ROMFS_DIRENT_DIR)
|
|
|
|
d->d_type = DT_DIR;
|
|
|
|
else
|
|
|
|
d->d_type = DT_REG;
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
d->d_namlen = rt_strlen(name);
|
|
|
|
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
2022-04-06 21:13:12 +08:00
|
|
|
rt_strncpy(d->d_name, name, rt_strlen(name) + 1);
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
/* move to next position */
|
|
|
|
++ file->pos;
|
|
|
|
}
|
2012-01-01 21:37:21 +08:00
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
return index * sizeof(struct dirent);
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:44:53 +08:00
|
|
|
static const struct dfs_file_ops _rom_fops =
|
2012-01-01 21:37:21 +08:00
|
|
|
{
|
2017-10-15 22:44:53 +08:00
|
|
|
dfs_romfs_open,
|
|
|
|
dfs_romfs_close,
|
|
|
|
dfs_romfs_ioctl,
|
|
|
|
dfs_romfs_read,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
dfs_romfs_lseek,
|
|
|
|
dfs_romfs_getdents,
|
|
|
|
};
|
|
|
|
static const struct dfs_filesystem_ops _romfs =
|
|
|
|
{
|
|
|
|
"rom",
|
|
|
|
DFS_FS_FLAG_DEFAULT,
|
|
|
|
&_rom_fops,
|
|
|
|
|
|
|
|
dfs_romfs_mount,
|
|
|
|
dfs_romfs_unmount,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
|
|
|
|
NULL,
|
|
|
|
dfs_romfs_stat,
|
|
|
|
NULL,
|
2012-01-01 21:37:21 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
int dfs_romfs_init(void)
|
|
|
|
{
|
|
|
|
/* register rom file system */
|
|
|
|
dfs_register(&_romfs);
|
2017-10-15 22:44:53 +08:00
|
|
|
return 0;
|
2012-01-01 21:37:21 +08:00
|
|
|
}
|
2017-11-03 11:44:37 +08:00
|
|
|
INIT_COMPONENT_EXPORT(dfs_romfs_init);
|
2012-01-01 21:37:21 +08:00
|
|
|
|