2020-07-21 00:18:26 +02:00
|
|
|
======================
|
|
|
|
File System Interfaces
|
|
|
|
======================
|
|
|
|
|
2020-10-20 10:40:45 +02:00
|
|
|
.. _file_system_overview:
|
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
NuttX File System Overview
|
|
|
|
==========================
|
|
|
|
|
|
|
|
**Overview**. NuttX includes an optional, scalable file system. This
|
|
|
|
file-system may be omitted altogether; NuttX does not depend on the
|
|
|
|
presence of any file system.
|
|
|
|
|
|
|
|
**Pseudo Root File System**. A simple *in-memory*, *pseudo* file system
|
|
|
|
can be enabled by default. This is an *in-memory* file system because it
|
|
|
|
does not require any storage medium or block driver support. Rather,
|
|
|
|
file system contents are generated on-the-fly as referenced via standard
|
|
|
|
file system operations (open, close, read, write, etc.). In this sense,
|
|
|
|
the file system is *pseudo* file system (in the same sense that the
|
|
|
|
Linux ``/proc`` file system is also referred to as a pseudo file
|
|
|
|
system).
|
|
|
|
|
|
|
|
Any user supplied data or logic can be accessed via the pseudo-file
|
|
|
|
system. Built in support is provided for character and block
|
2020-10-20 10:40:45 +02:00
|
|
|
:ref:`driver <drivers-porting>` *nodes* in the any
|
2020-07-21 00:18:26 +02:00
|
|
|
pseudo file system directory. (By convention, however, all driver nodes
|
|
|
|
should be in the ``/dev`` pseudo file system directory).
|
|
|
|
|
|
|
|
**Mounted File Systems** The simple in-memory file system can be
|
|
|
|
extended my mounting block devices that provide access to true file
|
|
|
|
systems backed up via some mass storage device. NuttX supports the
|
|
|
|
standard ``mount()`` command that allows a block driver to be bound to a
|
|
|
|
mount-point within the pseudo file system and to a a file system. At
|
|
|
|
present, NuttX supports only the VFAT file system.
|
|
|
|
|
|
|
|
**Comparison to Linux** From a programming perspective, the NuttX file
|
|
|
|
system appears very similar to a Linux file system. However, there is a
|
|
|
|
fundamental difference: The NuttX root file system is a pseudo file
|
|
|
|
system and true file systems may be mounted in the pseudo file system.
|
|
|
|
In the typical Linux installation by comparison, the Linux root file
|
|
|
|
system is a true file system and pseudo file systems may be mounted in
|
|
|
|
the true, root file system. The approach selected by NuttX is intended
|
|
|
|
to support greater scalability from the very tiny platform to the
|
|
|
|
moderate platform.
|
|
|
|
|
|
|
|
**File System Interfaces**. The NuttX file system simply supports a set
|
|
|
|
of standard, file system APIs (``open()``, ``close()``, ``read()``,
|
|
|
|
``write``, etc.) and a registration mechanism that allows devices
|
|
|
|
drivers to a associated with *nodes* in a file-system-like name space.
|
|
|
|
|
|
|
|
Driver Operations
|
|
|
|
=================
|
|
|
|
|
|
|
|
``fcntl.h``
|
|
|
|
-----------
|
|
|
|
|
|
|
|
.. c:function:: int creat(FAR const char *path, mode_t mode);
|
|
|
|
|
|
|
|
.. c:function:: int open(FAR const char *path, int oflag, ...);
|
|
|
|
|
|
|
|
.. c:function:: int fcntl(int fd, int cmd, ...);
|
|
|
|
|
|
|
|
``unistd.h``
|
|
|
|
------------
|
|
|
|
|
|
|
|
.. c:function:: int close(int fd);
|
|
|
|
.. c:function:: int dup(int fd);
|
|
|
|
.. c:function:: int dup2(int fd1, int fd2);
|
|
|
|
.. c:function:: off_t lseek(int fd, off_t offset, int whence);
|
|
|
|
.. c:function:: ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
|
|
|
|
.. c:function:: ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
|
|
|
|
.. c:function:: ssize_t read(int fd, void *buf, size_t nbytes);
|
|
|
|
.. c:function:: int unlink(const char *path);
|
|
|
|
.. c:function:: ssize_t write(int fd, const void *buf, size_t nbytes);
|
|
|
|
|
|
|
|
``sys/ioctl.h``
|
|
|
|
---------------
|
|
|
|
|
|
|
|
.. c:function:: int ioctl(int fd, int req, ...)
|
|
|
|
|
|
|
|
``poll.h``
|
|
|
|
----------
|
|
|
|
|
|
|
|
.. c:function:: int poll(struct pollfd *fds, nfds_t nfds, int timeout)
|
|
|
|
|
|
|
|
Waits for one of a set of file descriptors
|
|
|
|
to become ready to perform I/O. If none of the events requested (and no
|
|
|
|
error) has occurred for any of the file descriptors, then ``poll()``
|
|
|
|
blocks until one of the events occurs.
|
|
|
|
|
|
|
|
**Configuration Settings**. In order to use the select with TCP/IP
|
|
|
|
sockets test, you must have the following things selected in your NuttX
|
|
|
|
configuration file:
|
|
|
|
|
|
|
|
- ``CONFIG_NET`` Defined for general network support
|
|
|
|
- ``CONFIG_NET_TCP`` Defined for TCP/IP support
|
|
|
|
|
|
|
|
In order to for select to work with incoming connections, you must also
|
|
|
|
select:
|
|
|
|
|
|
|
|
- ``CONFIG_NET_TCPBACKLOG`` Incoming connections pend in a backlog
|
|
|
|
until ``accept()`` is called. The size of the backlog is selected
|
|
|
|
when ``listen()`` is called.
|
|
|
|
|
|
|
|
:param fds: List of structures describing file descriptors to be
|
|
|
|
monitored.
|
|
|
|
:param nfds: The number of entries in the list.
|
|
|
|
:param timeout: Specifies an upper limit on the time for which
|
|
|
|
``poll()`` will block in milliseconds. A negative value of
|
|
|
|
``timeout`` means an infinite timeout.
|
|
|
|
|
|
|
|
:return:
|
|
|
|
On success, the number of structures that have nonzero ``revents``
|
|
|
|
fields. A value of 0 indicates that the call timed out and no file
|
|
|
|
descriptors were ready. On error, -1 is returned, and ``errno`` is set
|
|
|
|
appropriately:
|
|
|
|
|
|
|
|
- ``EBADF``. An invalid file descriptor was given in one of the sets.
|
|
|
|
- ``EFAULT``. The fds address is invalid
|
|
|
|
- ``EINTR``. A signal occurred before any requested event.
|
|
|
|
- ``EINVAL``. The nfds value exceeds a system limit.
|
|
|
|
- ``ENOMEM``. There was no space to allocate internal data structures.
|
|
|
|
- ``ENOSYS``. One or more of the drivers supporting the file descriptor
|
|
|
|
does not support the poll method.
|
|
|
|
|
|
|
|
``sys/select.h``
|
|
|
|
----------------
|
|
|
|
|
|
|
|
.. c:function:: int select(int nfds, FAR fd_set *readfds, FAR fd_set *writefds, \
|
|
|
|
FAR fd_set *exceptfds, FAR struct timeval *timeout)
|
|
|
|
|
|
|
|
Allows a program to monitor multiple file
|
|
|
|
descriptors, waiting until one or more of the file descriptors become
|
|
|
|
"ready" for some class of I/O operation (e.g., input possible). A file
|
|
|
|
descriptor is considered ready if it is possible to perform the
|
|
|
|
corresponding I/O operation (e.g., read(2)) without blocking.
|
|
|
|
|
|
|
|
**NOTE:** ```poll()`` <#poll>`__ is the fundamental API for performing
|
|
|
|
such monitoring operation under NuttX. ``select()`` is provided for
|
|
|
|
compatibility and is simply a layer of added logic on top of ``poll()``.
|
|
|
|
As such, ``select()`` is more wasteful of resources and
|
|
|
|
```poll()`` <#poll>`__ is the recommended API to be used.
|
|
|
|
|
|
|
|
:param nfds: the maximum file descriptor number (+1) of any descriptor
|
|
|
|
in any of the three sets.
|
|
|
|
:param readfds: the set of descriptions to monitor for read-ready events
|
|
|
|
:param writefds: the set of descriptions to monitor for write-ready
|
|
|
|
events
|
|
|
|
:param exceptfds: the set of descriptions to monitor for error events
|
|
|
|
:param timeout: Return at this time if none of these events of interest
|
|
|
|
occur.
|
|
|
|
|
|
|
|
:return:
|
|
|
|
- ``0:`` Timer expired
|
|
|
|
- ``>0:`` The number of bits set in the three sets of descriptors
|
|
|
|
- ``-1:`` An error occurred (``errno`` will be set appropriately, see
|
|
|
|
```poll()`` <#poll>`__).
|
|
|
|
|
|
|
|
Directory Operations (``dirent.h``)
|
|
|
|
-----------------------------------
|
|
|
|
|
|
|
|
.. c:function:: int closedir(DIR *dirp);
|
|
|
|
|
|
|
|
.. c:function:: FAR DIR *opendir(const char *path);
|
|
|
|
|
|
|
|
.. c:function:: FAR struct dirent *readdir(FAR DIR *dirp);
|
|
|
|
|
|
|
|
.. c:function:: int readdir_r(FAR DIR *dirp, FAR struct dirent *entry, FAR struct dirent **result);
|
|
|
|
|
|
|
|
.. c:function:: void rewinddir(FAR DIR *dirp);
|
|
|
|
|
|
|
|
.. c:function:: void seekdir(FAR DIR *dirp, int loc);
|
|
|
|
|
|
|
|
.. c:function:: int telldir(FAR DIR *dirp);
|
|
|
|
|
|
|
|
UNIX Standard Operations (``unistd.h``)
|
|
|
|
---------------------------------------
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
/* Task Control Interfaces */
|
|
|
|
|
|
|
|
pid_t vfork(void);
|
|
|
|
pid_t getpid(void);
|
|
|
|
void _exit(int status) noreturn_function;
|
|
|
|
unsigned int sleep(unsigned int seconds);
|
|
|
|
void usleep(unsigned long usec);
|
|
|
|
int pause(void);
|
|
|
|
|
|
|
|
/* File descriptor operations */
|
|
|
|
|
|
|
|
int close(int fd);
|
|
|
|
int dup(int fd);
|
|
|
|
int dup2(int fd1, int fd2);
|
|
|
|
int fsync(int fd);
|
|
|
|
off_t lseek(int fd, off_t offset, int whence);
|
|
|
|
ssize_t read(int fd, FAR void *buf, size_t nbytes);
|
|
|
|
ssize_t write(int fd, FAR const void *buf, size_t nbytes);
|
|
|
|
ssize_t pread(int fd, FAR void *buf, size_t nbytes, off_t offset);
|
|
|
|
ssize_t pwrite(int fd, FAR const void *buf, size_t nbytes, off_t offset);
|
|
|
|
|
|
|
|
/* Check if a file descriptor corresponds to a terminal I/O file */
|
|
|
|
|
|
|
|
int isatty(int fd);
|
|
|
|
|
|
|
|
/* Memory management */
|
|
|
|
|
|
|
|
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_MM_PGALLOC) && \
|
|
|
|
defined(CONFIG_ARCH_USE_MMU)
|
|
|
|
FAR void *sbrk(intptr_t incr);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Special devices */
|
|
|
|
|
|
|
|
int pipe(int fd[2]);
|
|
|
|
|
|
|
|
/* Working directory operations */
|
|
|
|
|
|
|
|
int chdir(FAR const char *path);
|
|
|
|
FAR char *getcwd(FAR char *buf, size_t size);
|
|
|
|
|
|
|
|
/* File path operations */
|
|
|
|
|
|
|
|
int access(FAR const char *path, int amode);
|
|
|
|
int rmdir(FAR const char *pathname);
|
|
|
|
int unlink(FAR const char *pathname);
|
|
|
|
|
|
|
|
#ifdef CONFIG_PSEUDOFS_SOFTLINKS
|
|
|
|
int link(FAR const char *path1, FAR const char *path2);
|
|
|
|
ssize_t readlink(FAR const char *path, FAR char *buf, size_t bufsize);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Execution of programs from files */
|
|
|
|
|
|
|
|
#ifdef CONFIG_LIBC_EXECFUNCS
|
|
|
|
int execl(FAR const char *path, ...);
|
|
|
|
int execv(FAR const char *path, FAR char * const argv[]);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Networking */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET
|
|
|
|
int gethostname(FAR char *name, size_t size);
|
|
|
|
int sethostname(FAR const char *name, size_t size);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Other */
|
|
|
|
|
|
|
|
int getopt(int argc, FAR char * const argv[], FAR const char *optstring);
|
|
|
|
|
|
|
|
Standard I/O
|
|
|
|
------------
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
/* Operations on streams (FILE) */
|
|
|
|
|
|
|
|
void clearerr(FAR FILE *stream);
|
|
|
|
int fclose(FAR FILE *stream);
|
|
|
|
int fflush(FAR FILE *stream);
|
|
|
|
int feof(FAR FILE *stream);
|
|
|
|
int ferror(FAR FILE *stream);
|
|
|
|
int fileno(FAR FILE *stream);
|
|
|
|
int fgetc(FAR FILE *stream);
|
|
|
|
int fgetpos(FAR FILE *stream, FAR fpos_t *pos);
|
|
|
|
FAR char *fgets(FAR char *s, int n, FAR FILE *stream);
|
2022-04-25 18:13:41 +02:00
|
|
|
void flockfile(FAR FILE *stream);
|
2020-07-21 00:18:26 +02:00
|
|
|
FAR FILE *fopen(FAR const char *path, FAR const char *type);
|
|
|
|
int fprintf(FAR FILE *stream, FAR const char *format, ...);
|
|
|
|
int fputc(int c, FAR FILE *stream);
|
|
|
|
int fputs(FAR const char *s, FAR FILE *stream);
|
|
|
|
size_t fread(FAR void *ptr, size_t size, size_t n_items, FAR FILE *stream);
|
|
|
|
FAR FILE *freopen(FAR const char *path, FAR const char *mode,
|
|
|
|
FAR FILE *stream);
|
|
|
|
int fseek(FAR FILE *stream, long int offset, int whence);
|
|
|
|
int fsetpos(FAR FILE *stream, FAR fpos_t *pos);
|
|
|
|
long ftell(FAR FILE *stream);
|
2022-04-25 18:13:41 +02:00
|
|
|
int ftrylockfile(FAR FILE *stream);
|
|
|
|
void funlockfile(FAR FILE *stream);
|
2020-07-21 00:18:26 +02:00
|
|
|
size_t fwrite(FAR const void *ptr, size_t size, size_t n_items, FAR FILE *stream);
|
|
|
|
FAR char *gets(FAR char *s);
|
|
|
|
FAR char *gets_s(FAR char *s, rsize_t n);
|
|
|
|
void setbuf(FAR FILE *stream, FAR char *buf);
|
|
|
|
int setvbuf(FAR FILE *stream, FAR char *buffer, int mode, size_t size);
|
|
|
|
int ungetc(int c, FAR FILE *stream);
|
|
|
|
|
|
|
|
/* Operations on the stdout stream, buffers, paths, and the whole printf-family * /
|
|
|
|
|
|
|
|
int printf(FAR const char *format, ...);
|
|
|
|
int puts(FAR const char *s);
|
|
|
|
int rename(FAR const char *source, FAR const char *target);
|
|
|
|
int sprintf(FAR char *dest, FAR const char *format, ...);
|
|
|
|
int asprintf(FAR char **ptr, FAR const char *fmt, ...);
|
|
|
|
int snprintf(FAR char *buf, size_t size, FAR const char *format, ...);
|
|
|
|
int sscanf(FAR const char *buf, FAR const char *fmt, ...);
|
|
|
|
void perror(FAR const char *s);
|
|
|
|
|
|
|
|
int vprintf(FAR const char *s, va_list ap);
|
|
|
|
int vfprintf(FAR FILE *stream, FAR const char *s, va_list ap);
|
|
|
|
int vsprintf(FAR char *buf, FAR const char *s, va_list ap);
|
|
|
|
int vasprintf(FAR char **ptr, FAR const char *fmt, va_list ap);
|
|
|
|
int vsnprintf(FAR char *buf, size_t size, FAR const char *format, va_list ap);
|
|
|
|
int vsscanf(FAR char *buf, FAR const char *s, va_list ap);
|
|
|
|
|
|
|
|
/* Operations on file descriptors including:
|
|
|
|
*
|
|
|
|
* POSIX-like File System Interfaces (fdopen), and
|
|
|
|
* Extensions from the Open Group Technical Standard, 2006, Extended API Set
|
|
|
|
* Part 1 (dprintf and vdprintf)
|
|
|
|
*/
|
|
|
|
|
|
|
|
FAR FILE *fdopen(int fd, FAR const char *type);
|
|
|
|
int dprintf(int fd, FAR const char *fmt, ...);
|
|
|
|
int vdprintf(int fd, FAR const char *fmt, va_list ap);
|
|
|
|
|
|
|
|
/* Operations on paths */
|
|
|
|
|
|
|
|
FAR char *tmpnam(FAR char *s);
|
|
|
|
FAR char *tempnam(FAR const char *dir, FAR const char *pfx);
|
|
|
|
int remove(FAR const char *path);
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
int mkdir(FAR const char *pathname, mode_t mode);
|
|
|
|
int mkfifo(FAR const char *pathname, mode_t mode);
|
|
|
|
int stat(FAR const char *path, FAR struct stat *buf);
|
|
|
|
int fstat(int fd, FAR struct stat *buf);
|
|
|
|
|
|
|
|
#include <sys/statfs.h>
|
|
|
|
|
|
|
|
int statfs(FAR const char *path, FAR struct statfs *buf);
|
|
|
|
int fstatfs(int fd, FAR struct statfs *buf);
|
|
|
|
|
|
|
|
Standard Library (``stdlib.h``)
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
Generally addresses other operating system interfaces.
|
|
|
|
However, the following may also be considered as file system interfaces:
|
|
|
|
|
|
|
|
.. c:function:: int mktemp(FAR char *template);
|
|
|
|
.. c:function:: int mkstemp(FAR char *template);
|
|
|
|
|
|
|
|
Asynchronous I/O
|
|
|
|
----------------
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
#include <aio.h>
|
|
|
|
|
|
|
|
int aio_cancel(int, FAR struct aiocb *aiocbp);
|
|
|
|
int aio_error(FAR const struct aiocb *aiocbp);
|
|
|
|
int aio_fsync(int, FAR struct aiocb *aiocbp);
|
|
|
|
int aio_read(FAR struct aiocb *aiocbp);
|
|
|
|
ssize_t aio_return(FAR struct aiocb *aiocbp);
|
|
|
|
int aio_suspend(FAR const struct aiocb * const list[], int nent,
|
|
|
|
FAR const struct timespec *timeout);
|
|
|
|
int aio_write(FAR struct aiocb *aiocbp);
|
|
|
|
int lio_listio(int mode, FAR struct aiocb * const list[], int nent,
|
|
|
|
FAR struct sigevent *sig);
|
|
|
|
|
|
|
|
Standard String Operations
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
char *strchr(const char *s, int c);
|
|
|
|
FAR char *strdup(const char *s);
|
|
|
|
const char *strerror(int);
|
|
|
|
size_t strlen(const char *);
|
|
|
|
size_t strnlen(const char *, size_t);
|
|
|
|
char *strcat(char *, const char *);
|
|
|
|
char *strncat(char *, const char *, size_t);
|
|
|
|
int strcmp(const char *, const char *);
|
|
|
|
int strncmp(const char *, const char *, size_t);
|
|
|
|
int strcasecmp(const char *, const char *);
|
|
|
|
int strncasecmp(const char *, const char *, size_t);
|
|
|
|
char *strcpy(char *dest, const char *src);
|
|
|
|
char *strncpy(char *, const char *, size_t);
|
|
|
|
char *strpbrk(const char *, const char *);
|
|
|
|
char *strchr(const char *, int);
|
|
|
|
char *strrchr(const char *, int);
|
|
|
|
size_t strspn(const char *, const char *);
|
|
|
|
size_t strcspn(const char *, const char *);
|
|
|
|
char *strstr(const char *, const char *);
|
|
|
|
char *strtok(char *, const char *);
|
|
|
|
char *strtok_r(char *, const char *, char **);
|
|
|
|
|
|
|
|
void *memset(void *s, int c, size_t n);
|
|
|
|
void *memcpy(void *dest, const void *src, size_t n);
|
|
|
|
int memcmp(const void *s1, const void *s2, size_t n);
|
|
|
|
void *memmove(void *dest, const void *src, size_t count);
|
|
|
|
|
|
|
|
#include <strings.h>
|
|
|
|
|
|
|
|
#define bcmp(b1,b2,len) memcmp(b1,b2,(size_t)len)
|
2022-04-17 17:14:13 +02:00
|
|
|
#define bcopy(b1,b2,len) memmove(b2,b1,len)
|
|
|
|
#define bzero(s,n) memset(s,0,n)
|
2020-07-21 00:18:26 +02:00
|
|
|
#define index(s,c) strchr(s,c)
|
|
|
|
#define rindex(s,c) strrchr(s,c)
|
|
|
|
|
|
|
|
int ffs(int j);
|
|
|
|
int strcasecmp(const char *, const char *);
|
|
|
|
int strncasecmp(const char *, const char *, size_t);
|
|
|
|
|
|
|
|
Pipes and FIFOs
|
|
|
|
---------------
|
|
|
|
|
|
|
|
.. c:function:: int pipe(int fd[2])
|
|
|
|
|
|
|
|
Creates a pair of file descriptors, pointing to a pipe inode,
|
2020-10-18 18:48:44 +02:00
|
|
|
and places them in the array pointed to by ``fd``.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
:param fd: The user provided array in which to catch the pipe file
|
|
|
|
descriptors. ``fd[0]`` is for reading, ``fd[1]`` is for writing.
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
:return: 0 is returned on success; otherwise, -1 is returned with errno set appropriately.
|
|
|
|
|
2020-07-21 00:18:26 +02:00
|
|
|
.. c:function:: int mkfifo(FAR const char *pathname, mode_t mode);
|
|
|
|
|
|
|
|
mkfifo() makes a FIFO device driver file with name pathname. Unlike Linux,
|
|
|
|
a NuttX FIFO is not a special file type but simply a device driver instance.
|
|
|
|
mode specifies the FIFO's permissions (but is ignored in the current implementation).
|
|
|
|
|
|
|
|
Once the FIFO has been created by mkfifo(), any thread can open it for reading
|
|
|
|
or writing, in the same way as an ordinary file. However, it must have been
|
|
|
|
opened from both reading and writing before input or output can be performed.
|
2020-10-18 18:48:44 +02:00
|
|
|
This FIFO implementation will block all attempts to open a FIFO read-only
|
2020-07-21 00:18:26 +02:00
|
|
|
until at least one thread has opened the FIFO for writing.
|
|
|
|
|
|
|
|
If all threads that write to the FIFO have closed, subsequent calls to
|
|
|
|
read() on the FIFO will return 0 (end-of-file).
|
|
|
|
|
|
|
|
:param pathname: The full path to the FIFO instance to attach to or to
|
|
|
|
create (if not already created).
|
|
|
|
:param mode: Ignored for now
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
:return: 0 is returned on success; otherwise, -1 is returned with errno set appropriately.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
``mmap()`` and eXecute In Place (XIP)
|
|
|
|
-------------------------------------
|
|
|
|
|
|
|
|
NuttX operates in a flat open address space and is focused on MCUs that
|
|
|
|
do support Memory Management Units (MMUs). Therefore, NuttX generally
|
|
|
|
does not require ``mmap()`` functionality and the MCUs generally cannot
|
|
|
|
support true memory-mapped files.
|
|
|
|
|
|
|
|
However, memory mapping of files is the mechanism used by NXFLAT, the
|
|
|
|
NuttX tiny binary format, to get files into memory in order to execute
|
|
|
|
them. ``mmap()`` support is therefore required to support NXFLAT. There
|
|
|
|
are two conditions where ``mmap()`` can be supported:
|
|
|
|
|
|
|
|
1. ``mmap()`` can be used to support *eXecute In Place* (XIP) on random
|
|
|
|
access media under the following very restrictive conditions:
|
|
|
|
|
2023-01-02 14:02:51 +01:00
|
|
|
a. Any file system that maps files contiguously on the media
|
|
|
|
should implement the mmap file operation. By comparison, most
|
|
|
|
file system scatter files over the media in non-contiguous
|
|
|
|
sectors. As of this writing, ROMFS is the only file system
|
|
|
|
that meets this requirement.
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
b. The underlying block driver supports the ``BIOC_XIPBASE``
|
|
|
|
``ioctl`` command that maps the underlying media to a randomly
|
|
|
|
accessible address. At present, only the RAM/ROM disk driver does
|
|
|
|
this.
|
|
|
|
|
|
|
|
Some limitations of this approach are as follows:
|
|
|
|
|
|
|
|
a. Since no real mapping occurs, all of the file contents are
|
|
|
|
"mapped" into memory.
|
|
|
|
|
|
|
|
b. All mapped files are read-only.
|
|
|
|
|
|
|
|
c. There are no access privileges.
|
|
|
|
|
|
|
|
2. If ``CONFIG_FS_RAMMAP`` is defined in the configuration, then
|
|
|
|
``mmap()`` will support simulation of memory mapped files by copying
|
|
|
|
files whole into RAM. These copied files have some of the properties
|
|
|
|
of standard memory mapped files. There are many, many exceptions
|
|
|
|
exceptions, however. Some of these include:
|
|
|
|
|
|
|
|
a. The goal is to have a single region of memory that represents a
|
|
|
|
single file and can be shared by many threads. That is, given a
|
|
|
|
filename a thread should be able to open the file, get a file
|
|
|
|
descriptor, and call ``mmap()`` to get a memory region. Different
|
|
|
|
file descriptors opened with the same file path should get the
|
|
|
|
same memory region when mapped.
|
|
|
|
|
|
|
|
The limitation in the current design is that there is insufficient
|
|
|
|
knowledge to know that these different file descriptors correspond
|
|
|
|
to the same file. So, for the time being, a new memory region is
|
|
|
|
created each time that ``rammmap()`` is called. Not very useful!
|
|
|
|
|
|
|
|
b. The entire mapped portion of the file must be present in memory.
|
|
|
|
Since it is assumed that the MCU does not have an MMU,
|
|
|
|
on-demanding paging in of file blocks cannot be supported. Since
|
|
|
|
the while mapped portion of the file must be present in memory,
|
|
|
|
there are limitations in the size of files that may be memory
|
|
|
|
mapped (especially on MCUs with no significant RAM resources).
|
|
|
|
|
|
|
|
c. All mapped files are read-only. You can write to the in-memory
|
|
|
|
image, but the file contents will not change.
|
|
|
|
|
|
|
|
d. There are no access privileges.
|
|
|
|
|
|
|
|
e. Since there are no processes in NuttX, all ``mmap()`` and
|
|
|
|
``munmap()`` operations have immediate, global effects. Under
|
|
|
|
Linux, for example, ``munmap()`` would eliminate only the mapping
|
|
|
|
with a process; the mappings to the same file in other processes
|
|
|
|
would not be effected.
|
|
|
|
|
|
|
|
f. Like true mapped file, the region will persist after closing the
|
|
|
|
file descriptor. However, at present, these ram copied file
|
|
|
|
regions are *not* automatically "unmapped" (i.e., freed) when a
|
|
|
|
thread is terminated. This is primarily because it is not possible
|
|
|
|
to know how many users of the mapped region there are and,
|
|
|
|
therefore, when would be the appropriate time to free the region
|
|
|
|
(other than when munmap is called).
|
|
|
|
|
|
|
|
NOTE: Note, if the design limitation of a) were solved, then it
|
|
|
|
would be easy to solve exception d) as well.
|
|
|
|
|
|
|
|
.. c:function:: FAR void *mmap(FAR void *start, size_t length, int prot, int flags, int fd, off_t offset);
|
|
|
|
|
2020-10-18 18:48:44 +02:00
|
|
|
Provides minimal mmap() as needed to support eXecute In Place (XIP) operation (as described above).
|
2020-07-21 00:18:26 +02:00
|
|
|
|
|
|
|
:param start: A hint at where to map the memory -- ignored. The address
|
|
|
|
of the underlying media is fixed and cannot be re-mapped without MMU
|
|
|
|
support.
|
|
|
|
:param length: The length of the mapping -- ignored. The entire
|
|
|
|
underlying media is always accessible.
|
|
|
|
:param prot: See the ``PROT_*`` definitions in ``sys/mman.h``.
|
|
|
|
|
|
|
|
- ``PROT_NONE`` - Will cause an error.
|
|
|
|
- ``PROT_READ`` - ``PROT_WRITE`` and ``PROT_EXEC`` also assumed.
|
|
|
|
- ``PROT_WRITE`` - ``PROT_READ`` and ``PROT_EXEC`` also assumed.
|
|
|
|
- ``PROT_EXEC`` - ``PROT_READ`` and ``PROT_WRITE`` also assumed.
|
|
|
|
|
|
|
|
:param flags: See the ``MAP_*`` definitions in ``sys/mman.h``.
|
|
|
|
|
|
|
|
- ``MAP_SHARED`` - Required
|
|
|
|
- ``MAP_PRIVATE`` - Will cause an error
|
|
|
|
- ``MAP_FIXED`` - Will cause an error
|
|
|
|
- ``MAP_FILE`` - Ignored
|
|
|
|
- ``MAP_ANONYMOUS`` - Will cause an error
|
|
|
|
- ``MAP_ANON`` - Will cause an error
|
|
|
|
- ``MAP_GROWSDOWN`` - Ignored
|
|
|
|
- ``MAP_DENYWRITE`` - Will cause an error
|
|
|
|
- ``MAP_EXECUTABLE`` - Ignored
|
|
|
|
- ``MAP_LOCKED`` - Ignored
|
|
|
|
- ``MAP_NORESERVE`` - Ignored
|
|
|
|
- ``MAP_POPULATE`` - Ignored
|
|
|
|
- ``AP_NONBLOCK`` - Ignored
|
|
|
|
|
|
|
|
:param fd: file descriptor of the backing file -- required.
|
|
|
|
:param offset: The offset into the file to map.
|
|
|
|
|
|
|
|
:return:
|
|
|
|
|
|
|
|
On success, ``mmap()`` returns a pointer to the mapped area. On error,
|
|
|
|
the value ``MAP_FAILED`` is returned, and ``errno`` is set
|
|
|
|
appropriately.
|
|
|
|
|
|
|
|
- ``ENOSYS`` - Returned if any of the unsupported ``mmap()`` features
|
|
|
|
are attempted.
|
|
|
|
- ``EBADF`` - ``fd`` is not a valid file descriptor.
|
|
|
|
- ``EINVAL`` - Length is 0. flags contained neither ``MAP_PRIVATE`` or
|
|
|
|
``MAP_SHARED``, or contained both of these values.
|
|
|
|
- ``ENODEV`` - The underlying file-system of the specified file does
|
|
|
|
not support memory mapping.
|
|
|
|
|
2023-05-15 12:59:02 +02:00
|
|
|
Fdsan
|
|
|
|
---------------
|
|
|
|
FD (file descriptor) is widely used in system software development,
|
|
|
|
and almost all implementations of posix os (including nuttx) use FD as an index.
|
|
|
|
the value of fd needs to be allocated starting from the minimum available value of 3, and each process has a copy,
|
|
|
|
so the same fd value is very easy to reuse in the program.
|
|
|
|
|
|
|
|
In multi threaded or multi process environments without address isolation,
|
|
|
|
If the ownership, global variables, and competition relationships of fd are not properly handled,
|
|
|
|
there may be issues with fd duplication or accidental closure.
|
|
|
|
Further leading to the following issues, which are difficult to troubleshoot.
|
|
|
|
|
|
|
|
1. Security vulnerability: the fd we wrote is not the expected fd and will be accessed by hackers to obtain data
|
|
|
|
2. Program exceptions or crashes: write or read fd failures, and program logic errors
|
|
|
|
3. The structured file XML or database is damaged: the data format written to the database is not the expected format.
|
|
|
|
|
|
|
|
The implementation principle of fdsan is based on the implementation of Android
|
|
|
|
https://android.googlesource.com/platform/bionic/+/master/docs/fdsan.md
|
|
|
|
|
|
|
|
|
|
|
|
.. c:function:: uint64_t android_fdsan_create_owner_tag(enum android_fdsan_owner_type type, uint64_t tag);
|
|
|
|
|
|
|
|
Create an owner tag with the specified type and least significant 56 bits of tag.
|
|
|
|
|
|
|
|
:param type: See the ANDROID_* definitions in include/android/fdsan.h.
|
|
|
|
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_FILE`` - FILE
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_DIR`` - DIR
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_UNIQUE_FD`` - android::base::unique_fd
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_SQLITE`` - sqlite-owned file descriptors
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_FILEINPUTSTREAM`` - java.io.FileInputStream
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_FILEOUTPUTSTREAM`` - java.io.FileOutputStream
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_RANDOMACCESSFILE`` - java.io.RandomAccessFile
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_PARCELFILEDESCRIPTOR`` - android.os.ParcelFileDescriptor
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_ART_FDFILE`` - ART FdFile
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_DATAGRAMSOCKETIMPL`` - java.net.DatagramSocketImpl
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_SOCKETIMPL`` - java.net.SocketImpl
|
|
|
|
- ``ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE`` - libziparchive's ZipArchive
|
|
|
|
|
|
|
|
:param tag: least significant 56 bits of tag. Typically, it is a pointer to the object/structure where fd is located
|
|
|
|
|
|
|
|
.. c:function:: void android_fdsan_exchange_owner_tag(int fd, uint64_t expected_tag, uint64_t new_tag);
|
|
|
|
|
|
|
|
Exchange a file descriptor's tag. Logs and aborts if the fd's tag does not match expected_tag.
|
|
|
|
|
|
|
|
:param fd: The fd we want to protect
|
|
|
|
:param expected_tag: The tag corresponding to the current fd
|
|
|
|
:param new_tag: A new tag for fd binding
|
|
|
|
|
|
|
|
.. c:function:: int android_fdsan_close_with_tag(int fd, uint64_t tag);
|
|
|
|
|
|
|
|
Close a file descriptor with a tag, and resets the tag to 0. Logs and aborts if the tag is incorrect.
|
|
|
|
|
|
|
|
:param fd: The fd we want to protect.
|
|
|
|
:param tag: The tag corresponding to the current fd.
|
|
|
|
:return: Consistent with the return value of close.
|