/****************************************************************************
 * include/nuttx/fs/fs.h
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

#ifndef __INCLUDE_NUTTX_FS_FS_H
#define __INCLUDE_NUTTX_FS_FS_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <nuttx/compiler.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/fs/uio.h>

#include <sys/uio.h>
#include <sys/types.h>

#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <dirent.h>

#include <nuttx/atomic.h>
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
#include <nuttx/mm/map.h>
#include <nuttx/spawn.h>
#include <nuttx/queue.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock_type.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Most internal OS interfaces are not available in the user space in
 * PROTECTED and KERNEL builds.  In that context, the corresponding
 * application interfaces must be used.  The differences between the two
 * sets of interfaces are:  The internal OS interfaces (1) do not cause
 * cancellation points and (2) they do not modify the errno variable.
 *
 * This is only important when compiling libraries (libc or libnx) that are
 * used both by the OS (libkc.a and libknx.a) or by the applications
 * (libc.a and libnx.a).  In that case, the correct interface must be
 * used for the build context.
 *
 * REVISIT:  In the flat build, the same functions must be used both by
 * the OS and by applications.  We have to use the normal user functions
 * in this case or we will fail to set the errno or fail to create the
 * cancellation point.
 *
 * The interfaces close(), creat(), read(), pread(), write(), pwrite(),
 * poll(), select(), fcntl(), and aio_suspend() are all cancellation
 * points.
 *
 * REVISIT:  These cancellation points are an issue and may cause
 * violations:  It use of these internally will cause the calling function
 * to become a cancellation points!
 */

#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__)
#  define _NX_OPEN             nx_open
#  define _NX_CLOSE(f)         nx_close(f)
#  define _NX_READ(f,b,s)      nx_read(f,b,s)
#  define _NX_WRITE(f,b,s)     nx_write(f,b,s)
#  define _NX_SEEK(f,o,w)      nx_seek(f,o,w)
#  define _NX_STAT(f,s)        nx_fstat(f,s)
#  define _NX_GETERRNO(r)      (-(r))
#  define _NX_SETERRNO(r)      set_errno(-(r))
#  define _NX_GETERRVAL(r)     (r)
#else
#  define _NX_OPEN             open
#  define _NX_CLOSE(f)         close(f)
#  define _NX_READ(f,b,s)      read(f,b,s)
#  define _NX_WRITE(f,b,s)     write(f,b,s)
#  define _NX_SEEK(f,o,w)      lseek(f,o,w)
#  define _NX_STAT(f,s)        fstat(f,s)
#  define _NX_GETERRNO(r)      errno
#  define _NX_SETERRNO(r)      ((void)(r))
#  define _NX_GETERRVAL(r)     (-errno)
#endif

/* Stream flags for the fs_flags field of in struct file_struct */

#define __FS_FLAG_EOF   (1 << 0) /* EOF detected by a read operation */
#define __FS_FLAG_ERROR (1 << 1) /* Error detected by any operation */
#define __FS_FLAG_LBF   (1 << 2) /* Line buffered */
#define __FS_FLAG_UBF   (1 << 3) /* Buffer allocated by caller of setvbuf */

/* Inode i_flags values:
 *
 *   Bit 0-3: Inode type (Bit 3 indicates internal OS types)
 *   Bit 4:   Set if inode has been unlinked and is pending removal.
 */

#define FSNODEFLAG_TYPE_MASK         0x0000000f /* Isolates type field      */
#define   FSNODEFLAG_TYPE_PSEUDODIR  0x00000000 /*   Pseudo dir (default)   */
#define   FSNODEFLAG_TYPE_DRIVER     0x00000001 /*   Character driver       */
#define   FSNODEFLAG_TYPE_BLOCK      0x00000002 /*   Block driver           */
#define   FSNODEFLAG_TYPE_MOUNTPT    0x00000003 /*   Mount point            */
#define   FSNODEFLAG_TYPE_NAMEDSEM   0x00000004 /*   Named semaphore        */
#define   FSNODEFLAG_TYPE_MQUEUE     0x00000005 /*   Message Queue          */
#define   FSNODEFLAG_TYPE_SHM        0x00000006 /*   Shared memory region   */
#define   FSNODEFLAG_TYPE_MTD        0x00000007 /*   Named MTD driver       */
#define   FSNODEFLAG_TYPE_SOFTLINK   0x00000008 /*   Soft link              */
#define   FSNODEFLAG_TYPE_SOCKET     0x00000009 /*   Socket                 */
#define   FSNODEFLAG_TYPE_PIPE       0x0000000a /*   Pipe                   */
#define   FSNODEFLAG_TYPE_NAMEDEVENT 0x0000000b /*   Named event group      */

#define INODE_IS_TYPE(i,t) \
  (((i)->i_flags & FSNODEFLAG_TYPE_MASK) == (t))

#define INODE_IS_PSEUDODIR(i)  INODE_IS_TYPE(i,FSNODEFLAG_TYPE_PSEUDODIR)
#define INODE_IS_DRIVER(i)     INODE_IS_TYPE(i,FSNODEFLAG_TYPE_DRIVER)
#define INODE_IS_BLOCK(i)      INODE_IS_TYPE(i,FSNODEFLAG_TYPE_BLOCK)
#define INODE_IS_MOUNTPT(i)    INODE_IS_TYPE(i,FSNODEFLAG_TYPE_MOUNTPT)
#define INODE_IS_NAMEDSEM(i)   INODE_IS_TYPE(i,FSNODEFLAG_TYPE_NAMEDSEM)
#define INODE_IS_MQUEUE(i)     INODE_IS_TYPE(i,FSNODEFLAG_TYPE_MQUEUE)
#define INODE_IS_SHM(i)        INODE_IS_TYPE(i,FSNODEFLAG_TYPE_SHM)
#define INODE_IS_MTD(i)        INODE_IS_TYPE(i,FSNODEFLAG_TYPE_MTD)
#define INODE_IS_SOFTLINK(i)   INODE_IS_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK)
#define INODE_IS_SOCKET(i)     INODE_IS_TYPE(i,FSNODEFLAG_TYPE_SOCKET)
#define INODE_IS_PIPE(i)       INODE_IS_TYPE(i,FSNODEFLAG_TYPE_PIPE)
#define INODE_IS_NAMEDEVENT(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_NAMEDEVENT)

#define INODE_GET_TYPE(i)     ((i)->i_flags & FSNODEFLAG_TYPE_MASK)
#define INODE_SET_TYPE(i,t) \
  do \
    { \
      (i)->i_flags = ((i)->i_flags & ~FSNODEFLAG_TYPE_MASK) | (t); \
    } \
  while (0)

#define INODE_SET_DRIVER(i)     INODE_SET_TYPE(i,FSNODEFLAG_TYPE_DRIVER)
#define INODE_SET_BLOCK(i)      INODE_SET_TYPE(i,FSNODEFLAG_TYPE_BLOCK)
#define INODE_SET_MOUNTPT(i)    INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MOUNTPT)
#define INODE_SET_NAMEDSEM(i)   INODE_SET_TYPE(i,FSNODEFLAG_TYPE_NAMEDSEM)
#define INODE_SET_MQUEUE(i)     INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MQUEUE)
#define INODE_SET_SHM(i)        INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SHM)
#define INODE_SET_MTD(i)        INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MTD)
#define INODE_SET_SOFTLINK(i)   INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK)
#define INODE_SET_SOCKET(i)     INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SOCKET)
#define INODE_SET_PIPE(i)       INODE_SET_TYPE(i,FSNODEFLAG_TYPE_PIPE)
#define INODE_SET_NAMEDEVENT(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_NAMEDEVENT)

/* The status change flags.
 * These should be or-ed together to figure out what want to change.
 */

