/*             ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
 *
 *                 Copyright (c) 2014-2015 Datalight, Inc.
 *                     All Rights Reserved Worldwide.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; use version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
 *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/*  Businesses and individuals that for commercial or other reasons cannot
 *  comply with the terms of the GPLv2 license may obtain a commercial license
 *  before incorporating Reliance Edge into proprietary software for
 *  distribution in any form.  Visit http://www.datalight.com/reliance-edge for
 *  more information.
 */

/** @file
 *  @brief Interface for the Reliance Edge POSIX-like API.
 *
 *  The POSIX-like file system API is the primary file system API for
 *  Reliance Edge, which supports the full functionality of the file system.
 *  This API aims to be compatible with POSIX where reasonable, but it is
 *  simplified considerably to meet the needs of resource-constrained embedded
 *  systems.  The API has also been extended to provide access to the unique
 *  features of Reliance Edge, and to cover areas (like mountins and formatting)
 *  which do not have APIs in the POSIX specification.
 */
#ifndef REDPOSIX_H
    #define REDPOSIX_H

/*  This header is intended for application use; some applications are written
 *  in C++.
 */
    #ifdef __cplusplus
    extern "C" {
    #endif

    #include <redconf.h>

    #if REDCONF_API_POSIX == 1

        #include <redtypes.h>
        #include "redapimacs.h"
        #include "rederrno.h"
        #include "redstat.h"

/** Open for reading only. */
        #define RED_O_RDONLY    0x00000001U

/** Open for writing only. */
        #define RED_O_WRONLY    0x00000002U

/** Open for reading and writing. */
        #define RED_O_RDWR      0x00000004U

/** File offset for all writes is end-of-file. */
        #define RED_O_APPEND    0x00000008U

/** Create the file. */
        #define RED_O_CREAT     0x00000010U

/** Error if path already exists. */
        #define RED_O_EXCL      0x00000020U

/** Truncate file to size zero. */
        #define RED_O_TRUNC     0x00000040U


/** @brief Last file system error (errno).
 *
 *  Under normal circumstances, each task using the file system has an
 *  independent `red_errno` value.  Applications do not need to worry about
 *  one task obliterating an error value that another task needed to read.  The
 *  value is initially zero.  When one of the POSIX-like APIs return an
 *  indication of error, `red_errno` is set to an error value.
 *
 *  In some circumstances, `red_errno` will be a global errno location which
 *  is shared by multiple tasks.  If the calling task is not registered as a
 *  file system user and all of the task slots are full, there can be no
 *  task-specific errno, so the global errno is used.  Likewise, if the file
 *  system driver is uninitialized, there are no registered file system users
 *  and `red_errno` always refers to the global errno.  Under these
 *  circumstances, multiple tasks manipulating `red_errno` could be
 *  problematic.  When the task count is set to one, `red_errno` always refers
 *  to the global errno.
 *
 *  Note that `red_errno` is usable as an lvalue; i.e., in addition to reading
 *  the error value, the error value can be set:
 *
 *  ~~~{.c}
 *  red_errno = 0;
 *  ~~~
 */
        #define red_errno    ( *red_errnoptr() )


/** @brief Positions from which to seek within a file.
 */
        typedef enum
        {
            /*  0/1/2 are the traditional values for SET/CUR/END, respectively.  Prior
             *  to the release of Unix System V in 1983, the SEEK_* symbols did not
             *  exist and C programs hard-coded the 0/1/2 values with those meanings.
             */
            RED_SEEK_SET = 0, /**< Set file offset to given offset. */
            RED_SEEK_CUR = 1, /**< Set file offset to current offset plus signed offset. */
            RED_SEEK_END = 2  /**< Set file offset to EOF plus signed offset. */
        } REDWHENCE;


        #if REDCONF_API_POSIX_READDIR == 1

/** @brief Opaque directory handle.
 */
            typedef struct sREDHANDLE REDDIR;


/** @brief Directory entry information.
 */
            typedef struct
            {
                uint32_t d_ino;                       /**< File serial number (inode number). */
                char d_name[ REDCONF_NAME_MAX + 1U ]; /**< Name of entry. */
                REDSTAT d_stat;                       /**< File information (POSIX extension). */
            } REDDIRENT;
        #endif /* if REDCONF_API_POSIX_READDIR == 1 */


        int32_t red_init( void );
        int32_t red_uninit( void );
        int32_t red_mount( const char * pszVolume );
        int32_t red_umount( const char * pszVolume );
        #if ( REDCONF_READ_ONLY == 0 ) && ( REDCONF_API_POSIX_FORMAT == 1 )
            int32_t red_format( const char * pszVolume );
        #endif
        #if REDCONF_READ_ONLY == 0
            int32_t red_transact( const char * pszVolume );
        #endif
        #if REDCONF_READ_ONLY == 0
            int32_t red_settransmask( const char * pszVolume,
                                      uint32_t ulEventMask );
        #endif
        int32_t red_gettransmask( const char * pszVolume,
                                  uint32_t * pulEventMask );
        int32_t red_statvfs( const char * pszVolume,
                             REDSTATFS * pStatvfs );
        int32_t red_open( const char * pszPath,
                          uint32_t ulOpenMode );
        #if ( REDCONF_READ_ONLY == 0 ) && ( REDCONF_API_POSIX_UNLINK == 1 )
            int32_t red_unlink( const char * pszPath );
        #endif
        #if ( REDCONF_READ_ONLY == 0 ) && ( REDCONF_API_POSIX_MKDIR == 1 )
            int32_t red_mkdir( const char * pszPath );
        #endif
        #if ( REDCONF_READ_ONLY == 0 ) && ( REDCONF_API_POSIX_RMDIR == 1 )
            int32_t red_rmdir( const char * pszPath );
        #endif
        #if ( REDCONF_READ_ONLY == 0 ) && ( REDCONF_API_POSIX_RENAME == 1 )
            int32_t red_rename( const char * pszOldPath,
                                const char * pszNewPath );
        #endif
        #if ( REDCONF_READ_ONLY == 0 ) && ( REDCONF_API_POSIX_LINK == 1 )
            int32_t red_link( const char * pszPath,
                              const char * pszHardLink );
        #endif
        int32_t red_close( int32_t iFildes );
        int32_t red_read( int32_t iFildes,
                          void * pBuffer,
                          uint32_t ulLength );
        #if REDCONF_READ_ONLY == 0
            int32_t red_write( int32_t iFildes,
                               const void * pBuffer,
                               uint32_t ulLength );
        #endif
        #if REDCONF_READ_ONLY == 0
            int32_t red_fsync( int32_t iFildes );
        #endif
        int64_t red_lseek( int32_t iFildes,
                           int64_t llOffset,
                           REDWHENCE whence );
        #if ( REDCONF_READ_ONLY == 0 ) && ( REDCONF_API_POSIX_FTRUNCATE == 1 )
            int32_t red_ftruncate( int32_t iFildes,
                                   uint64_t ullSize );
        #endif
        int32_t red_fstat( int32_t iFildes,
                           REDSTAT * pStat );
        #if REDCONF_API_POSIX_READDIR == 1
            REDDIR * red_opendir( const char * pszPath );
            REDDIRENT * red_readdir( REDDIR * pDirStream );
            void red_rewinddir( REDDIR * pDirStream );
            int32_t red_closedir( REDDIR * pDirStream );
        #endif
        REDSTATUS * red_errnoptr( void );

    #endif /* REDCONF_API_POSIX */


    #ifdef __cplusplus
}
    #endif

#endif /* ifndef REDPOSIX_H */
