subrepo:
  subdir:   "libraries"
  merged:   "07af583b"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "07af583b"
git-subrepo:
  version:  "0.4.0"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "5d6aba9"
This commit is contained in:
Michael Scire
2019-12-09 03:57:37 -08:00
committed by SciresM
parent 28717bfd27
commit 0105455086
294 changed files with 29915 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::fs {
Result FileStorage::UpdateSize() {
R_UNLESS(this->size == InvalidSize, ResultSuccess());
return this->base_file->GetSize(&this->size);
}
Result FileStorage::Read(s64 offset, void *buffer, size_t size) {
/* Immediately succeed if there's nothing to read. */
R_UNLESS(size > 0, ResultSuccess());
/* Validate buffer. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
/* Ensure our size is valid. */
R_TRY(this->UpdateSize());
/* Ensure our access is valid. */
R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange());
size_t read_size;
return this->base_file->Read(&read_size, offset, buffer, size);
}
Result FileStorage::Write(s64 offset, const void *buffer, size_t size) {
/* Immediately succeed if there's nothing to write. */
R_UNLESS(size > 0, ResultSuccess());
/* Validate buffer. */
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
/* Ensure our size is valid. */
R_TRY(this->UpdateSize());
/* Ensure our access is valid. */
R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange());
return this->base_file->Write(offset, buffer, size, fs::WriteOption());
}
Result FileStorage::Flush() {
return this->base_file->Flush();
}
Result FileStorage::GetSize(s64 *out_size) {
R_TRY(this->UpdateSize());
*out_size = this->size;
return ResultSuccess();
}
Result FileStorage::SetSize(s64 size) {
this->size = InvalidSize;
return this->base_file->SetSize(size);
}
Result FileStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) {
switch (op_id) {
case OperationId::InvalidateCache:
case OperationId::QueryRange:
if (size == 0) {
if (op_id == OperationId::QueryRange) {
R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize());
reinterpret_cast<QueryRangeInfo *>(dst)->Clear();
}
return ResultSuccess();
}
R_TRY(this->UpdateSize());
R_UNLESS(IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultOutOfRange());
return this->base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size);
default:
return fs::ResultUnsupportedOperation();
}
}
}

View File