#define CH_STAT_MODE       (1 << 0)
#define CH_STAT_UID        (1 << 1)
#define CH_STAT_GID        (1 << 2)
#define CH_STAT_ATIME      (1 << 3)
#define CH_STAT_MTIME      (1 << 4)
#define CH_STAT_SIZE       (1 << 7)

/****************************************************************************
 * Public Type Definitions
 ****************************************************************************/

/* Forward references */

struct file;
struct inode;
struct stat;
struct statfs;
struct pollfd;
struct mtd_dev_s;
struct uio;

/* The internal representation of type DIR is just a container for an inode
 * reference, and the path of directory.
 */

struct fs_dirent_s
{
  /* This is the node that was opened by opendir.  The type of the inode
   * determines the way that the readdir() operations are performed. For the
   * pseudo root pseudo-file system, it is also used to support rewind.
   *
   * We hold a reference on this inode so we know that it will persist until
   * closedir() is called (although inodes linked to this inode may change).
   */

  FAR struct inode *fd_root;

  /* The path name of current directory for FIOC_FILEPATH */

  FAR char *fd_path;
};

/* This structure is provided by devices when they are registered with the
 * system.  It is used to call back to perform device specific operations.
 */

struct file_operations
{
  /* The device driver open method differs from the mountpoint open method */

  CODE int     (*open)(FAR struct file *filep);

  /* The following methods must be identical in signature and position
   * because the struct file_operations and struct mountpt_operations are
   * treated like unions.
   */

  CODE int     (*close)(FAR struct file *filep);
  CODE ssize_t (*read)(FAR struct file *filep, FAR char *buffer,
                       size_t buflen);
  CODE ssize_t (*write)(FAR struct file *filep, FAR const char *buffer,
                        size_t buflen);
  CODE off_t   (*seek)(FAR struct file *filep, off_t offset, int whence);
  CODE int     (*ioctl)(FAR struct file *filep, int cmd, unsigned long arg);
  CODE int     (*mmap)(FAR struct file *filep,
                       FAR struct mm_map_entry_s *map);
  CODE int     (*truncate)(FAR struct file *filep, off_t length);

  CODE int     (*poll)(FAR struct file *filep, FAR struct pollfd *fds,
                       bool setup);
  CODE ssize_t (*readv)(FAR struct file *filep, FAR struct uio *uio);
  CODE ssize_t (*writev)(FAR struct file *filep, FAR struct uio *uio);

  /* The two structures need not be common after this point */

#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  CODE int     (*unlink)(FAR struct inode *inode);
#endif
};

/* This structure provides information about the state of a block driver */

#ifndef CONFIG_DISABLE_MOUNTPOINT
/* This structure is provided by block devices when they register with the
 * system.  It is used by file systems to perform filesystem transfers.  It
 * differs from the normal driver vtable in several ways -- most notably in
 * that it deals in struct inode vs. struct filep.
 */

struct inode;
struct block_operations
{
  CODE int     (*open)(FAR struct inode *inode);
  CODE int     (*close)(FAR struct inode *inode);
  CODE ssize_t (*read)(FAR struct inode *inode, FAR unsigned char *buffer,
                       blkcnt_t start_sector, unsigned int nsectors);
  CODE ssize_t (*write)(FAR struct inode *inode,
                        FAR const unsigned char *buffer,
                        blkcnt_t start_sector, unsigned int nsectors);
  CODE int     (*geometry)(FAR struct inode *inode,
                           FAR struct geometry *geometry);
  CODE int     (*ioctl)(FAR struct inode *inode, int cmd, unsigned long arg);
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  CODE int     (*unlink)(FAR struct inode *inode);
#endif
};

/* This structure is provided by a filesystem to describe a mount point.
 * Note that this structure differs from file_operations ONLY in the form of
 * the open method.  Once the file is opened, it can be accessed either as a
 * struct file_operations or struct mountpt_operations
 */

struct mountpt_operations
{
  /* The mountpoint open method differs from the driver open method
   * because it receives (1) the inode that contains the mountpoint
   * private data, (2) the relative path into the mountpoint, and (3)
   * information to manage privileges.
   */

  CODE int     (*open)(FAR struct file *filep, FAR const char *relpath,
                       int oflags, mode_t mode);

  /* The following methods must be identical in signature and position
   * because the struct file_operations and struct mountpt_operations are
   * treated like unions.
   */

  CODE int     (*close)(FAR struct file *filep);
  CODE ssize_t (*read)(FAR struct file *filep, FAR char *buffer,
                       size_t buflen);
  CODE ssize_t (*write)(FAR struct file *filep, FAR const char *buffer,
                        size_t buflen);
  CODE off_t   (*seek)(FAR struct file *filep, off_t offset, int whence);
  CODE int     (*ioctl)(FAR struct file *filep, int cmd, unsigned long arg);
  CODE int     (*mmap)(FAR struct file *filep,
                       FAR struct mm_map_entry_s *map);
  CODE int     (*truncate)(FAR struct file *filep, off_t length);
  CODE int     (*poll)(FAR struct file *filep, FAR struct pollfd *fds,
                       bool setup);
  CODE ssize_t (*readv)(FAR struct file *filep, FAR struct uio *uio);
  CODE ssize_t (*writev)(FAR struct file *filep, FAR struct uio *uio);

  /* The two structures need not be common after this point. The following
   * are extended methods needed to deal with the unique needs of mounted
   * file systems.
   *
   * Additional open-file-specific mountpoint operations:
   */

  CODE int     (*sync)(FAR struct file *filep);
  CODE int     (*dup)(FAR const struct file *oldp, FAR struct file *newp);
  CODE int     (*fstat)(FAR const struct file *filep, FAR struct stat *buf);
  CODE int     (*fchstat)(FAR const struct file *filep,
                          FAR const struct stat *buf, int flags);

  /* Directory operations */

  CODE int     (*opendir)(FAR struct inode *mountpt, FAR const char *relpath,
                          FAR struct fs_dirent_s **dir);
  CODE int     (*closedir)(FAR struct inode *mountpt,
                           FAR struct fs_dirent_s *dir);
  CODE int     (*readdir)(FAR struct inode *mountpt,
                          FAR struct fs_dirent_s *dir,
                          FAR struct dirent *entry);
  CODE int     (*rewinddir)(FAR struct inode *mountpt,
                            FAR struct fs_dirent_s *dir);

  /* General volume-related mountpoint operations: */

  CODE int     (*bind)(FAR struct inode *blkdriver, FAR const void *data,
                       FAR void **handle);
  CODE int     (*unbind)(FAR void *handle, FAR struct inode **blkdriver,
                         unsigned int flags);
  CODE int     (*statfs)(FAR struct inode *mountpt, FAR struct statfs *buf);

  /* Operations on paths */

  CODE int     (*unlink)(FAR struct inode *mountpt, FAR const char *relpath);
  CODE int     (*mkdir)(FAR struct inode *mountpt, FAR const char *relpath,
                        mode_t mode);
  CODE int     (*rmdir)(FAR struct inode *mountpt, FAR const char *relpath);
  CODE int     (*rename)(FAR struct inode *mountpt,
                         FAR const char *oldrelpath,
                         FAR const char *newrelpath);
  CODE int     (*stat)(FAR struct inode *mountpt, FAR const char *relpath,
                       FAR struct stat *buf);
  CODE int     (*chstat)(FAR struct inode *mountpt, FAR const char *relpath,
                         FAR const struct stat *buf, int flags);
  CODE int     (*syncfs)(FAR struct inode *mountpt);
};
#endif /* CONFIG_DISABLE_MOUNTPOINT */

