apps/examples/userfs: Add a test case for verifying UserFS.

This commit is contained in:
Gregory Nutt 2017-10-31 09:00:49 -06:00
parent 6b9d23c6aa
commit 769ffb8a4b
6 changed files with 695 additions and 0 deletions

View File

@ -2127,6 +2127,11 @@ examples/usbserial
The host and target will exchange are variety of very small and very large The host and target will exchange are variety of very small and very large
serial messages. serial messages.
examples/userfs
^^^^^^^^^^^^^^^
A simple test of the UserFS file system.
examples/ustream examples/ustream
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^

11
examples/userfs/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
/Make.dep
/.depend
/.built
/*.asm
/*.obj
/*.rel
/*.lst
/*.sym
/*.adb
/*.lib
/*.src

30
examples/userfs/Kconfig Normal file
View File

@ -0,0 +1,30 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config EXAMPLES_USERFS
bool "UserFS test"
default n
---help---
Enables a simple test of the UserFS
if EXAMPLES_USERFS
config EXAMPLES_USERFS_PROGNAME
string "Program name"
default "userfs"
depends on BUILD_KERNEL
---help---
This is the name of the program that will be use when the NSH ELF
program is installed.
config EXAMPLES_USERFS_PRIORITY
int "UserFS task priority"
default 100
config EXAMPLES_USERFS_STACKSIZE
int "UserFS stack size"
default 2048
endif

39
examples/userfs/Make.defs Normal file
View File

@ -0,0 +1,39 @@
############################################################################
# apps/examples/userfs/Make.defs
# Adds selected applications to apps/ build
#
# Copyright (C) 2015 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
ifeq ($(CONFIG_EXAMPLES_USERFS),y)
CONFIGURED_APPS += examples/userfs
endif

56
examples/userfs/Makefile Normal file
View File

@ -0,0 +1,56 @@
############################################################################
# apps/examples/userfs/Makefile
#
# Copyright (C) 2017 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
-include $(TOPDIR)/Make.defs
# UserFS test application info
CONFIG_EXAMPLES_USERFS_PRIORITY ?= SCHED_PRIORITY_DEFAULT
CONFIG_EXAMPLES_USERFS_STACKSIZE ?= 2048
APPNAME = userfs
PRIORITY = $(CONFIG_EXAMPLES_USERFS_PRIORITY)
STACKSIZE = $(CONFIG_EXAMPLES_USERFS_STACKSIZE)
# UserFS test application source files
ASRCS =
CSRCS =
MAINSRC = userfs_main.c
CONFIG_EXAMPLES_USERFS_PROGNAME ?= userfs$(EXEEXT)
PROGNAME = $(CONFIG_EXAMPLES_USERFS_PROGNAME)
include $(APPDIR)/Application.mk

View File

@ -0,0 +1,554 @@
/****************************************************************************
* examples/userfs/userfs_main.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <nuttx/fs/userfs.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define UFSTEST_NFILES 3
#define UFSTEST_FS_BLOCKSIZE 32
#define UFSTEST_FILE1_BLOCKS (2)
#define UFSTEST_FILE1_MXSIZE (UFSTEST_FILE1_BLOCKS * UFSTEST_FS_BLOCKSIZE)
#define UFSTEST_FILE2_BLOCKS (3)
#define UFSTEST_FILE2_MXSIZE (UFSTEST_FILE2_BLOCKS * UFSTEST_FS_BLOCKSIZE)
#define UFSTEST_FILE3_BLOCKS (4)
#define UFSTEST_FILE3_MXSIZE (UFSTEST_FILE3_BLOCKS * UFSTEST_FS_BLOCKSIZE)
#define UFSTEST_FS_NBLOCKS (UFSTEST_FILE1_BLOCKS + UFSTEST_FILE2_BLOCKS + UFSTEST_FILE3_BLOCKS)
#define UFSTEST_FS_NBYTES (UFSTEST_FILE1_MXSIZE + UFSTEST_FILE2_MXSIZE + UFSTEST_FILE3_MXSIZE)
#define UFSTEST_MXWRITE UFSTEST_FILE3_MXSIZE
#define UFSTEST_MOUNTPOUNT "/mnt/ufstest"
/****************************************************************************
* Private Types
****************************************************************************/
struct ufstest_file_s
{
struct dirent entry;
uint16_t inuse;
uint16_t mxsize;
FAR char *data;
};
struct ufstest_openfile_s
{
int16_t pos;
FAR struct ufstest_file_s *file;
};
struct ufstest_opendir_s
{
int16_t index;
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* UserFS methods */
static int ufstest_open(FAR void *volinfo, FAR const char *relpath,
int oflags, mode_t mode, FAR void **openinfo);
static int ufstest_close(FAR void *volinfo, FAR void *openinfo);
static ssize_t ufstest_read(FAR void *volinfo, FAR void *openinfo,
FAR char *buffer, size_t buflen);
static ssize_t ufstest_write(FAR void *volinfo, FAR void *openinfo,
FAR const char *buffer, size_t buflen);
static off_t ufstest_seek(FAR void *volinfo, FAR void *openinfo,
off_t offset, int whence);
static int ufstest_ioctl(FAR void *volinfo, FAR void *openinfo, int cmd,
unsigned long arg);
static int ufstest_sync(FAR void *volinfo, FAR void *openinfo);
static int ufstest_dup(FAR void *volinfo, FAR void *oldinfo,
FAR void *newinfo);
static int ufstest_fstat(FAR void *volinfo, FAR void *openinfo,
FAR struct stat *buf);
static int ufstest_opendir(FAR void *volinfo, FAR const char *relpath,
FAR void **dir);
static int ufstest_closedir(FAR void *volinfo, FAR void *dir);
static int ufstest_readdir(FAR void *volinfo, FAR void *dir,
FAR struct dirent *entry);
static int ufstest_rewinddir(FAR void *volinfo, FAR void *dir);
static int ufstest_statfs(FAR void *volinfo, FAR struct statfs *buf);
static int ufstest_unlink(FAR void *volinfo, FAR const char *relpath);
static int ufstest_mkdir(FAR void *volinfo, FAR const char *relpath,
mode_t mode);
static int ufstest_rmdir(FAR void *volinfo, FAR const char *relpath);
static int ufstest_rename(FAR void *volinfo, FAR const char *oldrelpath,
FAR const char *newrelpath);
static int ufstest_stat(FAR void *volinfo, FAR const char *relpath,
FAR struct stat *buf);
static int ufstest_destroy(FAR void *volinfo);
/****************************************************************************
* Private Data
****************************************************************************/
static char g_file1_data[UFSTEST_FILE1_MXSIZE] = "This is file 1";
#define UFSTEST_INIT_FILE1_SIZE 14
static char g_file2_data[UFSTEST_FILE2_MXSIZE] = "This is file 2";
#define UFSTEST_INIT_FILE2_SIZE 14
static char g_file3_data[UFSTEST_FILE3_MXSIZE] = "This is file 3";
#define UFSTEST_INIT_FILE3_SIZE 14
static struct ufstest_file_s g_rootdir[UFSTEST_NFILES] =
{
{
{ DTYPE_FILE, "File1" },
UFSTEST_INIT_FILE1_SIZE,
UFSTEST_FILE1_MXSIZE,
g_file1_data
},
{
{ DTYPE_FILE, "File2" },
UFSTEST_INIT_FILE2_SIZE,
UFSTEST_FILE2_MXSIZE,
g_file2_data
},
{
{ DTYPE_FILE, "File3" },
UFSTEST_INIT_FILE3_SIZE,
UFSTEST_FILE3_MXSIZE,
g_file3_data
}
};
static const struct userfs_operations_s g_ufstest_ops =
{
ufstest_open,
ufstest_close,
ufstest_read,
ufstest_write,
ufstest_seek,
ufstest_ioctl,
ufstest_sync,
ufstest_dup,
ufstest_fstat,
ufstest_opendir,
ufstest_closedir,
ufstest_readdir,
ufstest_rewinddir,
ufstest_statfs,
ufstest_unlink,
ufstest_mkdir,
ufstest_rmdir,
ufstest_rename,
ufstest_stat,
ufstest_destroy
};
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ufstest_findbyname
****************************************************************************/
static FAR struct ufstest_file_s *ufstest_findbyname(FAR const char *relpath)
{
int i;
for (i = 0; i < UFSTEST_NFILES; i++)
{
if (strcmp(relpath, g_rootdir[i].entry.d_name) == 0)
{
return &g_rootdir[i];
}
}
return NULL;
}
/****************************************************************************
* UserFS methods
****************************************************************************/
static int ufstest_open(FAR void *volinfo, FAR const char *relpath,
int oflags, mode_t mode, FAR void **openinfo)
{
FAR struct ufstest_openfile_s *opriv;
FAR struct ufstest_file_s *file;
file = ufstest_findbyname(relpath);
if (file != NULL)
{
opriv = (FAR struct ufstest_openfile_s *)
malloc(sizeof(struct ufstest_openfile_s ));
if (opriv == NULL)
{
return -ENOMEM;
}
if ((oflags && O_APPEND) != 0)
{
opriv->pos = file->inuse;
}
else
{
opriv->pos = 0;
}
opriv->file = file;
*openinfo = opriv;
return OK;
}
return -ENOENT;
}
static int ufstest_close(FAR void *volinfo, FAR void *openinfo)
{
free(openinfo);
return OK;
}
static ssize_t ufstest_read(FAR void *volinfo, FAR void *openinfo,
FAR char *buffer, size_t buflen)
{
FAR struct ufstest_openfile_s *opriv =
(FAR struct ufstest_openfile_s *)openinfo;
ssize_t readsize;
readsize = opriv->file->inuse - opriv->pos;
if (readsize > buflen)
{
readsize = buflen;
}
if (readsize > 0)
{
memcpy(buffer, &opriv->file->data[opriv->pos], readsize);
opriv->pos += readsize;
}
return readsize <= 0 ? 0 : readsize;
}
static ssize_t ufstest_write(FAR void *volinfo, FAR void *openinfo,
FAR const char *buffer, size_t buflen)
{
FAR struct ufstest_openfile_s *opriv =
(FAR struct ufstest_openfile_s *)openinfo;
ssize_t writesize;
writesize = opriv->file->mxsize - opriv->pos;
if (writesize > buflen)
{
writesize = buflen;
}
memcpy(&opriv->file->data[opriv->pos], buffer, writesize);
opriv->pos += writesize;
if (opriv->pos > opriv->file->inuse)
{
opriv->file->inuse = opriv->pos;
}
return writesize;
}
static off_t ufstest_seek(FAR void *volinfo, FAR void *openinfo,
off_t offset, int whence)
{
FAR struct ufstest_openfile_s *opriv =
(FAR struct ufstest_openfile_s *)openinfo;
off_t newpos;
switch (whence)
{
case SEEK_SET: /* The offset is set to offset bytes. */
newpos = offset;
break;
case SEEK_CUR: /* The offset is set to its current location plus
* offset bytes. */
newpos = offset + opriv->pos;
break;
case SEEK_END: /* The offset is set to the size of the file plus
* offset bytes. */
newpos = offset + opriv->file->inuse;
break;
default:
fprintf(stderr, "ERROR: Whence is invalid: %d\n", whence);
return -EINVAL;
}
if (newpos < 0)
{
newpos = 0;
}
else if (newpos > opriv->file->mxsize)
{
newpos = opriv->file->mxsize;
}
opriv->pos = newpos;
return newpos;
}
static int ufstest_ioctl(FAR void *volinfo, FAR void *openinfo, int cmd,
unsigned long arg)
{
return -ENOTTY;
}
static int ufstest_sync(FAR void *volinfo, FAR void *openinfo)
{
return OK;
}
static int ufstest_dup(FAR void *volinfo, FAR void *oldinfo,
FAR void *newinfo)
{
memcpy(newinfo, oldinfo, sizeof(struct ufstest_openfile_s));
return OK;
}
static int ufstest_fstat(FAR void *volinfo, FAR void *openinfo,
FAR struct stat *buf)
{
FAR struct ufstest_openfile_s *opriv =
(FAR struct ufstest_openfile_s *)openinfo;
buf->st_mode = (S_IFREG | S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
buf->st_size = opriv->file->inuse;
buf->st_blksize = UFSTEST_FS_BLOCKSIZE;
buf->st_blocks = (opriv->file->inuse + UFSTEST_FS_BLOCKSIZE - 1) /
UFSTEST_FS_BLOCKSIZE;
buf->st_atime = 0;
buf->st_mtime = 0;
buf->st_ctime = 0;
return OK;
}
static int ufstest_opendir(FAR void *volinfo, FAR const char *relpath,
FAR void **dir)
{
FAR struct ufstest_opendir_s *odir;
if (!relpath || relpath[0] == '\0')
{
/* The path refers to the top level directory. */
odir = (FAR struct ufstest_opendir_s *)
malloc(sizeof(struct ufstest_opendir_s ));
if (odir == NULL)
{
return -ENOMEM;
}
odir->index = 0;
*dir = odir;
return OK;
}
return -ENOENT;
}
static int ufstest_closedir(FAR void *volinfo, FAR void *dir)
{
free(dir);
return OK;
}
static int ufstest_readdir(FAR void *volinfo, FAR void *dir,
FAR struct dirent *entry)
{
FAR struct ufstest_file_s *priv = (FAR struct ufstest_file_s *)volinfo;
FAR struct ufstest_opendir_s *odir = (FAR struct ufstest_opendir_s *)dir;
if (odir->index < UFSTEST_NFILES)
{
memcpy(entry, &priv[odir->index].entry, sizeof(struct dirent));
odir->index++;
return OK;
}
return -ENOENT;
}
static int ufstest_rewinddir(FAR void *volinfo, FAR void *dir)
{
FAR struct ufstest_opendir_s *odir = (FAR struct ufstest_opendir_s *)dir;
odir->index = 0;
return OK;
}
static int ufstest_statfs(FAR void *volinfo, FAR struct statfs *buf)
{
int inuse = 0;
int i;
for (i = 0; i < UFSTEST_NFILES; i++)
{
inuse += (g_rootdir[i].inuse + UFSTEST_FS_BLOCKSIZE - 1) /
UFSTEST_FS_BLOCKSIZE;
}
buf->f_type = USERFS_MAGIC;
buf->f_namelen = NAME_MAX;
buf->f_bsize = UFSTEST_FS_BLOCKSIZE;
buf->f_blocks = UFSTEST_FS_NBLOCKS;
buf->f_bfree = UFSTEST_FS_NBLOCKS - inuse;
buf->f_bavail = UFSTEST_FS_NBLOCKS - inuse;
buf->f_files = UFSTEST_NFILES;
buf->f_ffree = 0;
return OK;
}
static int ufstest_unlink(FAR void *volinfo, FAR const char *relpath)
{
return -ENOSYS;
}
static int ufstest_mkdir(FAR void *volinfo, FAR const char *relpath,
mode_t mode)
{
return -ENOSYS;
}
static int ufstest_rmdir(FAR void *volinfo, FAR const char *relpath)
{
return -ENOSYS;
}
static int ufstest_rename(FAR void *volinfo, FAR const char *oldrelpath,
FAR const char *newrelpath)
{
FAR struct ufstest_file_s *file;
file = ufstest_findbyname(oldrelpath);
if (file != NULL)
{
strncpy(file->entry.d_name, newrelpath, NAME_MAX + 1);
return OK;
}
return -ENOENT;
}
static int ufstest_stat(FAR void *volinfo, FAR const char *relpath,
FAR struct stat *buf)
{
FAR void *openinfo;
int ret;
ret = ufstest_open(volinfo, relpath, O_RDWR, 0644, &openinfo);
if (ret >= 0)
{
ret = ufstest_fstat(volinfo, openinfo, buf);
(void)ufstest_close(volinfo, openinfo);
}
return ret;
}
static int ufstest_destroy(FAR void *volinfo)
{
return OK;
}
/****************************************************************************
* ufstest_daemon
****************************************************************************/
int ufstest_daemon(int argc, char *argv[])
{
int ret;
ret = userfs_run(UFSTEST_MOUNTPOUNT, &g_ufstest_ops, g_rootdir,
UFSTEST_MXWRITE);
fprintf(stderr, "ERROR: userfs_run() returned: %d\n", ret);
return EXIT_FAILURE;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* userfs_main
****************************************************************************/
#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int userfs_main(int argc, char *argv[])
#endif
{
FAR char *nshargv[1];
int pid;
/* Spawn the UserFS test daemon */
nshargv[0] = NULL;
pid = task_create("UserFS", CONFIG_EXAMPLES_USERFS_PRIORITY,
CONFIG_EXAMPLES_USERFS_STACKSIZE, ufstest_daemon,
(FAR char * const *)nshargv);
if (pid < 0)
{
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}