@@ -0,0 +1,248 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::fs {
Result PathTool::Normalize(char *out, size_t *out_len, const char *src, size_t max_out_size, bool unc_preserved) {
/* Paths must start with / */
R_UNLESS(IsSeparator(src[0]), fs::ResultInvalidPathFormat());
bool skip_next_sep = false;
size_t i = 0;
size_t len = 0;
while (!IsNullTerminator(src[i])) {
if (IsSeparator(src[i])) {
/* Swallow separators. */
while (IsSeparator(src[++i])) { }
if (IsNullTerminator(src[i])) {
break;
}
/* Handle skip if needed */
if (!skip_next_sep) {
if (len + 1 == max_out_size) {
out[len] = StringTraits::NullTerminator;
if (out_len != nullptr) {
*out_len = len;
}
return fs::ResultTooLongPath();
}
out[len++] = StringTraits::DirectorySeparator;
if (unc_preserved && len == 1) {
while (len < i) {
if (len + 1 == max_out_size) {
out[len] = StringTraits::NullTerminator;
if (out_len != nullptr) {
*out_len = len;
}
return fs::ResultTooLongPath();
}
out[len++] = StringTraits::DirectorySeparator;
}
}
}
skip_next_sep = false;
}
/* See length of current dir. */
size_t dir_len = 0;
while (!IsSeparator(src[i+dir_len]) && !IsNullTerminator(src[i+dir_len])) {
dir_len++;
}
if (IsCurrentDirectory(&src[i])) {
skip_next_sep = true;
} else if (IsParentDirectory(&src[i])) {
AMS_ASSERT(IsSeparator(out[0]));
AMS_ASSERT(IsSeparator(out[len - 1]));
R_UNLESS(len != 1, fs::ResultDirectoryUnobtainable());
/* Walk up a directory. */
len -= 2;
while (!IsSeparator(out[len])) {
len--;
}
} else {
/* Copy, possibly truncating. */
if (len + dir_len + 1 <= max_out_size) {
for (size_t j = 0; j < dir_len; j++) {
out[len++] = src[i+j];
}
} else {
const size_t copy_len = max_out_size - 1 - len;
for (size_t j = 0; j < copy_len; j++) {
out[len++] = src[i+j];
}
out[len] = StringTraits::NullTerminator;
if (out_len != nullptr) {
*out_len = len;
}
return fs::ResultTooLongPath();
}
}
i += dir_len;
}
if (skip_next_sep) {
len--;
}
if (len == 0 && max_out_size) {
out[len++] = StringTraits::DirectorySeparator;
}
R_UNLESS(max_out_size >= len - 1, fs::ResultTooLongPath());
/* Null terminate. */
out[len] = StringTraits::NullTerminator;
if (out_len != nullptr) {
*out_len = len;
}
/* Assert normalized. */
bool normalized = false;
AMS_ASSERT(unc_preserved || (R_SUCCEEDED(IsNormalized(&normalized, out)) && normalized));
return ResultSuccess();
}
Result PathTool::IsNormalized(bool *out, const char *path) {
/* Nintendo uses a state machine here. */
enum class PathState {
Start,
Normal,
FirstSeparator,
Separator,
CurrentDir,
ParentDir,
WindowsDriveLetter,
};
PathState state = PathState::Start;
for (const char *cur = path; *cur != StringTraits::NullTerminator; cur++) {
const char c = *cur;
switch (state) {
case PathState::Start:
if (IsWindowsDriveCharacter(c)) {
state = PathState::WindowsDriveLetter;
} else if (IsSeparator(c)) {
state = PathState::FirstSeparator;
} else {
return fs::ResultInvalidPathFormat();
}
break;
case PathState::Normal:
if (IsSeparator(c)) {
state = PathState::Separator;
}
break;
case PathState::FirstSeparator:
case PathState::Separator:
if (IsSeparator(c)) {
*out = false;
return ResultSuccess();
} else if (IsDot(c)) {
state = PathState::CurrentDir;
} else {
state = PathState::Normal;
}
break;
case PathState::CurrentDir:
if (IsSeparator(c)) {
*out = false;
return ResultSuccess();
} else if (IsDot(c)) {
state = PathState::ParentDir;
} else {
state = PathState::Normal;
}
break;
case PathState::ParentDir:
if (IsSeparator(c)) {
*out = false;
return ResultSuccess();
} else {
state = PathState::Normal;
}
break;
case PathState::WindowsDriveLetter:
if (IsDriveSeparator(c)) {
*out = true;
return ResultSuccess();
} else {
return fs::ResultInvalidPathFormat();
}
break;
}
}
switch (state) {
case PathState::Start:
case PathState::WindowsDriveLetter:
return fs::ResultInvalidPathFormat();
case PathState::FirstSeparator:
case PathState::Normal:
*out = true;
break;
case PathState::CurrentDir:
case PathState::ParentDir:
case PathState::Separator:
*out = false;
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
return ResultSuccess();
}
bool PathTool::IsSubPath(const char *lhs, const char *rhs) {
AMS_ASSERT(lhs != nullptr);
AMS_ASSERT(rhs != nullptr);
/* Special case certain paths. */
if (IsSeparator(lhs[0]) && !IsSeparator(lhs[1]) && IsSeparator(rhs[0]) && IsSeparator(rhs[1])) {
return false;
}
if (IsSeparator(rhs[0]) && !IsSeparator(rhs[1]) && IsSeparator(lhs[0]) && IsSeparator(lhs[1])) {
return false;
}
if (IsSeparator(lhs[0]) && IsNullTerminator(lhs[1]) && IsSeparator(rhs[0]) && !IsNullTerminator(rhs[1])) {
return true;
}
if (IsSeparator(rhs[0]) && IsNullTerminator(rhs[1]) && IsSeparator(lhs[0]) && !IsNullTerminator(lhs[1])) {
return true;
}
/* Check subpath. */
for (size_t i = 0; /* No terminating condition */; i++) {
if (IsNullTerminator(lhs[i])) {
return IsSeparator(rhs[i]);
} else if (IsNullTerminator(rhs[i])) {
return IsSeparator(lhs[i]);
} else if (lhs[i] != rhs[i]) {
return false;
}
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::fs {
Result VerifyPath(const char *path, size_t max_path_len, size_t max_name_len) {
const char *cur = path;
size_t name_len = 0;
for (size_t path_len = 0; path_len <= max_path_len && name_len <= max_name_len; path_len++) {
const char c = *(cur++);
/* If terminated, we're done. */
R_UNLESS(c != StringTraits::NullTerminator, ResultSuccess());
/* TODO: Nintendo converts the path from utf-8 to utf-32, one character at a time. */
/* We should do this. */
/* Banned characters: :*?<>| */
R_UNLESS((c != ':' && c != '*' && c != '?' && c != '<' && c != '>' && c != '|'), fs::ResultInvalidCharacter());
name_len++;
/* Check for separator. */
if (c == '\\' || c == '/') {
name_len = 0;
}
}
return fs::ResultTooLongPath();
}
}