/* Named OS resources are also maintained by the VFS.  This includes:
 *
 *   - Named semaphores:     sem_open(), sem_close(), and sem_unlink()
 *   - POSIX Message Queues: mq_open() and mq_close()
 *   - Shared memory:        shm_open() and shm_unlink();
 *
 * These are a special case in that they do not follow quite the same
 * pattern as the other file system types in that they have operations.
 */

/* These are the various kinds of operations that can be associated with
 * an inode.
 */

union inode_ops_u
{
  FAR const struct file_operations     *i_ops;    /* Driver operations for inode */
#ifndef CONFIG_DISABLE_MOUNTPOINT
  FAR const struct block_operations    *i_bops;   /* Block driver operations */
  FAR struct mtd_dev_s                 *i_mtd;    /* MTD device driver */
  FAR const struct mountpt_operations  *i_mops;   /* Operations on a mountpoint */
#endif
#ifdef CONFIG_FS_NAMED_SEMAPHORES
  FAR struct nsem_inode_s              *i_nsem;   /* Named semaphore */
#endif
#ifdef CONFIG_FS_NAMED_EVENTS
  FAR struct nevent_inode_s            *i_nevent; /* Named event */
#endif
#ifdef CONFIG_PSEUDOFS_SOFTLINKS
  FAR char                             *i_link;   /* Full path to link target */
#endif
};

/* This structure represents one inode in the NuttX pseudo-file system */

struct inode
{
  FAR struct inode *i_parent;   /* Link to parent level inode */
  FAR struct inode *i_peer;     /* Link to same level inode */
  FAR struct inode *i_child;    /* Link to lower level inode */
  atomic_t          i_crefs;    /* References to inode */
  uint16_t          i_flags;    /* Flags for inode */
  union inode_ops_u u;          /* Inode operations */
  ino_t             i_ino;      /* Inode serial number */
  size_t            i_size;     /* The size of per inode driver */
#ifdef CONFIG_PSEUDOFS_ATTRIBUTES
  mode_t            i_mode;     /* Access mode flags */
  uid_t             i_owner;    /* Owner */
  gid_t             i_group;    /* Group */
  struct timespec   i_atime;    /* Time of last access */
  struct timespec   i_mtime;    /* Time of last modification */
  struct timespec   i_ctime;    /* Time of last status change */
#endif
  FAR void         *i_private;  /* Per inode driver private data */
  char              i_name[1];  /* Name of inode (variable) */
};

#define FSNODE_SIZE(n) (sizeof(struct inode) + (n))

/* Definitions for custom stream operations with fopencookie. The
 * implementation is as defined in Standard C library (libc). The only
 * difference is that we use off_t instead of off64_t. This means
 * off_t is int64_t if CONFIG_FS_LARGEFILE is defined and int32_t if not.
 *
 * These callbacks can either lead to custom functions if fopencookie is used
 * or to standard file system functions if not.
 */

typedef CODE ssize_t cookie_read_function_t(FAR void *cookie, FAR char *buf,
                                            size_t size);
typedef CODE ssize_t cookie_write_function_t(FAR void *cookie,
                                             FAR const char *buf,
                                             size_t size);
typedef CODE off_t cookie_seek_function_t(FAR void *cookie,
                                          FAR off_t *offset,
                                          int whence);
typedef CODE int cookie_close_function_t(FAR void *cookie);

typedef struct cookie_io_functions_t
{
  FAR cookie_read_function_t *read;
  FAR cookie_write_function_t *write;
  FAR cookie_seek_function_t *seek;
  FAR cookie_close_function_t *close;
} cookie_io_functions_t;

/* This is the underlying representation of an open file.  A file
 * descriptor is an index into an array of such types. The type associates
 * the file descriptor to the file state and to a set of inode operations.
 */

struct file
{
  int               f_oflags;   /* Open mode flags */
  atomic_t          f_refs;     /* Reference count */
  off_t             f_pos;      /* File position */
  FAR struct inode *f_inode;    /* Driver or file system interface */
  FAR void         *f_priv;     /* Per file driver private data */
#if CONFIG_FS_LOCK_BUCKET_SIZE > 0
  bool              f_locked;   /* Filelock state: false - unlocked, true - locked */
#endif
};

struct fd
{
  FAR struct file  *f_file;      /* The file associated with descriptor */
  bool              f_cloexec;   /* Close on exec */
#ifdef CONFIG_FDCHECK
  uint8_t           f_tag_fdcheck; /* File owner fdcheck tag, init to 0 */
#endif
  #ifdef CONFIG_FDSAN
  uint64_t          f_tag_fdsan; /* File owner fdsan tag, init to 0 */
#endif
#if CONFIG_FS_BACKTRACE > 0
  FAR void         *f_backtrace[CONFIG_FS_BACKTRACE]; /* Backtrace to while file opens */
#endif
};

/* This defines a two layer array of files indexed by the file descriptor.
 * Each row of this array is fixed size: CONFIG_NFILE_DESCRIPTORS_PER_BLOCK.
 * You can get file instance in filelist by the follow methods:
 * (file descriptor / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK) as row index and
 * (file descriptor % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK) as column index.
 */

struct fdlist
{
  spinlock_t        fl_lock;    /* Manage access to the file descriptor list */
  uint8_t           fl_rows;    /* The number of rows of fl_fds array */
  FAR struct fd   **fl_fds;     /* The pointer of two layer file descriptors array */

  /* Pre-allocated file descriptors to avoid allocator access during thread
   * creation phase, For functional safety requirements, increasing
   * CONFIG_NFILE_DESCRIPTORS_PER_BLOCK could also avoid allocator access
   * caused by the file descriptor exceeding the limit.
   */

  FAR struct fd    *fl_prefd;
  struct fd         fl_prefds[CONFIG_NFILE_DESCRIPTORS_PER_BLOCK];
};

/* The following structure defines the list of files used for standard C I/O.
 * Note that NuttX can support the standard C APIs with or without buffering
 *
 * When buffering is used, the following describes the usage of the I/O
 * buffer.
 * The buffer can be used for reading or writing -- but not both at the same
 * time.
 * An fflush is implied between each change in direction of access.
 *
 * The field fs_bufread determines whether the buffer is being used for
 * reading or for writing as follows:
 *
 *              BUFFER
 *     +----------------------+ <- fs_bufstart Points to the beginning of
 *     |                      |    the buffer.
 *     | WR: Buffered data    |                WR: Start of buffered write
 *     |                      |                    data.
 *     | RD: Already read     |                RD: Start of already read
 *     |                      |                    data.
 *     +----------------------+
 *     | WR: Available buffer | <- fs_bufpos   Points to next byte:
 *     | RD: Read-ahead data  |                WR: End+1 of buffered write
 *     |                      |                    data.
 *     |                      |                RD: Points to next char to
 *     |                      |                    return
 *     +----------------------+
 *     | WR: Available        | <- fs_bufread  Top+1 of buffered read data
 *     | RD: Available        |                WR: bufstart buffer used for
 *     |                      |                    writing.
 *     |                      |                RD: Pointer to last buffered
 *     |                      |                    read char+1
 *     +----------------------+
 *                              <- fs_bufend   Points to the end of the
 *                                             buffer+1
 */

#ifdef CONFIG_FILE_STREAM
struct file_struct
{
  sq_entry_t              fs_entry;     /* Entry of file stream */
  rmutex_t                fs_lock;      /* Recursive lock */
  cookie_io_functions_t   fs_iofunc;    /* Callbacks to user / system functions */
  FAR void               *fs_cookie;    /* Pointer to file descriptor / cookie struct */
#ifndef CONFIG_STDIO_DISABLE_BUFFERING
  FAR char               *fs_bufstart;  /* Pointer to start of buffer */
  FAR char               *fs_bufend;    /* Pointer to 1 past end of buffer */
  FAR char               *fs_bufpos;    /* Current position in buffer */
  FAR char               *fs_bufread;   /* Pointer to 1 past last buffered read char. */
#  if CONFIG_STDIO_BUFFER_SIZE > 0
  char                    fs_buffer[CONFIG_STDIO_BUFFER_SIZE];
#  endif
#endif
  uint16_t                fs_oflags;    /* Open mode flags */
  uint8_t                 fs_flags;     /* Stream flags */
#if CONFIG_NUNGET_CHARS > 0
  uint8_t                 fs_nungotten; /* The number of characters buffered for ungetc */
  char                    fs_ungotten[CONFIG_NUNGET_CHARS];
#endif
};

