/*****************************************************************************\
*                                                                             *
*   Filename:	    stat.h						      *
*                                                                             *
*   Description:    MsvcLibX extensions to sys/stat.h.                        *
*                                                                             *
*   Notes:	    							      *
*                                                                             *
*   History:								      *
*    2014-02-06 JFL Moved stat extensions from dirent.h.		      *
*    2014-02-26 JFL Added proprietary routines for managing file times.       *
*    2014-03-24 JFL Added a mechanism to also include MSVC's own sys/stat.h.  *
*                   Renamed this file from statx.h to sys/stat.h.             *
*    2014-05-27 JFL Added dummy definitions for S_TYPEISSHM() & S_TYPEISTMO().*
*    2014-06-03 JFL Moved struct timespec definition to sys/time.h.           *
*    2014-06-06 JFL Moved mode_t & off*_t definition to sys/types.h.	      *
*		    Moved fseeko* & ftello* functions definitions to stdio.h. *
*    2014-06-24 JFL Added fstat and fstat64 external references.	      *
*    2015-11-15 JFL Visual Studio 2015 moved this file to the Windows Kit UCRT.
*    2016-09-15 JFL Fixed a warning in Visual Studio 2015.		      *
*									      *
*        Copyright 2016 Hewlett Packard Enterprise Development LP          *
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
\*****************************************************************************/

#ifndef	_MSVCLIBX_STAT_H
#define	_MSVCLIBX_STAT_H	1

#include "msvclibx.h"

#include "sys/msvcTypes.h"
#include <sys/stat.h> /* Include MSVC's own <sys/stat.h> file */
#include "msvcDirent.h" /* For dirent2stat() arguments definitions */
#include "msvcTime.h" /* for time_t definition */
#include "sys/msvcTime.h" /* for timespec definition */
/* Include MsvcLibX's <direct.h> override, to avoid conflict with the standard mkdir defined here,
   should <direct.h> be manually included later on in the C source */
#include <direct.h>

