From 751b50a72412fbf385c4398f2cd62e22c33056ac Mon Sep 17 00:00:00 2001 From: Rick Gaiser Date: Sun, 1 Nov 2026 10:05:19 +0100 Subject: [PATCH] ps2client: open host: files read-write as O_RDWR The PS2's open flags hold the access mode in the low two bits (1 read, 2 write, 3 both). fix_flags or-ed O_RDONLY and O_WRONLY for 3, which is O_WRONLY | O_TRUNC on POSIX hosts: a file opened read-write was emptied and every read of it returned 0 bytes. Map the mode as a whole; 3 is now O_RDWR (without O_TRUNC). tests: the fake's rdwrback reads a file opened with flags 3; its size and CRC must match. Co-Authored-By: Claude Opus 5.5 --- src/utility.c | 11 ++++++++--- tests/fake_ps2link.c | 15 +++++++++------ tests/run-tests.sh | 6 ++++++ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/utility.c b/src/utility.c index d3ac43d..90a2d1e 100644 --- a/src/utility.c +++ b/src/utility.c @@ -17,9 +17,14 @@ int fix_flags(int flags) { int result = 0; - // Fix the flags. - if (flags & 0x0001) { result |= O_RDONLY; } - if (flags & 0x0002) { result |= O_WRONLY | O_TRUNC; } // FIXME: Truncate is needed for some programs. + // Fix the flags: the access mode is the low two bits (1 read, 2 write, + // 3 both). Read and write is O_RDWR, not O_RDONLY | O_WRONLY (which is + // O_WRONLY on most hosts, so reads fail). + switch (flags & 0x0003) { + case 0x0001: result |= O_RDONLY; break; + case 0x0002: result |= O_WRONLY | O_TRUNC; break; // FIXME: Truncate is needed for some programs. + case 0x0003: result |= O_RDWR; break; + } #ifndef _WIN32 if (flags & 0x0010) { result |= O_NONBLOCK; } #endif diff --git a/tests/fake_ps2link.c b/tests/fake_ps2link.c index 1e75b9d..d0239f9 100644 --- a/tests/fake_ps2link.c +++ b/tests/fake_ps2link.c @@ -129,12 +129,12 @@ static int fake_write(int fd, const unsigned char *data, int length) pthread_mutex_unlock(&fake.lock); return result; } -static unsigned char *load_file(const char *path, size_t *length) +static unsigned char *load_file(const char *path, int flags, size_t *length) { unsigned char *data = NULL; unsigned char chunk[128 * 1024]; size_t allocated = 0; - int fd = fake_open(path, 1), n; + int fd = fake_open(path, flags), n; *length = 0; if (fd < 0) return NULL; while ((n = fake_read(fd, chunk, sizeof(chunk))) > 0) { @@ -217,12 +217,15 @@ static void *run_script(void *context) } pthread_mutex_unlock(&fake.lock); break; - } else if (!strcmp(line, "readback")) { + } else if (!strcmp(line, "readback") || !strcmp(line, "rdwrback")) { + /* rdwrback: the same, the file opened for reading and writing + * (PS2 flags 3) */ + int rdwr = !strcmp(line, "rdwrback"); size_t length = 0; - unsigned char *data = load_file(arg, &length); + unsigned char *data = load_file(arg, rdwr ? 3 : 1, &length); if (data) { char report[128]; - snprintf(report, sizeof(report), "readback %zu %08x", + snprintf(report, sizeof(report), "%s %zu %08x", line, length, crc32_bytes(data, length)); line_out(report); free(data); @@ -261,7 +264,7 @@ static void command_packet(unsigned char *packet, size_t length) args[255] = '\0'; first = args; path = strncmp(first, "host:", 5) == 0 ? first + 5 : first; - script = load_file(path, &size); + script = load_file(path, 1, &size); if (!script) { line_out("fake: could not load script"); return; } offset = strnlen(first, sizeof(args)) + 1; for (i = 1; i < count && offset < 256; i++) { diff --git a/tests/run-tests.sh b/tests/run-tests.sh index cb85925..643c3a8 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -143,6 +143,12 @@ printf 'readback blob.bin\nprint @@END@@ status=0\n' > readback.elf check "big host: read" 0 "${H[@]}" -t 10 -e @@END@@ execee host:readback.elf expect "readback size and crc" grep -q "^readback 300000 $("$HERE/../bin/crc32" blob.bin)$" out.txt +# --- a host: file opened for reading and writing (PS2 flags 3) can be read, +# and is not truncated +printf 'rdwrback blob.bin\nprint @@END@@ status=0\n' > rdwr.elf +check "host: read of a read-write file" 0 "${H[@]}" -t 10 -e @@END@@ execee host:rdwr.elf +expect "read-write: size and crc" grep -q "^rdwrback 300000 $("$HERE/../bin/crc32" blob.bin)$" out.txt + # --- second client "$CLIENT" "${H[@]}" -t 5 listen > /dev/null 2>&1 & LISTENER=$!