struct streamlist
{
  mutex_t                 sl_lock;   /* For thread safety */
  struct file_struct      sl_std[3];
  sq_queue_t              sl_queue;
};
#endif /* CONFIG_FILE_STREAM */

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif

/****************************************************************************
 * Name: fs_initialize
 *
 * Description:
 *   This is called from the OS initialization logic to configure the file
 *   system.
 *
 ****************************************************************************/

void fs_initialize(void);

/****************************************************************************
 * Name: register_driver
 *
 * Description:
 *   Register a character driver inode the pseudo file system.
 *
 * Input Parameters:
 *   path - The path to the inode to create
 *   fops - The file operations structure
 *   mode - Access privileges
 *   priv - Private, user data that will be associated with the inode.
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on a failure (all error values returned by
 *   inode_reserve):
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 ****************************************************************************/

int register_driver(FAR const char *path,
                    FAR const struct file_operations *fops, mode_t mode,
                    FAR void *priv);

/****************************************************************************
 * Name: register_driver_with_size
 *
 * Description:
 *   Register a character driver inode into the pseudo file system and
 *   assign a size to it.
 *
 * Input Parameters:
 *   path - The path to the inode to create
 *   fops - The file operations structure
 *   mode - inmode privileges
 *   priv - Private, user data that will be associated with the inode.
 *   size - Size in bytes to assign to the driver
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on a failure (all error values returned by
 *   inode_reserve):
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 ****************************************************************************/

int register_driver_with_size(FAR const char *path,
                              FAR const struct file_operations *fops,
                              mode_t mode, FAR void *priv, size_t size);

/****************************************************************************
 * Name: register_blockdriver
 *
 * Description:
 *   Register a block driver inode the pseudo file system.
 *
 * Input Parameters:
 *   path - The path to the inode to create
 *   bops - The block driver operations structure
 *   mode - Access privileges
 *   priv - Private, user data that will be associated with the inode.
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on a failure (all error values returned by
 *   inode_reserve):
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 ****************************************************************************/

#ifndef CONFIG_DISABLE_MOUNTPOINT
int register_blockdriver(FAR const char *path,
                         FAR const struct block_operations *bops,
                         mode_t mode, FAR void *priv);
#endif

/****************************************************************************
 * Name: register_merge_blockdriver
 *
 * Description:
 *   This function registers a block driver that presents a contiguous block
 * device composed of multiple, non-contiguous partitions.  The partitions
 * are specified by the variable argument list which has 'nparts' elements.
 *
 * Input Parameters:
 *   merge - The partition name to be merged.
 *   ...   - The variable argument list for partition names.
 *
 *  Usage example for merging the factory partition and reserve partition
 *  into the merge partition:
 *
 * register_merge_blockdriver("/dev/merge", "/dev/factory",
 *                            "/dev/reserve", NULL);
 *
 * Returned Value:
 *   Zero on success;
 *   Negated errno value is returned on a failure
 *
 ****************************************************************************/

#ifndef CONFIG_DISABLE_MOUNTPOINT
int register_merge_blockdriver(FAR const char *merge, ...);
#endif

/****************************************************************************
 * Name: register_blockpartition
 *
 * Description:
 *   Register a block partition driver inode the pseudo file system.
 *
 * Input Parameters:
 *   partition   - The path to the partition inode
 *   parent      - The path to the parent inode
 *   firstsector - The offset in sectors to the partition
 *   nsectors    - The number of sectors in the partition
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on a failure (all error values returned by
 *   inode_reserve):
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 ****************************************************************************/

#ifndef CONFIG_DISABLE_MOUNTPOINT
int register_blockpartition(FAR const char *partition,
                            mode_t mode, FAR const char *parent,
                            off_t firstsector, off_t nsectors);
#endif

/****************************************************************************
 * Name: unregister_driver
 *
 * Description:
 *   Remove the character driver inode at 'path' from the pseudo-file system
 *
 ****************************************************************************/

int unregister_driver(FAR const char *path);

/****************************************************************************
 * Name: unregister_blockdriver
 *
 * Description:
 *   Remove the block driver inode at 'path' from the pseudo-file system
 *
 ****************************************************************************/

int unregister_blockdriver(FAR const char *path);

/****************************************************************************
 * Name: register_mtddriver
 *
 * Description:
 *   Register an MTD driver inode the pseudo file system.
 *
 * Input Parameters:
 *   path - The path to the inode to create
 *   mtd  - The MTD driver structure
 *   mode - inode privileges
 *   priv - Private, user data that will be associated with the inode.
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on a failure (all error values returned by
 *   inode_reserve):
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 ****************************************************************************/

#ifdef CONFIG_MTD
int register_mtddriver(FAR const char *path, FAR struct mtd_dev_s *mtd,
                       mode_t mode, FAR void *priv);
#endif

/****************************************************************************
 * Name: register_mtdpartition
 *
 * Description:
 *   Register a mtd partition driver inode the pseudo file system.
 *
 * Input Parameters:
 *   partition  - The path to the partition inode
 *   parent     - The path to the parent inode
 *   firstblock - The offset in block to the partition
 *   nblocks    - The number of block in the partition
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on a failure (all error values returned by
 *   inode_reserve):
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 ****************************************************************************/

#ifdef CONFIG_MTD
int register_mtdpartition(FAR const char *partition,
                          mode_t mode, FAR const char *parent,
                          off_t firstblock, off_t nblocks);
#endif

/****************************************************************************
 * Name: unregister_mtddriver
 *
 * Description:
 *   Remove the named TMD driver inode at 'path' from the pseudo-file system
 *
 ****************************************************************************/

#ifdef CONFIG_MTD
int unregister_mtddriver(FAR const char *path);
#endif

#ifdef CONFIG_PIPES

/****************************************************************************
 * Name: register_pipedriver
 *
 * Description:
 *   Register a pipe driver inode the pseudo file system.
 *
 * Input Parameters:
 *   path - The path to the inode to create
 *   fops - The file operations structure
 *   mode - inmode privileges
 *   priv - Private, user data that will be associated with the inode.
 *
 * Returned Value:
 *   Zero on success (with the inode point in 'inode'); A negated errno
 *   value is returned on a failure (all error values returned by
 *   inode_reserve):
 *
 *   EINVAL - 'path' is invalid for this operation
 *   EEXIST - An inode already exists at 'path'
 *   ENOMEM - Failed to allocate in-memory resources for the operation
 *
 ****************************************************************************/

int register_pipedriver(FAR const char *path,
                        FAR const struct file_operations *fops,
                        mode_t mode, FAR void *priv);

/****************************************************************************
 * Name: unregister_pipedriver
 *
 * Description:
 *   Remove the pipe driver inode at 'path' from the pseudo-file system
 *
 ****************************************************************************/

int unregister_pipedriver(FAR const char *path);

#endif /* CONFIG_PIPES */

/****************************************************************************
 * Name: nx_mount
 *
 * Description:
 *   nx_mount() is similar to the standard 'mount' interface except that is
 *   not a cancellation point and it does not modify the errno variable.
 *
 *   nx_mount() is an internal NuttX interface and should not be called from
 *   applications.
 *
 * Returned Value:
 *   Zero is returned on success; a negated value is returned on any failure.
 *
 ****************************************************************************/

