mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +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/>.
|
||||
*/
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <switch.h>
|
||||
#include "fs_path_utils.hpp"
|
||||
#include "fs_results.hpp"
|
||||
|
@ -162,7 +163,99 @@ Result FsPathUtils::IsNormalized(bool *out, const char *path) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, size_t *out_size) {
|
||||
/* TODO */
|
||||
return ResultFsNotImplemented;
|
||||
Result FsPathUtils::Normalize(char *out, size_t max_out_size, const char *src, size_t *out_len) {
|
||||
/* Paths must start with / */
|
||||
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');
|
||||
}
|
||||
|
||||
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) {
|
||||
/* Nintendo uses this in path comparisons... */
|
||||
return IsWindowsDriveLetter(path[0]) && path[1] == ':';
|
||||
|
|
Loading…
Reference in a new issue