fs: modernize mount utils

This commit is contained in:
Michael Scire 2020-03-06 10:32:11 -08:00
parent 7004ad3d7f
commit 901bed6350
5 changed files with 100 additions and 75 deletions

View file

@ -26,21 +26,25 @@ namespace ams::fs {
constexpr inline char Dot = '.';
constexpr inline char NullTerminator = '\x00';
constexpr inline char UnsupportedDirectorySeparator = '\\';
constexpr inline char AlternateDirectorySeparator = '\\';
}
class PathTool {
public:
static constexpr const char RootPath[] = "/";
public:
static constexpr inline bool IsUnsupportedSeparator(char c) {
return c == StringTraits::UnsupportedDirectorySeparator;
static constexpr inline bool IsAlternateSeparator(char c) {
return c == StringTraits::AlternateDirectorySeparator;
}
static constexpr inline bool IsSeparator(char c) {
return c == StringTraits::DirectorySeparator;
}
static constexpr inline bool IsAnySeparator(char c) {
return IsSeparator(c) || IsAlternateSeparator(c);
}
static constexpr inline bool IsNullTerminator(char c) {
return c == StringTraits::NullTerminator;
}
@ -61,6 +65,10 @@ namespace ams::fs {
return IsWindowsDriveCharacter(p[0]) && IsDriveSeparator(p[1]);
}
static constexpr inline bool IsUnc(const char *p) {
return (IsSeparator(p[0]) && IsSeparator(p[1])) || (IsAlternateSeparator(p[0]) && IsAlternateSeparator(p[1]));
}
static constexpr inline bool IsCurrentDirectory(const char *p) {
return IsDot(p[0]) && (IsSeparator(p[1]) || IsNullTerminator(p[1]));
}

View file

@ -33,47 +33,36 @@ namespace ams::fs::impl {
return nullptr;
}
Result GetMountNameImpl(MountName &out, const char *path) {
Result GetMountNameAndSubPath(MountName *out_mount_name, const char **out_sub_path, const char *path) {
/* Handle the Host-path case. */
if (PathTool::IsWindowsAbsolutePath(path) || PathTool::IsUnc(path)) {
std::strncpy(out_mount_name->str, HostRootFileSystemMountName, MountNameLengthMax);
out_mount_name->str[MountNameLengthMax] = '\x00';
return ResultSuccess();
}
/* Locate the drive separator. */
const char *drive_separator = FindMountNameDriveSeparator(path);
R_UNLESS(drive_separator != nullptr, fs::ResultInvalidMountName());
/* Ensure the mount name isn't too long. */
const size_t len = drive_separator - path;
R_UNLESS(len + 1 <= sizeof(MountName), fs::ResultInvalidMountName());
R_UNLESS(len <= MountNameLengthMax, fs::ResultInvalidMountName());
std::memcpy(out.str, path, len);
out.str[len] = StringTraits::NullTerminator;
/* Ensure the result sub-path is valid. */
const char *sub_path = drive_separator + 1;
R_UNLESS(!PathTool::IsNullTerminator(sub_path[0]), fs::ResultInvalidMountName());
R_UNLESS(PathTool::IsAnySeparator(sub_path[0]), fs::ResultInvalidPathFormat());
/* Set output. */
std::memcpy(out_mount_name->str, path, len);
out_mount_name->str[len] = StringTraits::NullTerminator;
*out_sub_path = sub_path;
return ResultSuccess();
}
}
MountName GetMountName(const char *path) {
MountName mount_name;
if (IsWindowsDrive(path)) {
std::strncpy(mount_name.str, HostRootFileSystemMountName, MountNameLengthMax);
mount_name.str[MountNameLengthMax] = StringTraits::NullTerminator;
} else {
R_ABORT_UNLESS(GetMountNameImpl(mount_name, path));
}
return mount_name;
}
const char *GetSubPath(const char *path) {
if (IsWindowsDrive(path)) {
return path;
}
const char *sub_path = path;
while (!PathTool::IsDriveSeparator(*sub_path)) {
sub_path++;
}
AMS_ABORT_UNLESS(PathTool::IsSeparator(sub_path[1]) || PathTool::IsUnsupportedSeparator(sub_path[1]));
return sub_path + 1;
}
bool IsValidMountName(const char *name) {
if (PathTool::IsNullTerminator(*name)) {
return false;
@ -118,12 +107,17 @@ namespace ams::fs::impl {
return ResultSuccess();
}
Result FindFileSystem(FileSystemAccessor **out, const char *path) {
R_UNLESS(path != nullptr, fs::ResultInvalidPath());
Result FindFileSystem(FileSystemAccessor **out_accessor, const char **out_sub_path, const char *path) {
R_UNLESS(out_accessor != nullptr, fs::ResultUnexpectedInFindFileSystemA());
R_UNLESS(out_sub_path != nullptr, fs::ResultUnexpectedInFindFileSystemA());
R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
R_UNLESS(strncmp(path, HostRootFileSystemMountName, strnlen(HostRootFileSystemMountName, sizeof(MountName))) != 0, fs::ResultInvalidPathFormat());
R_UNLESS(strncmp(path, HostRootFileSystemMountName, strnlen(HostRootFileSystemMountName, sizeof(MountName))) != 0, fs::ResultNotMounted());
return impl::Find(out, GetMountName(path).str);
MountName mount_name;
R_TRY(GetMountNameAndSubPath(std::addressof(mount_name), out_sub_path, path));
return impl::Find(out_accessor, mount_name.str);
}
}
@ -147,15 +141,21 @@ namespace ams::fs {
}
Result ConvertToFsCommonPath(char *dst, size_t dst_size, const char *src) {
/* Get the mount name for the path. */
MountName mount_name = impl::GetMountName(src);
/* Ensure neither argument is nullptr. */
R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
R_UNLESS(src != nullptr, fs::ResultNullptrArgument());
/* Get the mount name and sub path for the path. */
MountName mount_name;
const char *sub_path;
R_TRY(impl::GetMountNameAndSubPath(std::addressof(mount_name), std::addressof(sub_path), src));
impl::FileSystemAccessor *accessor;
R_TRY(impl::Find(std::addressof(accessor), mount_name.str));
R_TRY(accessor->GetCommonMountName(dst, dst_size));
const auto mount_name_len = strnlen(dst, dst_size);
const auto common_path_len = std::snprintf(dst + mount_name_len, dst_size - mount_name_len, "%s", impl::GetSubPath(src));
const auto common_path_len = std::snprintf(dst + mount_name_len, dst_size - mount_name_len, "%s", sub_path);
R_UNLESS(static_cast<size_t>(common_path_len) < dst_size - mount_name_len, fs::ResultTooLongPath());
return ResultSuccess();

View file

@ -20,9 +20,8 @@ namespace ams::fs::impl {
class FileSystemAccessor;
Result FindFileSystem(FileSystemAccessor **out, const char *path);
Result FindFileSystem(FileSystemAccessor **out_accessor, const char **out_sub_path, const char *path);
const char *GetSubPath(const char *path);
bool IsWindowsDrive(const char *name);
bool IsReservedMountName(const char *name);
Result CheckMountName(const char *name);

View file

@ -34,74 +34,85 @@ namespace ams::fs {
Result CreateFile(const char* path, s64 size, int option) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->CreateFile(impl::GetSubPath(path), size, option);
return accessor->CreateFile(sub_path, size, option);
}
Result DeleteFile(const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->DeleteFile(impl::GetSubPath(path));
return accessor->DeleteFile(sub_path);
}
Result CreateDirectory(const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->CreateDirectory(impl::GetSubPath(path));
return accessor->CreateDirectory(sub_path);
}
Result DeleteDirectory(const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->DeleteDirectory(impl::GetSubPath(path));
return accessor->DeleteDirectory(sub_path);
}
Result DeleteDirectoryRecursively(const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->DeleteDirectoryRecursively(impl::GetSubPath(path));
return accessor->DeleteDirectoryRecursively(sub_path);
}
Result RenameFile(const char *old_path, const char *new_path) {
impl::FileSystemAccessor *old_accessor;
impl::FileSystemAccessor *new_accessor;
R_TRY(impl::FindFileSystem(std::addressof(old_accessor), old_path));
R_TRY(impl::FindFileSystem(std::addressof(new_accessor), new_path));
const char *old_sub_path;
const char *new_sub_path;
R_TRY(impl::FindFileSystem(std::addressof(old_accessor), std::addressof(old_sub_path), old_path));
R_TRY(impl::FindFileSystem(std::addressof(new_accessor), std::addressof(new_sub_path), new_path));
R_UNLESS(old_accessor == new_accessor, fs::ResultRenameToOtherFileSystem());
return old_accessor->RenameFile(impl::GetSubPath(old_path), impl::GetSubPath(new_path));
return old_accessor->RenameFile(old_sub_path, new_sub_path);
}
Result RenameDirectory(const char *old_path, const char *new_path) {
impl::FileSystemAccessor *old_accessor;
impl::FileSystemAccessor *new_accessor;
R_TRY(impl::FindFileSystem(std::addressof(old_accessor), old_path));
R_TRY(impl::FindFileSystem(std::addressof(new_accessor), new_path));
const char *old_sub_path;
const char *new_sub_path;
R_TRY(impl::FindFileSystem(std::addressof(old_accessor), std::addressof(old_sub_path), old_path));
R_TRY(impl::FindFileSystem(std::addressof(new_accessor), std::addressof(new_sub_path), new_path));
R_UNLESS(old_accessor == new_accessor, fs::ResultRenameToOtherFileSystem());
return old_accessor->RenameDirectory(impl::GetSubPath(old_path), impl::GetSubPath(new_path));
return old_accessor->RenameDirectory(old_sub_path, new_sub_path);
}
Result GetEntryType(DirectoryEntryType *out, const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->GetEntryType(out, impl::GetSubPath(path));
return accessor->GetEntryType(out, sub_path);
}
Result OpenFile(FileHandle *out_file, const char *path, int mode) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
R_UNLESS(out_file != nullptr, fs::ResultNullptrArgument());
std::unique_ptr<impl::FileAccessor> file_accessor;
R_TRY(accessor->OpenFile(std::addressof(file_accessor), impl::GetSubPath(path), static_cast<OpenMode>(mode)));
R_TRY(accessor->OpenFile(std::addressof(file_accessor), sub_path, static_cast<OpenMode>(mode)));
out_file->handle = file_accessor.release();
return ResultSuccess();
@ -109,12 +120,13 @@ namespace ams::fs {
Result OpenDirectory(DirectoryHandle *out_dir, const char *path, int mode) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
R_UNLESS(out_dir != nullptr, fs::ResultNullptrArgument());
std::unique_ptr<impl::DirectoryAccessor> dir_accessor;
R_TRY(accessor->OpenDirectory(std::addressof(dir_accessor), impl::GetSubPath(path), static_cast<OpenDirectoryMode>(mode)));
R_TRY(accessor->OpenDirectory(std::addressof(dir_accessor), sub_path, static_cast<OpenDirectoryMode>(mode)));
out_dir->handle = dir_accessor.release();
return ResultSuccess();
@ -122,38 +134,43 @@ namespace ams::fs {
Result CleanDirectoryRecursively(const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->CleanDirectoryRecursively(impl::GetSubPath(path));
return accessor->CleanDirectoryRecursively(sub_path);
}
Result GetFreeSpaceSize(s64 *out, const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->GetFreeSpaceSize(out, impl::GetSubPath(path));
return accessor->GetFreeSpaceSize(out, sub_path);
}
Result GetTotalSpaceSize(s64 *out, const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->GetTotalSpaceSize(out, impl::GetSubPath(path));
return accessor->GetTotalSpaceSize(out, sub_path);
}
Result SetConcatenationFileAttribute(const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->QueryEntry(nullptr, 0, nullptr, 0, fsa::QueryId::SetConcatenationFileAttribute, impl::GetSubPath(path));
return accessor->QueryEntry(nullptr, 0, nullptr, 0, fsa::QueryId::SetConcatenationFileAttribute, sub_path);
}
Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) {
impl::FileSystemAccessor *accessor;
R_TRY(impl::FindFileSystem(std::addressof(accessor), path));
const char *sub_path;
R_TRY(impl::FindFileSystem(std::addressof(accessor), std::addressof(sub_path), path));
return accessor->GetFileTimeStampRaw(out, impl::GetSubPath(path));
return accessor->GetFileTimeStampRaw(out, sub_path);
}
Result OpenFile(FileHandle *out, std::unique_ptr<fsa::IFile> &&file, int mode) {

View file

@ -198,6 +198,7 @@ namespace ams::fs {
R_DEFINE_ERROR_RESULT(GameCardLogoDataCorrupted, 4781);
R_DEFINE_ERROR_RANGE(Unexpected, 5000, 5999);
R_DEFINE_ERROR_RESULT(UnexpectedInFindFileSystemA, 5319);
R_DEFINE_ERROR_RANGE(PreconditionViolation, 6000, 6499);
R_DEFINE_ERROR_RANGE(InvalidArgument, 6001, 6199);