#ifndef CONFIG_DISABLE_MOUNTPOINT
int nx_mount(FAR const char *source, FAR const char *target,
             FAR const char *filesystemtype, unsigned long mountflags,
             FAR const void *data);
#endif

/****************************************************************************
 * Name: nx_umount2
 *
 * Description:
 *   nx_umount2() is similar to the standard 'umount2' interface except that
 *   is not a cancellation point and it does not modify the errno variable.
 *
 *   nx_umount2() is an internal NuttX interface and should not be called
 *   from applications.
 *
 * Returned Value:
 *   Zero is returned on success; a negated value is returned on any failure.
 *
 ****************************************************************************/

#ifndef CONFIG_DISABLE_MOUNTPOINT
int nx_umount2(FAR const char *target, unsigned int flags);
#endif

/****************************************************************************
 * Name: fdlist_init
 *
 * Description:
 *   Initializes the list of file descriptors for a new task.
 *
 ****************************************************************************/

void fdlist_init(FAR struct fdlist *list);

/****************************************************************************
 * Name: fdlist_dump
 *
 * Description:
 *   Dump the list of file descriptors.
 *
 ****************************************************************************/

#ifdef CONFIG_SCHED_DUMP_ON_EXIT
void fdlist_dump(FAR struct fdlist *list);
#else
#  define fdlist_dump(l)
#endif

/****************************************************************************
 * Name: fdlist_free
 *
 * Description:
 *   Release the list of file descriptors.
 *
 * Assumptions:
 *   Called during task deletion in a safe context.
 *
 ****************************************************************************/

void fdlist_free(FAR struct fdlist *list);

/****************************************************************************
 * Name: fdlist_count
 *
 * Description:
 *   Get file descriptor count from file list.
 *
 * Input Parameters:
 *   list - Pointer to the file descriptor list structure.
 *
 * Returned Value:
 *   file descriptor count of file list.
 *
 ****************************************************************************/

int fdlist_count(FAR struct fdlist *list);

/****************************************************************************
 * Name: fdlist_copy
 *
 * Description:
 *   Copy parent task's file descriptors to child task.
 *
 * Returned Value:
 *   Zero (OK) is returned on success; a negated errno value is returned on
 *   any failure.
 *
 ****************************************************************************/

int fdlist_copy(FAR struct fdlist *plist, FAR struct fdlist *clist,
                FAR const posix_spawn_file_actions_t *actions,
                bool cloexec);

/****************************************************************************
 * Name: fdlist_get2
 *
 * Description:
 *   Given a file descriptor, return the corresponding instance of struct
 *   fd and filep.
 *
 * Input Parameters:
 *   list - Pointer to the file descriptor list structure.
 *   fd    - The file descriptor
 *   filep - The location to return the struct file instance
 *   fdp   - The location to return the struct fd instance
 *
 * Returned Value:
 *   Return the pointer to file structure of list[fd] when list[fd].f_file
 *   is valid, othersize, a null pointer is returned.
 *
 ****************************************************************************/

int fdlist_get2(FAR struct fdlist *list, int fd,
                FAR struct file **filep, FAR struct fd **fdp);

/****************************************************************************
 * Name: fdlist_get
 *
 * Description:
 *   Given a file descriptor, return the corresponding instance of struct
 *   filep.
 *
 * Input Parameters:
 *   list  - Pointer to the file descriptor list structure.
 *   fd    - The file descriptor
 *   filep - The location to return the struct file instance
 *
 * Returned Value:
 *   Return the pointer to file structure of list[fd] when list[fd].f_file
 *   is valid, othersize, a null pointer is returned.
 *
 ****************************************************************************/

#define fdlist_get(list, fd, filep) fdlist_get2(list, fd, filep, NULL)

/****************************************************************************
 * Name: fdlist_dupfile
 *
 * Description:
 *   Allocate a struct fd instance and bind it to the corresponding file
 *   handle.
 *
 * Returned Value:
 *   Returns the file descriptor == index into the files array on success;
 *   a negated errno value is returned on any failure.
 *
 ****************************************************************************/

int fdlist_dupfile(FAR struct fdlist *list, int oflags, int minfd,
                   FAR struct file *filep);

/****************************************************************************
 * Name: file_allocate_from_inode
 *
 * Description:
 *   Allocate a struct fd instance and associate it with an file instance.
 *   And initialize them with inode, oflags, pos and priv.
 *
 * Returned Value:
 *   Returns the file descriptor == index into the files array on success;
 *   a negated errno value is returned on any failure.
 *
 ****************************************************************************/

int file_allocate_from_inode(FAR struct inode *inode, int oflags, off_t pos,
                             FAR void *priv, int minfd);

/****************************************************************************
 * Name: file_dup
 *
 * Description:
 *   Equivalent to the standard dup() function except that it
 *   accepts a struct file instance instead of a file descriptor.
 *
 * Returned Value:
 *   Zero (OK) is returned on success; a negated errno value is returned on
 *   any failure.
 *
 ****************************************************************************/

int file_dup(FAR struct file *filep, int minfd, int flags);

/****************************************************************************
 * Name: file_dup2
 *
 * Description:
 *   Assign an inode to a specific files structure.  This is the heart of
 *   dup2.
 *
 *   Equivalent to the non-standard dup2() function except that it
 *   accepts struct file instances instead of file descriptors.
 *
 * Returned Value:
 *   Zero (OK) is returned on success; a negated errno value is return on
 *   any failure.
 *
 ****************************************************************************/

int file_dup2(FAR struct file *filep1, FAR struct file *filep2);

/****************************************************************************
 * Name: fdlist_dup3
 *
 * Description:
 *   fdlist_dup3() is similar to the standard 'dup3' interface
 *   except that is not a cancellation point and it does not modify the
 *   errno variable.
 *
 *   fdlist_dup3() is an internal NuttX interface and should not be
 *   called from applications.
 *
 *   Clone a file descriptor to a specific descriptor number.
 *
 * Returned Value:
 *   fd2 is returned on success; a negated errno value is return on
 *   any failure.
 *
 ****************************************************************************/

int fdlist_dup3(FAR struct fdlist *list, int fd1, int fd2, int flags);

/****************************************************************************
 * Name: fdlist_dup2
 *
 * Description:
 *   fdlist_dup2() is similar to the standard 'dup2' interface
 *   except that is not a cancellation point and it does not modify the
 *   errno variable.
 *
 *   fdlist_dup2() is an internal NuttX interface and should not be
 *   called from applications.
 *
 *   Clone a file descriptor to a specific descriptor number.
 *
 * Returned Value:
 *   fd2 is returned on success; a negated errno value is return on
 *   any failure.
 *
 ****************************************************************************/

int fdlist_dup2(FAR struct fdlist *list, int fd1, int fd2);

/****************************************************************************
 * Name: nx_dup2
 *
 * Description:
 *   nx_dup2() is similar to the standard 'dup2' interface except that is
 *   not a cancellation point and it does not modify the errno variable.
 *
 *   nx_dup2() is an internal NuttX interface and should not be called from
 *   applications.
 *
 * Returned Value:
 *   fd2 is returned on success; a negated errno value is return on
 *   any failure.
 *
 ****************************************************************************/

int nx_dup2(int fd1, int fd2);

/****************************************************************************
 * Name: file_open
 *
 * Description:
 *   file_open() is similar to the standard 'open' interface except that it
 *   returns an instance of 'struct file' rather than a file descriptor.  It
 *   also is not a cancellation point and does not modify the errno variable.
 *
 * Input Parameters:
 *   filep  - The caller provided location in which to return the 'struct
 *            file' instance.
 *   path   - The full path to the file to be open.
 *   oflags - open flags
 *   ...    - Variable number of arguments, may include 'mode_t mode'
 *
 * Returned Value:
 *   Zero (OK) is returned on success.  On failure, a negated errno value is
 *   returned.
 *
 ****************************************************************************/