#ifdef  __cplusplus
extern "C" {
#endif

/************************ MS-DOS-specific definitions ************************/

#ifdef _MSDOS	/* Automatically defined when targeting an MS-DOS application */

/* Define stat and fstat to use 32 or 64 file lengths, as defined by _FILE_OFFSET_BITS */
/* #undef  stat		/* Not normally defined by MSVC */
/* #undef  fstat	/* Not normally defined by MSVC */
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
  /* TO DO: Windows 95 has extended functions for handling 64-bits files sizes */
#else
#endif
/* For now, use the MSVC 32-bits functions in all cases */
#define stat _stat
#define fstat _fstat
#define lstat stat

/* Define standard 64-bits structures and functions */
#if defined(_LARGEFILE_SOURCE64)
  /* For now, hide the fact that DOS does not support 64-bits lengths */
  #define off64_t _off_t
  #define stat64 _stat
  #define fstat64 _fstat
  #define lstat64 stat64
#endif

/* Proprietary function for recovering available infos without calling stat */
extern int dirent2stat(struct dirent *pDE, struct _stat *pStat);
#define dirent2stat64 dirent2stat /* The current versions are the same */
#define _DIRENT2STAT_DEFINED 1

/* MS-DOS always reports local file times. MsvcLibX DOS version generates a
   pseudo GMT time for files using mktime(), which can then be undone by localtime(). */
#define LocalFileTime localtime

/* Proprietary function for converting a DOS date/time to a Posix time_t */
extern time_t Filetime2Timet(uint16_t date, uint16_t time);
/* Proprietary function for generating a string with the local file time, in the ISO 8601 date/time format */
extern char *Filetime2String(uint16_t date, uint16_t time, char *pBuf, size_t nBufSize);

#endif /* defined(_MSDOS) */

/************************ Win32-specific definitions *************************/

#ifdef _WIN32	/* Automatically defined when targeting a Win32 application */

/* Visual C++ sys/stat.h defines a series of _statXY functions and structures:
    XY = 32	st_*time is 32-bits __time32_t	&  st_size is 32-bits _off_t
    XY = 32i64	st_*time is 32-bits __time32_t	&  st_size is 64-bits __int64
    XY = 64i32	st_*time is 64-bits __time64_t	&  st_size is 32-bits _off_t
    XY = 64	st_*time is 64-bits __time64_t	&  st_size is 64-bits __int64
   Then it defines additional _statZ macros generating _statXY, based on:
    XY = 32	if _USE_32BIT_TIME_T defined	&  Z is ""
    XY = 32i64	if _USE_32BIT_TIME_T defined	&  Z is i64
    XY = 64i32	if _USE_32BIT_TIME_T undefined	&  Z is ""
    XY = 64	if _USE_32BIT_TIME_T undefined	&  Z is i64
   Special case: In 64-bits windows, _USE_32BIT_TIME_T defined is ignored and #undef(ined)
*/

/* Define stat and fstat to use 32 or 64 file lengths, as defined by _FILE_OFFSET_BITS */
/* #undef  stat		/* Not normally defined by MSVC */
/* #undef  fstat	/* Not normally defined by MSVC */

#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
  #define _STAT_FILE_SIZE 64
  #define _STAT_SUFFIX i64
#else
  #define _STAT_FILE_SIZE 32
  #define _STAT_SUFFIX 
#endif

#define _USE_EXTENDED_STAT_STRUCT 1

#define _VALUEOF(a) a				/* Get the token value */
#define _CONCAT2T(a,b) a##b			/* Concatenate two tokens (does not expand their values) */
#define _CONCAT3T(a,b,c) a##b##c		/* Concatenate three tokens (does not expand their values) */
#define _CONCAT4T(a,b,c,d) a##b##c##d		/* Concatenate four tokens (does not expand their values) */
#define _CONCAT(a,b) _CONCAT2T(a,b)		/* Concatenate two tokens values */
#define _CONCAT3(a,b,c) _CONCAT3T(a,b,c)	/* Concatenate three tokens values */
#define _CONCAT4(a,b,c,d) _CONCAT4T(a,b,c,d)	/* Concatenate four tokens values */
#define _CON_STAT_CAT1(pre,post) pre##stat##post
#define _CON_STAT_CAT(pre,post) _CON_STAT_CAT1(pre,post)

/* Define what stat, fstat, lstat, stat64 macros would be,
   if we were to use MSVC's own stat structures and routines */
/* Avoid concatenating tokens _stat and _fstat, as these are already macros
   that would be expanded, and we do not want this as this stage. */ 
#define _MSVC_stat    _CON_STAT_CAT(_ , _STAT_SUFFIX)
#define _MSVC_fstat   _CON_STAT_CAT(_f, _STAT_SUFFIX)
#define _MSVC_lstat   _CON_STAT_CAT(_l, _STAT_SUFFIX)
#define _MSVC_stat64  _CON_STAT_CAT(_ , i64)
#define _MSVC_lstat64 _CON_STAT_CAT(_l, i64)

#ifdef _USE_32BIT_TIME_T
#define _lstat       _lstat32
#define _lstati64    _lstat32i64
#define _lstat_ns    _lstat32_ns
#define _lstati64_ns _lstat32i64_ns
#else
#define _lstat       _lstat64i32
#define _lstati64    _lstat64
#define _lstat_ns    _lstat64i32_ns
#define _lstati64_ns _lstat64_ns
#endif

#if !_USE_EXTENDED_STAT_STRUCT
  #define _NS_SUFFIX
#else /* _USE_EXTENDED_STAT_STRUCT */
  #define _MSVCLIBX_STAT_DEFINED 1
  #define _NS_SUFFIX _ns
  /* Define what stat, fstat, lstat, stat64 macros and structures would be,
     if we were to use MsvcLibX extended stat structures and routines */
  #define _LIBX_stat   _CONCAT(_MSVC_stat,_ns)
  #define _LIBX_stat64 _CONCAT(_MSVC_stat64,_ns)
#include "msvcDebugm.h"
#pragma message("Defining type struct " VALUEIZE(_LIBX_stat))
  struct _LIBX_stat {
    /* MSVC standard stat structure fields */
    _dev_t          st_dev;
    _ino_t          st_ino;
    unsigned short  st_mode;
    short           st_nlink;
    short           st_uid;
    short           st_gid;
    _dev_t          st_rdev;
    off_t           st_size;
    /* End of MSVC standard stat structure fields */
    struct timespec st_ctim;		/* File creation date/time,  w. ns resolution */
    struct timespec st_mtim;		/* File modification date/time,  w. ns resolution */
    struct timespec st_atim;		/* File access date/time,  w. ns resolution */
    unsigned int    st_Win32Attrs;	/* Win32 file attributes */
    unsigned int    st_ReparseTag;	/* Reparse point tag */
  };
  /* Compatibility with old Unix fields */
  #define st_ctime st_ctim.tv_sec
  #define st_mtime st_mtim.tv_sec
  #define st_atime st_atim.tv_sec
  /* Compatibility with intermediate Unix fields */
  #define st_ctimensec st_ctim.tv_nsec	/* Nanosecond part of the file creation time */
  #define st_mtimensec st_mtim.tv_nsec	/* Nanosecond part of the file modification time */
  #define st_atimensec st_atim.tv_nsec	/* Nanosecond part of the file access time */

  #if (_STAT_FILE_SIZE != 64) /* Else it's the same as struct stat */
#pragma message("Defining type struct " VALUEIZE(_LIBX_stat64))
    struct _LIBX_stat64 {
      /* MSVC standard stat structure fields */
      _dev_t          st_dev;
      _ino_t          st_ino;
      unsigned short  st_mode;
      short           st_nlink;
      short           st_uid;
      short           st_gid;
      _dev_t          st_rdev;
      off64_t         st_size;
      /* End of MSVC standard stat structure fields */
      struct timespec st_ctim;		/* File creation date/time,  w. ns resolution */
      struct timespec st_mtim;		/* File modification date/time,  w. ns resolution */
      struct timespec st_atim;		/* File access date/time,  w. ns resolution */
      unsigned int    st_Win32Attrs;	/* Win32 file attributes */
      unsigned int    st_ReparseTag;	/* Reparse point tag */
    };
  #endif
#endif /* !_USE_EXTENDED_STAT_STRUCT */

/* Define standard stat, fstat, lstat macros */
#define stat    _CONCAT(_MSVC_stat,_NS_SUFFIX)
#define fstat   _CONCAT(_MSVC_fstat,_NS_SUFFIX)
#define lstat   _CONCAT(_MSVC_lstat,_NS_SUFFIX)

/* Reference standard stat, fstat, lstat functions that we redefine */
#if _USE_EXTENDED_STAT_STRUCT /* Else we'll use MSVC's version */
extern int stat(const char *path, struct stat *buf);
extern int fstat(int nFile, struct stat *buf);
#endif
extern int lstat(const char *path, struct stat *buf);

/* Define standard 64-bits macros and functions */
#if defined(_LARGEFILE_SOURCE64)
  #define stat64 _CONCAT(_stati64,_NS_SUFFIX)
  #define fstat64 _CONCAT(_fstati64,_NS_SUFFIX)
  #define lstat64 _CONCAT(_lstati64,_NS_SUFFIX)

  #if (_STAT_FILE_SIZE != 64) /* Else they're the same as functions stat & lstat */
    #if _USE_EXTENDED_STAT_STRUCT /* Else we'll use MSVC's version */
      extern int stat64(const char *path, struct stat64 *buf);
      extern int fstat64(int nFile, struct stat *buf);
    #endif
    extern int lstat64(const char *path, struct stat64 *buf);
  #endif
#endif

/* Proprietary function for recovering dirent infos without calling stat */
/* Note: MSDOS has a single stat version, and its dirent2stat implementation is in dirent.c */
#ifdef _USE_32BIT_TIME_T
#if (_STAT_FILE_SIZE != 64) /* Else if _STAT_FILE_SIZE=64, then struct _stat32_ns isn't defined */
extern int _CONCAT(_dirent2_stat32,_NS_SUFFIX)(struct dirent *pDE, struct _CONCAT(_stat32,_NS_SUFFIX) *pStat);
#endif
extern int _CONCAT(_dirent2_stat32i64,_NS_SUFFIX)(struct dirent *pDE, struct _CONCAT(_stat32i64,_NS_SUFFIX) *pStat);
#else
#if (_STAT_FILE_SIZE != 64) /* Else if _STAT_FILE_SIZE=64, then struct _stat64i32_ns isn't defined */
extern int _CONCAT(_dirent2_stat64i32,_NS_SUFFIX)(struct dirent *pDE, struct _CONCAT(_stat64i32,_NS_SUFFIX) *pStat);
#endif
extern int _CONCAT(_dirent2_stat64,_NS_SUFFIX)(struct dirent *pDE, struct _CONCAT(_stat64,_NS_SUFFIX) *pStat);
#endif
#define dirent2stat _CONCAT(_dirent2,stat)
#define _DIRENT2STAT_DEFINED 1

#define unlink _CONCAT(_unlink_, stat)
#define rmdir _CONCAT(_rmdir_, stat)
extern int unlink(const char *path);
extern int rmdir(const char *path);

/* Proprietary function for generating a printable local file time,
   using Windows' specific algorithm, to match cmd.exe dir output. */
extern struct tm *LocalFileTime(const time_t *pt);

/* Proprietary function for converting a Win32 FILETIME to a Posix time_t */
extern time_t Filetime2Timet(const FILETIME *pFT);
/* Proprietary function for converting a Posix time_t to a Win32 FILETIME */
extern void Timet2Filetime(time_t s, FILETIME *pFT);

/* Proprietary function for converting a Win32 FILETIME to a Posix {time_t,nanosecond} */
extern void Filetime2Timespec(const FILETIME *pFT, struct timespec *pTS);
/* Proprietary function for converting a Posix {time_t,nanosecond} to a Win32 FILETIME */
extern void Timespec2Filetime(const struct timespec *pTS, FILETIME *pFT);

/* Proprietary function for generating a string with the local file time, in the ISO 8601 date/time format */
extern char *Filetime2String(const FILETIME *pFT, char *pBuf, size_t nBufSize);

#endif /* defined(_WIN32) */

/************************* OS/2-specific definitions *************************/

#ifdef _OS2	/* Automatically defined when targeting an OS/2 application? */

/* Define stat and fstat to use 32 or 64 file lengths, as defined by _FILE_OFFSET_BITS */
/* #undef  stat		/* Not normally defined by MSVC */
/* #undef  fstat	/* Not normally defined by MSVC */
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
  /* TO DO: Windows 95 has extended functions for handling 64-bits files sizes */
#else
#endif
/* For now, use the MSVC 32-bits functions in all cases */
#define off_t _off_t
#define stat _stat
#define fstat _fstat
#define lstat stat

/* Define standard 64-bits functions */
#if defined(_LARGEFILE_SOURCE64)
  /* For now, hide the fact that DOS does not support 64-bits lengths */
  #define off64_t _off_t
  #define stat64 _stat
  #define fstat64 _fstat
  #define lstat64 stat64
#endif

/* Proprietary function for recovering available infos without calling stat */
/* extern int dirent2stat(struct dirent *pDE, struct _stat *pStat); */
/* #define dirent2stat64 dirent2stat /* The current versions are the same */
/* #define _DIRENT2STAT_DEFINED 1 */

/* To do: Check if OS/2 uses local or GMT times, and implement LocalFileTime() if needed. */
#define LocalFileTime localtime

#endif /* defined(_OS2) */

/********************** End of OS-specific definitions ***********************/

#define lchmod chmod /* MSVC is buggy and chmod() applies to the link itself */

/* Structure stat standard st_mode values not defined in DOS/Windows' sys/stat.h */
/* Must match the d_type field types in dirent.h. */
/* #define S_IFMT  0xF000   /* Mask for the 4-bit file type                    */
#define S_IFIFO    0x1000   /* FIFO                                            */
/* #define S_IFCHR 0x2000   /* Character device                                */
/* #define S_IFDIR 0x4000   /* Directory                                       */
#define S_IFBLK    0x6000   /* Block device                                    */
/* #define S_IFREG 0x8000   /* Regular file                                    */
#define S_IFLNK    0xA000   /* Symbolic link                                   */
#define S_IFSOCK   0xC000   /* Socket                                          */

/* Structure stat standard st_mode type test macros */
/* The existence of these macros can be used to test for the OS support of the feature */
#define S_ISTYPE(m, TYPE) ((m & S_IFMT) == TYPE)
/* Both DOS and Windows support these file types */
#define S_ISCHR(m)  S_ISTYPE(m, S_IFCHR)  /* Test for a character device */
#define S_ISDIR(m)  S_ISTYPE(m, S_IFDIR)  /* Test for a directory */
#define S_ISREG(m)  S_ISTYPE(m, S_IFREG)  /* Test for a regular file */
#ifdef _WIN32	/* Only Windows supports these */
#define S_ISLNK(m)  S_ISTYPE(m, S_IFLNK)  /* Test for a symbolic link */
#endif
#if 0		/* Only Unix supports these? At least MsvcLibX does not support them now. */
#define S_ISBLK(m)  S_ISTYPE(m, S_IFBLK)  /* Test for a block device */
#define S_ISFIFO(m) S_ISTYPE(m, S_IFIFO)  /* Test for a pipe or FIFO */
#define S_ISSOCK(m) S_ISTYPE(m, S_IFSOCK) /* Test for a socket */
#endif

#define S_ISBLK(m)  0	/* Test for a block device */
#define S_ISCTG(m)  0	/* Test for a high performance ("contiguous data") file */
#define S_ISDOOR(m) 0	/* Test for a door */
#define S_ISFIFO(m) 0	/* Test for a pipe or FIFO */
#define S_ISMPB(m)  0	/* Test for a multiplexed block device */
#define S_ISMPC(m)  0	/* Test for a multiplexed character device */
#define S_ISNWK(m)  0	/* Test for a network special file (HP-UX) */
#define S_ISPORT(m) 0	/* Test for a port */
#define S_ISSOCK(m) 0	/* Test for a socket */
#define S_ISWHT(m)  0	/* Test for a whiteout (4.4BSD) */


/* Other optional file types that some operating systems support */ 
#define S_TYPEISMQ(pStat) 0	/* Test for a message queue */
#define S_TYPEISSEM(pStat) 0	/* Test for a semaphore */
#define S_TYPEISSHM(pStat) 0	/* Test for a shared memory object */
#define S_TYPEISTMO(pStat) 0	/* Test for a typed memory object */

/* Structure stat standard st_mode flags */
#define S_ISUID    04000    /* Set UID bit                                     */
#define S_ISGID    02000    /* Set-group-ID bit                                */
#define S_ISVTX    01000    /* Sticky bit                                      */

#define S_IRWXU    0700     /* Mask for file owner permissions                 */
#define S_IRUSR    0400     /* Owner has read permission.    Alias S_IREAD     */
#define S_IWUSR    0200     /* Owner has write permission.   Alias S_IWRITE    */
#define S_IXUSR    0100     /* Owner has execute permission. Alias S_IEXEC     */

#define S_IRWXG    070      /* Mask for group permissions                      */
#define S_IRGRP    040      /* Group has read permission                       */
#define S_IWGRP    020      /* Group has write permission                      */
#define S_IXGRP    010      /* Group has execute permission                    */

#define S_IRWXO    07       /* Mask for permissions for others (not in group)  */
#define S_IROTH    04       /* Others have read permission                     */
#define S_IWOTH    02       /* Others have write permission                    */
#define S_IXOTH    01       /* Others have execute permission                  */

#define S_IRWXUGO  00777    /* S_IRWXU|S_IRWXG|S_IRWXO */
#define S_IALLUGO  07777    /* S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO */
#define S_IRUGO    00444    /* S_IRUSR|S_IRGRP|S_IROTH */
#define S_IWUGO    00222    /* S_IWUSR|S_IWGRP|S_IWOTH */
#define S_IXUGO    00111    /* S_IXUSR|S_IXGRP|S_IXOTH */

/* Structure stat extensions for DOS/Windows file attributes */
#define S_IFVOLID  0xF000   /* Volume ID pseudo-file, defined in FAT root dir */
#define S_ISVOLID(m) S_ISTYPE(m, S_IFVOLID) /* Test for a FAT volume ID */
#define S_HIDDEN		01	/* Reuse permissions bit not used in DOS/Windows */
#define S_ARCHIVE		02	/* Reuse permissions bit not used in DOS/Windows */
#define S_SYSTEM		04	/* Reuse permissions bit not used in DOS/Windows */
#define S_COMPRESSED		010	/* Reuse permissions bit not used in DOS/Windows */
#define S_ENCRYPTED		020	/* Reuse permissions bit not used in DOS/Windows */
#define S_NOT_CONTENT_INDEXED	040	/* Reuse permissions bit not used in DOS/Windows */
#define S_OFFLINE		01000	/* Reuse sticky bit, not used in DOS/Windows */
#define S_SPARSE_FILE		02000	/* Reuse GID bit, not used in DOS/Windows */
#define S_MOUNT_POINT		04000	/* Reuse UID bit, not used in DOS/Windows */
/* #define S_TEMPORARY			/* Reuse UID bit, not used in DOS/Windows */
/* #define S_VIRTUAL			/* No bit left for this one */

#if defined(_MSDOS)
#define _mkdirx(path, mode) _mkdir(path)
#elif defined(_WIN32)
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
#define _mkdirx(path, mode) mkdirU(path, mode)
#else /* _ANSI_SOURCE */
#define _mkdirx(path, mode) mkdirA(path, mode)
#endif /* defined(_UTF8_SOURCE) */
extern int mkdirU(const char *path, mode_t mode);
extern int mkdirA(const char *path, mode_t mode);
#endif /* defined(_MSDOS) */
#define mkdir(path, mode) _mkdirx(path, mode)

/* Special values for futimens() and utimensat(). Must not be in [0...((10^9)-1)] */
#define UTIME_NOW  1000000001
#define UTIME_OMIT 1000000002

#ifdef  __cplusplus
}
#endif

#endif /* defined(_MSVCLIBX_STAT_H)  */

