// 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 #include // 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