init project

Signed-off-by: a1012112796 <1012112796@qq.com>
This commit is contained in:
2022-09-26 15:31:48 +08:00
commit 02210074ec
2260 changed files with 1056951 additions and 0 deletions
+572
View File
@@ -0,0 +1,572 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2005-02-22 Bernard The first version.
* 2017-12-11 Bernard Use rt_free to instead of free in fd_is_open().
* 2018-03-20 Heyuanjie dynamic allocation FD
*/
#include <dfs.h>
#include <dfs_fs.h>
#include <dfs_file.h>
#include "dfs_private.h"
#ifdef RT_USING_LWP
#include <lwp.h>
#endif
#ifdef RT_USING_POSIX_STDIO
#include <libc.h>
#endif /* RT_USING_POSIX_STDIO */
/* Global variables */
const struct dfs_filesystem_ops *filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX];
struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX];
/* device filesystem lock */
static struct rt_mutex fslock;
#ifdef DFS_USING_WORKDIR
char working_directory[DFS_PATH_MAX] = {"/"};
#endif
static struct dfs_fdtable _fdtab;
/**
* @addtogroup DFS
*/
/*@{*/
/**
* this function will initialize device file system.
*/
int dfs_init(void)
{
static rt_bool_t init_ok = RT_FALSE;
if (init_ok)
{
rt_kprintf("dfs already init.\n");
return 0;
}
/* clear filesystem operations table */
rt_memset((void *)filesystem_operation_table, 0, sizeof(filesystem_operation_table));
/* clear filesystem table */
rt_memset(filesystem_table, 0, sizeof(filesystem_table));
/* clean fd table */
rt_memset(&_fdtab, 0, sizeof(_fdtab));
/* create device filesystem lock */
rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_PRIO);
#ifdef DFS_USING_WORKDIR
/* set current working directory */
rt_memset(working_directory, 0, sizeof(working_directory));
working_directory[0] = '/';
#endif
#ifdef RT_USING_DFS_DEVFS
{
extern int devfs_init(void);
/* if enable devfs, initialize and mount it as soon as possible */
devfs_init();
dfs_mount(NULL, "/dev", "devfs", 0, 0);
}
#endif
init_ok = RT_TRUE;
return 0;
}
INIT_PREV_EXPORT(dfs_init);
/**
* this function will lock device file system.
*
* @note please don't invoke it on ISR.
*/
void dfs_lock(void)
{
rt_err_t result = -RT_EBUSY;
while (result == -RT_EBUSY)
{
result = rt_mutex_take(&fslock, RT_WAITING_FOREVER);
}
if (result != RT_EOK)
{
RT_ASSERT(0);
}
}
/**
* this function will lock device file system.
*
* @note please don't invoke it on ISR.
*/
void dfs_unlock(void)
{
rt_mutex_release(&fslock);
}
#ifdef DFS_USING_POSIX
static int fd_alloc(struct dfs_fdtable *fdt, int startfd)
{
int idx;
/* find an empty fd entry */
for (idx = startfd; idx < (int)fdt->maxfd; idx++)
{
if (fdt->fds[idx] == RT_NULL)
break;
if (fdt->fds[idx]->ref_count == 0)
break;
}
/* allocate a larger FD container */
if (idx == (int)fdt->maxfd && fdt->maxfd < DFS_FD_MAX)
{
int cnt, index;
struct dfs_fd **fds;
/* increase the number of FD with 4 step length */
cnt = fdt->maxfd + 4;
cnt = cnt > DFS_FD_MAX ? DFS_FD_MAX : cnt;
fds = (struct dfs_fd **)rt_realloc(fdt->fds, cnt * sizeof(struct dfs_fd *));
if (fds == NULL) goto __exit; /* return fdt->maxfd */
/* clean the new allocated fds */
for (index = (int)fdt->maxfd; index < cnt; index ++)
{
fds[index] = NULL;
}
fdt->fds = fds;
fdt->maxfd = cnt;
}
/* allocate 'struct dfs_fd' */
if (idx < (int)fdt->maxfd && fdt->fds[idx] == RT_NULL)
{
fdt->fds[idx] = (struct dfs_fd *)rt_calloc(1, sizeof(struct dfs_fd));
if (fdt->fds[idx] == RT_NULL)
idx = fdt->maxfd;
}
__exit:
return idx;
}
/**
* @ingroup Fd
* This function will allocate a file descriptor.
*
* @return -1 on failed or the allocated file descriptor.
*/
int fd_new(void)
{
struct dfs_fd *d;
int idx;
struct dfs_fdtable *fdt;
fdt = dfs_fdtable_get();
/* lock filesystem */
dfs_lock();
/* find an empty fd entry */
idx = fd_alloc(fdt, 0);
/* can't find an empty fd entry */
if (idx == (int)fdt->maxfd)
{
idx = -(1 + DFS_FD_OFFSET);
LOG_E("DFS fd new is failed! Could not found an empty fd entry.");
goto __result;
}
d = fdt->fds[idx];
d->ref_count = 1;
d->magic = DFS_FD_MAGIC;
__result:
dfs_unlock();
return idx + DFS_FD_OFFSET;
}
/**
* @ingroup Fd
*
* This function will return a file descriptor structure according to file
* descriptor.
*
* @return NULL on on this file descriptor or the file descriptor structure
* pointer.
*/
struct dfs_fd *fd_get(int fd)
{
struct dfs_fd *d;
struct dfs_fdtable *fdt;
#ifdef RT_USING_POSIX_STDIO
if ((0 <= fd) && (fd <= 2))
fd = libc_stdio_get_console();
#endif /* RT_USING_POSIX_STDIO */
fdt = dfs_fdtable_get();
fd = fd - DFS_FD_OFFSET;
if (fd < 0 || fd >= (int)fdt->maxfd)
return NULL;
dfs_lock();
d = fdt->fds[fd];
/* check dfs_fd valid or not */
if ((d == NULL) || (d->magic != DFS_FD_MAGIC))
{
dfs_unlock();
return NULL;
}
/* increase the reference count */
d->ref_count ++;
dfs_unlock();
return d;
}
/**
* @ingroup Fd
*
* This function will put the file descriptor.
*/
void fd_put(struct dfs_fd *fd)
{
RT_ASSERT(fd != NULL);
dfs_lock();
fd->ref_count --;
/* clear this fd entry */
if (fd->ref_count == 0)
{
int index;
struct dfs_fdtable *fdt;
fdt = dfs_fdtable_get();
for (index = 0; index < (int)fdt->maxfd; index ++)
{
if (fdt->fds[index] == fd)
{
rt_free(fd);
fdt->fds[index] = 0;
break;
}
}
}
dfs_unlock();
}
#endif /* DFS_USING_POSIX */
/**
* @ingroup Fd
*
* This function will return whether this file has been opend.
*
* @param pathname the file path name.
*
* @return 0 on file has been open successfully, -1 on open failed.
*/
int fd_is_open(const char *pathname)
{
char *fullpath;
unsigned int index;
struct dfs_filesystem *fs;
struct dfs_fd *fd;
struct dfs_fdtable *fdt;
fdt = dfs_fdtable_get();
fullpath = dfs_normalize_path(NULL, pathname);
if (fullpath != NULL)
{
char *mountpath;
fs = dfs_filesystem_lookup(fullpath);
if (fs == NULL)
{
/* can't find mounted file system */
rt_free(fullpath);
return -1;
}
/* get file path name under mounted file system */
if (fs->path[0] == '/' && fs->path[1] == '\0')
mountpath = fullpath;
else
mountpath = fullpath + strlen(fs->path);
dfs_lock();
for (index = 0; index < fdt->maxfd; index++)
{
fd = fdt->fds[index];
if (fd == NULL || fd->fops == NULL || fd->path == NULL) continue;
if (fd->fs == fs && strcmp(fd->path, mountpath) == 0)
{
/* found file in file descriptor table */
rt_free(fullpath);
dfs_unlock();
return 0;
}
}
dfs_unlock();
rt_free(fullpath);
}
return -1;
}
/**
* this function will return a sub-path name under directory.
*
* @param directory the parent directory.
* @param filename the filename.
*
* @return the subdir pointer in filename
*/
const char *dfs_subdir(const char *directory, const char *filename)
{
const char *dir;
if (strlen(directory) == strlen(filename)) /* it's a same path */
return NULL;
dir = filename + strlen(directory);
if ((*dir != '/') && (dir != filename))
{
dir --;
}
return dir;
}
RTM_EXPORT(dfs_subdir);
/**
* this function will normalize a path according to specified parent directory
* and file name.
*
* @param directory the parent path
* @param filename the file name
*
* @return the built full file path (absolute path)
*/
char *dfs_normalize_path(const char *directory, const char *filename)
{
char *fullpath;
char *dst0, *dst, *src;
/* check parameters */
RT_ASSERT(filename != NULL);
#ifdef DFS_USING_WORKDIR
if (directory == NULL) /* shall use working directory */
directory = &working_directory[0];
#else
if ((directory == NULL) && (filename[0] != '/'))
{
rt_kprintf(NO_WORKING_DIR);
return NULL;
}
#endif
if (filename[0] != '/') /* it's a absolute path, use it directly */
{
fullpath = (char *)rt_malloc(strlen(directory) + strlen(filename) + 2);
if (fullpath == NULL)
return NULL;
/* join path and file name */
rt_snprintf(fullpath, strlen(directory) + strlen(filename) + 2,
"%s/%s", directory, filename);
}
else
{
fullpath = rt_strdup(filename); /* copy string */
if (fullpath == NULL)
return NULL;
}
src = fullpath;
dst = fullpath;
dst0 = dst;
while (1)
{
char c = *src;
if (c == '.')
{
if (!src[1]) src ++; /* '.' and ends */
else if (src[1] == '/')
{
/* './' case */
src += 2;
while ((*src == '/') && (*src != '\0'))
src ++;
continue;
}
else if (src[1] == '.')
{
if (!src[2])
{
/* '..' and ends case */
src += 2;
goto up_one;
}
else if (src[2] == '/')
{
/* '../' case */
src += 3;
while ((*src == '/') && (*src != '\0'))
src ++;
goto up_one;
}
}
}
/* copy up the next '/' and erase all '/' */
while ((c = *src++) != '\0' && c != '/')
*dst ++ = c;
if (c == '/')
{
*dst ++ = '/';
while (c == '/')
c = *src++;
src --;
}
else if (!c)
break;
continue;
up_one:
dst --;
if (dst < dst0)
{
rt_free(fullpath);
return NULL;
}
while (dst0 < dst && dst[-1] != '/')
dst --;
}
*dst = '\0';
/* remove '/' in the end of path if exist */
dst --;
if ((dst != fullpath) && (*dst == '/'))
*dst = '\0';
/* final check fullpath is not empty, for the special path of lwext "/.." */
if ('\0' == fullpath[0])
{
fullpath[0] = '/';
fullpath[1] = '\0';
}
return fullpath;
}
RTM_EXPORT(dfs_normalize_path);
/**
* This function will get the file descriptor table of current process.
*/
struct dfs_fdtable *dfs_fdtable_get(void)
{
struct dfs_fdtable *fdt;
#ifdef RT_USING_LWP
struct rt_lwp *lwp;
lwp = (struct rt_lwp *)rt_thread_self()->lwp;
if (lwp)
fdt = &lwp->fdt;
else
fdt = &_fdtab;
#else
fdt = &_fdtab;
#endif
return fdt;
}
#ifdef RT_USING_FINSH
#include <finsh.h>
int list_fd(void)
{
int index;
struct dfs_fdtable *fd_table;
fd_table = dfs_fdtable_get();
if (!fd_table) return -1;
rt_enter_critical();
rt_kprintf("fd type ref magic path\n");
rt_kprintf("-- ------ --- ----- ------\n");
for (index = 0; index < (int)fd_table->maxfd; index ++)
{
struct dfs_fd *fd = fd_table->fds[index];
if (fd && fd->fops)
{
rt_kprintf("%2d ", index + DFS_FD_OFFSET);
if (fd->type == FT_DIRECTORY) rt_kprintf("%-7.7s ", "dir");
else if (fd->type == FT_REGULAR) rt_kprintf("%-7.7s ", "file");
else if (fd->type == FT_SOCKET) rt_kprintf("%-7.7s ", "socket");
else if (fd->type == FT_USER) rt_kprintf("%-7.7s ", "user");
else if (fd->type == FT_DEVICE) rt_kprintf("%-7.7s ", "device");
else rt_kprintf("%-8.8s ", "unknown");
rt_kprintf("%3d ", fd->ref_count);
rt_kprintf("%04x ", fd->magic);
if (fd->fs && fd->fs->path && rt_strlen(fd->fs->path) > 1)
{
rt_kprintf("%s", fd->fs->path);
}
if (fd->path)
{
rt_kprintf("%s\n", fd->path);
}
else
{
rt_kprintf("\n");
}
}
}
rt_exit_critical();
return 0;
}
MSH_CMD_EXPORT(list_fd, list file descriptor);
#endif
/*@}*/
+850
View File
@@ -0,0 +1,850 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2005-02-22 Bernard The first version.
* 2011-12-08 Bernard Merges rename patch from iamcacy.
* 2015-05-27 Bernard Fix the fd clear issue.
* 2019-01-24 Bernard Remove file repeatedly open check.
*/
#include <dfs.h>
#include <dfs_file.h>
#include <dfs_private.h>
/**
* @addtogroup FileApi
*/
/*@{*/
/**
* this function will open a file which specified by path with specified flags.
*
* @param fd the file descriptor pointer to return the corresponding result.
* @param path the specified file path.
* @param flags the flags for open operator.
*
* @return 0 on successful, -1 on failed.
*/
int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
{
struct dfs_filesystem *fs;
char *fullpath;
int result;
/* parameter check */
if (fd == NULL)
return -EINVAL;
/* make sure we have an absolute path */
fullpath = dfs_normalize_path(NULL, path);
if (fullpath == NULL)
{
return -ENOMEM;
}
LOG_D("open file:%s", fullpath);
/* find filesystem */
fs = dfs_filesystem_lookup(fullpath);
if (fs == NULL)
{
rt_free(fullpath); /* release path */
return -ENOENT;
}
LOG_D("open in filesystem:%s", fs->ops->name);
fd->fs = fs; /* set file system */
fd->fops = fs->ops->fops; /* set file ops */
/* initialize the fd item */
fd->type = FT_REGULAR;
fd->flags = flags;
fd->size = 0;
fd->pos = 0;
fd->data = fs;
if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
{
if (dfs_subdir(fs->path, fullpath) == NULL)
fd->path = rt_strdup("/");
else
fd->path = rt_strdup(dfs_subdir(fs->path, fullpath));
rt_free(fullpath);
LOG_D("Actual file path: %s", fd->path);
}
else
{
fd->path = fullpath;
}
/* specific file system open routine */
if (fd->fops->open == NULL)
{
/* clear fd */
rt_free(fd->path);
fd->path = NULL;
return -ENOSYS;
}
if ((result = fd->fops->open(fd)) < 0)
{
/* clear fd */
rt_free(fd->path);
fd->path = NULL;
LOG_D("%s open failed", fullpath);
return result;
}
fd->flags |= DFS_F_OPEN;
if (flags & O_DIRECTORY)
{
fd->type = FT_DIRECTORY;
fd->flags |= DFS_F_DIRECTORY;
}
LOG_D("open successful");
return 0;
}
/**
* this function will close a file descriptor.
*
* @param fd the file descriptor to be closed.
*
* @return 0 on successful, -1 on failed.
*/
int dfs_file_close(struct dfs_fd *fd)
{
int result = 0;
if (fd == NULL)
return -ENXIO;
if (fd->fops->close != NULL)
result = fd->fops->close(fd);
/* close fd error, return */
if (result < 0)
return result;
rt_free(fd->path);
fd->path = NULL;
return result;
}
/**
* this function will perform a io control on a file descriptor.
*
* @param fd the file descriptor.
* @param cmd the command to send to file descriptor.
* @param args the argument to send to file descriptor.
*
* @return 0 on successful, -1 on failed.
*/
int dfs_file_ioctl(struct dfs_fd *fd, int cmd, void *args)
{
if (fd == NULL)
return -EINVAL;
/* regular file system fd */
if (fd->type == FT_REGULAR)
{
switch (cmd)
{
case F_GETFL:
return fd->flags; /* return flags */
case F_SETFL:
{
int flags = (int)(rt_base_t)args;
int mask = O_NONBLOCK | O_APPEND;
flags &= mask;
fd->flags &= ~mask;
fd->flags |= flags;
}
return 0;
}
}
if (fd->fops->ioctl != NULL)
return fd->fops->ioctl(fd, cmd, args);
return -ENOSYS;
}
/**
* this function will read specified length data from a file descriptor to a
* buffer.
*
* @param fd the file descriptor.
* @param buf the buffer to save the read data.
* @param len the length of data buffer to be read.
*
* @return the actual read data bytes or 0 on end of file or failed.
*/
int dfs_file_read(struct dfs_fd *fd, void *buf, size_t len)
{
int result = 0;
if (fd == NULL)
return -EINVAL;
if (fd->fops->read == NULL)
return -ENOSYS;
if ((result = fd->fops->read(fd, buf, len)) < 0)
fd->flags |= DFS_F_EOF;
return result;
}
/**
* this function will fetch directory entries from a directory descriptor.
*
* @param fd the directory descriptor.
* @param dirp the dirent buffer to save result.
* @param nbytes the available room in the buffer.
*
* @return the read dirent, others on failed.
*/
int dfs_file_getdents(struct dfs_fd *fd, struct dirent *dirp, size_t nbytes)
{
/* parameter check */
if (fd == NULL || fd->type != FT_DIRECTORY)
return -EINVAL;
if (fd->fops->getdents != NULL)
return fd->fops->getdents(fd, dirp, nbytes);
return -ENOSYS;
}
/**
* this function will unlink (remove) a specified path file from file system.
*
* @param path the specified path file to be unlinked.
*
* @return 0 on successful, -1 on failed.
*/
int dfs_file_unlink(const char *path)
{
int result;
char *fullpath;
struct dfs_filesystem *fs;
/* Make sure we have an absolute path */
fullpath = dfs_normalize_path(NULL, path);
if (fullpath == NULL)
{
return -EINVAL;
}
/* get filesystem */
if ((fs = dfs_filesystem_lookup(fullpath)) == NULL)
{
result = -ENOENT;
goto __exit;
}
/* Check whether file is already open */
if (fd_is_open(fullpath) == 0)
{
result = -EBUSY;
goto __exit;
}
if (fs->ops->unlink != NULL)
{
if (!(fs->ops->flags & DFS_FS_FLAG_FULLPATH))
{
if (dfs_subdir(fs->path, fullpath) == NULL)
result = fs->ops->unlink(fs, "/");
else
result = fs->ops->unlink(fs, dfs_subdir(fs->path, fullpath));
}
else
result = fs->ops->unlink(fs, fullpath);
}
else result = -ENOSYS;
__exit:
rt_free(fullpath);
return result;
}
/**
* this function will write some specified length data to file system.
*
* @param fd the file descriptor.
* @param buf the data buffer to be written.
* @param len the data buffer length
*
* @return the actual written data length.
*/
int dfs_file_write(struct dfs_fd *fd, const void *buf, size_t len)
{
if (fd == NULL)
return -EINVAL;
if (fd->fops->write == NULL)
return -ENOSYS;
return fd->fops->write(fd, buf, len);
}
/**
* this function will flush buffer on a file descriptor.
*
* @param fd the file descriptor.
*
* @return 0 on successful, -1 on failed.
*/
int dfs_file_flush(struct dfs_fd *fd)
{
if (fd == NULL)
return -EINVAL;
if (fd->fops->flush == NULL)
return -ENOSYS;
return fd->fops->flush(fd);
}
/**
* this function will seek the offset for specified file descriptor.
*
* @param fd the file descriptor.
* @param offset the offset to be sought.
*
* @return the current position after seek.
*/
int dfs_file_lseek(struct dfs_fd *fd, off_t offset)
{
int result;
if (fd == NULL)
return -EINVAL;
if (fd->fops->lseek == NULL)
return -ENOSYS;
result = fd->fops->lseek(fd, offset);
/* update current position */
if (result >= 0)
fd->pos = result;
return result;
}
/**
* this function will get file information.
*
* @param path the file path.
* @param buf the data buffer to save stat description.
*
* @return 0 on successful, -1 on failed.
*/
int dfs_file_stat(const char *path, struct stat *buf)
{
int result;
char *fullpath;
struct dfs_filesystem *fs;
fullpath = dfs_normalize_path(NULL, path);
if (fullpath == NULL)
{
return -1;
}
if ((fs = dfs_filesystem_lookup(fullpath)) == NULL)
{
LOG_E("can't find mounted filesystem on this path:%s", fullpath);
rt_free(fullpath);
return -ENOENT;
}
if ((fullpath[0] == '/' && fullpath[1] == '\0') ||
(dfs_subdir(fs->path, fullpath) == NULL))
{
/* it's the root directory */
buf->st_dev = 0;
buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH;
buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
buf->st_size = 0;
buf->st_mtime = 0;
/* release full path */
rt_free(fullpath);
return RT_EOK;
}
else
{
if (fs->ops->stat == NULL)
{
rt_free(fullpath);
LOG_E("the filesystem didn't implement this function");
return -ENOSYS;
}
/* get the real file path and get file stat */
if (fs->ops->flags & DFS_FS_FLAG_FULLPATH)
result = fs->ops->stat(fs, fullpath, buf);
else
result = fs->ops->stat(fs, dfs_subdir(fs->path, fullpath), buf);
}
rt_free(fullpath);
return result;
}
/**
* this function will rename an old path name to a new path name.
*
* @param oldpath the old path name.
* @param newpath the new path name.
*
* @return 0 on successful, -1 on failed.
*/
int dfs_file_rename(const char *oldpath, const char *newpath)
{
int result;
struct dfs_filesystem *oldfs, *newfs;
char *oldfullpath, *newfullpath;
result = RT_EOK;
newfullpath = NULL;
oldfullpath = NULL;
oldfullpath = dfs_normalize_path(NULL, oldpath);
if (oldfullpath == NULL)
{
result = -ENOENT;
goto __exit;
}
newfullpath = dfs_normalize_path(NULL, newpath);
if (newfullpath == NULL)
{
result = -ENOENT;
goto __exit;
}
oldfs = dfs_filesystem_lookup(oldfullpath);
newfs = dfs_filesystem_lookup(newfullpath);
if (oldfs == newfs)
{
if (oldfs->ops->rename == NULL)
{
result = -ENOSYS;
}
else
{
if (oldfs->ops->flags & DFS_FS_FLAG_FULLPATH)
result = oldfs->ops->rename(oldfs, oldfullpath, newfullpath);
else
/* use sub directory to rename in file system */
result = oldfs->ops->rename(oldfs,
dfs_subdir(oldfs->path, oldfullpath),
dfs_subdir(newfs->path, newfullpath));
}
}
else
{
result = -EXDEV;
}
__exit:
rt_free(oldfullpath);
rt_free(newfullpath);
/* not at same file system, return EXDEV */
return result;
}
/**
* this function is will cause the regular file referenced by fd
* to be truncated to a size of precisely length bytes.
*
* @param fd the file descriptor.
* @param length the length to be truncated.
*
* @return the status of truncated.
*/
int dfs_file_ftruncate(struct dfs_fd *fd, off_t length)
{
int result;
/* fd is null or not a regular file system fd, or length is invalid */
if (fd == NULL || fd->type != FT_REGULAR || length < 0)
return -EINVAL;
if (fd->fops->ioctl == NULL)
return -ENOSYS;
result = fd->fops->ioctl(fd, RT_FIOFTRUNCATE, (void*)&length);
/* update current size */
if (result == 0)
fd->size = length;
return result;
}
#ifdef RT_USING_FINSH
#include <finsh.h>
static struct dfs_fd fd;
static struct dirent dirent;
void ls(const char *pathname)
{
struct stat stat;
int length;
char *fullpath, *path;
fullpath = NULL;
if (pathname == NULL)
{
#ifdef DFS_USING_WORKDIR
/* open current working directory */
path = rt_strdup(working_directory);
#else
path = rt_strdup("/");
#endif
if (path == NULL)
return ; /* out of memory */
}
else
{
path = (char *)pathname;
}
/* list directory */
if (dfs_file_open(&fd, path, O_DIRECTORY) == 0)
{
rt_kprintf("Directory %s:\n", path);
do
{
rt_memset(&dirent, 0, sizeof(struct dirent));
length = dfs_file_getdents(&fd, &dirent, sizeof(struct dirent));
if (length > 0)
{
rt_memset(&stat, 0, sizeof(struct stat));
/* build full path for each file */
fullpath = dfs_normalize_path(path, dirent.d_name);
if (fullpath == NULL)
break;
if (dfs_file_stat(fullpath, &stat) == 0)
{
rt_kprintf("%-20s", dirent.d_name);
if (S_ISDIR(stat.st_mode))
{
rt_kprintf("%-25s\n", "<DIR>");
}
else
{
rt_kprintf("%-25lu\n", (unsigned long)stat.st_size);
}
}
else
rt_kprintf("BAD file: %s\n", dirent.d_name);
rt_free(fullpath);
}
}
while (length > 0);
dfs_file_close(&fd);
}
else
{
rt_kprintf("No such directory\n");
}
if (pathname == NULL)
rt_free(path);
}
FINSH_FUNCTION_EXPORT(ls, list directory contents);
void rm(const char *filename)
{
if (dfs_file_unlink(filename) < 0)
{
rt_kprintf("Delete %s failed\n", filename);
}
}
FINSH_FUNCTION_EXPORT(rm, remove files or directories);
void cat(const char *filename)
{
uint32_t length;
char buffer[81];
if (dfs_file_open(&fd, filename, O_RDONLY) < 0)
{
rt_kprintf("Open %s failed\n", filename);
return;
}
do
{
rt_memset(buffer, 0, sizeof(buffer));
length = dfs_file_read(&fd, buffer, sizeof(buffer) - 1);
if (length > 0)
{
rt_kprintf("%s", buffer);
}
}
while (length > 0);
rt_kprintf("\n");
dfs_file_close(&fd);
}
FINSH_FUNCTION_EXPORT(cat, print file);
#ifdef DFS_USING_POSIX
#define BUF_SZ 4096
static void copyfile(const char *src, const char *dst)
{
struct dfs_fd src_fd;
rt_uint8_t *block_ptr;
rt_int32_t read_bytes;
block_ptr = (rt_uint8_t *)rt_malloc(BUF_SZ);
if (block_ptr == NULL)
{
rt_kprintf("out of memory\n");
return;
}
if (dfs_file_open(&src_fd, src, O_RDONLY) < 0)
{
rt_free(block_ptr);
rt_kprintf("Read %s failed\n", src);
return;
}
if (dfs_file_open(&fd, dst, O_WRONLY | O_CREAT) < 0)
{
rt_free(block_ptr);
dfs_file_close(&src_fd);
rt_kprintf("Write %s failed\n", dst);
return;
}
do
{
read_bytes = dfs_file_read(&src_fd, block_ptr, BUF_SZ);
if (read_bytes > 0)
{
int length;
length = dfs_file_write(&fd, block_ptr, read_bytes);
if (length != read_bytes)
{
/* write failed. */
rt_kprintf("Write file data failed, errno=%d\n", length);
break;
}
}
}
while (read_bytes > 0);
dfs_file_close(&src_fd);
dfs_file_close(&fd);
rt_free(block_ptr);
}
extern int mkdir(const char *path, mode_t mode);
static void copydir(const char *src, const char *dst)
{
struct dirent dirent;
struct stat stat;
int length;
struct dfs_fd cpfd;
if (dfs_file_open(&cpfd, src, O_DIRECTORY) < 0)
{
rt_kprintf("open %s failed\n", src);
return ;
}
do
{
rt_memset(&dirent, 0, sizeof(struct dirent));
length = dfs_file_getdents(&cpfd, &dirent, sizeof(struct dirent));
if (length > 0)
{
char *src_entry_full = NULL;
char *dst_entry_full = NULL;
if (strcmp(dirent.d_name, "..") == 0 || strcmp(dirent.d_name, ".") == 0)
continue;
/* build full path for each file */
if ((src_entry_full = dfs_normalize_path(src, dirent.d_name)) == NULL)
{
rt_kprintf("out of memory!\n");
break;
}
if ((dst_entry_full = dfs_normalize_path(dst, dirent.d_name)) == NULL)
{
rt_kprintf("out of memory!\n");
rt_free(src_entry_full);
break;
}
rt_memset(&stat, 0, sizeof(struct stat));
if (dfs_file_stat(src_entry_full, &stat) != 0)
{
rt_kprintf("open file: %s failed\n", dirent.d_name);
continue;
}
if (S_ISDIR(stat.st_mode))
{
mkdir(dst_entry_full, 0);
copydir(src_entry_full, dst_entry_full);
}
else
{
copyfile(src_entry_full, dst_entry_full);
}
rt_free(src_entry_full);
rt_free(dst_entry_full);
}
}
while (length > 0);
dfs_file_close(&cpfd);
}
static const char *_get_path_lastname(const char *path)
{
char *ptr;
if ((ptr = (char *)strrchr(path, '/')) == NULL)
return path;
/* skip the '/' then return */
return ++ptr;
}
void copy(const char *src, const char *dst)
{
#define FLAG_SRC_TYPE 0x03
#define FLAG_SRC_IS_DIR 0x01
#define FLAG_SRC_IS_FILE 0x02
#define FLAG_SRC_NON_EXSIT 0x00
#define FLAG_DST_TYPE 0x0C
#define FLAG_DST_IS_DIR 0x04
#define FLAG_DST_IS_FILE 0x08
#define FLAG_DST_NON_EXSIT 0x00
struct stat stat;
uint32_t flag = 0;
/* check the staus of src and dst */
if (dfs_file_stat(src, &stat) < 0)
{
rt_kprintf("copy failed, bad %s\n", src);
return;
}
if (S_ISDIR(stat.st_mode))
flag |= FLAG_SRC_IS_DIR;
else
flag |= FLAG_SRC_IS_FILE;
if (dfs_file_stat(dst, &stat) < 0)
{
flag |= FLAG_DST_NON_EXSIT;
}
else
{
if (S_ISDIR(stat.st_mode))
flag |= FLAG_DST_IS_DIR;
else
flag |= FLAG_DST_IS_FILE;
}
//2. check status
if ((flag & FLAG_SRC_IS_DIR) && (flag & FLAG_DST_IS_FILE))
{
rt_kprintf("cp faild, cp dir to file is not permitted!\n");
return ;
}
//3. do copy
if (flag & FLAG_SRC_IS_FILE)
{
if (flag & FLAG_DST_IS_DIR)
{
char *fdst;
fdst = dfs_normalize_path(dst, _get_path_lastname(src));
if (fdst == NULL)
{
rt_kprintf("out of memory\n");
return;
}
copyfile(src, fdst);
rt_free(fdst);
}
else
{
copyfile(src, dst);
}
}
else //flag & FLAG_SRC_IS_DIR
{
if (flag & FLAG_DST_IS_DIR)
{
char *fdst;
fdst = dfs_normalize_path(dst, _get_path_lastname(src));
if (fdst == NULL)
{
rt_kprintf("out of memory\n");
return;
}
mkdir(fdst, 0);
copydir(src, fdst);
rt_free(fdst);
}
else if ((flag & FLAG_DST_TYPE) == FLAG_DST_NON_EXSIT)
{
mkdir(dst, 0);
copydir(src, dst);
}
else
{
copydir(src, dst);
}
}
}
FINSH_FUNCTION_EXPORT(copy, copy file or dir)
#endif /* DFS_USING_POSIX */
#endif /* RT_USING_FINSH */
/* @} */
+648
View File
@@ -0,0 +1,648 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2005-02-22 Bernard The first version.
* 2010-06-30 Bernard Optimize for RT-Thread RTOS
* 2011-03-12 Bernard fix the filesystem lookup issue.
* 2017-11-30 Bernard fix the filesystem_operation_table issue.
* 2017-12-05 Bernard fix the fs type search issue in mkfs.
*/
#include <dfs_fs.h>
#include <dfs_file.h>
#include "dfs_private.h"
/**
* @addtogroup FsApi
*/
/*@{*/
/**
* this function will register a file system instance to device file system.
*
* @param ops the file system instance to be registered.
*
* @return 0 on successful, -1 on failed.
*/
int dfs_register(const struct dfs_filesystem_ops *ops)
{
int ret = RT_EOK;
const struct dfs_filesystem_ops **empty = NULL;
const struct dfs_filesystem_ops **iter;
/* lock filesystem */
dfs_lock();
/* check if this filesystem was already registered */
for (iter = &filesystem_operation_table[0];
iter < &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; iter ++)
{
/* find out an empty filesystem type entry */
if (*iter == NULL)
(empty == NULL) ? (empty = iter) : 0;
else if (strcmp((*iter)->name, ops->name) == 0)
{
rt_set_errno(-EEXIST);
ret = -1;
break;
}
}
/* save the filesystem's operations */
if (empty == NULL)
{
rt_set_errno(-ENOSPC);
LOG_E("There is no space to register this file system (%s).", ops->name);
ret = -1;
}
else if (ret == RT_EOK)
{
*empty = ops;
}
dfs_unlock();
return ret;
}
/**
* this function will return the file system mounted on specified path.
*
* @param path the specified path string.
*
* @return the found file system or NULL if no file system mounted on
* specified path
*/
struct dfs_filesystem *dfs_filesystem_lookup(const char *path)
{
struct dfs_filesystem *iter;
struct dfs_filesystem *fs = NULL;
uint32_t fspath, prefixlen;
prefixlen = 0;
RT_ASSERT(path);
/* lock filesystem */
dfs_lock();
/* lookup it in the filesystem table */
for (iter = &filesystem_table[0];
iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
{
if ((iter->path == NULL) || (iter->ops == NULL))
continue;
fspath = strlen(iter->path);
if ((fspath < prefixlen)
|| (strncmp(iter->path, path, fspath) != 0))
continue;
/* check next path separator */
if (fspath > 1 && (strlen(path) > fspath) && (path[fspath] != '/'))
continue;
fs = iter;
prefixlen = fspath;
}
dfs_unlock();
return fs;
}
/**
* this function will return the mounted path for specified device.
*
* @param device the device object which is mounted.
*
* @return the mounted path or NULL if none device mounted.
*/
const char *dfs_filesystem_get_mounted_path(struct rt_device *device)
{
const char *path = NULL;
struct dfs_filesystem *iter;
dfs_lock();
for (iter = &filesystem_table[0];
iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
{
/* find the mounted device */
if (iter->ops == NULL) continue;
else if (iter->dev_id == device)
{
path = iter->path;
break;
}
}
/* release filesystem_table lock */
dfs_unlock();
return path;
}
/**
* this function will fetch the partition table on specified buffer.
*
* @param part the returned partition structure.
* @param buf the buffer contains partition table.
* @param pindex the index of partition table to fetch.
*
* @return RT_EOK on successful or -RT_ERROR on failed.
*/
int dfs_filesystem_get_partition(struct dfs_partition *part,
uint8_t *buf,
uint32_t pindex)
{
#define DPT_ADDRESS 0x1be /* device partition offset in Boot Sector */
#define DPT_ITEM_SIZE 16 /* partition item size */
uint8_t *dpt;
uint8_t type;
RT_ASSERT(part != NULL);
RT_ASSERT(buf != NULL);
dpt = buf + DPT_ADDRESS + pindex * DPT_ITEM_SIZE;
/* check if it is a valid partition table */
if ((*dpt != 0x80) && (*dpt != 0x00))
return -EIO;
/* get partition type */
type = *(dpt + 4);
if (type == 0)
return -EIO;
/* set partition information
* size is the number of 512-Byte */
part->type = type;
part->offset = *(dpt + 8) | *(dpt + 9) << 8 | *(dpt + 10) << 16 | *(dpt + 11) << 24;
part->size = *(dpt + 12) | *(dpt + 13) << 8 | *(dpt + 14) << 16 | *(dpt + 15) << 24;
rt_kprintf("found part[%d], begin: %d, size: ",
pindex, part->offset * 512);
if ((part->size >> 11) == 0)
rt_kprintf("%d%s", part->size >> 1, "KB\n"); /* KB */
else
{
unsigned int part_size;
part_size = part->size >> 11; /* MB */
if ((part_size >> 10) == 0)
rt_kprintf("%d.%d%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
else
rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
}
return RT_EOK;
}
/**
* this function will mount a file system on a specified path.
*
* @param device_name the name of device which includes a file system.
* @param path the path to mount a file system
* @param filesystemtype the file system type
* @param rwflag the read/write etc. flag.
* @param data the private data(parameter) for this file system.
*
* @return 0 on successful or -1 on failed.
*/
int dfs_mount(const char *device_name,
const char *path,
const char *filesystemtype,
unsigned long rwflag,
const void *data)
{
const struct dfs_filesystem_ops **ops;
struct dfs_filesystem *iter;
struct dfs_filesystem *fs = NULL;
char *fullpath = NULL;
rt_device_t dev_id;
/* open specific device */
if (device_name == NULL)
{
/* which is a non-device filesystem mount */
dev_id = NULL;
}
else if ((dev_id = rt_device_find(device_name)) == NULL)
{
/* no this device */
rt_set_errno(-ENODEV);
return -1;
}
/* find out the specific filesystem */
dfs_lock();
for (ops = &filesystem_operation_table[0];
ops < &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; ops++)
if ((*ops != NULL) && (strcmp((*ops)->name, filesystemtype) == 0))
break;
dfs_unlock();
if (ops == &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX])
{
/* can't find filesystem */
rt_set_errno(-ENODEV);
return -1;
}
/* check if there is mount implementation */
if ((*ops == NULL) || ((*ops)->mount == NULL))
{
rt_set_errno(-ENOSYS);
return -1;
}
/* make full path for special file */
fullpath = dfs_normalize_path(NULL, path);
if (fullpath == NULL) /* not an abstract path */
{
rt_set_errno(-ENOTDIR);
return -1;
}
/* Check if the path exists or not, raw APIs call, fixme */
if ((strcmp(fullpath, "/") != 0) && (strcmp(fullpath, "/dev") != 0))
{
struct dfs_fd fd;
if (dfs_file_open(&fd, fullpath, O_RDONLY | O_DIRECTORY) < 0)
{
rt_free(fullpath);
rt_set_errno(-ENOTDIR);
return -1;
}
dfs_file_close(&fd);
}
/* check whether the file system mounted or not in the filesystem table
* if it is unmounted yet, find out an empty entry */
dfs_lock();
for (iter = &filesystem_table[0];
iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
{
/* check if it is an empty filesystem table entry? if it is, save fs */
if (iter->ops == NULL)
(fs == NULL) ? (fs = iter) : 0;
/* check if the PATH is mounted */
else if (strcmp(iter->path, path) == 0)
{
rt_set_errno(-EINVAL);
goto err1;
}
}
if ((fs == NULL) && (iter == &filesystem_table[DFS_FILESYSTEMS_MAX]))
{
rt_set_errno(-ENOSPC);
LOG_E("There is no space to mount this file system (%s).", filesystemtype);
goto err1;
}
/* register file system */
fs->path = fullpath;
fs->ops = *ops;
fs->dev_id = dev_id;
/* release filesystem_table lock */
dfs_unlock();
/* open device, but do not check the status of device */
if (dev_id != NULL)
{
if (rt_device_open(fs->dev_id,
RT_DEVICE_OFLAG_RDWR) != RT_EOK)
{
/* The underlying device has error, clear the entry. */
dfs_lock();
rt_memset(fs, 0, sizeof(struct dfs_filesystem));
goto err1;
}
}
/* call mount of this filesystem */
if ((*ops)->mount(fs, rwflag, data) < 0)
{
/* close device */
if (dev_id != NULL)
rt_device_close(fs->dev_id);
/* mount failed */
dfs_lock();
/* clear filesystem table entry */
rt_memset(fs, 0, sizeof(struct dfs_filesystem));
goto err1;
}
return 0;
err1:
dfs_unlock();
rt_free(fullpath);
return -1;
}
/**
* this function will unmount a file system on specified path.
*
* @param specialfile the specified path which mounted a file system.
*
* @return 0 on successful or -1 on failed.
*/
int dfs_unmount(const char *specialfile)
{
char *fullpath;
struct dfs_filesystem *iter;
struct dfs_filesystem *fs = NULL;
fullpath = dfs_normalize_path(NULL, specialfile);
if (fullpath == NULL)
{
rt_set_errno(-ENOTDIR);
return -1;
}
/* lock filesystem */
dfs_lock();
for (iter = &filesystem_table[0];
iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
{
/* check if the PATH is mounted */
if ((iter->path != NULL) && (strcmp(iter->path, fullpath) == 0))
{
fs = iter;
break;
}
}
if (fs == NULL ||
fs->ops->unmount == NULL ||
fs->ops->unmount(fs) < 0)
{
goto err1;
}
/* close device, but do not check the status of device */
if (fs->dev_id != NULL)
rt_device_close(fs->dev_id);
if (fs->path != NULL)
rt_free(fs->path);
/* clear this filesystem table entry */
rt_memset(fs, 0, sizeof(struct dfs_filesystem));
dfs_unlock();
rt_free(fullpath);
return 0;
err1:
dfs_unlock();
rt_free(fullpath);
return -1;
}
/**
* make a file system on the special device
*
* @param fs_name the file system name
* @param device_name the special device name
*
* @return 0 on successful, otherwise failed.
*/
int dfs_mkfs(const char *fs_name, const char *device_name)
{
int index;
rt_device_t dev_id = NULL;
/* check device name, and it should not be NULL */
if (device_name != NULL)
dev_id = rt_device_find(device_name);
if (dev_id == NULL)
{
rt_set_errno(-ENODEV);
LOG_E("Device (%s) was not found", device_name);
return -1;
}
/* lock file system */
dfs_lock();
/* find the file system operations */
for (index = 0; index < DFS_FILESYSTEM_TYPES_MAX; index ++)
{
if (filesystem_operation_table[index] != NULL &&
strcmp(filesystem_operation_table[index]->name, fs_name) == 0)
break;
}
dfs_unlock();
if (index < DFS_FILESYSTEM_TYPES_MAX)
{
/* find file system operation */
const struct dfs_filesystem_ops *ops = filesystem_operation_table[index];
if (ops->mkfs == NULL)
{
LOG_E("The file system (%s) mkfs function was not implement", fs_name);
rt_set_errno(-ENOSYS);
return -1;
}
return ops->mkfs(dev_id);
}
LOG_E("File system (%s) was not found.", fs_name);
return -1;
}
/**
* this function will return the information about a mounted file system.
*
* @param path the path which mounted file system.
* @param buffer the buffer to save the returned information.
*
* @return 0 on successful, others on failed.
*/
int dfs_statfs(const char *path, struct statfs *buffer)
{
struct dfs_filesystem *fs;
fs = dfs_filesystem_lookup(path);
if (fs != NULL)
{
if (fs->ops->statfs != NULL)
return fs->ops->statfs(fs, buffer);
}
return -1;
}
#ifdef RT_USING_DFS_MNTTABLE
int dfs_mount_table(void)
{
int index = 0;
while (1)
{
if (mount_table[index].path == NULL) break;
if (dfs_mount(mount_table[index].device_name,
mount_table[index].path,
mount_table[index].filesystemtype,
mount_table[index].rwflag,
mount_table[index].data) != 0)
{
LOG_E("mount fs[%s] on %s failed.\n", mount_table[index].filesystemtype,
mount_table[index].path);
return -RT_ERROR;
}
index ++;
}
return 0;
}
INIT_ENV_EXPORT(dfs_mount_table);
int dfs_mount_device(rt_device_t dev)
{
int index = 0;
if(dev == RT_NULL) {
rt_kprintf("the device is NULL to be mounted.\n");
return -RT_ERROR;
}
while (1)
{
if (mount_table[index].path == NULL) break;
if(strcmp(mount_table[index].device_name, dev->parent.name) == 0) {
if (dfs_mount(mount_table[index].device_name,
mount_table[index].path,
mount_table[index].filesystemtype,
mount_table[index].rwflag,
mount_table[index].data) != 0)
{
LOG_E("mount fs[%s] device[%s] to %s failed.\n", mount_table[index].filesystemtype, dev->parent.name,
mount_table[index].path);
return -RT_ERROR;
} else {
LOG_D("mount fs[%s] device[%s] to %s ok.\n", mount_table[index].filesystemtype, dev->parent.name,
mount_table[index].path);
return RT_EOK;
}
}
index ++;
}
rt_kprintf("can't find device:%s to be mounted.\n", dev->parent.name);
return -RT_ERROR;
}
int dfs_unmount_device(rt_device_t dev)
{
struct dfs_filesystem *iter;
struct dfs_filesystem *fs = NULL;
/* lock filesystem */
dfs_lock();
for (iter = &filesystem_table[0];
iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++)
{
/* check if the PATH is mounted */
if (strcmp(iter->dev_id->parent.name, dev->parent.name) == 0)
{
fs = iter;
break;
}
}
if (fs == NULL ||
fs->ops->unmount == NULL ||
fs->ops->unmount(fs) < 0)
{
goto err1;
}
/* close device, but do not check the status of device */
if (fs->dev_id != NULL)
rt_device_close(fs->dev_id);
if (fs->path != NULL)
rt_free(fs->path);
/* clear this filesystem table entry */
rt_memset(fs, 0, sizeof(struct dfs_filesystem));
dfs_unlock();
return 0;
err1:
dfs_unlock();
return -1;
}
#endif
#ifdef RT_USING_FINSH
#include <finsh.h>
void mkfs(const char *fs_name, const char *device_name)
{
dfs_mkfs(fs_name, device_name);
}
FINSH_FUNCTION_EXPORT(mkfs, make a file system);
int df(const char *path)
{
int result;
int minor = 0;
long long cap;
struct statfs buffer;
int unit_index = 0;
char *unit_str[] = {"KB", "MB", "GB"};
result = dfs_statfs(path ? path : NULL, &buffer);
if (result != 0)
{
rt_kprintf("dfs_statfs failed.\n");
return -1;
}
cap = ((long long)buffer.f_bsize) * ((long long)buffer.f_bfree) / 1024LL;
for (unit_index = 0; unit_index < 2; unit_index ++)
{
if (cap < 1024) break;
minor = (cap % 1024) * 10 / 1024; /* only one decimal point */
cap = cap / 1024;
}
rt_kprintf("disk free: %d.%d %s [ %d block, %d bytes per block ]\n",
(unsigned long)cap, minor, unit_str[unit_index], buffer.f_bfree, buffer.f_bsize);
return 0;
}
FINSH_FUNCTION_EXPORT(df, get disk free);
#endif
/* @} */
+953
View File
@@ -0,0 +1,953 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2009-05-27 Yi.qiu The first version
* 2018-02-07 Bernard Change the 3rd parameter of open/fcntl/ioctl to '...'
* 2022-01-19 Meco Man add creat()
*/
#include <dfs_file.h>
#include <dfs_private.h>
#include <sys/errno.h>
/**
* this function is a POSIX compliant version, which will open a file and
* return a file descriptor according specified flags.
*
* @param file the path name of file.
* @param flags the file open flags.
*
* @return the non-negative integer on successful open, others for failed.
*/
int open(const char *file, int flags, ...)
{
int fd, result;
struct dfs_fd *d;
/* allocate a fd */
fd = fd_new();
if (fd < 0)
{
rt_set_errno(-ENOMEM);
return -1;
}
d = fd_get(fd);
result = dfs_file_open(d, file, flags);
if (result < 0)
{
/* release the ref-count of fd */
fd_put(d);
fd_put(d);
rt_set_errno(result);
return -1;
}
/* release the ref-count of fd */
fd_put(d);
return fd;
}
RTM_EXPORT(open);
/**
* this function is a POSIX compliant version,
* which will create a new file or rewrite an existing one
*
* @param path the path name of file.
* @param mode the file permission bits to be used in creating the file (not used, can be 0)
*
* @return the non-negative integer on successful open, others for failed.
*/
int creat(const char *path, mode_t mode)
{
return open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
}
RTM_EXPORT(creat);
/**
* this function is a POSIX compliant version, which will close the open
* file descriptor.
*
* @param fd the file descriptor.
*
* @return 0 on successful, -1 on failed.
*/
int close(int fd)
{
int result;
struct dfs_fd *d;
d = fd_get(fd);
if (d == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
result = dfs_file_close(d);
fd_put(d);
if (result < 0)
{
rt_set_errno(result);
return -1;
}
fd_put(d);
return 0;
}
RTM_EXPORT(close);
/**
* this function is a POSIX compliant version, which will read specified data
* buffer length for an open file descriptor.
*
* @param fd the file descriptor.
* @param buf the buffer to save the read data.
* @param len the maximal length of data buffer
*
* @return the actual read data buffer length. If the returned value is 0, it
* may be reach the end of file, please check errno.
*/
#ifdef _READ_WRITE_RETURN_TYPE
_READ_WRITE_RETURN_TYPE read(int fd, void *buf, size_t len) /* some gcc tool chains will use different data structure */
#else
ssize_t read(int fd, void *buf, size_t len)
#endif
{
int result;
struct dfs_fd *d;
/* get the fd */
d = fd_get(fd);
if (d == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
result = dfs_file_read(d, buf, len);
if (result < 0)
{
fd_put(d);
rt_set_errno(result);
return -1;
}
/* release the ref-count of fd */
fd_put(d);
return result;
}
RTM_EXPORT(read);
/**
* this function is a POSIX compliant version, which will write specified data
* buffer length for an open file descriptor.
*
* @param fd the file descriptor
* @param buf the data buffer to be written.
* @param len the data buffer length.
*
* @return the actual written data buffer length.
*/
#ifdef _READ_WRITE_RETURN_TYPE
_READ_WRITE_RETURN_TYPE write(int fd, const void *buf, size_t len) /* some gcc tool chains will use different data structure */
#else
ssize_t write(int fd, const void *buf, size_t len)
#endif
{
int result;
struct dfs_fd *d;
/* get the fd */
d = fd_get(fd);
if (d == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
result = dfs_file_write(d, buf, len);
if (result < 0)
{
fd_put(d);
rt_set_errno(result);
return -1;
}
/* release the ref-count of fd */
fd_put(d);
return result;
}
RTM_EXPORT(write);
/**
* this function is a POSIX compliant version, which will seek the offset for
* an open file descriptor.
*
* @param fd the file descriptor.
* @param offset the offset to be seeked.
* @param whence the directory of seek.
*
* @return the current read/write position in the file, or -1 on failed.
*/
off_t lseek(int fd, off_t offset, int whence)
{
int result;
struct dfs_fd *d;
d = fd_get(fd);
if (d == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
switch (whence)
{
case SEEK_SET:
break;
case SEEK_CUR:
offset += d->pos;
break;
case SEEK_END:
offset += d->size;
break;
default:
fd_put(d);
rt_set_errno(-EINVAL);
return -1;
}
if (offset < 0)
{
fd_put(d);
rt_set_errno(-EINVAL);
return -1;
}
result = dfs_file_lseek(d, offset);
if (result < 0)
{
fd_put(d);
rt_set_errno(result);
return -1;
}
/* release the ref-count of fd */
fd_put(d);
return offset;
}
RTM_EXPORT(lseek);
#ifndef _WIN32
/**
* this function is a POSIX compliant version, which will rename old file name
* to new file name.
*
* @param old the old file name.
* @param new the new file name.
*
* @return 0 on successful, -1 on failed.
*
* note: the old and new file name must be belong to a same file system.
*/
int rename(const char *old_file, const char *new_file)
{
int result;
result = dfs_file_rename(old_file, new_file);
if (result < 0)
{
rt_set_errno(result);
return -1;
}
return 0;
}
RTM_EXPORT(rename);
#endif
/**
* this function is a POSIX compliant version, which will unlink (remove) a
* specified path file from file system.
*
* @param pathname the specified path name to be unlinked.
*
* @return 0 on successful, -1 on failed.
*/
int unlink(const char *pathname)
{
int result;
result = dfs_file_unlink(pathname);
if (result < 0)
{
rt_set_errno(result);
return -1;
}
return 0;
}
RTM_EXPORT(unlink);
/**
* this function is a POSIX compliant version, which will get file information.
*
* @param file the file name
* @param buf the data buffer to save stat description.
*
* @return 0 on successful, -1 on failed.
*/
int stat(const char *file, struct stat *buf)
{
int result;
result = dfs_file_stat(file, buf);
if (result < 0)
{
rt_set_errno(result);
return -1;
}
return result;
}
RTM_EXPORT(stat);
/**
* this function is a POSIX compliant version, which will get file status.
*
* @param fildes the file description
* @param buf the data buffer to save stat description.
*
* @return 0 on successful, -1 on failed.
*/
int fstat(int fildes, struct stat *buf)
{
struct dfs_fd *d;
/* get the fd */
d = fd_get(fildes);
if (d == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
/* it's the root directory */
buf->st_dev = 0;
buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
S_IWUSR | S_IWGRP | S_IWOTH;
if (d->type == FT_DIRECTORY)
{
buf->st_mode &= ~S_IFREG;
buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
}
buf->st_size = d->size;
buf->st_mtime = 0;
fd_put(d);
return RT_EOK;
}
RTM_EXPORT(fstat);
/**
* this function is a POSIX compliant version, which shall request that all data
* for the open file descriptor named by fildes is to be transferred to the storage
* device associated with the file described by fildes.
*
* @param fildes the file description
*
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
* set to indicate the error.
*/
int fsync(int fildes)
{
int ret;
struct dfs_fd *d;
/* get the fd */
d = fd_get(fildes);
if (d == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
ret = dfs_file_flush(d);
fd_put(d);
return ret;
}
RTM_EXPORT(fsync);
/**
* this function is a POSIX compliant version, which shall perform a variety of
* control functions on devices.
*
* @param fildes the file description
* @param cmd the specified command
* @param data represents the additional information that is needed by this
* specific device to perform the requested function.
*
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
* set to indicate the error.
*/
int fcntl(int fildes, int cmd, ...)
{
int ret = -1;
struct dfs_fd *d;
/* get the fd */
d = fd_get(fildes);
if (d)
{
void *arg;
va_list ap;
va_start(ap, cmd);
arg = va_arg(ap, void *);
va_end(ap);
ret = dfs_file_ioctl(d, cmd, arg);
fd_put(d);
}
else ret = -EBADF;
if (ret < 0)
{
rt_set_errno(ret);
ret = -1;
}
return ret;
}
RTM_EXPORT(fcntl);
/**
* this function is a POSIX compliant version, which shall perform a variety of
* control functions on devices.
*
* @param fildes the file description
* @param cmd the specified command
* @param data represents the additional information that is needed by this
* specific device to perform the requested function.
*
* @return 0 on successful completion. Otherwise, -1 shall be returned and errno
* set to indicate the error.
*/
int ioctl(int fildes, int cmd, ...)
{
void *arg;
va_list ap;
va_start(ap, cmd);
arg = va_arg(ap, void *);
va_end(ap);
/* we use fcntl for this API. */
return fcntl(fildes, cmd, arg);
}
RTM_EXPORT(ioctl);
/**
*
* this function is a POSIX compliant version, which cause the regular file
* referenced by fd to be truncated to a size of precisely length bytes.
* @param fd the file descriptor.
* @param length the length to be truncated.
*
* @return Upon successful completion, ftruncate() shall return 0;
* otherwise, -1 shall be returned and errno set to indicate the error.
*/
int ftruncate(int fd, off_t length)
{
int result;
struct dfs_fd *d;
d = fd_get(fd);
if (d == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
if (length < 0)
{
fd_put(d);
rt_set_errno(-EINVAL);
return -1;
}
result = dfs_file_ftruncate(d, length);
if (result < 0)
{
fd_put(d);
rt_set_errno(result);
return -1;
}
/* release the ref-count of fd */
fd_put(d);
return 0;
}
RTM_EXPORT(ftruncate);
/**
* this function is a POSIX compliant version, which will return the
* information about a mounted file system.
*
* @param path the path which mounted file system.
* @param buf the buffer to save the returned information.
*
* @return 0 on successful, others on failed.
*/
int statfs(const char *path, struct statfs *buf)
{
int result;
result = dfs_statfs(path, buf);
if (result < 0)
{
rt_set_errno(result);
return -1;
}
return result;
}
RTM_EXPORT(statfs);
/**
* this function is a POSIX compliant version, which will make a directory
*
* @param path the directory path to be made.
* @param mode
*
* @return 0 on successful, others on failed.
*/
int mkdir(const char *path, mode_t mode)
{
int fd;
struct dfs_fd *d;
int result;
fd = fd_new();
if (fd == -1)
{
rt_set_errno(-ENOMEM);
return -1;
}
d = fd_get(fd);
result = dfs_file_open(d, path, O_DIRECTORY | O_CREAT);
if (result < 0)
{
fd_put(d);
fd_put(d);
rt_set_errno(result);
return -1;
}
dfs_file_close(d);
fd_put(d);
fd_put(d);
return 0;
}
RTM_EXPORT(mkdir);
/**
* this function is a POSIX compliant version, which will remove a directory.
*
* @param pathname the path name to be removed.
*
* @return 0 on successful, others on failed.
*/
int rmdir(const char *pathname)
{
int result;
result = dfs_file_unlink(pathname);
if (result < 0)
{
rt_set_errno(result);
return -1;
}
return 0;
}
RTM_EXPORT(rmdir);
/**
* this function is a POSIX compliant version, which will open a directory.
*
* @param name the path name to be open.
*
* @return the DIR pointer of directory, NULL on open directory failed.
*/
DIR *opendir(const char *name)
{
struct dfs_fd *d;
int fd, result;
DIR *t;
t = NULL;
/* allocate a fd */
fd = fd_new();
if (fd == -1)
{
rt_set_errno(-ENOMEM);
return NULL;
}
d = fd_get(fd);
result = dfs_file_open(d, name, O_RDONLY | O_DIRECTORY);
if (result >= 0)
{
/* open successfully */
t = (DIR *) rt_malloc(sizeof(DIR));
if (t == NULL)
{
dfs_file_close(d);
fd_put(d);
}
else
{
rt_memset(t, 0, sizeof(DIR));
t->fd = fd;
}
fd_put(d);
return t;
}
/* open failed */
fd_put(d);
fd_put(d);
rt_set_errno(result);
return NULL;
}
RTM_EXPORT(opendir);
/**
* this function is a POSIX compliant version, which will return a pointer
* to a dirent structure representing the next directory entry in the
* directory stream.
*
* @param d the directory stream pointer.
*
* @return the next directory entry, NULL on the end of directory or failed.
*/
struct dirent *readdir(DIR *d)
{
int result;
struct dfs_fd *fd;
fd = fd_get(d->fd);
if (fd == NULL)
{
rt_set_errno(-EBADF);
return NULL;
}
if (d->num)
{
struct dirent *dirent_ptr;
dirent_ptr = (struct dirent *)&d->buf[d->cur];
d->cur += dirent_ptr->d_reclen;
}
if (!d->num || d->cur >= d->num)
{
/* get a new entry */
result = dfs_file_getdents(fd,
(struct dirent *)d->buf,
sizeof(d->buf) - 1);
if (result <= 0)
{
fd_put(fd);
rt_set_errno(result);
return NULL;
}
d->num = result;
d->cur = 0; /* current entry index */
}
fd_put(fd);
return (struct dirent *)(d->buf + d->cur);
}
RTM_EXPORT(readdir);
/**
* this function is a POSIX compliant version, which will return current
* location in directory stream.
*
* @param d the directory stream pointer.
*
* @return the current location in directory stream.
*/
long telldir(DIR *d)
{
struct dfs_fd *fd;
long result;
fd = fd_get(d->fd);
if (fd == NULL)
{
rt_set_errno(-EBADF);
return 0;
}
result = fd->pos - d->num + d->cur;
fd_put(fd);
return result;
}
RTM_EXPORT(telldir);
/**
* this function is a POSIX compliant version, which will set position of
* next directory structure in the directory stream.
*
* @param d the directory stream.
* @param offset the offset in directory stream.
*/
void seekdir(DIR *d, off_t offset)
{
struct dfs_fd *fd;
fd = fd_get(d->fd);
if (fd == NULL)
{
rt_set_errno(-EBADF);
return ;
}
/* seek to the offset position of directory */
if (dfs_file_lseek(fd, offset) >= 0)
d->num = d->cur = 0;
fd_put(fd);
}
RTM_EXPORT(seekdir);
/**
* this function is a POSIX compliant version, which will reset directory
* stream.
*
* @param d the directory stream.
*/
void rewinddir(DIR *d)
{
struct dfs_fd *fd;
fd = fd_get(d->fd);
if (fd == NULL)
{
rt_set_errno(-EBADF);
return ;
}
/* seek to the beginning of directory */
if (dfs_file_lseek(fd, 0) >= 0)
d->num = d->cur = 0;
fd_put(fd);
}
RTM_EXPORT(rewinddir);
/**
* this function is a POSIX compliant version, which will close a directory
* stream.
*
* @param d the directory stream.
*
* @return 0 on successful, -1 on failed.
*/
int closedir(DIR *d)
{
int result;
struct dfs_fd *fd;
fd = fd_get(d->fd);
if (fd == NULL)
{
rt_set_errno(-EBADF);
return -1;
}
result = dfs_file_close(fd);
fd_put(fd);
fd_put(fd);
rt_free(d);
if (result < 0)
{
rt_set_errno(result);
return -1;
}
else
return 0;
}
RTM_EXPORT(closedir);
#ifdef DFS_USING_WORKDIR
/**
* this function is a POSIX compliant version, which will change working
* directory.
*
* @param path the path name to be changed to.
*
* @return 0 on successful, -1 on failed.
*/
int chdir(const char *path)
{
char *fullpath;
DIR *d;
if (path == NULL)
{
dfs_lock();
rt_kprintf("%s\n", working_directory);
dfs_unlock();
return 0;
}
if (strlen(path) > DFS_PATH_MAX)
{
rt_set_errno(-ENOTDIR);
return -1;
}
fullpath = dfs_normalize_path(NULL, path);
if (fullpath == NULL)
{
rt_set_errno(-ENOTDIR);
return -1; /* build path failed */
}
dfs_lock();
d = opendir(fullpath);
if (d == NULL)
{
rt_free(fullpath);
/* this is a not exist directory */
dfs_unlock();
return -1;
}
/* close directory stream */
closedir(d);
/* copy full path to working directory */
strncpy(working_directory, fullpath, DFS_PATH_MAX);
/* release normalize directory path name */
rt_free(fullpath);
dfs_unlock();
return 0;
}
RTM_EXPORT(chdir);
#ifdef RT_USING_FINSH
FINSH_FUNCTION_EXPORT_ALIAS(chdir, cd, change current working directory);
#endif
#endif
/**
* this function is a POSIX compliant version, which shall check the file named
* by the pathname pointed to by the path argument for accessibility according
* to the bit pattern contained in amode.
*
* @param path the specified file/dir path.
* @param amode the value is either the bitwise-inclusive OR of the access
* permissions to be checked (R_OK, W_OK, X_OK) or the existence test (F_OK).
*/
int access(const char *path, int amode)
{
struct stat sb;
if (stat(path, &sb) < 0)
return -1; /* already sets errno */
/* ignore R_OK,W_OK,X_OK condition */
return 0;
}
/**
* this function is a POSIX compliant version, which will return current
* working directory.
*
* @param buf the returned current directory.
* @param size the buffer size.
*
* @return the returned current directory.
*/
char *getcwd(char *buf, size_t size)
{
#ifdef DFS_USING_WORKDIR
dfs_lock();
strncpy(buf, working_directory, size);
dfs_unlock();
#else
rt_kprintf(NO_WORKING_DIR);
#endif
return buf;
}
RTM_EXPORT(getcwd);