mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-05 19:51:45 +00:00
fs.mitm: Implement path normalization
This commit is contained in:
parent
b62014554c
commit
c1588d0300
2 changed files with 104 additions and 3 deletions
|
@ -14,6 +14,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include "fs_path_utils.hpp"
|
#include "fs_path_utils.hpp"
|
||||||
#include "fs_results.hpp"
|
#include "fs_results.hpp"
|
||||||
|
@ -162,7 +163,99 @@ Result FsPathUtils::IsNormalized(bool *out, const char *path) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, size_t *out_size) {
|
Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, size_t *out_len) {
|
||||||
/* TODO */
|
/* Paths must start with / */
|
||||||
return ResultFsNotImplemented;
|
if (src[0] != '/') {
|
||||||
|
return ResultFsInvalidPathFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skip_next_sep = false;
|
||||||
|
size_t i = 0;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
while (src[i] != 0) {
|
||||||
|
if (src[i] == '/') {
|
||||||
|
/* Swallow separators. */
|
||||||
|
while (src[++i] == '/') { }
|
||||||
|
if (src[i] == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle skip if needed */
|
||||||
|
if (!skip_next_sep) {
|
||||||
|
if (len + 1 == max_out_size) {
|
||||||
|
out[len] = 0;
|
||||||
|
*out_len = len;
|
||||||
|
return ResultFsTooLongPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
out[len++] = '/';
|
||||||
|
|
||||||
|
/* TODO: N has some weird windows support stuff here under a bool. */
|
||||||
|
/* Boolean is normally false though? */
|
||||||
|
}
|
||||||
|
skip_next_sep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See length of current dir. */
|
||||||
|
size_t dir_len = 0;
|
||||||
|
while (src[i+dir_len] != '/' && src[i+dir_len] != 0) {
|
||||||
|
dir_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FsPathUtils::IsCurrentDirectory(&src[i])) {
|
||||||
|
skip_next_sep = true;
|
||||||
|
} else if (FsPathUtils::IsParentDirectory(&src[i])) {
|
||||||
|
if (len == 1) {
|
||||||
|
return ResultFsDirectoryUnobtainable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Walk up a directory. */
|
||||||
|
len -= 2;
|
||||||
|
while (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] = 0;
|
||||||
|
*out_len = len;
|
||||||
|
return ResultFsTooLongPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i += dir_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip_next_sep) {
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0 && max_out_size) {
|
||||||
|
out[len++] = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_out_size < len - 1) {
|
||||||
|
return ResultFsTooLongPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL terminate. */
|
||||||
|
out[len] = 0;
|
||||||
|
*out_len = len;
|
||||||
|
|
||||||
|
/* Assert normalized. */
|
||||||
|
bool normalized = false;
|
||||||
|
if (R_FAILED(FsPathUtils::IsNormalized(&normalized, out)) || !normalized) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,14 @@ class FsPathUtils {
|
||||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsCurrentDirectory(const char *path) {
|
||||||
|
return path[0] == '.' && (path[1] == 0 || path[1] == '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsParentDirectory(const char *path) {
|
||||||
|
return path[0] == '.' && path[1] == '.' && (path[2] == 0 || path[2] == '/');
|
||||||
|
}
|
||||||
|
|
||||||
static bool IsWindowsAbsolutePath(const char *path) {
|
static bool IsWindowsAbsolutePath(const char *path) {
|
||||||
/* Nintendo uses this in path comparisons... */
|
/* Nintendo uses this in path comparisons... */
|
||||||
return IsWindowsDriveLetter(path[0]) && path[1] == ':';
|
return IsWindowsDriveLetter(path[0]) && path[1] == ':';
|
||||||
|
|
Loading…
Reference in a new issue