sceIoRename: refuse wildcards, an existing destination, and don't wait on XDEV

Three ways our rename differed from the PSP's:

- A wildcard in either path was passed through to the host, so
  renaming "test*.txt" could quietly rename a real file. The PSP
  doesn't expand them here, it rejects them outright.
- Renaming onto a file that already exists succeeded, because the host
  rename() replaces the destination. The PSP refuses, and renaming a
  file onto itself counts as that too.
- Crossing devices returned the right error, but after the same wait
  as everything else. The hardware fails that one immediately.

Fixes io/file/rename, moved to tests_good.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
This commit is contained in:
Henrik Rydgård
2026-09-04 18:13:10 -06:00
co-authored by Claude Opus 5
parent fd72f308af
commit 5a84f287c4
2 changed files with 21 additions and 1 deletions
+20
View File
@@ -2096,12 +2096,32 @@ static u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 o
return hleNoLog(SCE_KERNEL_ERROR_UNSUP);
}
static bool IoPathHasWildcard(const char *path) {
return path && strpbrk(path, "*?") != nullptr;
}
static u32 sceIoRename(const char *from, const char *to) {
// TODO: Timing isn't terribly accurate.
// sceIoRename doesn't expand wildcards, it refuses them - in either path, and before it
// looks at whether anything is actually there.
if (IoPathHasWildcard(from) || IoPathHasWildcard(to)) {
return hleDelayResult(hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_INVALID_ARGUMENT, "wildcard in path"), "file renamed", 1000);
}
if (!pspFileSystem.GetFileInfo(from).exists)
return hleDelayResult(hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND), "file renamed", 1000);
// The PSP won't rename onto something that already exists, and renaming a file onto itself
// counts. Host rename() would happily replace the destination.
if (pspFileSystem.GetFileInfo(to).exists)
return hleDelayResult(hleLogError(Log::sceIo, SCE_KERNEL_ERROR_ERRNO_FILE_ALREADY_EXISTS, "destination exists"), "file renamed", 1000);
int result = pspFileSystem.RenameFile(from, to);
if (result == (int)SCE_KERNEL_ERROR_XDEV) {
// Renaming across devices is refused up front, without the wait the other errors take.
return hleLogError(Log::sceIo, result, "cannot rename across devices");
}
if (result < 0)
WARN_LOG(Log::sceIo, "Could not move %s to %s", from, to);
return hleDelayResult(hleLogDebug(Log::sceIo, result), "file renamed", 1000);
+1 -1
View File
@@ -211,6 +211,7 @@ tests_good = [
"intr/suspended",
"intr/vblank/vblank",
"io/cwd/cwd",
"io/file/rename",
"io/open/badparent",
"jpeg/create",
"jpeg/delete",
@@ -452,7 +453,6 @@ tests_next = [
"intr/waits",
"io/directory/directory",
"io/file/file",
"io/file/rename",
"io/io/io",
"io/iodrv/iodrv",
"io/open/tty0",