int file_open(FAR struct file *filep, FAR const char *path, int oflags, ...);

/****************************************************************************
 * Name: fdlist_open
 *
 * Description:
 *   fdlist_open() is similar to the standard 'open' interface except
 *   that it is not a cancellation point and it does not modify the errno
 *   variable.
 *
 *   fdlist_open() is an internal NuttX interface and should not be
 *   called from applications.
 *
 * Input Parameters:
 *   list   - Pointer to the file descriptor list structure.
 *   path   - The full path to the file to be opened.
 *   oflags - open flags.
 *   ...    - Variable number of arguments, may include 'mode_t mode'
 *
 * Returned Value:
 *   The new file descriptor is returned on success; a negated errno value is
 *   returned on any failure.
 *
 ****************************************************************************/

int fdlist_open(FAR struct fdlist *list,
                FAR const char *path, int oflags, ...);

/****************************************************************************
 * Name: nx_open
 *
 * Description:
 *   nx_open() is similar to the standard 'open' interface except that is is
 *   not a cancellation point and it does not modify the errno variable.
 *
 *   nx_open() is an internal NuttX interface and should not be called
 *   from applications.
 *
 * Returned Value:
 *   The new file descriptor is returned on success; a negated errno value is
 *   returned on any failure.
 *
 ****************************************************************************/

int nx_open(FAR const char *path, int oflags, ...);

/****************************************************************************
 * Name: file_allocate
 *
 * Description:
 *   Allocate a file instance and return
 *
 ****************************************************************************/

FAR struct file *file_allocate(void);

/****************************************************************************
 * Name: file_deallocate
 *
 * Description:
 *   Free a file instance.
 *
 ****************************************************************************/

void file_deallocate(FAR struct file *filep);

/****************************************************************************
 * Name: file_get2
 *
 * Description:
 *   Given a file descriptor, return the corresponding instance of struct
 *   fd and filep
 *
 * Input Parameters:
 *   fd    - The file descriptor
 *   filep - The location to return the struct file instance
 *   fdp   - The location to return the struct fd instance
 *
 * Returned Value:
 *   Zero (OK) is returned on success; a negated errno value is returned on
 *   any failure.
 *
 ****************************************************************************/

int file_get2(int fd, FAR struct file **filep, FAR struct fd **fdp);

/****************************************************************************
 * Name: file_get
 *
 * Description:
 *   Given a file descriptor, return the corresponding instance of struct
 *   file.  NOTE that this function will currently fail if it is provided
 *   with a socket descriptor.
 *
 * Input Parameters:
 *   fd    - The file descriptor
 *   filep - The location to return the struct file instance
 *
 * Returned Value:
 *   Zero (OK) is returned on success; a negated errno value is returned on
 *   any failure.
 *
 ****************************************************************************/

#define file_get(fd, filep) file_get2(fd, filep, NULL)

/****************************************************************************
 * Name: file_ref
 *
 * Description:
 *   To specify filep increase the reference count.
 *
 * Input Parameters:
 *   None.
 *
 * Returned Value:
 *   None.
 *
 ****************************************************************************/

void file_ref(FAR struct file *filep);

/****************************************************************************
 * Name: file_put
 *
 * Description:
 *   Release reference counts for files, less than or equal to 0 and close
 *   the file
 *
 * Input Parameters:
 *   filep  - The caller provided location in which to return the 'struct
 *            file' instance.
 *
 ****************************************************************************/

int file_put(FAR struct file *filep);

/****************************************************************************
 * Name: file_close
 *
 * Description:
 *   Close a file that was previously opened with file_open().
 *
 * Input Parameters:
 *   filep - A pointer to a user provided memory location containing the
 *           open file data returned by file_open().
 *
 * Returned Value:
 *   Zero (OK) is returned on success; A negated errno value is returned on
 *   any failure to indicate the nature of the failure.
 *
 ****************************************************************************/

int file_close(FAR struct file *filep);

/****************************************************************************
 * Name: fdlist_close
 *
 * Description:
 *   fdlist_close() is similar to the standard 'close' interface
 *   except that is not a cancellation point and it does not modify the
 *   errno variable.
 *
 *   fdlist_close() is an internal NuttX interface and should not
 *   be called from applications.
 *
 *   Close an inode (if open)
 *
 * Returned Value:
 *   Zero (OK) is returned on success; A negated errno value is returned on
 *   on any failure.
 *
 * Assumptions:
 *   Caller holds the list mutex because the file descriptor will be
 *   freed.
 *
 ****************************************************************************/

int fdlist_close(FAR struct fdlist *list, int fd);

/****************************************************************************
 * Name: nx_close
 *
 * Description:
 *   nx_close() is similar to the standard 'close' interface except that is
 *   not a cancellation point and it does not modify the errno variable.
 *
 *   nx_close() is an internal NuttX interface and should not be called from
 *   applications.
 *
 * Returned Value:
 *   The new file descriptor is returned on success; a negated errno value is
 *   returned on any failure.
 *
 ****************************************************************************/

int nx_close(int fd);

/****************************************************************************
 * Name: find_driver
 *
 * Description:
 *   Returns the pointer of a registered driver specified by 'pathname'
 *
 * Input Parameters:
 *   pathname - the full path to the driver's device node in file system
 *
 * Returned Value:
 *   Pointer to driver's registered private pointer or NULL if not found.
 *
 ****************************************************************************/

FAR void *find_driver(FAR const char *pathname);

/****************************************************************************
 * Name: open_blockdriver
 *
 * Description:
 *   Return the inode of the block driver specified by 'pathname'
 *
 * Input Parameters:
 *   pathname - the full path to the block driver to be opened
 *   mountflags - if MS_RDONLY is not set, then driver must support write
 *     operations (see include/sys/mount.h)
 *   ppinode - address of the location to return the inode reference
 *
 * Returned Value:
 *   Returns zero on success or a negated errno on failure:
 *
 *   EINVAL  - pathname or pinode is NULL
 *   ENOENT  - No block driver of this name is registered
 *   ENOTBLK - The inode associated with the pathname is not a block driver
 *   EACCESS - The MS_RDONLY option was not set but this driver does not
 *     support write access
 *
 ****************************************************************************/

int open_blockdriver(FAR const char *pathname, int mountflags,
                     FAR struct inode **ppinode);

/****************************************************************************
 * Name: close_blockdriver
 *
 * Description:
 *   Call the close method and release the inode
 *
 * Input Parameters:
 *   inode - reference to the inode of a block driver opened by
 *           open_blockdriver
 *
 * Returned Value:
 *   Returns zero on success or a negated errno on failure:
 *
 *   EINVAL  - inode is NULL
 *   ENOTBLK - The inode is not a block driver
 *
 ****************************************************************************/

int close_blockdriver(FAR struct inode *inode);

/****************************************************************************
 * Name: find_blockdriver
 *
 * Description:
 *   Return the inode of the block driver specified by 'pathname'
 *
 * Input Parameters:
 *   pathname   - The full path to the block driver to be located
 *   mountflags - If MS_RDONLY is not set, then driver must support write
 *                operations (see include/sys/mount.h)
 *   ppinode    - Address of the location to return the inode reference
 *
 * Returned Value:
 *   Returns zero on success or a negated errno on failure:
 *
 *   ENOENT  - No block driver of this name is registered
 *   ENOTBLK - The inode associated with the pathname is not a block driver
 *   EACCESS - The MS_RDONLY option was not set but this driver does not
 *             support write access
 *
 ****************************************************************************/

