Merge pull request #9101 from xXPBSXx/fix/flock-directory-windows

fix(libkernel): accept flock on a directory descriptor on Windows
This commit is contained in:
Adrià authored and GitHub committed 2026-10-22 19:42:03 +02:00
commit 29b25aaf4a
4 files changed
+23 -1

No files matched your search

+1 -1
View File
@@ -1843,7 +1843,7 @@ if(BUILD_TESTING)
target_include_directories(guest_file_lock_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_file_lock_tests PRIVATE libkernel libc)
configure_windows_unwind(guest_file_lock_tests)
foreach(fileLockCase IN ITEMS duplicate lifetime conversion threads streams process)
foreach(fileLockCase IN ITEMS duplicate lifetime conversion threads streams process directory)
add_test(NAME guest_file_lock_${fileLockCase} COMMAND guest_file_lock_tests ${fileLockCase})
set_tests_properties(guest_file_lock_${fileLockCase} PROPERTIES TIMEOUT 20 ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
@@ -865,6 +865,9 @@ int APS5_VABI flock_nid_postfix(int d, int operation) {
#endif
const int type = operation & 8 ? 8 : operation & 2 ? 2 : operation & 1 ? 1 : 0;
if (type == 0) return PosixFailure(GUEST_EBADF);
#ifdef _WIN32
if (File::IsDirectoryDescriptor(d)) return 0;
#endif
if (NativeFlock(d, type | (operation & 4)) != 0) {
#ifdef _WIN32
const auto error = ::GetLastError();
+18
View File
@@ -296,6 +296,23 @@ static void Processes() {
Require(ChildTry(fixtures, 2) == 0);
}
static void Directories() {
const std::filesystem::path directory = std::filesystem::temp_directory_path() / ("anyps5-flock-dir-" + std::to_string(::GetCurrentProcessId()));
std::filesystem::create_directories(directory);
const std::string path = directory.string();
const int descriptor = open_nid_postfix(path.c_str(), 0x20000, 0);
Require(descriptor >= 0);
Require(flock_nid_postfix(descriptor, 1 | 4) == 0);
Require(flock_nid_postfix(descriptor, 2 | 4) == 0);
Require(flock_nid_postfix(descriptor, 2) == 0);
Require(flock_nid_postfix(descriptor, 8) == 0);
Require(flock_nid_postfix(descriptor, 0) == -1 && *__error_nid_postfix() == 9);
Require(flock_nid_postfix(descriptor, 4) == -1 && *__error_nid_postfix() == 9);
Require(close_nid_postfix(descriptor) == 0);
std::error_code ignored;
std::filesystem::remove_all(directory, ignored);
}
int main(int argc, char** argv) {
if (argc >= 4 && std::string(argv[1]) == "child") {
int busy = 0;
@@ -320,5 +337,6 @@ int main(int argc, char** argv) {
else if (mode == "threads") Threads();
else if (mode == "streams") Streams();
else if (mode == "process") Processes();
else if (mode == "directory") Directories();
else std::abort();
}
+1
View File
@@ -249,3 +249,4 @@
- [param.sfo](../../../core/libs/prx/libkernel/AppMetadata/src/ParamSfoParser.cpp) (libkernel) is read when `param.json` is absent, for `TITLE`, `TITLE_ID`, `DOWNLOAD_DATA_SIZE` and `USER_DEFINED_PARAM_1` to `_4`, and mounts `/data` and `/download0` like `param.json`; the localized `TITLE_00` to `TITLE_30` are not selected by the console language.
- [sysctl MIBs for kern.smp.maxcpus, kern.stackprot, kern.sched.name and kern.timecounter.hardware](../../../core/libs/prx/libkernel/System/src/SystemConfiguration.cpp) (libkernel) - on a PS5 (firmware 12.70), a payload process resolves these names to {1, 2147482816, 2147482814}, {1, 2147483151}, {1, 2147483182, 2147483181} and {1, 2147482838, 2147482834}; `sysctl` returns -1 with `ENOENT` for reads and size queries by those exact MIBs, leaving the buffer and length unchanged, including when either or both output pointers are null. Writes were not measured and throw. `sysctlnametomib` still throws for these four names; #7541 implements the mappings for nine of the other names.
- [sceKernelGetProcessAbiType](../../../core/libs/prx/libkernel/Unimplemented.cpp) (libkernel) throws: no measured value, prototype or documented consumer of the process ABI type was found, and PS5_MihawkOS (`mihawk-99/PS5_MihawkOS`, PPSA99170) is the only title known to import it. Returning a guessed constant would let a title branch on a value the console never answered with, so the declaration only resolves the import until the console value is measured
- [flock on a directory descriptor](../../../core/libs/prx/libkernel/File/src/Stdio.cpp) (libkernel) returns 0 on Windows without taking a lock, as FreeBSD 11.4's `sys_flock` accepts any vnode descriptor and so succeeds on a directory; Windows `LockFileEx` rejects a directory handle, which used to abort the process. Two descriptors of the same directory therefore never conflict: a second `LOCK_EX | LOCK_NB` succeeds where FreeBSD fails with `EWOULDBLOCK`. Linux and macOS use the host `flock`. Not measured on a console