Skip to content

Commit c6fa592

Browse files
authored
Handle dwCreationDisposition in CreateFileA to fix PSYLINK (#60)
Before this change, dwCreationDisposition parameter of CreateFileA was ignored by wibo. However, it turns out that PSYLINK.EXE in PsyQ 4.4 sometimes depends on correct handling of that parameter. When building overlays with PSYLINK.EXE, it sometimes opens the resulting overlay file the second time, with OPEN_EXISTING creation disposition (as opposed to TRUNCATE_EXISTING). Before the change, wibo opened that file with fopen(..., "wb+") which truncated the file even though OPEN_EXISTING (non-truncating) was requested. This affected https://github.com/foxdieteam/mgs_reversing, where one of the overlays (camera.bin) was built incorrectly when using wibo (worked correctly on Windows or with wine). This commit adds proper handling of dwCreationDisposition parameter. The file now can be opened in truncating or non-truncating mode. Additionally, the implementation now reacts correctly to file existing/non-existing as specified by the requested creation disposition mode. For example, if CreateFileA is called with OPEN_EXISTING and the file does not exist it will set an error and not create a new file (the previous behavior). If the file exists, it's opened in non-truncating mode, as TRUNCATE_EXISTING or CREATE_ALWAYS is required for truncation. After the fix you can correctly build the whole mgs_reversing project with wibo - tools running under wibo: ASMPSX, ASPSX, CC1PSX 4.0 & 4.4, PSYLINK. I have NOT tested other executables apart from those.
1 parent 2d627de commit c6fa592

File tree

1 file changed

+63
-3
lines changed

1 file changed

+63
-3
lines changed

dll/kernel32.cpp

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,13 @@ namespace kernel32 {
840840
return 1;
841841
}
842842

843+
enum {
844+
CREATE_NEW = 1,
845+
CREATE_ALWAYS = 2,
846+
OPEN_EXISTING = 3,
847+
OPEN_ALWAYS = 4,
848+
TRUNCATE_EXISTING = 5,
849+
};
843850
void *WIN_FUNC CreateFileA(
844851
const char* lpFileName,
845852
unsigned int dwDesiredAccess,
@@ -853,19 +860,72 @@ namespace kernel32 {
853860
lpFileName, path.c_str(),
854861
dwDesiredAccess, dwShareMode, lpSecurityAttributes,
855862
dwCreationDisposition, dwFlagsAndAttributes);
863+
864+
wibo::lastError = 0; // possibly overwritten later in this function
865+
866+
// Based on https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#parameters
867+
// and this table: https://stackoverflow.com/a/14469641
868+
bool fileExists = (access(path.c_str(), F_OK) == 0);
869+
bool shouldTruncate = false;
870+
switch (dwCreationDisposition) {
871+
case CREATE_ALWAYS:
872+
if (fileExists) {
873+
wibo::lastError = 183; // ERROR_ALREADY_EXISTS
874+
shouldTruncate = true; // "The function overwrites the file"
875+
// Function succeeds
876+
}
877+
break;
878+
case CREATE_NEW:
879+
if (fileExists) {
880+
wibo::lastError = 80; // ERROR_FILE_EXISTS
881+
return INVALID_HANDLE_VALUE;
882+
}
883+
break;
884+
case OPEN_ALWAYS:
885+
if (fileExists) {
886+
wibo::lastError = 183; // ERROR_ALREADY_EXISTS
887+
// Function succeeds
888+
}
889+
break;
890+
case OPEN_EXISTING:
891+
if (!fileExists) {
892+
wibo::lastError = 2; // ERROR_FILE_NOT_FOUND
893+
return INVALID_HANDLE_VALUE;
894+
}
895+
break;
896+
case TRUNCATE_EXISTING:
897+
shouldTruncate = true;
898+
if (!fileExists) {
899+
wibo::lastError = 2; // ERROR_FILE_NOT_FOUND
900+
return INVALID_HANDLE_VALUE;
901+
}
902+
break;
903+
default:
904+
assert(0);
905+
}
906+
856907
FILE *fp;
857908
if (dwDesiredAccess == 0x80000000) { // read
858909
fp = fopen(path.c_str(), "rb");
859910
} else if (dwDesiredAccess == 0x40000000) { // write
860-
fp = fopen(path.c_str(), "wb");
911+
if (shouldTruncate || !fileExists) {
912+
fp = fopen(path.c_str(), "wb");
913+
} else {
914+
// There is no way to fopen with only write permissions
915+
// and without truncating the file...
916+
fp = fopen(path.c_str(), "rb+");
917+
}
861918
} else if (dwDesiredAccess == 0xc0000000) { // read/write
862-
fp = fopen(path.c_str(), "wb+");
919+
if (shouldTruncate || !fileExists) {
920+
fp = fopen(path.c_str(), "wb+");
921+
} else {
922+
fp = fopen(path.c_str(), "rb+");
923+
}
863924
} else {
864925
assert(0);
865926
}
866927

867928
if (fp) {
868-
wibo::lastError = 0;
869929
void *handle = files::allocFpHandle(fp);
870930
DEBUG_LOG("-> %p\n", handle);
871931
return handle;

0 commit comments

Comments
 (0)