// POSIX fd-layer regression for GNO (punch-list #9): exercise the GS/OS-toolbox
// emulation of creat/write/close/open/read/lseek/unlink over the gsos* wrappers.
// Round-trips a fixed 16-byte payload through a real GS/OS file in the login cwd
// (/home/root) and asserts every stage via bank-2 absolute markers (DBR-
// independent), per the gnoHeapProbe/gnoForkWaitProbe convention.
//
//   0x025000  C0DE  reached end (no hang in the fd layer)
//   0x025002  0001  read-back payload matched what was written
//   0x025004  0001  creat() returned a real GS/OS refNum (>= 4)
//   0x025006  0001  write() wrote all 16 bytes
//   0x025008  0001  read() read all 16 bytes back
//   0x02500A  0001  open(O_RDONLY) returned a real refNum (>= 4)
//   0x02500C  0001  lseek(SEEK_SET,4) + 1-byte read landed on payload[4]
//   0x02500E  0001  unlink() removed the file
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>

#define M(a) (*(volatile uint16_t *)(a))

static const char    kPath[] = "fdprobe.tmp";
static const uint8_t kData[16] = {
    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
    0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50
};


int main(void) {
    uint8_t  rbuf[16];
    uint16_t ok;
    int      fd;
    long     n;
    long     pos;
    char     one;
    uint8_t  i;

    M(0x025000UL) = 0x0000;
    M(0x025002UL) = 0xDEAD;
    M(0x025004UL) = 0xDEAD;
    M(0x025006UL) = 0xDEAD;
    M(0x025008UL) = 0xDEAD;
    M(0x02500AUL) = 0xDEAD;
    M(0x02500CUL) = 0xDEAD;
    M(0x02500EUL) = 0xDEAD;
    ok = 1;

    // Create + write the payload.
    fd = creat(kPath, 0);
    if (fd >= 4) {
        M(0x025004UL) = 0x0001;
        n = write(fd, kData, 16);
        if (n == 16) {
            M(0x025006UL) = 0x0001;
        } else {
            ok = 0;
        }
        close(fd);
    } else {
        ok = 0;
    }

    // Reopen read-only and read the payload back.
    fd = open(kPath, O_RDONLY);
    if (fd >= 4) {
        M(0x02500AUL) = 0x0001;
        n = read(fd, rbuf, 16);
        if (n == 16) {
            M(0x025008UL) = 0x0001;
        } else {
            ok = 0;
        }
        for (i = 0; i < 16; i++) {
            if (rbuf[i] != kData[i]) {
                ok = 0;
            }
        }
        // Seek back into the file and confirm the byte at offset 4.
        pos = lseek(fd, 4, SEEK_SET);
        one = 0;
        read(fd, &one, 1);
        if (pos == 4 && (uint8_t)one == kData[4]) {
            M(0x02500CUL) = 0x0001;
        } else {
            ok = 0;
        }
        close(fd);
    } else {
        ok = 0;
    }

    // Remove the file.
    if (unlink(kPath) == 0) {
        M(0x02500EUL) = 0x0001;
    } else {
        ok = 0;
    }

    M(0x025002UL) = ok ? 0x0001 : 0xDEAD;
    M(0x025000UL) = 0xC0DE;
    for (volatile unsigned long j = 0; j < 600000UL; j++) {
    }
    return 0;
}
