[hatari-devel] GEMDOS HD issue when running under Windows

[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]


Some days ago, I investigated an issue I observed with SoftPC, a PC
emulator, running on a GEMDOS-emulated hard disk. I only managed to
write it up today. Upon further inspection, I found that the issue was
with Hatari running under Windows, but not a regression compared to
Hatari 2.4.1. To create an example, I used the following code snippet:

    int fid;
    long res;

    fid = (int)Fopen("FBUG.DAT", 2);
    Fread(fid, 512, buf);
    strcpy(buf, "MARKER");
    res = Fwrite(fid, 512, buf);
    Fclose(fid);

When this code is run with a file called FBUG.DAT, which is at least
1024 bytes in size, the Fwrite call is successful according to GEMDOS.
Hatari's GEMDOS trace doesn't show any abnormalities, either:

GEMDOS 0x3D Fopen("FBUG.DAT", read/write) at PC=0x13FF2
GEMDOS: FBUG.DAT -> host: C:\[REDACTED]\fbug.dat
-> FD 64 (read/write -> read+write)
GEMDOS 0x3F Fread(64, 512, 0x30010) at PC 0x1400E
GEMDOS 0x40 Fwrite(64, 512, 0x30010) at PC 0x14050
GEMDOS 0x3E Fclose(64) at PC 0x1405E

However, when running Hatari on Windows, the write operation does in
fact *not* succeed. If you check FBUG.DAT with a hex editor, you won't
find the "MARKER" string.

Initially, this observation puzzled me because Hatari calls the standard
library functions fread and fwrite in the end. It would be unlikely that
these functions are buggy. However, upon reading the C standard, I
discovered the following:

"When a file is opened with update mode ('+' as the second or third
character in the above list of mode argument values), both input and
output may be performed on the associated stream. However, output shall
not be directly followed by input without an intervening call to the
fflush function or to a file positioning function (fseek, fsetpos, or
rewind), and input shall not be directly followed by output without an
intervening call to a file positioning function, unless the input
operation encounters end-of-file."
(Source: ISO/IEC 9899:1999)

In Hatari, GEMDOS_Write calls fflush after each write, which makes the
transition from writing to reading safe. However, the other way around,
i.e., reading to writing, is not. There is no "file positioning
function" enforced before writing.

To resolve the issue, I have attached a patch that fixes the problem and
ensures that the test program and SoftPC run correctly with Hatari's
GEMDOS HD emulation on Windows. Feel free to rework it into a more
clever solution, if you think the unconditional dummy fseek should be
avoided.

Regards
Christian

Attachment: fbug.zip
Description: Zip compressed data

From 08af7debbd4de22c0ea959f0a75884d05581036f Mon Sep 17 00:00:00 2001
From: Christian Zietz <czietz@xxxxxxx>
Date: Thu, 28 Mar 2024 16:34:49 +0100
Subject: [PATCH] GEMDOS emulation: Fix Fread/Fwrite combination on Windows

The C99 standard mandates that a "file positioning function" is called
when following fread() by fwrite(). To simplify the logic, a dummy
fseek() is performed before every write operation.
---
 src/gemdos.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/gemdos.c b/src/gemdos.c
index f13f7bb2..036deed6 100644
--- a/src/gemdos.c
+++ b/src/gemdos.c
@@ -2408,6 +2408,7 @@ static bool GemDOS_Write(uint32_t Params)
 	}
 
 	pBuffer = (char *)STMemory_STAddrToPointer(Addr);
+	fseek(fp, 0, SEEK_CUR);
 	nBytesWritten = fwrite(pBuffer, 1, Size, fp);
 	if (fh_idx >= 0 && ferror(fp))
 	{
-- 
2.30.2



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/