int find_blockdriver(FAR const char *pathname, int mountflags,
                     FAR struct inode **ppinode);

/****************************************************************************
 * Name: find_mtddriver
 *
 * Description:
 *   Return the inode of the named MTD driver specified by 'pathname'
 *
 * Input Parameters:
 *   pathname   - the full path to the named MTD driver to be located
 *   ppinode    - address of the location to return the inode reference
 *
 * Returned Value:
 *   Returns zero on success or a negated errno on failure:
 *
 *   ENOENT  - No MTD driver of this name is registered
 *   ENOTBLK - The inode associated with the pathname is not an MTD driver
 *
 ****************************************************************************/

int find_mtddriver(FAR const char *pathname, FAR struct inode **ppinode);

/****************************************************************************
 * Name: close_mtddriver
 *
 * Description:
 *   Release the inode got by function find_mtddriver()
 *
 * Input Parameters:
 *   pinode    - pointer to the inode
 *
 * Returned Value:
 *   Returns zero on success or a negated errno on failure:
 *
 *   EINVAL  - inode is NULL
 *
 ****************************************************************************/

int close_mtddriver(FAR struct inode *pinode);

/****************************************************************************
 * Name: file_read
 *
 * Description:
 *   file_read() is an internal OS interface.  It is functionally similar to
 *   the standard read() interface except:
 *
 *    - It does not modify the errno variable,
 *    - It is not a cancellation point,
 *    - It does not handle socket descriptors, and
 *    - It accepts a file structure instance instead of file descriptor.
 *
 * Input Parameters:
 *   filep  - File structure instance
 *   buf    - User-provided to save the data
 *   nbytes - The maximum size of the user-provided buffer
 *
 * Returned Value:
 *   The positive non-zero number of bytes read on success, 0 on if an
 *   end-of-file condition, or a negated errno value on any failure.
 *
 ****************************************************************************/

ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes);
ssize_t file_readv(FAR struct file *filep,
                   FAR const struct iovec *iov, int iovcnt);

/****************************************************************************
 * Name: nx_read
 *
 * Description:
 *   nx_read() is an internal OS interface.  It is functionally similar to
 *   the standard read() interface except:
 *
 *    - It does not modify the errno variable, and
 *    - It is not a cancellation point.
 *
 * Input Parameters:
 *   fd     - File descriptor to read from
 *   buf    - User-provided to save the data
 *   nbytes - The maximum size of the user-provided buffer
 *
 * Returned Value:
 *   The positive non-zero number of bytes read on success, 0 on if an
 *   end-of-file condition, or a negated errno value on any failure.
 *
 ****************************************************************************/

ssize_t nx_read(int fd, FAR void *buf, size_t nbytes);
ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt);

/****************************************************************************
 * Name: file_write
 *
 * Description:
 *   Equivalent to the standard write() function except that is accepts a
 *   struct file instance instead of a file descriptor.  It is functionally
 *   equivalent to write() except that in addition to the differences in
 *   input parameters:
 *
 *  - It does not modify the errno variable,
 *  - It is not a cancellation point, and
 *  - It does not handle socket descriptors.
 *
 * Input Parameters:
 *   filep  - Instance of struct file to use with the write
 *   buf    - Data to write
 *   nbytes - Length of data to write
 *
 * Returned Value:
 *  On success, the number of bytes written are returned (zero indicates
 *  nothing was written).  On any failure, a negated errno value is returned
 *  (see comments withwrite() for a description of the appropriate errno
 *  values).
 *
 ****************************************************************************/

ssize_t file_write(FAR struct file *filep, FAR const void *buf,
                   size_t nbytes);
ssize_t file_writev(FAR struct file *filep,
                    FAR const struct iovec *iov, int iovcnt);

/****************************************************************************
 * Name: nx_write
 *
 * Description:
 *  nx_write() writes up to nbytes bytes to the file referenced by the file
 *  descriptor fd from the buffer starting at buf.  nx_write() is an
 *  internal OS function.  It is functionally equivalent to write() except
 *  that:
 *
 *  - It does not modify the errno variable, and
 *  - It is not a cancellation point.
 *
 * Input Parameters:
 *   fd     - file descriptor (or socket descriptor) to write to
 *   buf    - Data to write
 *   nbytes - Length of data to write
 *
 * Returned Value:
 *  On success, the number of bytes written are returned (zero indicates
 *  nothing was written).  On any failure, a negated errno value is returned
 *  (see comments with write() for a description of the appropriate errno
 *   values).
 *
 ****************************************************************************/

ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes);
ssize_t nx_writev(int fd, FAR const struct iovec *iov, int iovcnt);

/****************************************************************************
 * Name: file_pread
 *
 * Description:
 *   Equivalent to the standard pread function except that is accepts a
 *   struct file instance instead of a file descriptor.  Currently used
 *   only by aio_read();
 *
 ****************************************************************************/

ssize_t file_pread(FAR struct file *filep, FAR void *buf, size_t nbytes,
                   off_t offset);

/****************************************************************************
 * Name: file_pwrite
 *
 * Description:
 *   Equivalent to the standard pwrite function except that is accepts a
 *   struct file instance instead of a file descriptor.  Currently used
 *   only by aio_write();
 *
 ****************************************************************************/

ssize_t file_pwrite(FAR struct file *filep, FAR const void *buf,
                    size_t nbytes, off_t offset);

/****************************************************************************
 * Name: file_sendfile
 *
 * Description:
 *   Equivalent to the standard sendfile function except that is accepts a
 *   struct file instance instead of a file descriptor.
 *
 ****************************************************************************/

ssize_t file_sendfile(FAR struct file *outfile, FAR struct file *infile,
                      FAR off_t *offset, size_t count);

/****************************************************************************
 * Name: file_seek
 *
 * Description:
 *   Equivalent to the standard lseek() function except that is accepts a
 *   struct file instance instead of a file descriptor.  Currently used
 *   only by net_sendfile()
 *
 ****************************************************************************/

off_t file_seek(FAR struct file *filep, off_t offset, int whence);

/****************************************************************************
 * Name: nx_seek
 *
 * Description:
 *  nx_seek() function repositions the offset of the open file associated
 *  with the file descriptor fd to the argument 'offset' according to the
 *  directive 'whence'.  nx_seek() is an internal OS function. It is
 *  functionally equivalent to lseek() except that:
 *
 *  - It does not modify the errno variable, and
 *  - It is not a cancellation point.
 *
 ****************************************************************************/

off_t nx_seek(int fd, off_t offset, int whence);

/****************************************************************************
 * Name: file_fsync
 *
 * Description:
 *   Equivalent to the standard fsync() function except that is accepts a
 *   struct file instance instead of a file descriptor and it does not set
 *   the errno variable.
 *
 ****************************************************************************/

int file_fsync(FAR struct file *filep);

/****************************************************************************
 * Name: file_syncfs
 *
 * Description:
 *   Equivalent to the standard syncsf() function except that is accepts a
 *   struct file instance instead of a fd descriptor and it does not set
 *   the errno variable
 *
 ****************************************************************************/

int file_syncfs(FAR struct file *filep);

/****************************************************************************
 * Name: file_truncate
 *
 * Description:
 *   Equivalent to the standard ftruncate() function except that is accepts
 *   a struct file instance instead of a file descriptor and it does not set
 *   the errno variable.
 *
 ****************************************************************************/

int file_truncate(FAR struct file *filep, off_t length);

/****************************************************************************
 * Name: file_mmap
 *
 * Description:
 *   Equivalent to the standard mmap() function except that is accepts
 *   a struct file instance instead of a file descriptor and it does not set
 *   the errno variable.
 *
 ****************************************************************************/

