// sys/stat.h -- file status for the GNO/ME runtime.
//
// struct stat MUST byte-match the layout the GNO kernel's stat.c writes
// (kern/gno/stat.c, compiled by ORCA/C with 16-bit int / 32-bit long).
// Kstat/Kfstat/Klstat (gno/kernel.h) fill this buffer directly, so any
// field-order or size drift silently corrupts every returned field.  The
// _Static_assert below pins sizeof to the ORCA/C layout (54 bytes); the
// field offsets all land on even boundaries, so our 2-byte i32 alignment
// (datalayout i32:16) inserts no padding and matches ORCA/C's packing.
// (Verified: sizeof==54, offsetof(st_size)==16, st_mtime==26, st_blocks==42,
// matching the __GNO__ branch of tools/gno/src-repo/include/sys/stat.h.)
//
// Field semantics follow GNO's kernel: st_nlink/st_uid/st_gid/st_rdev are
// always 0, st_ino is a per-call fake, times are Unix epoch seconds, and
// st_mode carries the S_IF* type bits plus ProDOS-derived permission bits.
#ifndef _SYS_STAT_H_
#define _SYS_STAT_H_

#include <sys/types.h>
#include <time.h>          // time_t (single source of truth)

#ifdef __cplusplus
extern "C" {
#endif

struct stat {
    dev_t          st_dev;         // device number
    ino_t          st_ino;         // (faked) inode number
    unsigned short st_mode;        // file type + permission bits
    short          st_nlink;       // link count (always 0 under GNO)
    uid_t          st_uid;         // owner uid (always 0)
    gid_t          st_gid;         // owner gid (always 0)
    dev_t          st_rdev;        // device type (always 0)
    off_t          st_size;        // file size in bytes
    time_t         st_atime;       // last access time (== mod time)
    int            st_spare1;
    time_t         st_mtime;       // last modification time
    int            st_spare2;
    time_t         st_ctime;       // creation / status-change time
    int            st_spare3;
    long           st_blksize;     // preferred I/O block size (512)
    long           st_blocks;      // 512-byte blocks allocated
    long           st_spare4[2];
};

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
_Static_assert(sizeof(struct stat) == 54, "struct stat must byte-match the GNO kernel layout");
#endif

// File type mask + type values (ProDOS/GS-OS mapped by the kernel).
#define S_IFMT   0170000           // type-of-file mask
#define S_IFIFO  0010000           // named pipe (fifo)
#define S_IFCHR  0020000           // character special (TTY / device)
#define S_IFDIR  0040000           // directory
#define S_IFBLK  0060000           // block special
#define S_IFREG  0100000           // regular file
#define S_IFLNK  0120000           // symbolic link
#define S_IFSOCK 0140000           // socket (GNO reports pipes as this)

// Permission bits.
#define S_ISUID  0004000           // set-user-id on execution
#define S_ISGID  0002000           // set-group-id on execution
#define S_ISVTX  0001000           // sticky bit

#define S_IRWXU  0000700           // RWX mask for owner
#define S_IRUSR  0000400           // R for owner
#define S_IWUSR  0000200           // W for owner
#define S_IXUSR  0000100           // X for owner
#define S_IREAD  S_IRUSR
#define S_IWRITE S_IWUSR
#define S_IEXEC  S_IXUSR

#define S_IRWXG  0000070           // RWX mask for group
#define S_IRGRP  0000040           // R for group
#define S_IWGRP  0000020           // W for group
#define S_IXGRP  0000010           // X for group

#define S_IRWXO  0000007           // RWX mask for other
#define S_IROTH  0000004           // R for other
#define S_IWOTH  0000002           // W for other
#define S_IXOTH  0000001           // X for other

// File-type test macros.
#define S_ISDIR(m)  (((m) & S_IFMT) == S_IFDIR)
#define S_ISCHR(m)  (((m) & S_IFMT) == S_IFCHR)
#define S_ISBLK(m)  (((m) & S_IFMT) == S_IFBLK)
#define S_ISREG(m)  (((m) & S_IFMT) == S_IFREG)
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#define S_ISLNK(m)  (((m) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)

int stat(const char *path, struct stat *sb);
int fstat(int fd, struct stat *sb);
int lstat(const char *path, struct stat *sb);

#ifdef __cplusplus
}
#endif

#endif
