Merge pull request #3677 from MarcZX100/carry/libkernel-delete-sharing-3316

fix(libkernel): allow delete sharing for open Windows files
This commit is contained in:
Adrià 2026-10-11 23:49:25 +02:00 committed by GitHub
commit 6c6c5552dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 1 deletions

View File

@ -21,8 +21,55 @@
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <windows.h>
static int OpenError(DWORD error) {
switch (error) {
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
case ERROR_INVALID_DRIVE:
case ERROR_BAD_NETPATH:
case ERROR_BAD_NET_NAME:
case ERROR_BAD_PATHNAME:
case ERROR_FILENAME_EXCED_RANGE:
return ENOENT;
case ERROR_ACCESS_DENIED:
case ERROR_SHARING_VIOLATION:
case ERROR_LOCK_VIOLATION:
case ERROR_WRITE_PROTECT:
case ERROR_NETWORK_ACCESS_DENIED:
case ERROR_CANNOT_MAKE:
case ERROR_DRIVE_LOCKED:
return EACCES;
case ERROR_FILE_EXISTS:
case ERROR_ALREADY_EXISTS:
return EEXIST;
case ERROR_TOO_MANY_OPEN_FILES:
return EMFILE;
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OUTOFMEMORY:
return ENOMEM;
case ERROR_DISK_FULL:
return ENOSPC;
default:
return EINVAL;
}
}
static int NativeOpen(const std::filesystem::path& p, int nativeFlags, std::uint16_t mode) {
return ::_wopen(p.wstring().c_str(), nativeFlags, static_cast<int>(mode));
const int access = nativeFlags & (_O_RDONLY | _O_WRONLY | _O_RDWR);
const DWORD desired = access == _O_RDONLY ? GENERIC_READ : access == _O_WRONLY ? GENERIC_WRITE : GENERIC_READ | GENERIC_WRITE;
DWORD disposition = OPEN_EXISTING;
if (nativeFlags & _O_CREAT) disposition = (nativeFlags & _O_EXCL) ? CREATE_NEW : (nativeFlags & _O_TRUNC) ? CREATE_ALWAYS : OPEN_ALWAYS;
else if (nativeFlags & _O_TRUNC) disposition = TRUNCATE_EXISTING;
const DWORD attributes = (nativeFlags & _O_CREAT) && !(mode & _S_IWRITE) ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_NORMAL;
SECURITY_ATTRIBUTES security{sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE};
const auto handle = CreateFileW(p.c_str(), desired, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &security, disposition, attributes, nullptr);
if (handle == INVALID_HANDLE_VALUE) {
errno = OpenError(GetLastError());
return -1;
}
const int descriptor = ::_open_osfhandle(reinterpret_cast<std::intptr_t>(handle), nativeFlags & (_O_APPEND | _O_RDONLY | _O_BINARY));
if (descriptor < 0) CloseHandle(handle);
return descriptor;
}
static std::int64_t NativeLseek(int fd, std::int64_t offset, int whence) {
return ::_lseeki64(fd, offset, whence);

View File

@ -230,6 +230,21 @@ int main() {
Require(mkdir_nid_postfix(nullptr, 0700) == -1 && *__error_nid_postfix() == 14);
const auto file = root / "file.txt";
{ std::ofstream stream(file); stream << "retained until removal"; }
const auto held = root / "held.txt";
const auto heldName = held.string();
{ std::ofstream stream(held); stream << "held"; }
const int heldDescriptor = sceKernelOpen(heldName.c_str(), 2, 0);
Require(heldDescriptor >= 0 && sceKernelUnlink(heldName.c_str()) == 0 && !std::filesystem::exists(held));
char heldBytes[4]{};
Require(read_nid_postfix(heldDescriptor, heldBytes, sizeof(heldBytes)) == sizeof(heldBytes) && std::memcmp(heldBytes, "held", 4) == 0);
const int recreated = sceKernelOpen(heldName.c_str(), 0x0a01, 0644);
Require(recreated >= 0 && sceKernelClose(heldDescriptor) == 0 && std::filesystem::file_size(held) == 0);
const auto moved = root / "moved.txt";
Require(rename_nid_postfix(heldName.c_str(), moved.string().c_str()) == 0 && !std::filesystem::exists(held));
Require(write_nid_postfix(recreated, "moved", 5) == 5 && sceKernelClose(recreated) == 0 && std::filesystem::file_size(moved) == 5);
const int removing = open_nid_postfix(moved.string().c_str(), 0, 0);
Require(removing >= 0 && remove_nid_postfix(moved.string().c_str()) == 0 && !std::filesystem::exists(moved));
Require(close_nid_postfix(removing) == 0);
Require(remove_nid_postfix(root.string().c_str()) == -1);
Require(*__error_nid_postfix() == 66);
Require(std::filesystem::is_regular_file(file));