int file_mmap(FAR struct file *filep, FAR void *start, size_t length,
              int prot, int flags, off_t offset, FAR void **mapped);

/****************************************************************************
 * Name: file_mummap
 *
 * Description:
 *   Equivalent to the standard mummap() function except it does not set
 *   the errno variable.
 *
 ****************************************************************************/

int file_munmap(FAR void *start, size_t length);

/****************************************************************************
 * Name: file_ioctl
 *
 * Description:
 *   Perform device specific operations.
 *
 * Input Parameters:
 *   file     File structure instance
 *   req      The ioctl command
 *   ap       The argument of the ioctl cmd
 *
 * Returned Value:
 *   Returns a non-negative number on success;  A negated errno value is
 *   returned on any failure (see comments ioctl() for a list of appropriate
 *   errno values).
 *
 ****************************************************************************/

int file_ioctl(FAR struct file *filep, int req, ...);

/****************************************************************************
 * Name: file_fcntl
 *
 * Description:
 *   Similar to the standard fcntl function except that is accepts a struct
 *   struct file instance instead of a file descriptor.
 *
 * Input Parameters:
 *   filep - Instance for struct file for the opened file.
 *   cmd   - Identifies the operation to be performed.  Command specific
 *           arguments may follow.
 *
 * Returned Value:
 *   The nature of the return value depends on the command.  Non-negative
 *   values indicate success.  Failures are reported as negated errno
 *   values.
 *
 ****************************************************************************/

int file_fcntl(FAR struct file *filep, int cmd, ...);

/****************************************************************************
 * Name: file_poll
 *
 * Description:
 *   Low-level poll operation based on struct file.  This is used to
 *   support detached file.
 *
 * Input Parameters:
 *   file     File structure instance
 *   fds   - The structure describing the events to be monitored, OR NULL if
 *           this is a request to stop monitoring events.
 *   setup - true: Setup up the poll; false: Teardown the poll
 *
 * Returned Value:
 *  0: Success; Negated errno on failure
 *
 ****************************************************************************/

int file_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup);

/****************************************************************************
 * Name: file_fstat
 *
 * Description:
 *   file_fstat() is an internal OS interface.  It is functionally similar to
 *   the standard fstat() interface except:
 *
 *    - It does not modify the errno variable,
 *    - It is not a cancellation point,
 *    - It does not handle socket descriptors, and
 *    - It accepts a file structure instance instead of file descriptor.
 *
 * Input Parameters:
 *   filep  - File structure instance
 *   buf    - The caller provide location in which to return information
 *            about the open file.
 *
 * Returned Value:
 *   Upon successful completion, 0 shall be returned. Otherwise, -1 shall be
 *   returned and errno set to indicate the error.
 *
 ****************************************************************************/

int file_fstat(FAR struct file *filep, FAR struct stat *buf);

/****************************************************************************
 * Name: nx_fstat
 *
 * Description:
 *   nx_fstat() is similar to the standard 'fstat' interface except that is
 *   not a cancellation point and it does not modify the errno variable.
 *
 *   nx_fstat() is an internal NuttX interface and should not be called from
 *   applications.
 *
 * Returned Value:
 *   Zero is returned on success; a negated value is returned on any failure.
 *
 ****************************************************************************/

int nx_fstat(int fd, FAR struct stat *buf);

/****************************************************************************
 * Name: nx_stat
 *
 * Description:
 *   nx_stat() is similar to the standard 'stat' interface except that is
 *   not a cancellation point and it does not modify the errno variable.
 *
 *   nx_stat() is an internal NuttX interface and should not be called from
 *   applications.
 *
 * Returned Value:
 *   Zero is returned on success; a negated value is returned on any failure.
 *
 ****************************************************************************/

int nx_stat(FAR const char *path, FAR struct stat *buf, int resolve);

/****************************************************************************
 * Name: file_fchstat
 *
 * Description:
 *   file_fchstat() is an internal OS interface. It is functionally similar
 *   to the combination of fchmod/fchown/futimens standard interface except:
 *
 *    - It does not modify the errno variable,
 *    - It is not a cancellation point,
 *    - It does not handle socket descriptors, and
 *    - It accepts a file structure instance instead of file descriptor.
 *
 * Input Parameters:
 *   filep  - File structure instance
 *   buf    - The stat to be modified
 *   flags  - The valid field in buf
 *
 * Returned Value:
 *   Upon successful completion, 0 shall be returned. Otherwise, the
 *   negative errno shall be returned to indicate the error.
 *
 ****************************************************************************/

int file_fchstat(FAR struct file *filep, FAR struct stat *buf, int flags);

/****************************************************************************
 * Name: nx_unlink
 *
 * Description:
 *   nx_unlink() is similar to the standard 'unlink' interface except that
 *   is not a cancellation point and it does not modify the errno variable.
 *
 *   nx_unlink() is an internal NuttX interface and should not be called
 *   from applications.
 *
 * Returned Value:
 *   Zero is returned on success; a negated value is returned on any failure.
 *
 ****************************************************************************/

int nx_unlink(FAR const char *pathname);

/****************************************************************************
 * Name: file_pipe
 *
 * Description:
 *   file_pipe() creates a pair of file descriptors, pointing to a pipe
 *   inode, and places them in the array pointed to by 'filep'. filep[0]
 *   is for reading, filep[1] is for writing.
 *
 * Input Parameters:
 *   filep[2] - The user provided array in which to catch the pipe file
 *   descriptors
 *   bufsize - The size of the in-memory, circular buffer in bytes.
 *   flags - The file status flags.
 *
 * Returned Value:
 *   0 is returned on success; a negated errno value is returned on a
 *   failure.
 *
 ****************************************************************************/

#if defined(CONFIG_PIPES) && CONFIG_DEV_PIPE_SIZE > 0
int file_pipe(FAR struct file *filep[2], size_t bufsize, int flags);
#endif

/****************************************************************************
 * Name: nx_mkfifo
 *
 * Description:
 *   nx_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.
 *
 *   Once the FIFO has been created by nx_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.  This FIFO implementation will block all
 *   attempts to open a FIFO read-only 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).
 *
 *   NOTE: nx_mkfifo is a special, non-standard, NuttX-only interface.  Since
 *   the NuttX FIFOs are based in in-memory, circular buffers, the ability
 *   to control the size of those buffers is critical for system tuning.
 *
 * Input Parameters:
 *   pathname - The full path to the FIFO instance to attach to or to create
 *     (if not already created).
 *   mode - Ignored for now
 *   bufsize - The size of the in-memory, circular buffer in bytes.
 *
 * Returned Value:
 *   0 is returned on success; a negated errno value is returned on a
 *   failure.
 *
 ****************************************************************************/

#if defined(CONFIG_PIPES) && CONFIG_DEV_FIFO_SIZE > 0
int nx_mkfifo(FAR const char *pathname, mode_t mode, size_t bufsize);
#endif

/****************************************************************************
 * Name: map_anonymous
 *
 * Description:
 *   Support simulation of private anonymous mapping by allocating memory
 *   from heap
 *
 * Input Parameters:
 *   map     Input struct containing user request
 *   kernel  fs_heap_zalloc or kumm_zalloc
 *
 * Returned Value:
 *   On success returns 0. Otherwise negated errno is returned appropriately.
 *
 *     ENOMEM
 *       Insufficient memory is available to simulate mapping
 *
 ****************************************************************************/

#ifdef CONFIG_FS_ANONMAP
int map_anonymous(FAR struct mm_map_entry_s *entry, bool kernel);
#else
#  define map_anonymous(entry, kernel) (-ENOSYS)
#endif /* CONFIG_FS_ANONMAP */

#undef EXTERN
#if defined(__cplusplus)
}
#endif

#endif /* __INCLUDE_NUTTX_FS_FS_H */
