Merge pull request #3436 from MarcZX100/codex/rmdir-dot-einval-3116
fix(filesystem): reject final dot removal paths
This commit is contained in:
commit
ea31cff19c
|
|
@ -15,6 +15,7 @@ extern "C" bool StopAtPrefixLetter_nid_no_patch(const char* str, char** endptr,
|
|||
|
||||
extern "C" std::filesystem::path ResolvePath_nid_no_patch(const char* path);
|
||||
extern "C" int SetWorkingDirectory_nid_no_patch(const char* resolved);
|
||||
extern "C" bool FinalPathComponentIsDot_nid_no_patch(const char* path);
|
||||
// Guest path aliases: a guest prefix such as "/savedata0" (a save-data mount point) resolves to a host
|
||||
// directory instead of the run directory; the prefix matches whole path components only.
|
||||
extern "C" void AddPathAlias_nid_no_patch(const char* guestPrefix, const char* hostPath);
|
||||
|
|
|
|||
|
|
@ -75,6 +75,15 @@ extern "C" int APS5_VABI remove_nid_postfix(const char* path) {
|
|||
if (!*path) { errno = 2; return -1; }
|
||||
try {
|
||||
const auto resolved = ResolvePath_nid_no_patch(path);
|
||||
if (FinalPathComponentIsDot_nid_no_patch(path)) {
|
||||
std::error_code statusError;
|
||||
const auto status = std::filesystem::status(resolved, statusError);
|
||||
if (statusError) { errno = FilesystemError(statusError); return -1; }
|
||||
if (!std::filesystem::exists(status)) { errno = 2; return -1; }
|
||||
if (!std::filesystem::is_directory(status)) { errno = 20; return -1; }
|
||||
errno = 22;
|
||||
return -1;
|
||||
}
|
||||
std::error_code error;
|
||||
#ifdef _WIN32
|
||||
const DWORD attributes = GetFileAttributesW(resolved.c_str());
|
||||
|
|
|
|||
|
|
@ -328,6 +328,14 @@ extern "C" int SetWorkingDirectory_nid_no_patch(const char* resolved) {
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" bool FinalPathComponentIsDot_nid_no_patch(const char* path) {
|
||||
std::string_view text(path);
|
||||
while (!text.empty() && (text.back() == '/' || text.back() == '\\')) text.remove_suffix(1);
|
||||
const auto separator = text.find_last_of("/\\");
|
||||
const auto component = text.substr(separator == std::string_view::npos ? 0 : separator + 1);
|
||||
return component == ".";
|
||||
}
|
||||
|
||||
extern "C" int APS5_VABI chdir_nid_postfix(const char* path) {
|
||||
if (!path) { errno = 14; return -1; }
|
||||
if (!*path) { errno = 2; return -1; }
|
||||
|
|
|
|||
|
|
@ -1018,6 +1018,7 @@ int APS5_VABI sceKernelRmdir(const char* path) {
|
|||
const bool blockedByFile = HasNonDirectoryPrefix(native) || std::filesystem::exists(WithoutTrailingSeparator(native), error);
|
||||
return SceErrorFromErrno(blockedByFile ? GUEST_ENOTDIR : GUEST_ENOENT);
|
||||
}
|
||||
if (FinalPathComponentIsDot_nid_no_patch(path)) return SceErrorFromErrno(GUEST_EINVAL);
|
||||
if (!std::filesystem::is_empty(native, error)) return SceErrorFromErrno(GUEST_ENOTEMPTY);
|
||||
if (!RemoveEmptyDirectory(native)) return SceErrorFromErrno(GUEST_EIO);
|
||||
RecordWrittenPath_nid_no_patch(native);
|
||||
|
|
|
|||
|
|
@ -460,6 +460,25 @@ int main() {
|
|||
Require(rmdir_nid_postfix((missingName + "/").c_str()) == -1 && *__error_nid_postfix() == 2);
|
||||
Require(sceKernelRmdir((presentName + "/").c_str()) == static_cast<int>(0x80020014u));
|
||||
Require(sceKernelRmdir((missingName + "/").c_str()) == static_cast<int>(0x80020002u));
|
||||
const auto dotDirectory = root / "dot-directory";
|
||||
Require(std::filesystem::create_directory(dotDirectory));
|
||||
const auto dotDirectoryName = dotDirectory.string() + "/.";
|
||||
const auto dotDirectoryTrailingName = dotDirectoryName + "/";
|
||||
Require(rmdir_nid_postfix(dotDirectoryName.c_str()) == -1 && *__error_nid_postfix() == 22);
|
||||
Require(sceKernelRmdir(dotDirectoryName.c_str()) == static_cast<int>(0x80020016u));
|
||||
Require(remove_nid_postfix(dotDirectoryName.c_str()) == -1 && *__error_nid_postfix() == 22);
|
||||
Require(rmdir_nid_postfix(dotDirectoryTrailingName.c_str()) == -1 && *__error_nid_postfix() == 22);
|
||||
Require(sceKernelRmdir(dotDirectoryTrailingName.c_str()) == static_cast<int>(0x80020016u));
|
||||
Require(remove_nid_postfix(dotDirectoryTrailingName.c_str()) == -1 && *__error_nid_postfix() == 22);
|
||||
Require(std::filesystem::is_directory(dotDirectory));
|
||||
const auto dotFileName = presentName + "/.";
|
||||
Require(rmdir_nid_postfix(dotFileName.c_str()) == -1 && *__error_nid_postfix() == 20);
|
||||
Require(sceKernelRmdir(dotFileName.c_str()) == static_cast<int>(0x80020014u));
|
||||
Require(remove_nid_postfix(dotFileName.c_str()) == -1 && *__error_nid_postfix() == 20);
|
||||
const auto dotMissingName = missingName + "/.";
|
||||
Require(rmdir_nid_postfix(dotMissingName.c_str()) == -1 && *__error_nid_postfix() == 2);
|
||||
Require(sceKernelRmdir(dotMissingName.c_str()) == static_cast<int>(0x80020002u));
|
||||
Require(remove_nid_postfix(dotMissingName.c_str()) == -1 && *__error_nid_postfix() == 2);
|
||||
const auto missingParentLeaf = rootName + "/missing/leaf";
|
||||
Require(sceKernelMkdir(missingParentLeaf.c_str(), 0700) == static_cast<int>(0x80020002u));
|
||||
const auto invalidNameUnderFile = presentName + "/a:b/x";
|
||||
|
|
@ -500,6 +519,7 @@ int main() {
|
|||
const auto empty = root / "empty";
|
||||
Require(std::filesystem::create_directory(empty));
|
||||
Require(rmdir_nid_postfix(empty.string().c_str()) == 0 && !std::filesystem::exists(empty));
|
||||
Require(rmdir_nid_postfix(dotDirectory.string().c_str()) == 0 && !std::filesystem::exists(dotDirectory));
|
||||
Require(remove_nid_postfix(root.string().c_str()) == 0);
|
||||
Require(!std::filesystem::exists(root));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue