first
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# files format check exclude path, please follow the instructions below to modify;
|
||||
|
||||
dir_path:
|
||||
- elmfat
|
15
rt-thread/components/dfs/dfs_v2/filesystems/SConscript
Normal file
15
rt-thread/components/dfs/dfs_v2/filesystems/SConscript
Normal file
@@ -0,0 +1,15 @@
|
||||
# RT-Thread building script for bridge
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
objs = []
|
||||
list = os.listdir(cwd)
|
||||
|
||||
for d in list:
|
||||
path = os.path.join(cwd, d)
|
||||
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||
objs = objs + SConscript(os.path.join(d, 'SConscript'))
|
||||
|
||||
Return('objs')
|
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS','RT_USING_DFS_CROMFS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
1382
rt-thread/components/dfs/dfs_v2/filesystems/cromfs/dfs_cromfs.c
Normal file
1382
rt-thread/components/dfs/dfs_v2/filesystems/cromfs/dfs_cromfs.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2020, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2020/08/21 ShaoJinchun firset version
|
||||
*/
|
||||
|
||||
#ifndef __DFS_CROMFS_H__
|
||||
#define __DFS_CROMFS_H__
|
||||
|
||||
int dfs_cromfs_init(void);
|
||||
|
||||
#endif /*__DFS_CROMFS_H__*/
|
11
rt-thread/components/dfs/dfs_v2/filesystems/devfs/SConscript
Normal file
11
rt-thread/components/dfs/dfs_v2/filesystems/devfs/SConscript
Normal file
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_DEVFS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
520
rt-thread/components/dfs/dfs_v2/filesystems/devfs/devfs.c
Normal file
520
rt-thread/components/dfs/dfs_v2/filesystems/devfs/devfs.c
Normal file
@@ -0,0 +1,520 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2018-02-11 Bernard Ignore O_CREAT flag in open.
|
||||
*/
|
||||
#include <rthw.h>
|
||||
#include <rtdbg.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/unistd.h>
|
||||
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
|
||||
static int dfs_devfs_open(struct dfs_file *file)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
RT_ASSERT(file->vnode->ref_count > 0);
|
||||
|
||||
if (file->vnode->ref_count > 1)
|
||||
{
|
||||
if (file->vnode->type == FT_DIRECTORY
|
||||
&& !(file->flags & O_DIRECTORY))
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
file->fpos = 0;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(file->vnode->mode))
|
||||
{
|
||||
rt_device_t device = RT_NULL;
|
||||
struct dfs_dentry *de = file->dentry;
|
||||
char *device_name = rt_malloc(DFS_PATH_MAX);
|
||||
|
||||
if (!device_name)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* skip `/dev` */
|
||||
rt_snprintf(device_name, DFS_PATH_MAX, "%s%s", de->mnt->fullpath + sizeof("/dev") - 1, de->pathname);
|
||||
|
||||
device = rt_device_find(device_name + 1);
|
||||
if (device)
|
||||
{
|
||||
file->vnode->data = device;
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->open)
|
||||
{
|
||||
ret = device->fops->open(file);
|
||||
if (ret == RT_EOK || ret == -RT_ENOSYS)
|
||||
{
|
||||
ret = RT_EOK;
|
||||
}
|
||||
}
|
||||
else if (device->ops && file->vnode->ref_count == 1)
|
||||
#else
|
||||
if (device->ops && file->vnode->ref_count == 1)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
ret = rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
|
||||
if (ret == RT_EOK || ret == -RT_ENOSYS)
|
||||
{
|
||||
ret = RT_EOK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_devfs_close(struct dfs_file *file)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
RT_ASSERT(file->vnode->ref_count > 0);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->close)
|
||||
{
|
||||
ret = device->fops->close(file);
|
||||
}
|
||||
else if (file->vnode->ref_count == 1)
|
||||
#else
|
||||
if (device->ops && file->vnode->ref_count == 1)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
/* close device handler */
|
||||
ret = rt_device_close(device);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dfs_devfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
ssize_t ret = -RT_EIO;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->read)
|
||||
{
|
||||
ret = device->fops->read(file, buf, count, pos);
|
||||
}
|
||||
else
|
||||
#else
|
||||
if (device->ops)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
/* read device data */
|
||||
ret = rt_device_read(device, *pos, buf, count);
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dfs_devfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
ssize_t ret = -RT_EIO;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if(file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
if ((file->dentry->pathname[0] == '/') && (file->dentry->pathname[1] == '\0'))
|
||||
return -RT_ENOSYS;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->write)
|
||||
{
|
||||
ret = device->fops->write(file, buf, count, pos);
|
||||
}
|
||||
else
|
||||
#else
|
||||
if (device->ops)
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
/* read device data */
|
||||
ret = rt_device_write(device, *pos, buf, count);
|
||||
*pos += ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_devfs_ioctl(struct dfs_file *file, int cmd, void *args)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
if ((file->dentry->pathname[0] == '/') && (file->dentry->pathname[1] == '\0'))
|
||||
return -RT_ENOSYS;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->ioctl)
|
||||
{
|
||||
ret = device->fops->ioctl(file, cmd, args);
|
||||
}
|
||||
else
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
{
|
||||
ret = rt_device_control(device, cmd, args);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_devfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
int ret = -RT_ENOSYS;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_devfs_poll(struct dfs_file *file, struct rt_pollreq *req)
|
||||
{
|
||||
int mask = 0;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->poll)
|
||||
{
|
||||
mask = device->fops->poll(file, req);
|
||||
}
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int dfs_devfs_flush(struct dfs_file *file)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->flush)
|
||||
{
|
||||
ret = device->fops->flush(file);
|
||||
}
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static off_t dfs_devfs_lseek(struct dfs_file *file, off_t offset, int wherece)
|
||||
{
|
||||
off_t ret = 0;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->lseek)
|
||||
{
|
||||
ret = device->fops->lseek(file, offset, wherece);
|
||||
}
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_devfs_truncate(struct dfs_file *file, off_t offset)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->truncate)
|
||||
{
|
||||
ret = device->fops->truncate(file, offset);
|
||||
}
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_devfs_mmap(struct dfs_file *file, struct lwp_avl_struct *mmap)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->mmap)
|
||||
{
|
||||
ret = device->fops->mmap(file, mmap);
|
||||
}
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_devfs_lock(struct dfs_file *file, struct file_lock *flock)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->lock)
|
||||
{
|
||||
ret = device->fops->lock(file, flock);
|
||||
}
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dfs_devfs_flock(struct dfs_file *file, int operation, struct file_lock *flock)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
rt_device_t device;
|
||||
|
||||
RT_ASSERT(file != RT_NULL);
|
||||
|
||||
if (file->vnode && file->vnode->data)
|
||||
{
|
||||
/* get device handler */
|
||||
device = (rt_device_t)file->vnode->data;
|
||||
|
||||
#ifdef RT_USING_POSIX_DEVIO
|
||||
if (device->fops && device->fops->flock)
|
||||
{
|
||||
ret = device->fops->flock(file, operation, flock);
|
||||
}
|
||||
#endif /* RT_USING_POSIX_DEVIO */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _dev_fops =
|
||||
{
|
||||
.open = dfs_devfs_open,
|
||||
.close = dfs_devfs_close,
|
||||
.read = dfs_devfs_read,
|
||||
.write = dfs_devfs_write,
|
||||
.ioctl = dfs_devfs_ioctl,
|
||||
.getdents = dfs_devfs_getdents,
|
||||
.poll = dfs_devfs_poll,
|
||||
|
||||
.flush = dfs_devfs_flush,
|
||||
.lseek = dfs_devfs_lseek,
|
||||
.truncate = dfs_devfs_truncate,
|
||||
.mmap = dfs_devfs_mmap,
|
||||
.lock = dfs_devfs_lock,
|
||||
.flock = dfs_devfs_flock,
|
||||
};
|
||||
|
||||
const struct dfs_file_ops *dfs_devfs_fops(void)
|
||||
{
|
||||
return &_dev_fops;
|
||||
}
|
||||
|
||||
mode_t dfs_devfs_device_to_mode(struct rt_device *device)
|
||||
{
|
||||
mode_t mode = 0;
|
||||
|
||||
switch (device->type)
|
||||
{
|
||||
case RT_Device_Class_Char:
|
||||
mode = S_IFCHR | 0777;
|
||||
break;
|
||||
case RT_Device_Class_Block:
|
||||
mode = S_IFBLK | 0777;
|
||||
break;
|
||||
case RT_Device_Class_Pipe:
|
||||
mode = S_IFIFO | 0777;
|
||||
break;
|
||||
default:
|
||||
mode = S_IFCHR | 0777;
|
||||
break;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static void dfs_devfs_mkdir(const char *fullpath, mode_t mode)
|
||||
{
|
||||
int len = rt_strlen(fullpath);
|
||||
char *path = (char *)rt_malloc(len + 1);
|
||||
|
||||
if (path)
|
||||
{
|
||||
int index = len - 1;
|
||||
|
||||
rt_strcpy(path, fullpath);
|
||||
|
||||
if (path[index] == '/')
|
||||
{
|
||||
path[index] = '\0';
|
||||
index --;
|
||||
}
|
||||
|
||||
while (path[index] != '/' && index >= 0)
|
||||
{
|
||||
index --;
|
||||
}
|
||||
|
||||
path[index] = '\0';
|
||||
|
||||
if (index > 0 && access(path, 0) != 0)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (path[i] == '/')
|
||||
{
|
||||
i ++;
|
||||
}
|
||||
|
||||
while (index > i)
|
||||
{
|
||||
if (path[i] == '/')
|
||||
{
|
||||
path[i] = '\0';
|
||||
mkdir(path, mode);
|
||||
path[i] = '/';
|
||||
}
|
||||
|
||||
i ++;
|
||||
}
|
||||
|
||||
mkdir(path, mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dfs_devfs_device_add(rt_device_t device)
|
||||
{
|
||||
int fd;
|
||||
char path[512];
|
||||
|
||||
if (device)
|
||||
{
|
||||
rt_snprintf(path, 512, "/dev/%s", device->parent.name);
|
||||
|
||||
if (access(path, 0) != 0)
|
||||
{
|
||||
mode_t mode = dfs_devfs_device_to_mode(device);
|
||||
|
||||
dfs_devfs_mkdir(path, mode);
|
||||
|
||||
fd = open(path, O_RDWR | O_CREAT, mode);
|
||||
if (fd >= 0)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dfs_devfs_update(void)
|
||||
{
|
||||
int count = rt_object_get_length(RT_Object_Class_Device);
|
||||
if (count > 0)
|
||||
{
|
||||
rt_device_t *devices = rt_malloc(count * sizeof(rt_device_t));
|
||||
if (devices)
|
||||
{
|
||||
rt_object_get_pointers(RT_Object_Class_Device, (rt_object_t *)devices, count);
|
||||
|
||||
for (int index = 0; index < count; index ++)
|
||||
{
|
||||
dfs_devfs_device_add(devices[index]);
|
||||
}
|
||||
rt_free(devices);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
18
rt-thread/components/dfs/dfs_v2/filesystems/devfs/devfs.h
Normal file
18
rt-thread/components/dfs/dfs_v2/filesystems/devfs/devfs.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __DEVICE_FS_H__
|
||||
#define __DEVICE_FS_H__
|
||||
|
||||
const struct dfs_file_ops *dfs_devfs_fops(void);
|
||||
mode_t dfs_devfs_device_to_mode(struct rt_device *device);
|
||||
void dfs_devfs_device_add(rt_device_t device);
|
||||
int dfs_devfs_update(void);
|
||||
|
||||
#endif
|
678
rt-thread/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c
Normal file
678
rt-thread/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c
Normal file
@@ -0,0 +1,678 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-10-24 flybreak the first version
|
||||
* 2023-02-01 xqyjlj fix cannot open the same file repeatedly in 'w' mode
|
||||
* 2023-09-20 zmq810150896 adds truncate functionality and standardized unlink adaptations
|
||||
* 2023-12-02 Shell Support of dynamic device
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <devfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define TMPFS_MAGIC 0x0B0B0B0B
|
||||
#define TMPFS_TYPE_FILE 0x00
|
||||
#define TMPFS_TYPE_DIR 0x01
|
||||
#define TMPFS_TYPE_DYN_DEV 0x02 /* dynamic device */
|
||||
|
||||
struct devtmpfs_sb;
|
||||
|
||||
struct devtmpfs_file
|
||||
{
|
||||
char name[DIRENT_NAME_MAX]; /* file name */
|
||||
|
||||
rt_uint32_t type; /* file type */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
|
||||
struct devtmpfs_sb *sb; /* superblock ptr */
|
||||
|
||||
rt_uint32_t mode;
|
||||
char *link;
|
||||
};
|
||||
|
||||
struct devtmpfs_sb
|
||||
{
|
||||
rt_uint32_t magic; /* TMPFS_MAGIC */
|
||||
struct devtmpfs_file root; /* root dir */
|
||||
rt_size_t df_size; /* df size */
|
||||
rt_list_t sibling; /* sb sibling list */
|
||||
struct rt_spinlock lock; /* tmpfs lock */
|
||||
};
|
||||
|
||||
static struct dfs_file_ops _default_fops = { 0 };
|
||||
|
||||
static int _path_separate(const char *path, char *parent_path, char *file_name)
|
||||
{
|
||||
const char *path_p, *path_q;
|
||||
|
||||
RT_ASSERT(path[0] == '/');
|
||||
|
||||
file_name[0] = '\0';
|
||||
path_p = path_q = &path[1];
|
||||
__next_dir:
|
||||
while (*path_q != '/' && *path_q != '\0')
|
||||
{
|
||||
path_q++;
|
||||
}
|
||||
if (path_q != path_p) /*sub dir*/
|
||||
{
|
||||
if (*path_q != '\0')
|
||||
{
|
||||
path_q++;
|
||||
path_p = path_q;
|
||||
goto __next_dir;
|
||||
}
|
||||
else /* Last level dir */
|
||||
{
|
||||
rt_memcpy(parent_path, path, path_p - path - 1);
|
||||
parent_path[path_p - path - 1] = '\0';
|
||||
rt_memcpy(file_name, path_p, path_q - path_p);
|
||||
file_name[path_q - path_p] = '\0';
|
||||
}
|
||||
}
|
||||
if (parent_path[0] == 0)
|
||||
{
|
||||
parent_path[0] = '/';
|
||||
parent_path[1] = '\0';
|
||||
}
|
||||
//LOG_D("parent_path: %s", parent_path);
|
||||
//LOG_D("file_name: %s", file_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_subdir(const char *path, char *name)
|
||||
{
|
||||
const char *subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
subpath ++;
|
||||
while (*subpath != '/' && *subpath)
|
||||
{
|
||||
*name = *subpath;
|
||||
name ++;
|
||||
subpath ++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int _free_subdir(struct devtmpfs_file *dfile)
|
||||
{
|
||||
struct devtmpfs_file *file;
|
||||
rt_list_t *list, *temp_list;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||
|
||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
||||
{
|
||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
if (file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
_free_subdir(file);
|
||||
}
|
||||
|
||||
if (file->link)
|
||||
{
|
||||
rt_free(file->link);
|
||||
}
|
||||
|
||||
superblock = file->sb;
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int devtmpfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
|
||||
{
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
superblock = rt_calloc(1, sizeof(struct devtmpfs_sb));
|
||||
if (superblock)
|
||||
{
|
||||
superblock->df_size = sizeof(struct devtmpfs_sb);
|
||||
superblock->magic = TMPFS_MAGIC;
|
||||
rt_list_init(&superblock->sibling);
|
||||
|
||||
superblock->root.name[0] = '/';
|
||||
superblock->root.sb = superblock;
|
||||
superblock->root.type = TMPFS_TYPE_DIR;
|
||||
superblock->root.mode = S_IFDIR | (S_IRUSR | S_IRGRP | S_IROTH) | (S_IXUSR | S_IXGRP | S_IXOTH);
|
||||
rt_list_init(&superblock->root.sibling);
|
||||
rt_list_init(&superblock->root.subdirs);
|
||||
|
||||
rt_spin_lock_init(&superblock->lock);
|
||||
|
||||
mnt->data = superblock;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int devtmpfs_unmount(struct dfs_mnt *mnt)
|
||||
{
|
||||
#if 0
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
/* FIXME: don't unmount on busy. */
|
||||
superblock = (struct devtmpfs_sb *)mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
mnt->data = NULL;
|
||||
_free_subdir(&(superblock->root));
|
||||
rt_free(superblock);
|
||||
#endif
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
static struct devtmpfs_file *devtmpfs_file_lookup(struct devtmpfs_sb *superblock, const char *path)
|
||||
{
|
||||
const char *subpath, *curpath, *filename = RT_NULL;
|
||||
char subdir_name[DIRENT_NAME_MAX];
|
||||
struct devtmpfs_file *file, *curfile;
|
||||
rt_list_t *list;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
subpath ++;
|
||||
|
||||
if (! *subpath) /* is root directory */
|
||||
{
|
||||
return &(superblock->root);
|
||||
}
|
||||
|
||||
curpath = subpath;
|
||||
curfile = &superblock->root;
|
||||
|
||||
find_subpath:
|
||||
while (*subpath != '/' && *subpath)
|
||||
subpath ++;
|
||||
|
||||
if (! *subpath) /* is last directory */
|
||||
filename = curpath;
|
||||
else
|
||||
subpath ++; /* skip '/' */
|
||||
|
||||
memset(subdir_name, 0, DIRENT_NAME_MAX);
|
||||
_get_subdir(curpath, subdir_name);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
{
|
||||
file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
if (filename) /* find file */
|
||||
{
|
||||
if (rt_strcmp(file->name, filename) == 0)
|
||||
{
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
else if (rt_strcmp(file->name, subdir_name) == 0)
|
||||
{
|
||||
curpath = subpath;
|
||||
curfile = file;
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
goto find_subpath;
|
||||
}
|
||||
}
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
/* not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int devtmpfs_statfs(struct dfs_mnt *mnt, struct statfs *buf)
|
||||
{
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(mnt != NULL);
|
||||
RT_ASSERT(buf != NULL);
|
||||
|
||||
superblock = (struct devtmpfs_sb *)mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
buf->f_bsize = 512;
|
||||
buf->f_blocks = (superblock->df_size + 511) / 512;
|
||||
buf->f_bfree = 1;
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int devtmpfs_stat(struct dfs_dentry *dentry, struct stat *st)
|
||||
{
|
||||
struct dfs_vnode *vnode;
|
||||
|
||||
if (dentry && dentry->vnode)
|
||||
{
|
||||
vnode = dentry->vnode;
|
||||
|
||||
st->st_dev = (dev_t)(long)(dentry->mnt->dev_id);
|
||||
st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
|
||||
|
||||
st->st_gid = vnode->gid;
|
||||
st->st_uid = vnode->uid;
|
||||
st->st_mode = vnode->mode;
|
||||
st->st_nlink = vnode->nlink;
|
||||
st->st_size = vnode->size;
|
||||
st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
|
||||
st->st_mtim.tv_sec = vnode->mtime.tv_sec;
|
||||
st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
|
||||
st->st_ctim.tv_sec = vnode->ctime.tv_sec;
|
||||
st->st_atim.tv_nsec = vnode->atime.tv_nsec;
|
||||
st->st_atim.tv_sec = vnode->atime.tv_sec;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
struct devtmpfs_file *d_file;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(file);
|
||||
RT_ASSERT(file->dentry);
|
||||
RT_ASSERT(file->dentry->mnt);
|
||||
|
||||
superblock = (struct devtmpfs_sb *)file->dentry->mnt->data;
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
d_file = devtmpfs_file_lookup(superblock, file->dentry->pathname);
|
||||
if (d_file)
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct devtmpfs_file *n_file;
|
||||
rt_list_t *list;
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
end = file->fpos + count;
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
{
|
||||
if (index >= (rt_size_t)file->fpos)
|
||||
{
|
||||
n_file = rt_list_entry(list, struct devtmpfs_file, sibling);
|
||||
|
||||
d = dirp + count;
|
||||
if (n_file->type == TMPFS_TYPE_FILE)
|
||||
{
|
||||
d->d_type = DT_REG;
|
||||
}
|
||||
if (n_file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
d->d_type = DT_DIR;
|
||||
}
|
||||
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_strncpy(d->d_name, n_file->name, DIRENT_NAME_MAX);
|
||||
d->d_namlen = rt_strlen(d->d_name);
|
||||
|
||||
count += 1;
|
||||
file->fpos += 1;
|
||||
}
|
||||
index += 1;
|
||||
if (index >= end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
static int devtmpfs_symlink(struct dfs_dentry *parent_dentry, const char *target, const char *linkpath)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
struct devtmpfs_file *p_file, *l_file;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(parent_dentry);
|
||||
RT_ASSERT(parent_dentry->mnt);
|
||||
|
||||
superblock = (struct devtmpfs_sb *)parent_dentry->mnt->data;
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
p_file = devtmpfs_file_lookup(superblock, parent_dentry->pathname);
|
||||
if (p_file)
|
||||
{
|
||||
l_file = (struct devtmpfs_file *)rt_calloc(1, sizeof(struct devtmpfs_file));
|
||||
if (l_file)
|
||||
{
|
||||
superblock->df_size += sizeof(struct devtmpfs_file);
|
||||
|
||||
strncpy(l_file->name, linkpath, DIRENT_NAME_MAX - 1);
|
||||
|
||||
rt_list_init(&(l_file->subdirs));
|
||||
rt_list_init(&(l_file->sibling));
|
||||
l_file->sb = superblock;
|
||||
l_file->type = TMPFS_TYPE_FILE;
|
||||
l_file->mode = p_file->mode;
|
||||
l_file->mode &= ~S_IFMT;
|
||||
l_file->mode |= S_IFLNK;
|
||||
l_file->link = rt_strdup(target);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(l_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int devtmpfs_readlink(struct dfs_dentry *dentry, char *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
struct devtmpfs_file *d_file;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dentry);
|
||||
RT_ASSERT(dentry->mnt);
|
||||
|
||||
superblock = (struct devtmpfs_sb *)dentry->mnt->data;
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
|
||||
if (d_file)
|
||||
{
|
||||
if (d_file->link)
|
||||
{
|
||||
if (d_file->type == TMPFS_TYPE_DYN_DEV)
|
||||
{
|
||||
rt_device_t device = (void *)d_file->link;
|
||||
buf[0] = '\0';
|
||||
ret = device->readlink(device, buf, len);
|
||||
if (ret == 0)
|
||||
{
|
||||
buf[len - 1] = '\0';
|
||||
ret = rt_strlen(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_strncpy(buf, (const char *)d_file->link, len);
|
||||
buf[len - 1] = '\0';
|
||||
ret = rt_strlen(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int devtmpfs_unlink(struct dfs_dentry *dentry)
|
||||
{
|
||||
struct devtmpfs_file *d_file;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dentry);
|
||||
RT_ASSERT(dentry->mnt);
|
||||
|
||||
superblock = (struct devtmpfs_sb *)dentry->mnt->data;
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
|
||||
if (d_file)
|
||||
{
|
||||
if (d_file->link && d_file->type != TMPFS_TYPE_DYN_DEV)
|
||||
{
|
||||
rt_free(d_file->link);
|
||||
}
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(d_file);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int devtmpfs_setattr(struct dfs_dentry *dentry, struct dfs_attr *attr)
|
||||
{
|
||||
struct devtmpfs_file *d_file;
|
||||
struct devtmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dentry);
|
||||
RT_ASSERT(dentry->mnt);
|
||||
|
||||
superblock = (struct devtmpfs_sb *)dentry->mnt->data;
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
|
||||
if (d_file)
|
||||
{
|
||||
d_file->mode &= ~0xFFF;
|
||||
d_file->mode |= attr->st_mode & 0xFFF;
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
|
||||
{
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
struct devtmpfs_sb *superblock;
|
||||
struct devtmpfs_file *d_file, *p_file;
|
||||
char parent_path[DFS_PATH_MAX], file_name[DIRENT_NAME_MAX];
|
||||
|
||||
if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
superblock = (struct devtmpfs_sb *)dentry->mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode)
|
||||
{
|
||||
/* find parent file */
|
||||
_path_separate(dentry->pathname, parent_path, file_name);
|
||||
if (file_name[0] == '\0') /* it's root dir */
|
||||
{
|
||||
dfs_vnode_destroy(vnode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open parent directory */
|
||||
p_file = devtmpfs_file_lookup(superblock, parent_path);
|
||||
if (p_file == NULL)
|
||||
{
|
||||
dfs_vnode_destroy(vnode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create a file entry */
|
||||
d_file = (struct devtmpfs_file *)rt_calloc(1, sizeof(struct devtmpfs_file));
|
||||
if (d_file == NULL)
|
||||
{
|
||||
dfs_vnode_destroy(vnode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
superblock->df_size += sizeof(struct devtmpfs_file);
|
||||
|
||||
strncpy(d_file->name, file_name, DIRENT_NAME_MAX);
|
||||
|
||||
rt_list_init(&(d_file->subdirs));
|
||||
rt_list_init(&(d_file->sibling));
|
||||
d_file->sb = superblock;
|
||||
|
||||
vnode->nlink = 1;
|
||||
vnode->size = 0;
|
||||
vnode->mode = mode;
|
||||
vnode->mnt = dentry->mnt;
|
||||
vnode->fops = &_default_fops;
|
||||
|
||||
if (type == FT_DIRECTORY)
|
||||
{
|
||||
d_file->type = TMPFS_TYPE_DIR;
|
||||
vnode->type = FT_DIRECTORY;
|
||||
vnode->mode &= ~S_IFMT;
|
||||
vnode->mode |= S_IFDIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_file->type = TMPFS_TYPE_FILE;
|
||||
vnode->type = FT_DEVICE;
|
||||
}
|
||||
|
||||
d_file->mode = vnode->mode;
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
}
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *devtmpfs_lookup(struct dfs_dentry *dentry)
|
||||
{
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
struct devtmpfs_sb *superblock;
|
||||
struct devtmpfs_file *d_file;
|
||||
|
||||
if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
superblock = (struct devtmpfs_sb *)dentry->mnt->data;
|
||||
|
||||
d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
|
||||
if (d_file)
|
||||
{
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode)
|
||||
{
|
||||
vnode->nlink = 1;
|
||||
vnode->size = 0;
|
||||
vnode->mnt = dentry->mnt;
|
||||
vnode->fops = &_default_fops;
|
||||
vnode->mode = d_file->mode;
|
||||
|
||||
if (d_file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
vnode->type = FT_DIRECTORY;
|
||||
}
|
||||
else if (d_file->link)
|
||||
{
|
||||
vnode->type = FT_SYMLINK;
|
||||
}
|
||||
else
|
||||
{
|
||||
vnode->type = FT_DEVICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_device_t device = RT_NULL;
|
||||
|
||||
device = rt_device_find(&dentry->pathname[1]);
|
||||
if (device)
|
||||
{
|
||||
vnode = devtmpfs_create_vnode(dentry, FT_REGULAR, dfs_devfs_device_to_mode(device));
|
||||
if (device->flag & RT_DEVICE_FLAG_DYNAMIC)
|
||||
{
|
||||
d_file = devtmpfs_file_lookup(superblock, dentry->pathname);
|
||||
d_file->type = TMPFS_TYPE_DYN_DEV;
|
||||
d_file->link = (char *)device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static int devtmpfs_free_vnode(struct dfs_vnode *vnode)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct dfs_filesystem_ops _devtmpfs_ops =
|
||||
{
|
||||
.name = "devtmpfs",
|
||||
.flags = DFS_FS_FLAG_DEFAULT,
|
||||
.default_fops = &_default_fops,
|
||||
|
||||
.mount = devtmpfs_mount,
|
||||
.umount = devtmpfs_unmount,
|
||||
|
||||
.symlink = devtmpfs_symlink,
|
||||
.readlink = devtmpfs_readlink,
|
||||
|
||||
.unlink = devtmpfs_unlink,
|
||||
.setattr = devtmpfs_setattr,
|
||||
|
||||
.statfs = devtmpfs_statfs,
|
||||
.stat = devtmpfs_stat,
|
||||
|
||||
.lookup = devtmpfs_lookup,
|
||||
.create_vnode = devtmpfs_create_vnode,
|
||||
.free_vnode = devtmpfs_free_vnode
|
||||
};
|
||||
|
||||
static struct dfs_filesystem_type _devtmpfs =
|
||||
{
|
||||
.fs_ops = &_devtmpfs_ops,
|
||||
};
|
||||
|
||||
int dfs_devtmpfs_init(void)
|
||||
{
|
||||
_default_fops = *dfs_devfs_fops();
|
||||
_default_fops.getdents = devtmpfs_getdents;
|
||||
|
||||
/* register file system */
|
||||
dfs_register(&_devtmpfs);
|
||||
|
||||
dfs_mount(RT_NULL, "/dev", "devtmpfs", 0, RT_NULL);
|
||||
dfs_devfs_update();
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(dfs_devtmpfs_init);
|
@@ -0,0 +1,11 @@
|
||||
# Available style options are described in https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
#
|
||||
# An easy way to create the .clang-format file is:
|
||||
#
|
||||
# clang-format -style=llvm -dump-config > .clang-format
|
||||
#
|
||||
---
|
||||
Language: Cpp
|
||||
DisableFormat: true
|
||||
---
|
||||
|
@@ -0,0 +1,10 @@
|
||||
# files format check exclude path, please follow the instructions below to modify;
|
||||
# If you need to exclude an entire folder, add the folder path in dir_path;
|
||||
# If you need to exclude a file, add the path to the file in file_path.
|
||||
|
||||
file_path:
|
||||
- diskio.h
|
||||
- ff.c
|
||||
- ff.h
|
||||
- ffconf.h
|
||||
- ffunicode.c
|
369
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/00history.txt
Normal file
369
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/00history.txt
Normal file
@@ -0,0 +1,369 @@
|
||||
----------------------------------------------------------------------------
|
||||
Revision history of FatFs module
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
R0.00 (February 26, 2006)
|
||||
|
||||
Prototype.
|
||||
|
||||
|
||||
|
||||
R0.01 (April 29, 2006)
|
||||
|
||||
The first release.
|
||||
|
||||
|
||||
|
||||
R0.02 (June 01, 2006)
|
||||
|
||||
Added FAT12 support.
|
||||
Removed unbuffered mode.
|
||||
Fixed a problem on small (<32M) partition.
|
||||
|
||||
|
||||
|
||||
R0.02a (June 10, 2006)
|
||||
|
||||
Added a configuration option (_FS_MINIMUM).
|
||||
|
||||
|
||||
|
||||
R0.03 (September 22, 2006)
|
||||
|
||||
Added f_rename().
|
||||
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
||||
|
||||
|
||||
|
||||
R0.03a (December 11, 2006)
|
||||
|
||||
Improved cluster scan algorithm to write files fast.
|
||||
Fixed f_mkdir() creates incorrect directory on FAT32.
|
||||
|
||||
|
||||
|
||||
R0.04 (February 04, 2007)
|
||||
|
||||
Added f_mkfs().
|
||||
Supported multiple drive system.
|
||||
Changed some interfaces for multiple drive system.
|
||||
Changed f_mountdrv() to f_mount().
|
||||
|
||||
|
||||
|
||||
R0.04a (April 01, 2007)
|
||||
|
||||
Supported multiple partitions on a physical drive.
|
||||
Added a capability of extending file size to f_lseek().
|
||||
Added minimization level 3.
|
||||
Fixed an endian sensitive code in f_mkfs().
|
||||
|
||||
|
||||
|
||||
R0.04b (May 05, 2007)
|
||||
|
||||
Added a configuration option _USE_NTFLAG.
|
||||
Added FSINFO support.
|
||||
Fixed DBCS name can result FR_INVALID_NAME.
|
||||
Fixed short seek (<= csize) collapses the file object.
|
||||
|
||||
|
||||
|
||||
R0.05 (August 25, 2007)
|
||||
|
||||
Changed arguments of f_read(), f_write() and f_mkfs().
|
||||
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
||||
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
||||
|
||||
|
||||
|
||||
R0.05a (February 03, 2008)
|
||||
|
||||
Added f_truncate() and f_utime().
|
||||
Fixed off by one error at FAT sub-type determination.
|
||||
Fixed btr in f_read() can be mistruncated.
|
||||
Fixed cached sector is not flushed when create and close without write.
|
||||
|
||||
|
||||
|
||||
R0.06 (April 01, 2008)
|
||||
|
||||
Added fputc(), fputs(), fprintf() and fgets().
|
||||
Improved performance of f_lseek() on moving to the same or following cluster.
|
||||
|
||||
|
||||
|
||||
R0.07 (April 01, 2009)
|
||||
|
||||
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
||||
Added long file name feature. (_USE_LFN)
|
||||
Added multiple code page feature. (_CODE_PAGE)
|
||||
Added re-entrancy for multitask operation. (_FS_REENTRANT)
|
||||
Added auto cluster size selection to f_mkfs().
|
||||
Added rewind option to f_readdir().
|
||||
Changed result code of critical errors.
|
||||
Renamed string functions to avoid name collision.
|
||||
|
||||
|
||||
|
||||
R0.07a (April 14, 2009)
|
||||
|
||||
Septemberarated out OS dependent code on reentrant cfg.
|
||||
Added multiple sector size feature.
|
||||
|
||||
|
||||
|
||||
R0.07c (June 21, 2009)
|
||||
|
||||
Fixed f_unlink() can return FR_OK on error.
|
||||
Fixed wrong cache control in f_lseek().
|
||||
Added relative path feature.
|
||||
Added f_chdir() and f_chdrive().
|
||||
Added proper case conversion to extended character.
|
||||
|
||||
|
||||
|
||||
R0.07e (November 03, 2009)
|
||||
|
||||
Septemberarated out configuration options from ff.h to ffconf.h.
|
||||
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
||||
Fixed name matching error on the 13 character boundary.
|
||||
Added a configuration option, _LFN_UNICODE.
|
||||
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
||||
|
||||
|
||||
|
||||
R0.08 (May 15, 2010)
|
||||
|
||||
Added a memory configuration option. (_USE_LFN = 3)
|
||||
Added file lock feature. (_FS_SHARE)
|
||||
Added fast seek feature. (_USE_FASTSEEK)
|
||||
Changed some types on the API, XCHAR->TCHAR.
|
||||
Changed .fname in the FILINFO structure on Unicode cfg.
|
||||
String functions support UTF-8 encoding files on Unicode cfg.
|
||||
|
||||
|
||||
|
||||
R0.08a (August 16, 2010)
|
||||
|
||||
Added f_getcwd(). (_FS_RPATH = 2)
|
||||
Added sector erase feature. (_USE_ERASE)
|
||||
Moved file lock semaphore table from fs object to the bss.
|
||||
Fixed f_mkfs() creates wrong FAT32 volume.
|
||||
|
||||
|
||||
|
||||
R0.08b (January 15, 2011)
|
||||
|
||||
Fast seek feature is also applied to f_read() and f_write().
|
||||
f_lseek() reports required table size on creating CLMP.
|
||||
Extended format syntax of f_printf().
|
||||
Ignores duplicated directory separators in given path name.
|
||||
|
||||
|
||||
|
||||
R0.09 (September 06, 2011)
|
||||
|
||||
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
||||
Added f_fdisk().
|
||||
|
||||
|
||||
|
||||
R0.09a (August 27, 2012)
|
||||
|
||||
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
||||
Changed option name _FS_SHARE to _FS_LOCK.
|
||||
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
||||
|
||||
|
||||
|
||||
R0.09b (January 24, 2013)
|
||||
|
||||
Added f_setlabel() and f_getlabel().
|
||||
|
||||
|
||||
|
||||
R0.10 (October 02, 2013)
|
||||
|
||||
Added selection of character encoding on the file. (_STRF_ENCODE)
|
||||
Added f_closedir().
|
||||
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
||||
Added forced mount feature with changes of f_mount().
|
||||
Improved behavior of volume auto detection.
|
||||
Improved write throughput of f_puts() and f_printf().
|
||||
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
|
||||
Fixed f_write() can be truncated when the file size is close to 4GB.
|
||||
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
|
||||
|
||||
|
||||
|
||||
R0.10a (January 15, 2014)
|
||||
|
||||
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
||||
Added a configuration option of minimum sector size. (_MIN_SS)
|
||||
2nd argument of f_rename() can have a drive number and it will be ignored.
|
||||
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
|
||||
Fixed f_close() invalidates the file object without volume lock.
|
||||
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
|
||||
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10b (May 19, 2014)
|
||||
|
||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||
Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10c (November 09, 2014)
|
||||
|
||||
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
||||
Changed option name _USE_ERASE to _USE_TRIM.
|
||||
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
||||
Fixed a potential problem of FAT access that can appear on disk error.
|
||||
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
||||
|
||||
|
||||
|
||||
R0.11 (February 09, 2015)
|
||||
|
||||
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
||||
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
||||
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.11a (September 05, 2015)
|
||||
|
||||
Fixed wrong media change can lead a deadlock at thread-safe configuration.
|
||||
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
|
||||
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
|
||||
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
|
||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12 (April 12, 2016)
|
||||
|
||||
Added support for exFAT file system. (_FS_EXFAT)
|
||||
Added f_expand(). (_USE_EXPAND)
|
||||
Changed some members in FINFO structure and behavior of f_readdir().
|
||||
Added an option _USE_CHMOD.
|
||||
Removed an option _WORD_ACCESS.
|
||||
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12a (July 10, 2016)
|
||||
|
||||
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||
f_forward() is available regardless of _FS_TINY.
|
||||
Fixed f_mkfs() creates wrong volume. (appeared at R0.12)
|
||||
Fixed wrong memory read in create_name(). (appeared at R0.12)
|
||||
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||
|
||||
|
||||
|
||||
R0.12b (September 04, 2016)
|
||||
|
||||
Made f_rename() be able to rename objects with the same name but case.
|
||||
Fixed an error in the case conversion teble of code page 866. (ff.c)
|
||||
Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
|
||||
Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
|
||||
Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12)
|
||||
Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12)
|
||||
Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
|
||||
Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.12c (March 04, 2017)
|
||||
|
||||
Improved write throughput at the fragmented file on the exFAT volume.
|
||||
Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN.
|
||||
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.13 (May 21, 2017)
|
||||
|
||||
Changed heading character of configuration keywords "_" to "FF_".
|
||||
Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead.
|
||||
Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0)
|
||||
Improved cluster allocation time on stretch a deep buried cluster chain.
|
||||
Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3.
|
||||
Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous.
|
||||
Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12)
|
||||
Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c)
|
||||
Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c)
|
||||
|
||||
|
||||
|
||||
R0.13a (October 14, 2017)
|
||||
|
||||
Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2)
|
||||
Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF).
|
||||
Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk().
|
||||
Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09)
|
||||
Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c)
|
||||
Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.13b (April 07, 2018)
|
||||
|
||||
Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3)
|
||||
Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2)
|
||||
Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c)
|
||||
Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b)
|
||||
|
||||
|
||||
|
||||
R0.13c (October 14, 2018)
|
||||
Supported stdint.h for C99 and later. (integer.h was included in ff.h)
|
||||
Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
|
||||
Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
|
||||
Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)
|
||||
|
||||
|
||||
|
||||
R0.14 (October 14, 2019)
|
||||
Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1)
|
||||
Changed some API functions, f_mkfs() and f_fdisk().
|
||||
Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters.
|
||||
Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters.
|
||||
Fixed f_readdir() function returns file names with wrong case conversion. (appeared at R0.12)
|
||||
Fixed f_mkfs() function can fail to create exFAT volume in the second partition. (appeared at R0.12)
|
||||
|
||||
|
||||
R0.14a (December 5, 2020)
|
||||
Limited number of recursive calls in f_findnext().
|
||||
Fixed old floppy disks formatted with MS-DOS 2.x and 3.x cannot be mounted.
|
||||
Fixed some compiler warnings.
|
||||
|
||||
|
||||
|
||||
R0.14b (April 17, 2021)
|
||||
Made FatFs uses standard library <string.h> for copy, compare and search instead of built-in string functions.
|
||||
Added support for long long integer and floating point to f_printf(). (FF_STRF_LLI and FF_STRF_FP)
|
||||
Made path name parser ignore the terminating separator to allow "dir/".
|
||||
Improved the compatibility in Unix style path name feature.
|
||||
Fixed the file gets dead-locked when f_open() failed with some conditions. (appeared at R0.12a)
|
||||
Fixed f_mkfs() can create wrong exFAT volume due to a timing dependent error. (appeared at R0.12)
|
||||
Fixed code page 855 cannot be set by f_setcp().
|
||||
Fixed some compiler warnings.
|
||||
|
||||
|
||||
|
||||
R0.15 (November 6, 2022)
|
||||
Changed user provided synchronization functions in order to completely eliminate the platform dependency from FatFs code.
|
||||
FF_SYNC_t is removed from the configuration options.
|
||||
Fixed a potential error in f_mount when FF_FS_REENTRANT.
|
||||
Fixed file lock control FF_FS_LOCK is not mutal excluded when FF_FS_REENTRANT && FF_VOLUMES > 1 is true.
|
||||
Fixed f_mkfs() creates broken exFAT volume when the size of volume is >= 2^32 sectors.
|
||||
Fixed string functions cannot write the unicode characters not in BMP when FF_LFN_UNICODE == 2 (UTF-8).
|
||||
Fixed a compatibility issue in identification of GPT header.
|
||||
|
@@ -0,0 +1,21 @@
|
||||
FatFs Module Source Files R0.15
|
||||
|
||||
|
||||
FILES
|
||||
|
||||
00readme.txt This file.
|
||||
00history.txt Revision history.
|
||||
ff.c FatFs module.
|
||||
ffconf.h Configuration file of FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
ffunicode.c Optional Unicode utility functions.
|
||||
ffsystem.c An example of optional O/S related functions.
|
||||
|
||||
|
||||
Low level disk I/O module is not included in this archive because the FatFs
|
||||
module is only a generic file system layer and it does not depend on any specific
|
||||
storage device. You need to provide a low level disk I/O module written to
|
||||
control the storage device that attached to the target system.
|
||||
|
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_ELMFAT'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
1279
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c
Normal file
1279
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c
Normal file
File diff suppressed because it is too large
Load Diff
24
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.h
Normal file
24
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2010-02-06 Bernard Add elm_init function declaration
|
||||
*/
|
||||
|
||||
#ifndef __DFS_ELM_H__
|
||||
#define __DFS_ELM_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int elm_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
77
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/diskio.h
Normal file
77
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/diskio.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2019 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
|
||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||
#define CTRL_EJECT 7 /* Eject media */
|
||||
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||
|
||||
/* MMC/SDC specific ioctl command */
|
||||
#define MMC_GET_TYPE 10 /* Get card type */
|
||||
#define MMC_GET_CSD 11 /* Get CSD */
|
||||
#define MMC_GET_CID 12 /* Get CID */
|
||||
#define MMC_GET_OCR 13 /* Get OCR */
|
||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
|
||||
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
|
||||
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
|
||||
|
||||
/* ATA/CF specific ioctl command */
|
||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||
#define ATA_GET_MODEL 21 /* Get model name */
|
||||
#define ATA_GET_SN 22 /* Get serial number */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
7116
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/ff.c
Normal file
7116
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/ff.c
Normal file
File diff suppressed because it is too large
Load Diff
431
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/ff.h
Normal file
431
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/ff.h
Normal file
@@ -0,0 +1,431 @@
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem module R0.15 /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2022, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
/ that the following condition is met:
|
||||
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef FF_DEFINED
|
||||
#define FF_DEFINED 80286 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <rtthread.h>
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if FF_DEFINED != FFCONF_DEF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
/* Integer types used for FatFs API */
|
||||
|
||||
#if defined(_WIN32) /* Windows VC++ (for development only) */
|
||||
#define FF_INTDEF 2
|
||||
#include <windows.h>
|
||||
typedef unsigned __int64 QWORD;
|
||||
#include <float.h>
|
||||
#define isnan(v) _isnan(v)
|
||||
#define isinf(v) (!_finite(v))
|
||||
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
|
||||
#define FF_INTDEF 2
|
||||
#include <stdint.h>
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef uint16_t WORD; /* 16-bit unsigned integer */
|
||||
typedef uint32_t DWORD; /* 32-bit unsigned integer */
|
||||
typedef uint64_t QWORD; /* 64-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
|
||||
#else /* Earlier than C99 */
|
||||
#define FF_INTDEF 1
|
||||
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||
typedef unsigned short WORD; /* 16-bit unsigned integer */
|
||||
typedef unsigned long DWORD; /* 32-bit unsigned integer */
|
||||
typedef WORD WCHAR; /* UTF-16 character type */
|
||||
#endif
|
||||
|
||||
|
||||
/* Type of file size and LBA variables */
|
||||
|
||||
#if FF_FS_EXFAT
|
||||
#if FF_INTDEF != 2
|
||||
#error exFAT feature wants C99 or later
|
||||
#endif
|
||||
typedef QWORD FSIZE_t;
|
||||
#if FF_LBA64
|
||||
typedef QWORD LBA_t;
|
||||
#else
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
#else
|
||||
#if FF_LBA64
|
||||
#error exFAT needs to be enabled when enable 64-bit LBA
|
||||
#endif
|
||||
typedef DWORD FSIZE_t;
|
||||
typedef DWORD LBA_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API (TCHAR) */
|
||||
|
||||
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) u8 ## x
|
||||
#define _TEXT(x) u8 ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
|
||||
typedef DWORD TCHAR;
|
||||
#define _T(x) U ## x
|
||||
#define _TEXT(x) U ## x
|
||||
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
|
||||
#error Wrong FF_LFN_UNICODE setting
|
||||
#else /* ANSI/OEM code in SBCS/DBCS */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if FF_MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
|
||||
#endif
|
||||
|
||||
#if FF_STR_VOLUME_ID
|
||||
#ifndef FF_VOLUME_STRS
|
||||
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||
BYTE pdrv; /* Volume hosting physical drive */
|
||||
BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
BYTE wflag; /* win[] status (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */
|
||||
WORD id; /* Volume mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
WORD csize; /* Cluster size [sectors] */
|
||||
#if FF_MAX_SS != FF_MIN_SS
|
||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if FF_USE_LFN
|
||||
WCHAR* lfnbuf; /* LFN working buffer */
|
||||
#endif
|
||||
#if FF_FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
|
||||
#endif
|
||||
#if !FF_FS_READONLY
|
||||
DWORD last_clst; /* Last allocated cluster */
|
||||
DWORD free_clst; /* Number of free clusters */
|
||||
#endif
|
||||
#if FF_FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
|
||||
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
|
||||
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
|
||||
#endif
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
|
||||
DWORD fsize; /* Number of sectors per FAT */
|
||||
LBA_t volbase; /* Volume base sector */
|
||||
LBA_t fatbase; /* FAT base sector */
|
||||
LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */
|
||||
LBA_t database; /* Data base sector */
|
||||
#if FF_FS_EXFAT
|
||||
LBA_t bitbase; /* Allocation bitmap base sector */
|
||||
#endif
|
||||
LBA_t winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* Object ID and allocation information (FFOBJID) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume's mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
|
||||
#endif
|
||||
#if FF_FS_LOCK
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
} FFOBJID;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !FF_FS_READONLY
|
||||
LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
LBA_t sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if FF_USE_LFN
|
||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||
#endif
|
||||
#if FF_USE_FIND
|
||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File information structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
FSIZE_t fsize; /* File size */
|
||||
WORD fdate; /* Modified date */
|
||||
WORD ftime; /* Modified time */
|
||||
BYTE fattrib; /* File attribute */
|
||||
#if FF_USE_LFN
|
||||
TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */
|
||||
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
|
||||
#else
|
||||
TCHAR fname[12 + 1]; /* File name */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* Format parameter structure (MKFS_PARM) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */
|
||||
BYTE n_fat; /* Number of FATs */
|
||||
UINT align; /* Data area alignment (sector) */
|
||||
UINT n_root; /* Number of root directory entries */
|
||||
DWORD au_size; /* Cluster size (byte) */
|
||||
} MKFS_PARM;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs Module Application Interface */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||
FRESULT f_seekdir(DIR *dj, int offset); /* Seek in directory */
|
||||
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
||||
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */
|
||||
FRESULT f_setcp (WORD cp); /* Set current code page */
|
||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||
|
||||
/* Some API fucntions are implemented as macro */
|
||||
|
||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
||||
#define f_error(fp) ((fp)->err)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
#define f_unmount(path) f_mount(0, path, 0)
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional Functions */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
/* RTC function (provided by user) */
|
||||
#if !FF_FS_READONLY && !FF_FS_NORTC
|
||||
DWORD get_fattime (void); /* Get current time */
|
||||
#endif
|
||||
|
||||
|
||||
/* LFN support functions (defined in ffunicode.c) */
|
||||
|
||||
#if FF_USE_LFN >= 1
|
||||
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
|
||||
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
|
||||
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
|
||||
#endif
|
||||
|
||||
|
||||
/* O/S dependent functions (samples available in ffsystem.c) */
|
||||
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||
void ff_memfree (void* mblock); /* Free memory block */
|
||||
#endif
|
||||
#if FF_FS_REENTRANT /* Sync functions */
|
||||
int ff_mutex_create (int vol); /* Create a sync object */
|
||||
void ff_mutex_delete (int vol); /* Delete a sync object */
|
||||
int ff_mutex_take (int vol); /* Lock sync object */
|
||||
void ff_mutex_give (int vol); /* Unlock sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and Offset Address */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
/* File access mode and open method flags (3rd argument of f_open) */
|
||||
#define FA_READ 0x01
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA_OPEN_APPEND 0x30
|
||||
|
||||
/* Fast seek controls (2nd argument of f_lseek) */
|
||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||
|
||||
/* Format options (2nd argument of f_mkfs) */
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
#define FM_EXFAT 0x04
|
||||
#define FM_ANY 0x07
|
||||
#define FM_SFD 0x08
|
||||
|
||||
/* Filesystem type (FATFS.fs_type) */
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
#define FS_EXFAT 4
|
||||
|
||||
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FF_DEFINED */
|
339
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/ffconf.h
Normal file
339
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/ffconf.h
Normal file
@@ -0,0 +1,339 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Configurations of FatFs Module
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FFCONF_DEF 80286 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_FS_READONLY 0
|
||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define FF_FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: Basic functions are fully enabled.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
|
||||
/ are removed.
|
||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define FF_USE_FIND 0
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
|
||||
#define FF_USE_MKFS 1
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_FASTSEEK 1
|
||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_EXPAND 0
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_CHMOD 0
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
||||
#define FF_USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_STRFUNC 0
|
||||
#define FF_PRINT_LLI 0
|
||||
#define FF_PRINT_FLOAT 0
|
||||
#define FF_STRF_ENCODE 3
|
||||
/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and
|
||||
/ f_printf().
|
||||
/
|
||||
/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect.
|
||||
/ 1: Enable without LF-CRLF conversion.
|
||||
/ 2: Enable with LF-CRLF conversion.
|
||||
/
|
||||
/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2
|
||||
/ makes f_printf() support floating point argument. These features want C99 or later.
|
||||
/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character
|
||||
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
|
||||
/ to be read/written via those functions.
|
||||
/
|
||||
/ 0: ANSI/OEM in current CP
|
||||
/ 1: Unicode in UTF-16LE
|
||||
/ 2: Unicode in UTF-16BE
|
||||
/ 3: Unicode in UTF-8
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef RT_DFS_ELM_CODE_PAGE
|
||||
# define FF_CODE_PAGE RT_DFS_ELM_CODE_PAGE
|
||||
#else
|
||||
# define FF_CODE_PAGE 936
|
||||
#endif
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect code page setting can cause a file open failure.
|
||||
/
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
/ 771 - KBL
|
||||
/ 775 - Baltic
|
||||
/ 850 - Latin 1
|
||||
/ 852 - Latin 2
|
||||
/ 855 - Cyrillic
|
||||
/ 857 - Turkish
|
||||
/ 860 - Portuguese
|
||||
/ 861 - Icelandic
|
||||
/ 862 - Hebrew
|
||||
/ 863 - Canadian French
|
||||
/ 864 - Arabic
|
||||
/ 865 - Nordic
|
||||
/ 866 - Russian
|
||||
/ 869 - Greek 2
|
||||
/ 932 - Japanese (DBCS)
|
||||
/ 936 - Simplified Chinese (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese (DBCS)
|
||||
/ 0 - Include all code pages above and configured by f_setcp()
|
||||
*/
|
||||
|
||||
|
||||
#if RT_DFS_ELM_USE_LFN
|
||||
#define FF_USE_LFN RT_DFS_ELM_USE_LFN
|
||||
#define FF_MAX_LFN RT_DFS_ELM_MAX_LFN
|
||||
#else
|
||||
#define FF_USE_LFN 0 /* 0 to 3 */
|
||||
#define FF_MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
|
||||
#endif
|
||||
/* The FF_USE_LFN switches the support for LFN (long file name).
|
||||
/
|
||||
/ 0: Disable LFN. FF_MAX_LFN has no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
|
||||
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
|
||||
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
|
||||
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
|
||||
/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN
|
||||
/ specification.
|
||||
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||
/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */
|
||||
|
||||
|
||||
#ifdef RT_DFS_ELM_LFN_UNICODE
|
||||
/* This option switches the character encoding on the API when LFN is enabled.
|
||||
/
|
||||
/ 0: ANSI/OEM in current CP (TCHAR = char)
|
||||
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
|
||||
/ 2: Unicode in UTF-8 (TCHAR = char)
|
||||
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
|
||||
/
|
||||
/ Also behavior of string I/O functions will be affected by this option.
|
||||
/ When LFN is not enabled, this option has no effect. */
|
||||
#define FF_LFN_UNICODE RT_DFS_ELM_LFN_UNICODE /* 0:ANSI/OEM or 1:Unicode */
|
||||
#else
|
||||
#define FF_LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
|
||||
#endif
|
||||
/* This option switches the character encoding on the API when LFN is enabled.
|
||||
/
|
||||
/ 0: ANSI/OEM in current CP (TCHAR = char)
|
||||
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
|
||||
/ 2: Unicode in UTF-8 (TCHAR = char)
|
||||
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
|
||||
/
|
||||
/ Also behavior of string I/O functions will be affected by this option.
|
||||
/ When LFN is not enabled, this option has no effect. */
|
||||
|
||||
|
||||
#define FF_LFN_BUF 255
|
||||
#define FF_SFN_BUF 12
|
||||
/* This set of options defines size of file name members in the FILINFO structure
|
||||
/ which is used to read out directory items. These values should be suffcient for
|
||||
/ the file names to read. The maximum possible length of the read file name depends
|
||||
/ on character encoding. When LFN is not enabled, these options have no effect. */
|
||||
|
||||
|
||||
#define FF_FS_RPATH 0
|
||||
/* This option configures support for relative path.
|
||||
/
|
||||
/ 0: Disable relative path and remove related functions.
|
||||
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
|
||||
/ 2: f_getcwd() function is available in addition to 1.
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef RT_DFS_ELM_DRIVES
|
||||
#define FF_VOLUMES RT_DFS_ELM_DRIVES
|
||||
#else
|
||||
#define FF_VOLUMES 1
|
||||
#endif
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define FF_STR_VOLUME_ID 0
|
||||
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
|
||||
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
|
||||
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
|
||||
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
|
||||
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
|
||||
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
|
||||
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
|
||||
/ not defined, a user defined volume string table is needed as:
|
||||
/
|
||||
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
|
||||
*/
|
||||
|
||||
|
||||
#define FF_MULTI_PARTITION 0
|
||||
/* This option switches support for multiple volumes on the physical drive.
|
||||
/ By default (0), each logical drive number is bound to the same physical drive
|
||||
/ number and only an FAT volume found on the physical drive will be mounted.
|
||||
/ When this function is enabled (1), each logical drive number can be bound to
|
||||
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
|
||||
/ function will be available. */
|
||||
|
||||
|
||||
#define FF_MIN_SS 512
|
||||
#ifdef RT_DFS_ELM_MAX_SECTOR_SIZE
|
||||
#define FF_MAX_SS RT_DFS_ELM_MAX_SECTOR_SIZE
|
||||
#else
|
||||
#define FF_MAX_SS 512 /* 512, 1024, 2048 or 4096 */
|
||||
#endif
|
||||
/* This set of options configures the range of sector size to be supported. (512,
|
||||
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||
/ harddisk, but a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
|
||||
/ for variable sector size mode and disk_ioctl() function needs to implement
|
||||
/ GET_SECTOR_SIZE command. */
|
||||
|
||||
|
||||
#define FF_LBA64 0
|
||||
/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable)
|
||||
/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
|
||||
|
||||
|
||||
#define FF_MIN_GPT 0x10000000
|
||||
/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and
|
||||
/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
|
||||
|
||||
|
||||
#define FF_USE_TRIM 0
|
||||
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
|
||||
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
|
||||
|
||||
#ifdef RT_DFS_ELM_USE_EXFAT
|
||||
#define FF_FS_EXFAT 1
|
||||
#else
|
||||
#define FF_FS_EXFAT 0
|
||||
#endif
|
||||
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
||||
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define FF_FS_NORTC 0
|
||||
#define FF_NORTC_MON 1
|
||||
#define FF_NORTC_MDAY 1
|
||||
#define FF_NORTC_YEAR 2022
|
||||
/* The option FF_FS_NORTC switches timestamp feature. If the system does not have
|
||||
/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the
|
||||
/ timestamp feature. Every object modified by FatFs will have a fixed timestamp
|
||||
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
|
||||
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
|
||||
/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */
|
||||
|
||||
|
||||
#define FF_FS_NOFSINFO 0
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at the first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
/
|
||||
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||
*/
|
||||
|
||||
|
||||
#define FF_FS_LOCK 0
|
||||
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
|
||||
/ is 1.
|
||||
/
|
||||
/ 0: Disable file lock function. To avoid volume corruption, application program
|
||||
/ should avoid illegal open, remove and rename to the open objects.
|
||||
/ >0: Enable file lock function. The value defines how many files/sub-directories
|
||||
/ can be opened simultaneously under file lock control. Note that the file
|
||||
/ lock control is independent of re-entrancy. */
|
||||
|
||||
|
||||
/* #include <somertos.h> // O/S definitions */
|
||||
#include <rtdef.h>
|
||||
#ifdef RT_DFS_ELM_REENTRANT
|
||||
#define FF_FS_REENTRANT 1 /* 0 or 1 */
|
||||
#else
|
||||
#define FF_FS_REENTRANT 0 /* 0:Disable or 1:Enable */
|
||||
#endif
|
||||
#ifndef RT_DFS_ELM_MUTEX_TIMEOUT
|
||||
#define RT_DFS_ELM_MUTEX_TIMEOUT 3000
|
||||
#endif
|
||||
#define FF_FS_TIMEOUT RT_DFS_ELM_MUTEX_TIMEOUT
|
||||
//#define FF_SYNC_t rt_mutex_t
|
||||
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
|
||||
/ module itself. Note that regardless of this option, file access to different
|
||||
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||
/ to the same volume is under control of this featuer.
|
||||
/
|
||||
/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect.
|
||||
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||
/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give()
|
||||
/ function, must be added to the project. Samples are available in ffsystem.c.
|
||||
/
|
||||
/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
15593
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/ffunicode.c
Normal file
15593
rt-thread/components/dfs/dfs_v2/filesystems/elmfat/ffunicode.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_MQUEUE'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
241
rt-thread/components/dfs/dfs_v2/filesystems/mqueue/dfs_mqueue.c
Normal file
241
rt-thread/components/dfs/dfs_v2/filesystems/mqueue/dfs_mqueue.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-07-04 zhkag first Version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include "dfs_mqueue.h"
|
||||
|
||||
static rt_list_t _mqueue_file_list = RT_LIST_OBJECT_INIT(_mqueue_file_list);
|
||||
struct rt_spinlock mqueue_lock;
|
||||
|
||||
void dfs_mqueue_insert_after(rt_list_t *n) {
|
||||
rt_spin_lock(&mqueue_lock);
|
||||
rt_list_insert_after(&(_mqueue_file_list), n);
|
||||
rt_spin_unlock(&mqueue_lock);
|
||||
}
|
||||
|
||||
struct mqueue_file *dfs_mqueue_lookup(const char *path, rt_size_t *size) {
|
||||
struct mqueue_file *file;
|
||||
rt_list_t *node;
|
||||
rt_spin_lock(&mqueue_lock);
|
||||
rt_list_for_each(node, &_mqueue_file_list) {
|
||||
file = rt_list_entry(node, struct mqueue_file, list);
|
||||
|
||||
if (rt_strncmp(file->name, path, RT_NAME_MAX) == 0) {
|
||||
*size = file->size;
|
||||
rt_spin_unlock(&mqueue_lock);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
rt_spin_unlock(&mqueue_lock);
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
int dfs_mqueue_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data) {
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_mqueue_umount(struct dfs_mnt *mnt) {
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_mqueue_statfs(struct dfs_mnt *mnt, struct statfs *buf) {
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_mqueue_close(struct dfs_file *file) {
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_mqueue_open(struct dfs_file *file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfs_mqueue_stat(struct dfs_dentry *dentry, struct stat *st) {
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
if (dentry && dentry->vnode) {
|
||||
vnode = dentry->vnode;
|
||||
st->st_dev = 0;
|
||||
st->st_gid = vnode->gid;
|
||||
st->st_uid = vnode->uid;
|
||||
st->st_ino = 0;
|
||||
st->st_mode = vnode->mode;
|
||||
st->st_nlink = vnode->nlink;
|
||||
st->st_size = vnode->size;
|
||||
st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
|
||||
st->st_mtim.tv_sec = vnode->mtime.tv_sec;
|
||||
st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
|
||||
st->st_ctim.tv_sec = vnode->ctime.tv_sec;
|
||||
st->st_atim.tv_nsec = vnode->atime.tv_nsec;
|
||||
st->st_atim.tv_sec = vnode->atime.tv_sec;
|
||||
}
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_mqueue_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count) {
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
count = (count / sizeof(struct dirent));
|
||||
end = file->fpos + count;
|
||||
index = 0;
|
||||
count = 0;
|
||||
struct mqueue_file *mq_file;
|
||||
rt_list_t *node;
|
||||
rt_spin_lock(&mqueue_lock);
|
||||
rt_list_for_each(node, &_mqueue_file_list) {
|
||||
if (index >= (rt_size_t)file->fpos) {
|
||||
mq_file = rt_list_entry(node, struct mqueue_file, list);
|
||||
d = dirp + count;
|
||||
d->d_namlen = RT_NAME_MAX;
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_strncpy(d->d_name, mq_file->name, RT_NAME_MAX);
|
||||
count += 1;
|
||||
file->fpos += 1;
|
||||
}
|
||||
index += 1;
|
||||
if (index >= end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
rt_spin_unlock(&mqueue_lock);
|
||||
return count * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
int dfs_mqueue_unlink(struct dfs_dentry *dentry) {
|
||||
rt_size_t size;
|
||||
struct mqueue_file *mq_file;
|
||||
mq_file = dfs_mqueue_lookup(dentry->pathname + 1, &size);
|
||||
if (mq_file == RT_NULL)
|
||||
return -ENOENT;
|
||||
rt_list_remove(&(mq_file->list));
|
||||
if (mq_file->data != RT_NULL)
|
||||
rt_mq_delete((rt_mq_t)mq_file->data);
|
||||
rt_free(mq_file);
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *dfs_mqueue_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode) {
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
rt_size_t size;
|
||||
struct mqueue_file *mq_file;
|
||||
|
||||
if (dentry == NULL || dentry->mnt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode) {
|
||||
mq_file = dfs_mqueue_lookup(dentry->pathname + 1, &size);
|
||||
if (mq_file == RT_NULL) {
|
||||
mq_file = (struct mqueue_file *)rt_malloc(sizeof(struct mqueue_file));
|
||||
if (mq_file == RT_NULL) {
|
||||
return NULL;
|
||||
}
|
||||
mq_file->msg_size = 8192;
|
||||
mq_file->max_msgs = 10;
|
||||
strncpy(mq_file->name, dentry->pathname + 1, RT_NAME_MAX - 1);
|
||||
dfs_mqueue_insert_after(&(mq_file->list));
|
||||
}
|
||||
|
||||
vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
vnode->type = FT_REGULAR;
|
||||
rt_mq_t mq = rt_mq_create(dentry->pathname + 1, mq_file->msg_size, mq_file->max_msgs,
|
||||
RT_IPC_FLAG_FIFO);
|
||||
mq_file->data = (void *)mq;
|
||||
vnode->data = mq_file;
|
||||
vnode->size = 0;
|
||||
}
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static int dfs_mqueue_free_vnode(struct dfs_vnode *vnode) {
|
||||
/* nothing to be freed */
|
||||
if (vnode && vnode->ref_count <= 1) {
|
||||
vnode->data = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _mqueue_fops = {
|
||||
.open = dfs_mqueue_open,
|
||||
.close = dfs_mqueue_close,
|
||||
.getdents = dfs_mqueue_getdents,
|
||||
};
|
||||
|
||||
struct dfs_vnode *_dfs_mqueue_lookup(struct dfs_dentry *dentry) {
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
rt_size_t size;
|
||||
// struct tmpfs_sb *superblock;
|
||||
struct mqueue_file *mq_file;
|
||||
|
||||
if (dentry == NULL || dentry->mnt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dentry->pathname[0] == '/' && dentry->pathname[1] == '\0') {
|
||||
}
|
||||
|
||||
mq_file = dfs_mqueue_lookup(dentry->pathname + 1, &size);
|
||||
|
||||
vnode = dfs_vnode_create();
|
||||
if (mq_file && mq_file->data) {
|
||||
vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
vnode->type = FT_REGULAR;
|
||||
vnode->mnt = dentry->mnt;
|
||||
vnode->data = mq_file;
|
||||
vnode->size = mq_file->size;
|
||||
} else {
|
||||
vnode->size = 0;
|
||||
vnode->nlink = 1;
|
||||
vnode->fops = &_mqueue_fops;
|
||||
vnode->mnt = dentry->mnt;
|
||||
vnode->type = FT_DIRECTORY;
|
||||
vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||
}
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static const struct dfs_filesystem_ops _mqueue_ops = {
|
||||
.name = "mqueue",
|
||||
.flags = DFS_FS_FLAG_DEFAULT,
|
||||
.default_fops = &_mqueue_fops,
|
||||
|
||||
.mount = dfs_mqueue_mount,
|
||||
.umount = dfs_mqueue_umount,
|
||||
.statfs = dfs_mqueue_statfs,
|
||||
|
||||
.unlink = dfs_mqueue_unlink,
|
||||
.stat = dfs_mqueue_stat,
|
||||
|
||||
.lookup = _dfs_mqueue_lookup,
|
||||
.create_vnode = dfs_mqueue_create_vnode,
|
||||
.free_vnode = dfs_mqueue_free_vnode
|
||||
};
|
||||
|
||||
static struct dfs_filesystem_type _mqueue = {
|
||||
.fs_ops = &_mqueue_ops,
|
||||
};
|
||||
|
||||
int dfs_mqueue_init(void) {
|
||||
/* register mqueue file system */
|
||||
dfs_register(&_mqueue);
|
||||
mkdir("/dev/mqueue", 0x777);
|
||||
if (dfs_mount(RT_NULL, "/dev/mqueue", "mqueue", 0, 0) != 0)
|
||||
{
|
||||
rt_kprintf("Dir /dev/mqueue mount failed!\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
INIT_ENV_EXPORT(dfs_mqueue_init);
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-07-04 zhkag first Version
|
||||
*/
|
||||
|
||||
#ifndef __DFS_MQUEUE_H__
|
||||
#define __DFS_MQUEUE_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
struct mqueue_file {
|
||||
char name[RT_NAME_MAX]; /* file name */
|
||||
rt_uint16_t msg_size; /**< message size of each message */
|
||||
rt_uint16_t max_msgs; /**< max number of messages */
|
||||
rt_list_t list;
|
||||
rt_uint8_t *data; /* file date ptr */
|
||||
rt_size_t size; /* file size */
|
||||
};
|
||||
|
||||
struct mqueue_file *dfs_mqueue_lookup(const char *path, rt_size_t *size);
|
||||
void dfs_mqueue_insert_after(rt_list_t *n);
|
||||
|
||||
#endif
|
@@ -0,0 +1,5 @@
|
||||
# The Pseudo Terminal Filesystem
|
||||
|
||||
The device register on ptyfs is also registered in device frameworks with `rt_device_register()`.
|
||||
|
||||
It's possible to mount a new ptyfs instance on another path. Each instance is isolated to each other. And they don't share the id system. But generally speaking, you have to mount the ptyfs on `/dev` root, since all the file nodes in ptyfs are devices.
|
11
rt-thread/components/dfs/dfs_v2/filesystems/ptyfs/SConscript
Normal file
11
rt-thread/components/dfs/dfs_v2/filesystems/ptyfs/SConscript
Normal file
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_PTYFS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
658
rt-thread/components/dfs/dfs_v2/filesystems/ptyfs/ptyfs.c
Normal file
658
rt-thread/components/dfs/dfs_v2/filesystems/ptyfs/ptyfs.c
Normal file
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-12-02 Shell init ver.
|
||||
*/
|
||||
#define DBG_TAG "filesystem.ptyfs"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "ptyfs.h"
|
||||
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_mnt.h>
|
||||
#include <devfs.h>
|
||||
#include <rid_bitmap.h>
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <terminal/terminal.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef S_IRWXUGO
|
||||
#define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
|
||||
#endif /* S_IRWXUGO */
|
||||
#ifndef S_IALLUGO
|
||||
#define S_IALLUGO (S_ISUID | S_ISGID | S_ISVTX | S_IRWXUGO)
|
||||
#endif /* S_IALLUGO */
|
||||
#ifndef S_IRUGO
|
||||
#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
|
||||
#endif /* S_IRUGO */
|
||||
#ifndef S_IWUGO
|
||||
#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
|
||||
#endif /* S_IWUGO */
|
||||
#ifndef S_IXUGO
|
||||
#define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
|
||||
#endif /* S_IXUGO */
|
||||
|
||||
#define PTYFS_MAGIC 0x9D94A07D
|
||||
#define PTYFS_TYPE_DIR 0x00
|
||||
#define PTYFS_TYPE_FILE_PTMX 0x01
|
||||
#define PTYFS_TYPE_FILE_SLAVE 0x02
|
||||
|
||||
/* TODO: using Symbolic permission, but not ours */
|
||||
#define PTMX_DEFAULT_FILE_MODE (S_IFCHR | 0666)
|
||||
#define PTS_DEFAULT_FILE_MODE (S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP)
|
||||
#define ROOT_DEFUALT_FILE_MODE (S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR)
|
||||
|
||||
struct ptyfs_sb;
|
||||
|
||||
struct ptyfs_file
|
||||
{
|
||||
char basename[DIRENT_NAME_MAX]; /* file name */
|
||||
rt_uint32_t mode; /* file modes allowed */
|
||||
rt_uint32_t type; /* file type */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t ent_node; /* entry node in subdir list */
|
||||
struct ptyfs_sb *sb; /* superblock ptr */
|
||||
rt_device_t device; /* device binding on this file */
|
||||
};
|
||||
|
||||
struct ptyfs_sb
|
||||
{
|
||||
struct rt_device ptmx_device; /* ptmx device */
|
||||
struct rt_mutex lock; /* tmpfs lock */
|
||||
struct ptyfs_file root_file; /* root dir */
|
||||
struct ptyfs_file ptmx_file; /* `/ptmx` file */
|
||||
struct rid_bitmap ptsno_pool; /* pts number pool */
|
||||
rt_uint32_t magic; /* PTYFS_MAGIC */
|
||||
rt_size_t df_size; /* df size */
|
||||
rt_list_t sibling; /* sb sibling list */
|
||||
struct dfs_mnt *mount; /* mount data */
|
||||
|
||||
/**
|
||||
* Note: This upper limit is set to protect kernel memory from draining
|
||||
* out by the application if it keeps allocating pty devices.
|
||||
*
|
||||
* Still, current implementation of bitmap can not efficiently use the
|
||||
* memory
|
||||
*/
|
||||
rt_bitmap_t
|
||||
ptsno_pool_bitset[LWP_PTY_MAX_PARIS_LIMIT / (sizeof(rt_bitmap_t) * 8)];
|
||||
};
|
||||
|
||||
static struct dfs_file_ops _default_fops;
|
||||
|
||||
static int _split_out_subdir(const char *path, char *name)
|
||||
{
|
||||
const char *subpath = path;
|
||||
|
||||
while (*subpath == '/' && *subpath)
|
||||
{
|
||||
subpath++;
|
||||
}
|
||||
|
||||
while (*subpath != '/' && *subpath)
|
||||
{
|
||||
*name++ = *subpath++;
|
||||
}
|
||||
|
||||
*name = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t ptyfile_init(struct ptyfs_file *file, struct ptyfs_sb *sb,
|
||||
const char *name, rt_uint32_t type,
|
||||
rt_uint32_t mode, rt_device_t device)
|
||||
{
|
||||
if (name)
|
||||
strncpy(file->basename, name, sizeof(file->basename));
|
||||
|
||||
file->type = type;
|
||||
file->mode = mode;
|
||||
rt_list_init(&file->subdirs);
|
||||
rt_list_init(&file->ent_node);
|
||||
file->sb = sb;
|
||||
file->device = device;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t ptyfile_add_to_root(struct ptyfs_sb *sb,
|
||||
struct ptyfs_file *new_file)
|
||||
{
|
||||
struct ptyfs_file *root_file = &sb->root_file;
|
||||
|
||||
/* update super block */
|
||||
sb->df_size += sizeof(struct ptyfs_file);
|
||||
|
||||
rt_mutex_take(&sb->lock, RT_WAITING_FOREVER);
|
||||
rt_list_insert_after(&(root_file->subdirs), &(new_file->ent_node));
|
||||
rt_mutex_release(&sb->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static rt_err_t ptyfile_remove_from_root(struct ptyfs_sb *sb,
|
||||
struct ptyfs_file *rm_file)
|
||||
{
|
||||
/* update super block */
|
||||
sb->df_size -= sizeof(struct ptyfs_file);
|
||||
|
||||
rt_mutex_take(&sb->lock, RT_WAITING_FOREVER);
|
||||
rt_list_remove(&(rm_file->ent_node));
|
||||
rt_mutex_release(&sb->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ptyfs_file *ptyfile_lookup(struct ptyfs_sb *superblock,
|
||||
const char *path)
|
||||
{
|
||||
const char *subpath_iter, *curpath_iter, *basename = RT_NULL;
|
||||
char subdir_name[DIRENT_NAME_MAX];
|
||||
struct ptyfs_file *curfile, *found_file = RT_NULL;
|
||||
rt_list_t *list;
|
||||
int do_path_resolve = 1;
|
||||
|
||||
subpath_iter = path;
|
||||
|
||||
/* skip starting "/" */
|
||||
while (*subpath_iter == '/') subpath_iter++;
|
||||
if (!*subpath_iter)
|
||||
{
|
||||
return &(superblock->root_file);
|
||||
}
|
||||
|
||||
curpath_iter = subpath_iter;
|
||||
curfile = &superblock->root_file;
|
||||
|
||||
/* resolve chain of files splited from path one by one */
|
||||
while (do_path_resolve)
|
||||
{
|
||||
do_path_resolve = 0;
|
||||
|
||||
/* splitout sub-directory or basename */
|
||||
while (*subpath_iter != '/' && *subpath_iter) subpath_iter++;
|
||||
if (!*subpath_iter)
|
||||
{
|
||||
basename = curpath_iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
_split_out_subdir(curpath_iter, subdir_name);
|
||||
|
||||
/* skip "/" for next search */
|
||||
subpath_iter++;
|
||||
}
|
||||
|
||||
rt_mutex_take(&superblock->lock, RT_WAITING_FOREVER);
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
{
|
||||
struct ptyfs_file *file_iter;
|
||||
file_iter = rt_list_entry(list, struct ptyfs_file, ent_node);
|
||||
if (basename)
|
||||
{
|
||||
if (strcmp(file_iter->basename, basename) == 0)
|
||||
{
|
||||
found_file = file_iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (strcmp(file_iter->basename, subdir_name) == 0)
|
||||
{
|
||||
curpath_iter = subpath_iter;
|
||||
curfile = file_iter;
|
||||
do_path_resolve = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rt_mutex_release(&superblock->lock);
|
||||
}
|
||||
|
||||
return found_file;
|
||||
}
|
||||
|
||||
const char *ptyfs_get_rootpath(rt_device_t ptmx)
|
||||
{
|
||||
const char *rc;
|
||||
struct ptyfs_sb *sb;
|
||||
/* allocate id for it and register file */
|
||||
sb = rt_container_of(ptmx, struct ptyfs_sb, ptmx_device);
|
||||
if (sb->magic != PTYFS_MAGIC)
|
||||
{
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fullpath is always started with /dev/ */
|
||||
return sb->mount->fullpath + 5;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
ptsno_t ptyfs_register_pts(rt_device_t ptmx, rt_device_t pts)
|
||||
{
|
||||
ptsno_t rc;
|
||||
struct ptyfs_sb *sb;
|
||||
struct ptyfs_file *pts_file;
|
||||
struct rid_bitmap *ptsno_pool;
|
||||
|
||||
/* allocate id for it and register file */
|
||||
sb = rt_container_of(ptmx, struct ptyfs_sb, ptmx_device);
|
||||
if (sb->magic != PTYFS_MAGIC)
|
||||
{
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptsno_pool = &sb->ptsno_pool;
|
||||
rc = rid_bitmap_get(ptsno_pool);
|
||||
if (rc >= 0)
|
||||
{
|
||||
pts_file = rt_calloc(1, sizeof(struct ptyfs_file));
|
||||
if (pts_file)
|
||||
{
|
||||
snprintf(pts_file->basename, DIRENT_NAME_MAX, "%lu", rc);
|
||||
ptyfile_init(pts_file, sb, 0, PTYFS_TYPE_FILE_SLAVE,
|
||||
PTS_DEFAULT_FILE_MODE, pts);
|
||||
ptyfile_add_to_root(sb, pts_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
rid_bitmap_put(ptsno_pool, rc);
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
/* else rc == -1 */
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
rt_err_t ptyfs_unregister_pts(rt_device_t ptmx, ptsno_t ptsno)
|
||||
{
|
||||
ptsno_t rc;
|
||||
struct ptyfs_sb *sb;
|
||||
struct ptyfs_file *pts_file;
|
||||
struct rid_bitmap *ptsno_pool;
|
||||
char path_buf[DIRENT_NAME_MAX];
|
||||
|
||||
/* allocate id for it and register file */
|
||||
sb = rt_container_of(ptmx, struct ptyfs_sb, ptmx_device);
|
||||
if (sb->magic != PTYFS_MAGIC || ptsno < 0)
|
||||
{
|
||||
rc = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* get path and findout device */
|
||||
snprintf(path_buf, sizeof(path_buf), "%lu", ptsno);
|
||||
pts_file = ptyfile_lookup(sb, path_buf);
|
||||
if (pts_file)
|
||||
{
|
||||
ptyfile_remove_from_root(sb, pts_file);
|
||||
ptsno_pool = &sb->ptsno_pool;
|
||||
rid_bitmap_put(ptsno_pool, ptsno);
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define DEVFS_PREFIX "/dev/"
|
||||
#define DEVFS_PREFIX_LEN (sizeof(DEVFS_PREFIX) - 1)
|
||||
|
||||
/**
|
||||
* Create an new instance of ptyfs, and mount on target point
|
||||
* 2 basic files are created: root, ptmx.
|
||||
*
|
||||
* todo: support of mount options?
|
||||
*/
|
||||
static int ptyfs_ops_mount(struct dfs_mnt *mnt, unsigned long rwflag,
|
||||
const void *data)
|
||||
{
|
||||
struct ptyfs_sb *sb;
|
||||
rt_device_t ptmx_device;
|
||||
rt_err_t rc;
|
||||
|
||||
if (strncmp(mnt->fullpath, DEVFS_PREFIX, DEVFS_PREFIX_LEN) != 0)
|
||||
{
|
||||
LOG_I("%s() Not mounted on `/dev/'", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sb = rt_calloc(1, sizeof(struct ptyfs_sb));
|
||||
if (sb)
|
||||
{
|
||||
rt_mutex_init(&sb->lock, "ptyfs", RT_IPC_FLAG_PRIO);
|
||||
|
||||
/* setup the ptmx device */
|
||||
ptmx_device = &sb->ptmx_device;
|
||||
rc = lwp_ptmx_init(ptmx_device, mnt->fullpath + DEVFS_PREFIX_LEN);
|
||||
if (rc == RT_EOK)
|
||||
{
|
||||
/* setup 2 basic files */
|
||||
ptyfile_init(&sb->root_file, sb, "/", PTYFS_TYPE_DIR,
|
||||
ROOT_DEFUALT_FILE_MODE, 0);
|
||||
ptyfile_init(&sb->ptmx_file, sb, "ptmx", PTYFS_TYPE_FILE_PTMX,
|
||||
PTMX_DEFAULT_FILE_MODE, ptmx_device);
|
||||
ptyfile_add_to_root(sb, &sb->ptmx_file);
|
||||
|
||||
/* setup rid */
|
||||
rid_bitmap_init(&sb->ptsno_pool, 0, LWP_PTY_MAX_PARIS_LIMIT,
|
||||
sb->ptsno_pool_bitset, &sb->lock);
|
||||
|
||||
/* setup properties and members */
|
||||
sb->magic = PTYFS_MAGIC;
|
||||
|
||||
sb->df_size = sizeof(struct ptyfs_sb);
|
||||
rt_list_init(&sb->sibling);
|
||||
|
||||
/* binding superblocks and mount point */
|
||||
mnt->data = sb;
|
||||
sb->mount = mnt;
|
||||
rc = 0;
|
||||
}
|
||||
/* else just return rc */
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ptyfs_ops_umount(struct dfs_mnt *mnt)
|
||||
{
|
||||
/* Not supported yet */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ptyfs_ops_setattr(struct dfs_dentry *dentry, struct dfs_attr *attr)
|
||||
{
|
||||
struct ptyfs_file *pty_file;
|
||||
struct ptyfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dentry);
|
||||
RT_ASSERT(dentry->mnt);
|
||||
|
||||
superblock = (struct ptyfs_sb *)dentry->mnt->data;
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
/* find the device related to current pts slave device */
|
||||
pty_file = ptyfile_lookup(superblock, dentry->pathname);
|
||||
if (pty_file && pty_file->type == PTYFS_TYPE_FILE_SLAVE)
|
||||
{
|
||||
pty_file->mode &= ~0xFFF;
|
||||
pty_file->mode |= attr->st_mode & 0xFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define OPTIMAL_BSIZE 1024
|
||||
|
||||
static int ptyfs_ops_statfs(struct dfs_mnt *mnt, struct statfs *buf)
|
||||
{
|
||||
struct ptyfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(mnt != NULL);
|
||||
RT_ASSERT(buf != NULL);
|
||||
|
||||
superblock = (struct ptyfs_sb *)mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
buf->f_bsize = OPTIMAL_BSIZE;
|
||||
buf->f_blocks = (superblock->df_size + OPTIMAL_BSIZE - 1) / OPTIMAL_BSIZE;
|
||||
buf->f_bfree = 1;
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int ptyfs_ops_stat(struct dfs_dentry *dentry, struct stat *st)
|
||||
{
|
||||
struct dfs_vnode *vnode;
|
||||
|
||||
if (dentry && dentry->vnode)
|
||||
{
|
||||
vnode = dentry->vnode;
|
||||
|
||||
/* device id ? */
|
||||
st->st_dev = (dev_t)(long)(dentry->mnt->dev_id);
|
||||
st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
|
||||
|
||||
st->st_gid = vnode->gid;
|
||||
st->st_uid = vnode->uid;
|
||||
st->st_mode = vnode->mode;
|
||||
st->st_nlink = vnode->nlink;
|
||||
st->st_size = vnode->size;
|
||||
st->st_mtim.tv_nsec = vnode->mtime.tv_nsec;
|
||||
st->st_mtim.tv_sec = vnode->mtime.tv_sec;
|
||||
st->st_ctim.tv_nsec = vnode->ctime.tv_nsec;
|
||||
st->st_ctim.tv_sec = vnode->ctime.tv_sec;
|
||||
st->st_atim.tv_nsec = vnode->atime.tv_nsec;
|
||||
st->st_atim.tv_sec = vnode->atime.tv_sec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *ptyfs_ops_lookup(struct dfs_dentry *dentry)
|
||||
{
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
struct ptyfs_sb *superblock;
|
||||
struct ptyfs_file *pty_file;
|
||||
|
||||
if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
superblock = (struct ptyfs_sb *)dentry->mnt->data;
|
||||
|
||||
pty_file = ptyfile_lookup(superblock, dentry->pathname);
|
||||
if (pty_file)
|
||||
{
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode)
|
||||
{
|
||||
vnode->data = pty_file->device;
|
||||
vnode->nlink = 1;
|
||||
vnode->size = 0;
|
||||
vnode->mnt = dentry->mnt;
|
||||
/* if it's root directory */
|
||||
vnode->fops = &_default_fops;
|
||||
vnode->mode = pty_file->mode;
|
||||
vnode->type = pty_file->type == PTYFS_TYPE_DIR ? FT_DIRECTORY : FT_DEVICE;
|
||||
}
|
||||
}
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *ptyfs_ops_create_vnode(struct dfs_dentry *dentry,
|
||||
int type, mode_t mode)
|
||||
{
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
struct ptyfs_sb *sb;
|
||||
struct ptyfs_file *pty_file;
|
||||
char *vnode_path;
|
||||
|
||||
if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sb = (struct ptyfs_sb *)dentry->mnt->data;
|
||||
RT_ASSERT(sb != NULL);
|
||||
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode)
|
||||
{
|
||||
vnode_path = dentry->pathname;
|
||||
|
||||
/* Query if file existed. Filter out illegal open modes */
|
||||
pty_file = ptyfile_lookup(sb, vnode_path);
|
||||
if (!pty_file || (~pty_file->mode & mode))
|
||||
{
|
||||
dfs_vnode_destroy(vnode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vnode->data = pty_file->device;
|
||||
vnode->nlink = 1;
|
||||
vnode->size = 0;
|
||||
vnode->mnt = dentry->mnt;
|
||||
vnode->fops = pty_file->device ? pty_file->device->fops : RT_NULL;
|
||||
vnode->mode &= pty_file->mode;
|
||||
|
||||
if (type == FT_DIRECTORY)
|
||||
{
|
||||
vnode->mode |= S_IFDIR;
|
||||
vnode->type = FT_DIRECTORY;
|
||||
LOG_I("%s: S_IFDIR created", __func__);
|
||||
}
|
||||
else if (type == FT_REGULAR)
|
||||
{
|
||||
vnode->mode |= S_IFCHR;
|
||||
vnode->type = FT_DEVICE;
|
||||
LOG_I("%s: S_IFDIR created", __func__);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* unsupported types */
|
||||
dfs_vnode_destroy(vnode);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static int ptyfs_ops_free_vnode(struct dfs_vnode *vnode)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int devpty_deffops_getdents(struct dfs_file *file, struct dirent *dirp,
|
||||
uint32_t count)
|
||||
{
|
||||
struct ptyfs_file *d_file;
|
||||
struct ptyfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(file);
|
||||
RT_ASSERT(file->dentry);
|
||||
RT_ASSERT(file->dentry->mnt);
|
||||
|
||||
superblock = (struct ptyfs_sb *)file->dentry->mnt->data;
|
||||
RT_ASSERT(superblock);
|
||||
|
||||
d_file = ptyfile_lookup(superblock, file->dentry->pathname);
|
||||
if (d_file)
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct ptyfs_file *n_file;
|
||||
rt_list_t *list;
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
end = file->fpos + count;
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
{
|
||||
if (index >= (rt_size_t)file->fpos)
|
||||
{
|
||||
n_file = rt_list_entry(list, struct ptyfs_file, ent_node);
|
||||
|
||||
d = dirp + count;
|
||||
if (n_file->type == PTYFS_TYPE_DIR)
|
||||
{
|
||||
d->d_type = DT_DIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ptmx(5,2) or slave(136,[0,1048575]) device, on Linux */
|
||||
d->d_type = DT_CHR;
|
||||
}
|
||||
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_strncpy(d->d_name, n_file->basename, DIRENT_NAME_MAX);
|
||||
d->d_namlen = rt_strlen(d->d_name);
|
||||
|
||||
count += 1;
|
||||
file->fpos += 1;
|
||||
}
|
||||
index += 1;
|
||||
if (index >= end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
static const struct dfs_filesystem_ops _ptyfs_ops = {
|
||||
.name = "ptyfs",
|
||||
.flags = DFS_FS_FLAG_DEFAULT,
|
||||
.default_fops = &_default_fops,
|
||||
|
||||
.mount = ptyfs_ops_mount,
|
||||
.umount = ptyfs_ops_umount,
|
||||
|
||||
/* don't allow to create symbolic link */
|
||||
.symlink = RT_NULL,
|
||||
.readlink = RT_NULL,
|
||||
.unlink = RT_NULL,
|
||||
|
||||
.setattr = ptyfs_ops_setattr,
|
||||
.statfs = ptyfs_ops_statfs,
|
||||
.stat = ptyfs_ops_stat,
|
||||
|
||||
.lookup = ptyfs_ops_lookup,
|
||||
.create_vnode = ptyfs_ops_create_vnode,
|
||||
.free_vnode = ptyfs_ops_free_vnode,
|
||||
};
|
||||
|
||||
static struct dfs_filesystem_type _devptyfs = {
|
||||
.fs_ops = &_ptyfs_ops,
|
||||
};
|
||||
|
||||
static int _ptyfs_init(void)
|
||||
{
|
||||
_default_fops = *dfs_devfs_fops();
|
||||
_default_fops.getdents = devpty_deffops_getdents;
|
||||
|
||||
/* register file system */
|
||||
dfs_register(&_devptyfs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(_ptyfs_init);
|
22
rt-thread/components/dfs/dfs_v2/filesystems/ptyfs/ptyfs.h
Normal file
22
rt-thread/components/dfs/dfs_v2/filesystems/ptyfs/ptyfs.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-12-02 Shell init ver.
|
||||
*/
|
||||
#ifndef __FS_PTYFS_H__
|
||||
#define __FS_PTYFS_H__
|
||||
#include <rtthread.h>
|
||||
|
||||
typedef rt_base_t ptsno_t;
|
||||
|
||||
ptsno_t ptyfs_register_pts(rt_device_t ptmx, rt_device_t pts);
|
||||
|
||||
rt_err_t ptyfs_unregister_pts(rt_device_t ptmx, ptsno_t ptsno);
|
||||
|
||||
const char *ptyfs_get_rootpath(rt_device_t ptmx);
|
||||
|
||||
#endif /* __FS_PTYFS_H__ */
|
@@ -0,0 +1,9 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_MEMHEAP', 'RT_USING_DFS_RAMFS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
479
rt-thread/components/dfs/dfs_v2/filesystems/ramfs/dfs_ramfs.c
Normal file
479
rt-thread/components/dfs/dfs_v2/filesystems/ramfs/dfs_ramfs.c
Normal file
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-04-15 Bernard the first version
|
||||
* 2013-05-05 Bernard remove CRC for ramfs persistence
|
||||
* 2013-05-22 Bernard fix the no entry issue.
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
|
||||
#include "dfs_ramfs.h"
|
||||
|
||||
int dfs_ramfs_mount(struct dfs_filesystem *fs,
|
||||
unsigned long rwflag,
|
||||
const void *data)
|
||||
{
|
||||
struct dfs_ramfs *ramfs;
|
||||
|
||||
if (data == NULL)
|
||||
return -EIO;
|
||||
|
||||
ramfs = (struct dfs_ramfs *)data;
|
||||
fs->data = ramfs;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_ramfs_unmount(struct dfs_filesystem *fs)
|
||||
{
|
||||
fs->data = NULL;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_ramfs_statfs(struct dfs_filesystem *fs, struct statfs *buf)
|
||||
{
|
||||
struct dfs_ramfs *ramfs;
|
||||
|
||||
ramfs = (struct dfs_ramfs *)fs->data;
|
||||
RT_ASSERT(ramfs != NULL);
|
||||
RT_ASSERT(buf != NULL);
|
||||
|
||||
buf->f_bsize = 512;
|
||||
buf->f_blocks = ramfs->memheap.pool_size / 512;
|
||||
buf->f_bfree = ramfs->memheap.available_size / 512;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_ramfs_ioctl(struct dfs_file *file, int cmd, void *args)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
struct ramfs_dirent *dfs_ramfs_lookup(struct dfs_ramfs *ramfs,
|
||||
const char *path,
|
||||
rt_size_t *size)
|
||||
{
|
||||
const char *subpath;
|
||||
struct ramfs_dirent *dirent;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
subpath ++;
|
||||
if (! *subpath) /* is root directory */
|
||||
{
|
||||
*size = 0;
|
||||
|
||||
return &(ramfs->root);
|
||||
}
|
||||
|
||||
for (dirent = rt_list_entry(ramfs->root.list.next, struct ramfs_dirent, list);
|
||||
dirent != &(ramfs->root);
|
||||
dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list))
|
||||
{
|
||||
if (rt_strcmp(dirent->name, subpath) == 0)
|
||||
{
|
||||
*size = dirent->size;
|
||||
|
||||
return dirent;
|
||||
}
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dfs_ramfs_read(struct dfs_file *file, void *buf, size_t count)
|
||||
{
|
||||
rt_size_t length;
|
||||
struct ramfs_dirent *dirent;
|
||||
|
||||
dirent = (struct ramfs_dirent *)file->vnode->data;
|
||||
RT_ASSERT(dirent != NULL);
|
||||
|
||||
if (count < file->vnode->size - file->pos)
|
||||
length = count;
|
||||
else
|
||||
length = file->vnode->size - file->pos;
|
||||
|
||||
if (length > 0)
|
||||
rt_memcpy(buf, &(dirent->data[file->pos]), length);
|
||||
|
||||
/* update file current position */
|
||||
file->pos += length;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int dfs_ramfs_write(struct dfs_file *fd, const void *buf, size_t count)
|
||||
{
|
||||
struct ramfs_dirent *dirent;
|
||||
struct dfs_ramfs *ramfs;
|
||||
|
||||
dirent = (struct ramfs_dirent *)fd->vnode->data;
|
||||
RT_ASSERT(dirent != NULL);
|
||||
|
||||
ramfs = dirent->fs;
|
||||
RT_ASSERT(ramfs != NULL);
|
||||
|
||||
if (count + fd->pos > fd->vnode->size)
|
||||
{
|
||||
rt_uint8_t *ptr;
|
||||
ptr = rt_memheap_realloc(&(ramfs->memheap), dirent->data, fd->pos + count);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
rt_set_errno(-ENOMEM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* update dirent and file size */
|
||||
dirent->data = ptr;
|
||||
dirent->size = fd->pos + count;
|
||||
fd->vnode->size = dirent->size;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
rt_memcpy(dirent->data + fd->pos, buf, count);
|
||||
|
||||
/* update file current position */
|
||||
fd->pos += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int dfs_ramfs_lseek(struct dfs_file *file, off_t offset)
|
||||
{
|
||||
if (offset <= (off_t)file->vnode->size)
|
||||
{
|
||||
file->pos = offset;
|
||||
|
||||
return file->pos;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int dfs_ramfs_close(struct dfs_file *file)
|
||||
{
|
||||
RT_ASSERT(file->vnode->ref_count > 0);
|
||||
if (file->vnode->ref_count > 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
file->vnode->data = NULL;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_ramfs_open(struct dfs_file *file)
|
||||
{
|
||||
rt_size_t size;
|
||||
struct dfs_ramfs *ramfs;
|
||||
struct ramfs_dirent *dirent;
|
||||
struct dfs_filesystem *fs;
|
||||
|
||||
RT_ASSERT(file->vnode->ref_count > 0);
|
||||
if (file->vnode->ref_count > 1)
|
||||
{
|
||||
if (file->vnode->type == FT_DIRECTORY
|
||||
&& !(file->flags & O_DIRECTORY))
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
file->pos = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fs = file->vnode->fs;
|
||||
|
||||
ramfs = (struct dfs_ramfs *)fs->data;
|
||||
RT_ASSERT(ramfs != NULL);
|
||||
|
||||
if (file->flags & O_DIRECTORY)
|
||||
{
|
||||
if (file->flags & O_CREAT)
|
||||
{
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* open directory */
|
||||
dirent = dfs_ramfs_lookup(ramfs, file->vnode->path, &size);
|
||||
if (dirent == NULL)
|
||||
return -ENOENT;
|
||||
if (dirent == &(ramfs->root)) /* it's root directory */
|
||||
{
|
||||
if (!(file->flags & O_DIRECTORY))
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
file->vnode->type = FT_DIRECTORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
dirent = dfs_ramfs_lookup(ramfs, file->vnode->path, &size);
|
||||
if (dirent == &(ramfs->root)) /* it's root directory */
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (dirent == NULL)
|
||||
{
|
||||
if (file->flags & O_CREAT || file->flags & O_WRONLY)
|
||||
{
|
||||
char *name_ptr;
|
||||
|
||||
/* create a file entry */
|
||||
dirent = (struct ramfs_dirent *)
|
||||
rt_memheap_alloc(&(ramfs->memheap),
|
||||
sizeof(struct ramfs_dirent));
|
||||
if (dirent == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* remove '/' separator */
|
||||
name_ptr = file->vnode->path;
|
||||
while (*name_ptr == '/' && *name_ptr)
|
||||
{
|
||||
name_ptr++;
|
||||
}
|
||||
strncpy(dirent->name, name_ptr, RAMFS_NAME_MAX);
|
||||
|
||||
rt_list_init(&(dirent->list));
|
||||
dirent->data = NULL;
|
||||
dirent->size = 0;
|
||||
dirent->fs = ramfs;
|
||||
file->vnode->type = FT_DIRECTORY;
|
||||
|
||||
/* add to the root directory */
|
||||
rt_list_insert_after(&(ramfs->root.list), &(dirent->list));
|
||||
}
|
||||
else
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Creates a new file.
|
||||
* If the file is existing, it is truncated and overwritten.
|
||||
*/
|
||||
if (file->flags & O_TRUNC)
|
||||
{
|
||||
dirent->size = 0;
|
||||
if (dirent->data != NULL)
|
||||
{
|
||||
rt_memheap_free(dirent->data);
|
||||
dirent->data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file->vnode->data = dirent;
|
||||
file->vnode->size = dirent->size;
|
||||
if (file->flags & O_APPEND)
|
||||
{
|
||||
file->pos = file->vnode->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
file->pos = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dfs_ramfs_stat(struct dfs_filesystem *fs,
|
||||
const char *path,
|
||||
struct stat *st)
|
||||
{
|
||||
rt_size_t size;
|
||||
struct ramfs_dirent *dirent;
|
||||
struct dfs_ramfs *ramfs;
|
||||
|
||||
ramfs = (struct dfs_ramfs *)fs->data;
|
||||
dirent = dfs_ramfs_lookup(ramfs, path, &size);
|
||||
|
||||
if (dirent == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
st->st_dev = 0;
|
||||
st->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
|
||||
S_IWUSR | S_IWGRP | S_IWOTH;
|
||||
|
||||
st->st_size = dirent->size;
|
||||
st->st_mtime = 0;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_ramfs_getdents(struct dfs_file *file,
|
||||
struct dirent *dirp,
|
||||
uint32_t count)
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct ramfs_dirent *dirent;
|
||||
struct dfs_ramfs *ramfs;
|
||||
|
||||
dirent = (struct ramfs_dirent *)file->vnode->data;
|
||||
|
||||
ramfs = dirent->fs;
|
||||
RT_ASSERT(ramfs != RT_NULL);
|
||||
|
||||
if (dirent != &(ramfs->root))
|
||||
return -EINVAL;
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
return -EINVAL;
|
||||
|
||||
end = file->pos + count;
|
||||
index = 0;
|
||||
count = 0;
|
||||
for (dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list);
|
||||
dirent != &(ramfs->root) && index < end;
|
||||
dirent = rt_list_entry(dirent->list.next, struct ramfs_dirent, list))
|
||||
{
|
||||
if (index >= (rt_size_t)file->pos)
|
||||
{
|
||||
d = dirp + count;
|
||||
d->d_type = DT_REG;
|
||||
d->d_namlen = RT_NAME_MAX;
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_strncpy(d->d_name, dirent->name, RAMFS_NAME_MAX);
|
||||
|
||||
count += 1;
|
||||
file->pos += 1;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return count * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
int dfs_ramfs_unlink(struct dfs_filesystem *fs, const char *path)
|
||||
{
|
||||
rt_size_t size;
|
||||
struct dfs_ramfs *ramfs;
|
||||
struct ramfs_dirent *dirent;
|
||||
|
||||
ramfs = (struct dfs_ramfs *)fs->data;
|
||||
RT_ASSERT(ramfs != NULL);
|
||||
|
||||
dirent = dfs_ramfs_lookup(ramfs, path, &size);
|
||||
if (dirent == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
rt_list_remove(&(dirent->list));
|
||||
if (dirent->data != NULL)
|
||||
rt_memheap_free(dirent->data);
|
||||
rt_memheap_free(dirent);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_ramfs_rename(struct dfs_filesystem *fs,
|
||||
const char *oldpath,
|
||||
const char *newpath)
|
||||
{
|
||||
struct ramfs_dirent *dirent;
|
||||
struct dfs_ramfs *ramfs;
|
||||
rt_size_t size;
|
||||
|
||||
ramfs = (struct dfs_ramfs *)fs->data;
|
||||
RT_ASSERT(ramfs != NULL);
|
||||
|
||||
dirent = dfs_ramfs_lookup(ramfs, newpath, &size);
|
||||
if (dirent != NULL)
|
||||
return -EEXIST;
|
||||
|
||||
dirent = dfs_ramfs_lookup(ramfs, oldpath, &size);
|
||||
if (dirent == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
strncpy(dirent->name, newpath, RAMFS_NAME_MAX);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _ram_fops =
|
||||
{
|
||||
dfs_ramfs_open,
|
||||
dfs_ramfs_close,
|
||||
dfs_ramfs_ioctl,
|
||||
dfs_ramfs_read,
|
||||
dfs_ramfs_write,
|
||||
NULL, /* flush */
|
||||
dfs_ramfs_lseek,
|
||||
dfs_ramfs_getdents,
|
||||
};
|
||||
|
||||
static const struct dfs_filesystem_ops _ramfs =
|
||||
{
|
||||
"ram",
|
||||
DFS_FS_FLAG_DEFAULT,
|
||||
&_ram_fops,
|
||||
|
||||
dfs_ramfs_mount,
|
||||
dfs_ramfs_unmount,
|
||||
NULL, /* mkfs */
|
||||
dfs_ramfs_statfs,
|
||||
|
||||
dfs_ramfs_unlink,
|
||||
dfs_ramfs_stat,
|
||||
dfs_ramfs_rename,
|
||||
};
|
||||
|
||||
int dfs_ramfs_init(void)
|
||||
{
|
||||
/* register ram file system */
|
||||
dfs_register(&_ramfs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(dfs_ramfs_init);
|
||||
|
||||
struct dfs_ramfs *dfs_ramfs_create(rt_uint8_t *pool, rt_size_t size)
|
||||
{
|
||||
struct dfs_ramfs *ramfs;
|
||||
rt_uint8_t *data_ptr;
|
||||
rt_err_t result;
|
||||
|
||||
size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
|
||||
ramfs = (struct dfs_ramfs *)pool;
|
||||
|
||||
data_ptr = (rt_uint8_t *)(ramfs + 1);
|
||||
size = size - sizeof(struct dfs_ramfs);
|
||||
size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
|
||||
|
||||
result = rt_memheap_init(&ramfs->memheap, "ramfs", data_ptr, size);
|
||||
if (result != RT_EOK)
|
||||
return NULL;
|
||||
/* detach this memheap object from the system */
|
||||
rt_object_detach((rt_object_t) & (ramfs->memheap));
|
||||
|
||||
/* initialize ramfs object */
|
||||
ramfs->magic = RAMFS_MAGIC;
|
||||
ramfs->memheap.parent.type = RT_Object_Class_MemHeap | RT_Object_Class_Static;
|
||||
|
||||
/* initialize root directory */
|
||||
rt_memset(&(ramfs->root), 0x00, sizeof(ramfs->root));
|
||||
rt_list_init(&(ramfs->root.list));
|
||||
ramfs->root.size = 0;
|
||||
strcpy(ramfs->root.name, ".");
|
||||
ramfs->root.fs = ramfs;
|
||||
|
||||
return ramfs;
|
||||
}
|
||||
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2013-04-15 Bernard the first version
|
||||
* 2013-05-05 Bernard remove CRC for ramfs persistence
|
||||
*/
|
||||
|
||||
#ifndef __DFS_RAMFS_H__
|
||||
#define __DFS_RAMFS_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtservice.h>
|
||||
|
||||
#define RAMFS_NAME_MAX 32
|
||||
#define RAMFS_MAGIC 0x0A0A0A0A
|
||||
|
||||
struct ramfs_dirent
|
||||
{
|
||||
rt_list_t list;
|
||||
struct dfs_ramfs *fs; /* file system ref */
|
||||
|
||||
char name[RAMFS_NAME_MAX]; /* dirent name */
|
||||
rt_uint8_t *data;
|
||||
|
||||
rt_size_t size; /* file size */
|
||||
};
|
||||
|
||||
/**
|
||||
* DFS ramfs object
|
||||
*/
|
||||
struct dfs_ramfs
|
||||
{
|
||||
rt_uint32_t magic;
|
||||
|
||||
struct rt_memheap memheap;
|
||||
struct ramfs_dirent root;
|
||||
};
|
||||
|
||||
int dfs_ramfs_init(void);
|
||||
struct dfs_ramfs *dfs_ramfs_create(rt_uint8_t *pool, rt_size_t size);
|
||||
|
||||
#endif
|
||||
|
11
rt-thread/components/dfs/dfs_v2/filesystems/romfs/SConscript
Normal file
11
rt-thread/components/dfs/dfs_v2/filesystems/romfs/SConscript
Normal file
@@ -0,0 +1,11 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS','RT_USING_DFS_ROMFS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
397
rt-thread/components/dfs/dfs_v2/filesystems/romfs/dfs_romfs.c
Normal file
397
rt-thread/components/dfs/dfs_v2/filesystems/romfs/dfs_romfs.c
Normal file
@@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_mnt.h>
|
||||
|
||||
#include "dfs_romfs.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <rtdbg.h>
|
||||
|
||||
static const struct dfs_file_ops _rom_fops;
|
||||
|
||||
static const mode_t romfs_modemap[] =
|
||||
{
|
||||
S_IFREG | 0644, /* regular file */
|
||||
S_IFDIR | 0644, /* directory */
|
||||
0, /* hard link */
|
||||
S_IFLNK | 0777, /* symlink */
|
||||
S_IFBLK | 0600, /* blockdev */
|
||||
S_IFCHR | 0600, /* chardev */
|
||||
S_IFSOCK | 0644, /* socket */
|
||||
S_IFIFO | 0644 /* FIFO */
|
||||
};
|
||||
|
||||
static int dfs_romfs_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
|
||||
{
|
||||
struct romfs_dirent *root_dirent;
|
||||
|
||||
if (data == NULL)
|
||||
return -1;
|
||||
|
||||
root_dirent = (struct romfs_dirent *)data;
|
||||
mnt->data = root_dirent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfs_romfs_umount(struct dfs_mnt *fs)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_romfs_ioctl(struct dfs_file *file, int cmd, void *args)
|
||||
{
|
||||
int ret = RT_EOK;
|
||||
struct romfs_dirent *dirent;
|
||||
|
||||
dirent = (struct romfs_dirent *)file->data;
|
||||
RT_ASSERT(dirent != NULL);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case RT_FIOGETADDR:
|
||||
{
|
||||
*(rt_ubase_t*)args = (rt_ubase_t)dirent->data;
|
||||
break;
|
||||
}
|
||||
case RT_FIOFTRUNCATE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -RT_EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
rt_inline int check_dirent(struct romfs_dirent *dirent)
|
||||
{
|
||||
if (dirent == NULL
|
||||
||(dirent->type != ROMFS_DIRENT_FILE && dirent->type != ROMFS_DIRENT_DIR)
|
||||
|| dirent->size == ~0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct romfs_dirent *__dfs_romfs_lookup(struct romfs_dirent *root_dirent, const char *path, rt_size_t *size)
|
||||
{
|
||||
rt_size_t index, found;
|
||||
const char *subpath, *subpath_end;
|
||||
struct romfs_dirent *dirent;
|
||||
rt_size_t dirent_size;
|
||||
|
||||
/* Check the root_dirent. */
|
||||
if (check_dirent(root_dirent) != 0)
|
||||
return NULL;
|
||||
|
||||
if (path[0] == '/' && path[1] == '\0')
|
||||
{
|
||||
*size = root_dirent->size;
|
||||
return root_dirent;
|
||||
}
|
||||
|
||||
/* goto root directy entries */
|
||||
dirent = (struct romfs_dirent *)root_dirent->data;
|
||||
dirent_size = root_dirent->size;
|
||||
|
||||
/* 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 ++)
|
||||
{
|
||||
if (check_dirent(&dirent[index]) != 0)
|
||||
return NULL;
|
||||
if (rt_strlen(dirent[index].name) == (subpath_end - subpath) &&
|
||||
rt_strncmp(dirent[index].name, subpath, (subpath_end - subpath)) == 0)
|
||||
{
|
||||
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 */
|
||||
dirent = (struct romfs_dirent *)dirent[index].data;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* return file dirent */
|
||||
return &dirent[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
break; /* not found */
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *dfs_romfs_lookup (struct dfs_dentry *dentry)
|
||||
{
|
||||
rt_size_t size;
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
struct romfs_dirent *root_dirent = RT_NULL, *dirent = RT_NULL;
|
||||
|
||||
RT_ASSERT(dentry != RT_NULL);
|
||||
RT_ASSERT(dentry->mnt != RT_NULL);
|
||||
|
||||
root_dirent = (struct romfs_dirent *)dentry->mnt->data;
|
||||
if (check_dirent(root_dirent) == 0)
|
||||
{
|
||||
/* create a vnode */
|
||||
DLOG(msg, "rom", "vnode", DLOG_MSG, "dfs_vnode_create()");
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode)
|
||||
{
|
||||
dirent = __dfs_romfs_lookup(root_dirent, dentry->pathname, &size);
|
||||
if (dirent)
|
||||
{
|
||||
vnode->nlink = 1;
|
||||
vnode->size = dirent->size;
|
||||
if (dirent->type == ROMFS_DIRENT_DIR)
|
||||
{
|
||||
vnode->mode = romfs_modemap[ROMFS_DIRENT_DIR] | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||
vnode->type = FT_DIRECTORY;
|
||||
}
|
||||
else if (dirent->type == ROMFS_DIRENT_FILE)
|
||||
{
|
||||
vnode->mode = romfs_modemap[ROMFS_DIRENT_FILE] | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||
vnode->type = FT_REGULAR;
|
||||
}
|
||||
|
||||
DLOG(msg, "rom", "rom", DLOG_MSG, "vnode->data = dirent");
|
||||
vnode->data = dirent;
|
||||
vnode->mnt = dentry->mnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no-entry */
|
||||
DLOG(msg, "rom", "vnode", DLOG_MSG, "dfs_vnode_destroy, no-dentry");
|
||||
dfs_vnode_destroy(vnode);
|
||||
vnode = RT_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static int dfs_romfs_free_vnode(struct dfs_vnode *vnode)
|
||||
{
|
||||
/* nothing to be freed */
|
||||
if (vnode->ref_count <= 1)
|
||||
{
|
||||
vnode->data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dfs_romfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
rt_size_t length;
|
||||
struct romfs_dirent *dirent;
|
||||
|
||||
dirent = (struct romfs_dirent *)file->vnode->data;
|
||||
RT_ASSERT(dirent != NULL);
|
||||
|
||||
if (check_dirent(dirent) != 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (count < file->vnode->size - *pos)
|
||||
length = count;
|
||||
else
|
||||
length = file->vnode->size - *pos;
|
||||
|
||||
if (length > 0)
|
||||
memcpy(buf, &(dirent->data[*pos]), length);
|
||||
|
||||
/* update file current position */
|
||||
*pos += length;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int dfs_romfs_close(struct dfs_file *file)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_romfs_open(struct dfs_file *file)
|
||||
{
|
||||
rt_size_t size;
|
||||
struct romfs_dirent *dirent;
|
||||
struct romfs_dirent *root_dirent;
|
||||
struct dfs_mnt *mnt;
|
||||
|
||||
if (file->flags & (O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_RDWR))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mnt = file->dentry->mnt;
|
||||
RT_ASSERT(mnt != RT_NULL);
|
||||
|
||||
root_dirent = (struct romfs_dirent *)mnt->data;
|
||||
if (check_dirent(root_dirent) != 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* get rom dirent */
|
||||
dirent = __dfs_romfs_lookup(root_dirent, file->dentry->pathname, &size);
|
||||
if (dirent == NULL)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
file->data = dirent;
|
||||
file->fops = &_rom_fops;
|
||||
file->fpos = 0;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int dfs_romfs_stat(struct dfs_dentry *dentry, struct stat *st)
|
||||
{
|
||||
rt_err_t ret = dfs_file_lock();
|
||||
if (ret == RT_EOK)
|
||||
{
|
||||
st->st_dev = 0;
|
||||
st->st_mode = dentry->vnode->mode;
|
||||
st->st_size = dentry->vnode->size;
|
||||
st->st_nlink = dentry->vnode->nlink;
|
||||
st->st_mtime = 0;
|
||||
|
||||
dfs_file_unlock();
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int dfs_romfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
|
||||
{
|
||||
rt_size_t index;
|
||||
const char *name;
|
||||
struct dirent *d;
|
||||
struct romfs_dirent *dirent, *sub_dirent;
|
||||
|
||||
dirent = (struct romfs_dirent *)file->vnode->data;
|
||||
if (check_dirent(dirent) != 0)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
RT_ASSERT(dirent->type == ROMFS_DIRENT_DIR);
|
||||
|
||||
/* enter directory */
|
||||
dirent = (struct romfs_dirent *)dirent->data;
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
for (index = 0; index < count && file->fpos < file->vnode->size; index++)
|
||||
{
|
||||
d = dirp + index;
|
||||
|
||||
sub_dirent = &dirent[file->fpos];
|
||||
name = sub_dirent->name;
|
||||
|
||||
/* fill dirent */
|
||||
if (sub_dirent->type == ROMFS_DIRENT_DIR)
|
||||
d->d_type = DT_DIR;
|
||||
else
|
||||
d->d_type = DT_REG;
|
||||
|
||||
d->d_namlen = rt_strlen(name);
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_strncpy(d->d_name, name, DIRENT_NAME_MAX);
|
||||
|
||||
/* move to next position */
|
||||
++ file->fpos;
|
||||
}
|
||||
|
||||
return index * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _rom_fops =
|
||||
{
|
||||
.open = dfs_romfs_open,
|
||||
.close = dfs_romfs_close,
|
||||
.lseek = generic_dfs_lseek,
|
||||
.read = dfs_romfs_read,
|
||||
.getdents = dfs_romfs_getdents,
|
||||
};
|
||||
|
||||
static const struct dfs_filesystem_ops _romfs_ops =
|
||||
{
|
||||
.name ="rom",
|
||||
.flags = 0,
|
||||
.default_fops = &_rom_fops,
|
||||
.mount = dfs_romfs_mount,
|
||||
.umount = dfs_romfs_umount,
|
||||
.stat = dfs_romfs_stat,
|
||||
.lookup = dfs_romfs_lookup,
|
||||
.free_vnode = dfs_romfs_free_vnode
|
||||
};
|
||||
|
||||
static struct dfs_filesystem_type _romfs =
|
||||
{
|
||||
.fs_ops = &_romfs_ops,
|
||||
};
|
||||
|
||||
int dfs_romfs_init(void)
|
||||
{
|
||||
/* register rom file system */
|
||||
dfs_register(&_romfs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(dfs_romfs_init);
|
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019/01/13 Bernard code cleanup
|
||||
*/
|
||||
|
||||
#ifndef __DFS_ROMFS_H__
|
||||
#define __DFS_ROMFS_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define ROMFS_DIRENT_FILE 0x00
|
||||
#define ROMFS_DIRENT_DIR 0x01
|
||||
|
||||
struct romfs_dirent
|
||||
{
|
||||
rt_uint32_t type; /* dirent type */
|
||||
|
||||
const char *name; /* dirent name */
|
||||
const rt_uint8_t *data; /* file date ptr */
|
||||
rt_size_t size; /* file size */
|
||||
};
|
||||
|
||||
int dfs_romfs_init(void);
|
||||
extern const struct romfs_dirent romfs_root;
|
||||
|
||||
#endif
|
42
rt-thread/components/dfs/dfs_v2/filesystems/romfs/romfs.c
Normal file
42
rt-thread/components/dfs/dfs_v2/filesystems/romfs/romfs.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs_romfs.h>
|
||||
|
||||
static const unsigned char _dummy_dummy_txt[] =
|
||||
{
|
||||
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x21, 0x0d, 0x0a,
|
||||
};
|
||||
|
||||
static const struct romfs_dirent _dummy[] =
|
||||
{
|
||||
{ROMFS_DIRENT_FILE, "dummy.txt", _dummy_dummy_txt, sizeof(_dummy_dummy_txt)},
|
||||
};
|
||||
|
||||
static const unsigned char _dummy_txt[] =
|
||||
{
|
||||
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x21, 0x0d, 0x0a,
|
||||
};
|
||||
|
||||
rt_weak const struct romfs_dirent _root_dirent[] =
|
||||
{
|
||||
{ROMFS_DIRENT_DIR, "dev", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "mnt", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "proc", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "etc", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "bin", RT_NULL, 0},
|
||||
{ROMFS_DIRENT_DIR, "dummy", (rt_uint8_t *)_dummy, sizeof(_dummy) / sizeof(_dummy[0])},
|
||||
{ROMFS_DIRENT_FILE, "dummy.txt", _dummy_txt, sizeof(_dummy_txt)},
|
||||
};
|
||||
|
||||
rt_weak const struct romfs_dirent romfs_root =
|
||||
{
|
||||
ROMFS_DIRENT_DIR, "/", (rt_uint8_t *)_root_dirent, sizeof(_root_dirent) / sizeof(_root_dirent[0])
|
||||
};
|
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_file.h>
|
||||
|
||||
#include "dfs_skt_fs.h"
|
||||
|
||||
int dfs_skt_mount(struct dfs_filesystem *fs, unsigned long rwflag, const void *data)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_skt_unmount(struct dfs_filesystem *fs)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_skt_ioctl(struct dfs_file *file, int cmd, void *args)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
int dfs_skt_read(struct dfs_file *file, void *buf, rt_size_t count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
int dfs_skt_lseek(struct dfs_file *file, rt_off_t offset)
|
||||
{
|
||||
return -RT_EIO;
|
||||
}
|
||||
|
||||
int dfs_skt_close(struct dfs_file *file)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_skt_open(struct dfs_file *file)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_skt_stat(struct dfs_filesystem *fs, const char *path, struct stat *st)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_skt_getdents(struct dfs_file *file, struct dirent *dirp, rt_uint32_t count)
|
||||
{
|
||||
return count * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _skt_fops =
|
||||
{
|
||||
dfs_skt_open,
|
||||
dfs_skt_close,
|
||||
dfs_skt_ioctl,
|
||||
dfs_skt_read,
|
||||
NULL, /* write */
|
||||
NULL, /* flush */
|
||||
dfs_skt_lseek,
|
||||
dfs_skt_getdents,
|
||||
};
|
||||
|
||||
static const struct dfs_filesystem_ops _skt_fs =
|
||||
{
|
||||
"skt",
|
||||
DFS_FS_FLAG_DEFAULT,
|
||||
&_skt_fops,
|
||||
|
||||
dfs_skt_mount,
|
||||
dfs_skt_unmount,
|
||||
NULL, /* mkfs */
|
||||
NULL, /* statfs */
|
||||
|
||||
NULL, /* unlink */
|
||||
dfs_skt_stat,
|
||||
NULL, /* rename */
|
||||
};
|
||||
|
||||
int dfs_skt_init(void)
|
||||
{
|
||||
/* register rom file system */
|
||||
dfs_register(&_skt_fs);
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(dfs_skt_init);
|
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
*/
|
||||
|
||||
#ifndef __SKELETON_H__
|
||||
#define __SKELETON_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
int dfs_skt_init(void);
|
||||
|
||||
#endif
|
@@ -0,0 +1,9 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Filesystem', src, depend = ['RT_USING_DFS', 'RT_USING_DFS_TMPFS'], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
908
rt-thread/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c
Normal file
908
rt-thread/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c
Normal file
@@ -0,0 +1,908 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-10-24 flybreak the first version
|
||||
* 2023-02-01 xqyjlj fix cannot open the same file repeatedly in 'w' mode
|
||||
* 2023-09-20 zmq810150896 adds truncate functionality and standardized unlink adaptations
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <dfs.h>
|
||||
#include <dfs_fs.h>
|
||||
#include <dfs_dentry.h>
|
||||
#include <dfs_file.h>
|
||||
#include <dfs_mnt.h>
|
||||
|
||||
#ifdef RT_USING_SMART
|
||||
#include <lwp.h>
|
||||
#include <lwp_user_mm.h>
|
||||
#endif
|
||||
|
||||
#include "dfs_tmpfs.h"
|
||||
|
||||
#define DBG_TAG "tmpfs"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
#include "dfs_pcache.h"
|
||||
#endif
|
||||
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
static ssize_t dfs_tmp_page_read(struct dfs_file *file, struct dfs_page *page);
|
||||
static ssize_t dfs_tmp_page_write(struct dfs_page *page);
|
||||
|
||||
static struct dfs_aspace_ops dfs_tmp_aspace_ops =
|
||||
{
|
||||
.read = dfs_tmp_page_read,
|
||||
.write = dfs_tmp_page_write,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int _path_separate(const char *path, char *parent_path, char *file_name)
|
||||
{
|
||||
const char *path_p, *path_q;
|
||||
|
||||
RT_ASSERT(path[0] == '/');
|
||||
|
||||
file_name[0] = '\0';
|
||||
path_p = path_q = &path[1];
|
||||
__next_dir:
|
||||
while (*path_q != '/' && *path_q != '\0')
|
||||
{
|
||||
path_q++;
|
||||
}
|
||||
if (path_q != path_p) /*sub dir*/
|
||||
{
|
||||
if (*path_q != '\0')
|
||||
{
|
||||
path_q++;
|
||||
path_p = path_q;
|
||||
goto __next_dir;
|
||||
}
|
||||
else /* Last level dir */
|
||||
{
|
||||
rt_memcpy(parent_path, path, path_p - path - 1);
|
||||
parent_path[path_p - path - 1] = '\0';
|
||||
rt_memcpy(file_name, path_p, path_q - path_p);
|
||||
file_name[path_q - path_p] = '\0';
|
||||
}
|
||||
}
|
||||
if (parent_path[0] == 0)
|
||||
{
|
||||
parent_path[0] = '/';
|
||||
parent_path[1] = '\0';
|
||||
}
|
||||
LOG_D("parent_path: %s", parent_path);
|
||||
LOG_D("file_name: %s", file_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_subdir(const char *path, char *name)
|
||||
{
|
||||
const char *subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
subpath ++;
|
||||
while (*subpath != '/' && *subpath)
|
||||
{
|
||||
*name = *subpath;
|
||||
name ++;
|
||||
subpath ++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _free_subdir(struct tmpfs_file *dfile)
|
||||
{
|
||||
struct tmpfs_file *file;
|
||||
rt_list_t *list, *temp_list;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(dfile->type == TMPFS_TYPE_DIR);
|
||||
|
||||
rt_list_for_each_safe(list, temp_list, &dfile->subdirs)
|
||||
{
|
||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
_free_subdir(file);
|
||||
}
|
||||
if (file->data != NULL)
|
||||
{
|
||||
/* TODO: fix for rt-smart */
|
||||
rt_free(file->data);
|
||||
}
|
||||
|
||||
superblock = file->sb;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_mount(struct dfs_mnt *mnt,
|
||||
unsigned long rwflag,
|
||||
const void *data)
|
||||
{
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
superblock = rt_calloc(1, sizeof(struct tmpfs_sb));
|
||||
if (superblock)
|
||||
{
|
||||
superblock->df_size = sizeof(struct tmpfs_sb);
|
||||
superblock->magic = TMPFS_MAGIC;
|
||||
rt_list_init(&superblock->sibling);
|
||||
|
||||
superblock->root.name[0] = '/';
|
||||
superblock->root.sb = superblock;
|
||||
superblock->root.type = TMPFS_TYPE_DIR;
|
||||
rt_list_init(&superblock->root.sibling);
|
||||
rt_list_init(&superblock->root.subdirs);
|
||||
|
||||
rt_spin_lock_init(&superblock->lock);
|
||||
|
||||
mnt->data = superblock;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_unmount(struct dfs_mnt *mnt)
|
||||
{
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
/* FIXME: don't unmount on busy. */
|
||||
superblock = (struct tmpfs_sb *)mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
mnt->data = NULL;
|
||||
_free_subdir(&(superblock->root));
|
||||
rt_free(superblock);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_tmpfs_statfs(struct dfs_mnt *mnt, struct statfs *buf)
|
||||
{
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
superblock = (struct tmpfs_sb *)mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
RT_ASSERT(buf != NULL);
|
||||
|
||||
buf->f_bsize = 512;
|
||||
buf->f_blocks = (superblock->df_size + 511) / 512;
|
||||
buf->f_bfree = 1;
|
||||
buf->f_bavail = buf->f_bfree;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
int dfs_tmpfs_ioctl(struct dfs_file *file, int cmd, void *args)
|
||||
{
|
||||
struct tmpfs_file *d_file;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
RT_ASSERT(d_file != NULL);
|
||||
|
||||
superblock = d_file->sb;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
RT_UNUSED(superblock);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
#ifdef RT_USING_SMART
|
||||
case RT_FIOMMAP2:
|
||||
{
|
||||
struct dfs_mmap2_args *mmap2 = (struct dfs_mmap2_args *)args;
|
||||
if (mmap2)
|
||||
{
|
||||
if (mmap2->length > file->vnode->size)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
LOG_D("tmpfile mmap ptr:%x , size:%d\n", d_file->data, mmap2->length);
|
||||
mmap2->ret = lwp_map_user_phy(lwp_self(), RT_NULL, d_file->data, mmap2->length, 0);
|
||||
}
|
||||
return RT_EOK;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
struct tmpfs_file *dfs_tmpfs_lookup(struct tmpfs_sb *superblock,
|
||||
const char *path,
|
||||
rt_size_t *size)
|
||||
{
|
||||
const char *subpath, *curpath, *filename = RT_NULL;
|
||||
char subdir_name[TMPFS_NAME_MAX];
|
||||
struct tmpfs_file *file, *curfile;
|
||||
rt_list_t *list;
|
||||
|
||||
subpath = path;
|
||||
while (*subpath == '/' && *subpath)
|
||||
subpath ++;
|
||||
if (! *subpath) /* is root directory */
|
||||
{
|
||||
*size = 0;
|
||||
return &(superblock->root);
|
||||
}
|
||||
|
||||
curpath = subpath;
|
||||
curfile = &superblock->root;
|
||||
|
||||
find_subpath:
|
||||
while (*subpath != '/' && *subpath)
|
||||
subpath ++;
|
||||
|
||||
if (! *subpath) /* is last directory */
|
||||
filename = curpath;
|
||||
else
|
||||
subpath ++; /* skip '/' */
|
||||
|
||||
memset(subdir_name, 0, TMPFS_NAME_MAX);
|
||||
_get_subdir(curpath, subdir_name);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
|
||||
rt_list_for_each(list, &curfile->subdirs)
|
||||
{
|
||||
file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (filename) /* find file */
|
||||
{
|
||||
if (rt_strcmp(file->name, filename) == 0)
|
||||
{
|
||||
*size = file->size;
|
||||
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
else if (rt_strcmp(file->name, subdir_name) == 0)
|
||||
{
|
||||
*size = file->size;
|
||||
curpath = subpath;
|
||||
curfile = file;
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
goto find_subpath;
|
||||
}
|
||||
}
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
/* not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t dfs_tmpfs_read(struct dfs_file *file, void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
ssize_t length;
|
||||
struct tmpfs_file *d_file;
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
RT_ASSERT(d_file != NULL);
|
||||
|
||||
rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
|
||||
ssize_t size = (ssize_t)file->vnode->size;
|
||||
if ((ssize_t)count < size - *pos)
|
||||
length = count;
|
||||
else
|
||||
length = size - *pos;
|
||||
|
||||
if (length > 0)
|
||||
memcpy(buf, &(d_file->data[*pos]), length);
|
||||
|
||||
/* update file current position */
|
||||
*pos += length;
|
||||
|
||||
rt_mutex_release(&file->vnode->lock);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static ssize_t _dfs_tmpfs_write(struct tmpfs_file *d_file, const void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
RT_ASSERT(d_file != NULL);
|
||||
|
||||
superblock = d_file->sb;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
if (count + *pos > d_file->size)
|
||||
{
|
||||
rt_uint8_t *ptr;
|
||||
ptr = rt_realloc(d_file->data, *pos + count);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
rt_set_errno(-ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
superblock->df_size += (*pos - d_file->size + count);
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
/* update d_file and file size */
|
||||
d_file->data = ptr;
|
||||
d_file->size = *pos + count;
|
||||
LOG_D("tmpfile ptr:%x, size:%d", ptr, d_file->size);
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
memcpy(d_file->data + *pos, buf, count);
|
||||
|
||||
/* update file current position */
|
||||
*pos += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t dfs_tmpfs_write(struct dfs_file *file, const void *buf, size_t count, off_t *pos)
|
||||
{
|
||||
struct tmpfs_file *d_file;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
RT_ASSERT(d_file != NULL);
|
||||
|
||||
rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
|
||||
|
||||
count = _dfs_tmpfs_write(d_file, buf, count, pos);
|
||||
|
||||
rt_mutex_release(&file->vnode->lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static off_t dfs_tmpfs_lseek(struct dfs_file *file, off_t offset, int wherece)
|
||||
{
|
||||
switch (wherece)
|
||||
{
|
||||
case SEEK_SET:
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
offset += file->fpos;
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
offset += file->vnode->size;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (offset <= (off_t)file->vnode->size)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_close(struct dfs_file *file)
|
||||
{
|
||||
struct tmpfs_file *d_file;
|
||||
|
||||
RT_ASSERT(file->vnode->ref_count > 0);
|
||||
|
||||
if (file->vnode->ref_count != 1)
|
||||
return 0;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
|
||||
if (d_file == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (d_file->fre_memory == RT_TRUE)
|
||||
{
|
||||
if (d_file->data != NULL)
|
||||
{
|
||||
rt_free(d_file->data);
|
||||
d_file->data = RT_NULL;
|
||||
}
|
||||
|
||||
rt_free(d_file);
|
||||
}
|
||||
|
||||
rt_mutex_detach(&file->vnode->lock);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_open(struct dfs_file *file)
|
||||
{
|
||||
struct tmpfs_file *d_file;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
RT_ASSERT(d_file != RT_NULL);
|
||||
/* Creates a new file.
|
||||
* If the file is existing, it is truncated and overwritten.
|
||||
*/
|
||||
if (file->flags & O_TRUNC)
|
||||
{
|
||||
d_file->size = 0;
|
||||
file->vnode->size = d_file->size;
|
||||
file->fpos = file->vnode->size;
|
||||
if (d_file->data != NULL)
|
||||
{
|
||||
/* ToDo: fix for rt-smart. */
|
||||
rt_free(d_file->data);
|
||||
d_file->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (file->flags & O_APPEND)
|
||||
{
|
||||
file->fpos = file->vnode->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
file->fpos = 0;
|
||||
}
|
||||
|
||||
RT_ASSERT(file->vnode->ref_count > 0);
|
||||
if(file->vnode->ref_count == 1)
|
||||
{
|
||||
rt_mutex_init(&file->vnode->lock, file->dentry->pathname, RT_IPC_FLAG_PRIO);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_stat(struct dfs_dentry *dentry, struct stat *st)
|
||||
{
|
||||
rt_size_t size;
|
||||
struct tmpfs_file *d_file;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
superblock = (struct tmpfs_sb *)dentry->mnt->data;
|
||||
d_file = dfs_tmpfs_lookup(superblock, dentry->pathname, &size);
|
||||
|
||||
if (d_file == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
st->st_dev = (dev_t)(size_t)(dentry->mnt->dev_id);
|
||||
st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
|
||||
|
||||
if (d_file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
st->st_mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
st->st_mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
}
|
||||
|
||||
st->st_size = d_file->size;
|
||||
st->st_mtime = 0;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_getdents(struct dfs_file *file,
|
||||
struct dirent *dirp,
|
||||
uint32_t count)
|
||||
{
|
||||
rt_size_t index, end;
|
||||
struct dirent *d;
|
||||
struct tmpfs_file *d_file, *n_file;
|
||||
rt_list_t *list;
|
||||
struct tmpfs_sb *superblock;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
|
||||
rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
|
||||
|
||||
superblock = d_file->sb;
|
||||
RT_ASSERT(superblock != RT_NULL);
|
||||
RT_UNUSED(superblock);
|
||||
|
||||
/* make integer count */
|
||||
count = (count / sizeof(struct dirent));
|
||||
if (count == 0)
|
||||
{
|
||||
rt_mutex_release(&file->vnode->lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
end = file->fpos + count;
|
||||
index = 0;
|
||||
count = 0;
|
||||
|
||||
rt_list_for_each(list, &d_file->subdirs)
|
||||
{
|
||||
n_file = rt_list_entry(list, struct tmpfs_file, sibling);
|
||||
if (index >= (rt_size_t)file->fpos)
|
||||
{
|
||||
d = dirp + count;
|
||||
if (d_file->type == TMPFS_TYPE_FILE)
|
||||
{
|
||||
d->d_type = DT_REG;
|
||||
}
|
||||
if (d_file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
d->d_type = DT_DIR;
|
||||
}
|
||||
d->d_namlen = RT_NAME_MAX;
|
||||
d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
|
||||
rt_strncpy(d->d_name, n_file->name, TMPFS_NAME_MAX);
|
||||
|
||||
count += 1;
|
||||
file->fpos += 1;
|
||||
}
|
||||
index += 1;
|
||||
if (index >= end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
rt_mutex_release(&file->vnode->lock);
|
||||
|
||||
return count * sizeof(struct dirent);
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_unlink(struct dfs_dentry *dentry)
|
||||
{
|
||||
rt_size_t size;
|
||||
struct tmpfs_sb *superblock;
|
||||
struct tmpfs_file *d_file;
|
||||
|
||||
superblock = (struct tmpfs_sb *)dentry->mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
d_file = dfs_tmpfs_lookup(superblock, dentry->pathname, &size);
|
||||
if (d_file == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
if (rt_atomic_load(&(dentry->ref_count)) == 1)
|
||||
{
|
||||
if (d_file->data != NULL)
|
||||
{
|
||||
rt_free(d_file->data);
|
||||
d_file->data = RT_NULL;
|
||||
}
|
||||
|
||||
rt_free(d_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
d_file->fre_memory = RT_TRUE;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *new_dentry)
|
||||
{
|
||||
struct tmpfs_file *d_file, *p_file;
|
||||
struct tmpfs_sb *superblock;
|
||||
rt_size_t size;
|
||||
char *parent_path;
|
||||
char file_name[TMPFS_NAME_MAX];
|
||||
|
||||
superblock = (struct tmpfs_sb *)old_dentry->mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
d_file = dfs_tmpfs_lookup(superblock, new_dentry->pathname, &size);
|
||||
if (d_file != NULL)
|
||||
return -EEXIST;
|
||||
|
||||
d_file = dfs_tmpfs_lookup(superblock, old_dentry->pathname, &size);
|
||||
if (d_file == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
parent_path = rt_malloc(DFS_PATH_MAX);
|
||||
if (!parent_path)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* find parent file */
|
||||
_path_separate(new_dentry->pathname, parent_path, file_name);
|
||||
if (file_name[0] == '\0') /* it's root dir */
|
||||
{
|
||||
rt_free(parent_path);
|
||||
return -ENOENT;
|
||||
}
|
||||
/* open parent directory */
|
||||
p_file = dfs_tmpfs_lookup(superblock, parent_path, &size);
|
||||
RT_ASSERT(p_file != NULL);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_remove(&(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
rt_free(parent_path);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *_dfs_tmpfs_lookup(struct dfs_dentry *dentry)
|
||||
{
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
rt_size_t size;
|
||||
struct tmpfs_sb *superblock;
|
||||
struct tmpfs_file *d_file;
|
||||
|
||||
if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
superblock = (struct tmpfs_sb *)dentry->mnt->data;
|
||||
|
||||
d_file = dfs_tmpfs_lookup(superblock, dentry->pathname, &size);
|
||||
if (d_file)
|
||||
{
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode)
|
||||
{
|
||||
if (d_file->type == TMPFS_TYPE_DIR)
|
||||
{
|
||||
vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||
vnode->type = FT_DIRECTORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
vnode->type = FT_REGULAR;
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_tmp_aspace_ops);
|
||||
#endif
|
||||
}
|
||||
|
||||
vnode->mnt = dentry->mnt;
|
||||
vnode->data = d_file;
|
||||
vnode->size = d_file->size;
|
||||
}
|
||||
}
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
|
||||
{
|
||||
struct dfs_vnode *vnode = RT_NULL;
|
||||
rt_size_t size;
|
||||
struct tmpfs_sb *superblock;
|
||||
struct tmpfs_file *d_file, *p_file;
|
||||
char *parent_path;
|
||||
char file_name[TMPFS_NAME_MAX];
|
||||
|
||||
if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
superblock = (struct tmpfs_sb *)dentry->mnt->data;
|
||||
RT_ASSERT(superblock != NULL);
|
||||
|
||||
parent_path = rt_malloc(DFS_PATH_MAX);
|
||||
if (!parent_path)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vnode = dfs_vnode_create();
|
||||
if (vnode)
|
||||
{
|
||||
/* find parent file */
|
||||
_path_separate(dentry->pathname, parent_path, file_name);
|
||||
if (file_name[0] == '\0') /* it's root dir */
|
||||
{
|
||||
rt_free(parent_path);
|
||||
dfs_vnode_destroy(vnode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open parent directory */
|
||||
p_file = dfs_tmpfs_lookup(superblock, parent_path, &size);
|
||||
if (p_file == NULL)
|
||||
{
|
||||
rt_free(parent_path);
|
||||
dfs_vnode_destroy(vnode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create a file entry */
|
||||
d_file = (struct tmpfs_file *)rt_calloc(1, sizeof(struct tmpfs_file));
|
||||
if (d_file == NULL)
|
||||
{
|
||||
rt_free(parent_path);
|
||||
dfs_vnode_destroy(vnode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
superblock->df_size += sizeof(struct tmpfs_file);
|
||||
|
||||
strncpy(d_file->name, file_name, TMPFS_NAME_MAX);
|
||||
|
||||
rt_list_init(&(d_file->subdirs));
|
||||
rt_list_init(&(d_file->sibling));
|
||||
d_file->data = NULL;
|
||||
d_file->size = 0;
|
||||
d_file->sb = superblock;
|
||||
d_file->fre_memory = RT_FALSE;
|
||||
if (type == FT_DIRECTORY)
|
||||
{
|
||||
d_file->type = TMPFS_TYPE_DIR;
|
||||
vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
|
||||
vnode->type = FT_DIRECTORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_file->type = TMPFS_TYPE_FILE;
|
||||
vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
vnode->type = FT_REGULAR;
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_tmp_aspace_ops);
|
||||
#endif
|
||||
}
|
||||
rt_spin_lock(&superblock->lock);
|
||||
rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling));
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
vnode->mnt = dentry->mnt;
|
||||
vnode->data = d_file;
|
||||
vnode->size = d_file->size;
|
||||
}
|
||||
|
||||
rt_free(parent_path);
|
||||
|
||||
return vnode;
|
||||
}
|
||||
|
||||
static int dfs_tmpfs_free_vnode(struct dfs_vnode *vnode)
|
||||
{
|
||||
/* nothing to be freed */
|
||||
if (vnode && vnode->ref_count <= 1)
|
||||
{
|
||||
vnode->data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RT_USING_PAGECACHE
|
||||
static ssize_t dfs_tmp_page_read(struct dfs_file *file, struct dfs_page *page)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (page->page)
|
||||
{
|
||||
off_t fpos = page->fpos;
|
||||
ret = dfs_tmpfs_read(file, page->page, page->size, &fpos);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t dfs_tmp_page_write(struct dfs_page *page)
|
||||
{
|
||||
off_t pos;
|
||||
size_t count = 0;
|
||||
struct tmpfs_file *d_file;
|
||||
|
||||
if (page->aspace->vnode->type == FT_DIRECTORY)
|
||||
{
|
||||
return -EISDIR;
|
||||
}
|
||||
|
||||
d_file = (struct tmpfs_file *)(page->aspace->vnode->data);
|
||||
RT_ASSERT(d_file != RT_NULL);
|
||||
|
||||
rt_mutex_take(&page->aspace->vnode->lock, RT_WAITING_FOREVER);
|
||||
if (page->len > 0)
|
||||
{
|
||||
pos = page->fpos;
|
||||
count = _dfs_tmpfs_write(d_file, page->page, page->len, &pos);
|
||||
}
|
||||
rt_mutex_release(&page->aspace->vnode->lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dfs_tmpfs_truncate(struct dfs_file *file, off_t offset)
|
||||
{
|
||||
struct tmpfs_file *d_file = RT_NULL;
|
||||
struct tmpfs_sb *superblock = RT_NULL;
|
||||
rt_uint8_t *ptr = RT_NULL;
|
||||
|
||||
d_file = (struct tmpfs_file *)file->vnode->data;
|
||||
RT_ASSERT(d_file != RT_NULL);
|
||||
|
||||
superblock = d_file->sb;
|
||||
RT_ASSERT(superblock != RT_NULL);
|
||||
|
||||
ptr = rt_realloc(d_file->data, offset);
|
||||
if (ptr == RT_NULL)
|
||||
{
|
||||
rt_set_errno(-ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_spin_lock(&superblock->lock);
|
||||
superblock->df_size = offset;
|
||||
rt_spin_unlock(&superblock->lock);
|
||||
|
||||
/* update d_file and file size */
|
||||
d_file->data = ptr;
|
||||
d_file->size = offset;
|
||||
file->vnode->size = d_file->size;
|
||||
LOG_D("tmpfile ptr:%x, size:%d", ptr, d_file->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dfs_file_ops _tmp_fops =
|
||||
{
|
||||
.open = dfs_tmpfs_open,
|
||||
.close = dfs_tmpfs_close,
|
||||
.ioctl = dfs_tmpfs_ioctl,
|
||||
.read = dfs_tmpfs_read,
|
||||
.write = dfs_tmpfs_write,
|
||||
.lseek = dfs_tmpfs_lseek,
|
||||
.getdents = dfs_tmpfs_getdents,
|
||||
.truncate = dfs_tmpfs_truncate,
|
||||
};
|
||||
|
||||
static const struct dfs_filesystem_ops _tmpfs_ops =
|
||||
{
|
||||
.name = "tmp",
|
||||
.flags = DFS_FS_FLAG_DEFAULT,
|
||||
.default_fops = &_tmp_fops,
|
||||
|
||||
.mount = dfs_tmpfs_mount,
|
||||
.umount = dfs_tmpfs_unmount,
|
||||
.statfs = dfs_tmpfs_statfs,
|
||||
|
||||
.unlink = dfs_tmpfs_unlink,
|
||||
.stat = dfs_tmpfs_stat,
|
||||
.rename = dfs_tmpfs_rename,
|
||||
.lookup = _dfs_tmpfs_lookup,
|
||||
.create_vnode = dfs_tmpfs_create_vnode,
|
||||
.free_vnode = dfs_tmpfs_free_vnode
|
||||
};
|
||||
|
||||
static struct dfs_filesystem_type _tmpfs =
|
||||
{
|
||||
.fs_ops = &_tmpfs_ops,
|
||||
};
|
||||
|
||||
int dfs_tmpfs_init(void)
|
||||
{
|
||||
/* register tmp file system */
|
||||
dfs_register(&_tmpfs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_COMPONENT_EXPORT(dfs_tmpfs_init);
|
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2018, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-10-24 flybreak the first version
|
||||
*/
|
||||
|
||||
#ifndef __DFS_TMPFS_H__
|
||||
#define __DFS_TMPFS_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#define TMPFS_NAME_MAX 32
|
||||
#define TMPFS_MAGIC 0x0B0B0B0B
|
||||
|
||||
#define TMPFS_TYPE_FILE 0x00
|
||||
#define TMPFS_TYPE_DIR 0x01
|
||||
|
||||
struct tmpfs_sb;
|
||||
|
||||
struct tmpfs_file
|
||||
{
|
||||
rt_uint32_t type; /* file type */
|
||||
char name[TMPFS_NAME_MAX]; /* file name */
|
||||
rt_list_t subdirs; /* file subdir list */
|
||||
rt_list_t sibling; /* file sibling list */
|
||||
struct tmpfs_sb *sb; /* superblock ptr */
|
||||
rt_uint8_t *data; /* file date ptr */
|
||||
rt_size_t size; /* file size */
|
||||
rt_bool_t fre_memory;/* Whether to release memory upon close */
|
||||
};
|
||||
|
||||
|
||||
struct tmpfs_sb
|
||||
{
|
||||
rt_uint32_t magic; /* TMPFS_MAGIC */
|
||||
struct tmpfs_file root; /* root dir */
|
||||
rt_size_t df_size; /* df size */
|
||||
rt_list_t sibling; /* sb sibling list */
|
||||
struct rt_spinlock lock; /* tmpfs lock */
|
||||
};
|
||||
|
||||
int dfs_tmpfs_init(void);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user