Merge pull request #3395 from LeandroLP23/fix/kernel-mkdir-enotdir
fix(libkernel): report ENOTDIR from mkdir and rmdir when a path component is a file
This commit is contained in:
commit
ec77a616b6
|
|
@ -408,6 +408,19 @@ bool DescriptorIsOpen_nid_no_patch(int descriptor) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static std::filesystem::path WithoutTrailingSeparator(const std::filesystem::path& native) {
|
||||
return native.has_filename() ? native : native.parent_path();
|
||||
}
|
||||
|
||||
static bool HasNonDirectoryPrefix(const std::filesystem::path& native) {
|
||||
std::error_code error;
|
||||
for (auto prefix = WithoutTrailingSeparator(native).parent_path(); prefix.has_relative_path(); prefix = prefix.parent_path()) {
|
||||
const auto status = std::filesystem::status(prefix, error);
|
||||
if (std::filesystem::exists(status)) return !std::filesystem::is_directory(status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI chmod_nid_postfix(const char* path, int mode) {
|
||||
|
|
@ -553,7 +566,9 @@ int APS5_VABI mkdir_nid_postfix(const char* path, uint16_t mode) {
|
|||
if (const int error = PathError(path)) return PosixFailure(error);
|
||||
auto native = ResolvePath_nid_no_patch(path);
|
||||
if (NativeMkdir(native, mode) != 0) {
|
||||
return PosixResult(SceErrorFromErrno(errno));
|
||||
const int nativeError = errno;
|
||||
const bool blockedByFile = (nativeError == ENOENT || nativeError == EINVAL) && HasNonDirectoryPrefix(native);
|
||||
return PosixResult(SceErrorFromErrno(blockedByFile ? GUEST_ENOTDIR : nativeError));
|
||||
}
|
||||
RecordWrittenPath_nid_no_patch(native);
|
||||
return 0;
|
||||
|
|
@ -784,14 +799,10 @@ int APS5_VABI sceKernelMkdir(const char* path, uint16_t mode) {
|
|||
auto native = ResolvePath_nid_no_patch(path);
|
||||
while (!native.has_filename() && native.has_relative_path()) native = native.parent_path();
|
||||
std::error_code error;
|
||||
const auto status = std::filesystem::status(native, error);
|
||||
if (error && error != std::errc::no_such_file_or_directory) return SceErrorFromErrno(error.value());
|
||||
if (std::filesystem::exists(status)) return SceErrorFromErrno(GUEST_EEXIST);
|
||||
error.clear();
|
||||
const auto parent = std::filesystem::status(native.parent_path(), error);
|
||||
if (error) return SceErrorFromErrno(error.value());
|
||||
if (!std::filesystem::exists(parent)) return SceErrorFromErrno(GUEST_ENOENT);
|
||||
if (!std::filesystem::is_directory(parent)) return SceErrorFromErrno(GUEST_ENOTDIR);
|
||||
if (std::filesystem::exists(native, error)) return SceErrorFromErrno(GUEST_EEXIST);
|
||||
if (!std::filesystem::is_directory(WithoutTrailingSeparator(native).parent_path(), error)) {
|
||||
return SceErrorFromErrno(HasNonDirectoryPrefix(native) ? GUEST_ENOTDIR : GUEST_ENOENT);
|
||||
}
|
||||
if (!std::filesystem::create_directory(native, error)) return SceErrorFromErrno(error.value() ? error.value() : GUEST_EIO);
|
||||
RecordWrittenPath_nid_no_patch(native);
|
||||
return 0;
|
||||
|
|
@ -992,7 +1003,10 @@ int APS5_VABI sceKernelRmdir(const char* path) {
|
|||
if (path == nullptr) throw std::invalid_argument("sceKernelRmdir: path is null");
|
||||
const auto native = ResolvePath_nid_no_patch(path);
|
||||
std::error_code error;
|
||||
if (!std::filesystem::is_directory(native, error)) return SceErrorFromErrno(std::filesystem::exists(native, error) ? GUEST_ENOTDIR : GUEST_ENOENT);
|
||||
if (!std::filesystem::is_directory(native, error)) {
|
||||
const bool blockedByFile = HasNonDirectoryPrefix(native) || std::filesystem::exists(WithoutTrailingSeparator(native), error);
|
||||
return SceErrorFromErrno(blockedByFile ? GUEST_ENOTDIR : GUEST_ENOENT);
|
||||
}
|
||||
if (!std::filesystem::is_empty(native, error)) return SceErrorFromErrno(GUEST_ENOTEMPTY);
|
||||
if (!RemoveEmptyDirectory(native)) return SceErrorFromErrno(GUEST_EIO);
|
||||
RecordWrittenPath_nid_no_patch(native);
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ int APS5_VABI sceKernelStat(const char*, FileStat*);
|
|||
int APS5_VABI sceKernelFstat(int, FileStat*);
|
||||
int APS5_VABI sceKernelUnlink(const char*);
|
||||
int APS5_VABI sceKernelRmdir(const char*);
|
||||
int APS5_VABI sceKernelMkdir(const char*, unsigned short);
|
||||
int* APS5_VABI __error_nid_postfix();
|
||||
int APS5_VABI pipe_nid_postfix(int*);
|
||||
std::int64_t APS5_VABI read_nid_postfix(int, void*, std::size_t);
|
||||
|
|
@ -447,6 +448,32 @@ int main() {
|
|||
Require(rmdir_nid_postfix(lockedDirectoryPosix.string().c_str()) == 0 && !std::filesystem::exists(lockedDirectoryPosix));
|
||||
const auto lockedDirectoryKernel = lockedDirectory("locked-directory-kernel");
|
||||
Require(sceKernelRmdir(lockedDirectoryKernel.string().c_str()) == 0 && !std::filesystem::exists(lockedDirectoryKernel));
|
||||
const auto underFile = presentName + "/child";
|
||||
const auto deepUnderFile = presentName + "/child/leaf";
|
||||
Require(mkdir_nid_postfix(underFile.c_str(), 0700) == -1 && *__error_nid_postfix() == 20);
|
||||
Require(mkdir_nid_postfix(deepUnderFile.c_str(), 0700) == -1 && *__error_nid_postfix() == 20);
|
||||
Require(sceKernelMkdir(underFile.c_str(), 0700) == static_cast<int>(0x80020014u));
|
||||
Require(sceKernelMkdir(deepUnderFile.c_str(), 0700) == static_cast<int>(0x80020014u));
|
||||
Require(rmdir_nid_postfix(underFile.c_str()) == -1 && *__error_nid_postfix() == 20);
|
||||
Require(sceKernelRmdir(deepUnderFile.c_str()) == static_cast<int>(0x80020014u));
|
||||
Require(rmdir_nid_postfix((presentName + "/").c_str()) == -1 && *__error_nid_postfix() == 20);
|
||||
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 missingParentLeaf = rootName + "/missing/leaf";
|
||||
Require(sceKernelMkdir(missingParentLeaf.c_str(), 0700) == static_cast<int>(0x80020002u));
|
||||
const auto invalidNameUnderFile = presentName + "/a:b/x";
|
||||
Require(mkdir_nid_postfix(invalidNameUnderFile.c_str(), 0700) == -1 && *__error_nid_postfix() == 20);
|
||||
Require(sceKernelMkdir(invalidNameUnderFile.c_str(), 0700) == static_cast<int>(0x80020014u));
|
||||
const auto trailingPosix = root / "trailing_posix";
|
||||
const auto trailingKernel = root / "trailing_kernel";
|
||||
const auto trailingPosixName = trailingPosix.string() + "/";
|
||||
const auto trailingKernelName = trailingKernel.string() + "/";
|
||||
Require(mkdir_nid_postfix(trailingPosixName.c_str(), 0700) == 0 && std::filesystem::is_directory(trailingPosix));
|
||||
Require(sceKernelMkdir(trailingKernelName.c_str(), 0700) == 0 && std::filesystem::is_directory(trailingKernel));
|
||||
Require(rmdir_nid_postfix(trailingPosix.string().c_str()) == 0 && sceKernelRmdir(trailingKernel.string().c_str()) == 0);
|
||||
Require(!std::filesystem::exists(trailingPosix) && !std::filesystem::exists(trailingKernel));
|
||||
Require(std::filesystem::is_regular_file(present));
|
||||
Require(rmdir_nid_postfix("") == -1 && *__error_nid_postfix() == 2);
|
||||
Require(rmdir_nid_postfix(nullptr) == -1 && *__error_nid_postfix() == 14);
|
||||
Require(unlink_nid_postfix(missingName.c_str()) == -1 && *__error_nid_postfix() == 2);
|
||||
|
|
|
|||
Loading…
Reference in New Issue