mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2025-09-24 09:03:32 +02:00
Compare commits
2 Commits
4a5562549c
...
4581c59f4d
Author | SHA1 | Date | |
---|---|---|---|
|
4581c59f4d | ||
|
59eb01b890 |
1
TODO.md
1
TODO.md
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
# Bugfixes
|
# Bugfixes
|
||||||
|
|
||||||
- Rework filesystem component to pre-process paths to ensure proper sandboxing and not allow arbitrary remote file access
|
|
||||||
- Do a huge audit at some point
|
- Do a huge audit at some point
|
||||||
- `nn_unicode_charWidth` appears to be bugged, look into that.
|
- `nn_unicode_charWidth` appears to be bugged, look into that.
|
||||||
|
|
||||||
|
@ -47,10 +47,12 @@ void nn_retainFilesystem(nn_filesystem *fs) {
|
|||||||
nn_bool_t nn_destroyFilesystem(nn_filesystem *fs) {
|
nn_bool_t nn_destroyFilesystem(nn_filesystem *fs) {
|
||||||
if(!nn_decRef(&fs->refc)) return false;
|
if(!nn_decRef(&fs->refc)) return false;
|
||||||
|
|
||||||
|
nn_errorbuf_t err = ""; // ignored
|
||||||
|
|
||||||
// close all files
|
// close all files
|
||||||
for(nn_size_t i = 0; i < NN_MAX_OPEN_FILES; i++) {
|
for(nn_size_t i = 0; i < NN_MAX_OPEN_FILES; i++) {
|
||||||
void *f = fs->files[i];
|
void *f = fs->files[i];
|
||||||
if(f != NULL) fs->table.close(fs->table.userdata, f);
|
if(f != NULL) fs->table.close(fs->table.userdata, f, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fs->table.deinit != NULL) {
|
if(fs->table.deinit != NULL) {
|
||||||
@ -102,16 +104,6 @@ void *nn_fs_unwrapFD(nn_filesystem *fs, nn_size_t fd) {
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
nn_bool_t nn_fs_illegalPath(const char *path) {
|
|
||||||
// absolute disaster
|
|
||||||
const char *illegal = "\"\\:*?<>|";
|
|
||||||
|
|
||||||
for(nn_size_t i = 0; illegal[i] != '\0'; i++) {
|
|
||||||
if(nn_strchr(path, illegal[i]) != NULL) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nn_fs_readCost(nn_filesystem *fs, nn_size_t bytes, nn_component *component) {
|
void nn_fs_readCost(nn_filesystem *fs, nn_size_t bytes, nn_component *component) {
|
||||||
nn_filesystemControl control = fs->control;
|
nn_filesystemControl control = fs->control;
|
||||||
nn_computer *computer = nn_getComputerOfComponent(component);
|
nn_computer *computer = nn_getComputerOfComponent(component);
|
||||||
@ -151,9 +143,14 @@ void nn_fs_createCost(nn_filesystem *fs, nn_size_t count, nn_component *componen
|
|||||||
void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
|
void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
|
||||||
char buf[NN_LABEL_SIZE];
|
char buf[NN_LABEL_SIZE];
|
||||||
nn_size_t l = NN_LABEL_SIZE;
|
nn_size_t l = NN_LABEL_SIZE;
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
fs->table.getLabel(fs->table.userdata, buf, &l);
|
fs->table.getLabel(fs->table.userdata, buf, &l, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(l == 0) {
|
if(l == 0) {
|
||||||
nn_return(computer, nn_values_nil());
|
nn_return(computer, nn_values_nil());
|
||||||
} else {
|
} else {
|
||||||
@ -171,9 +168,14 @@ void nn_fs_setLabel(nn_filesystem *fs, void *_, nn_component *component, nn_comp
|
|||||||
nn_setCError(computer, "bad label (string expected)");
|
nn_setCError(computer, "bad label (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
l = fs->table.setLabel(fs->table.userdata, buf, l);
|
l = fs->table.setLabel(fs->table.userdata, buf, l, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
nn_return_string(computer, buf, l);
|
nn_return_string(computer, buf, l);
|
||||||
|
|
||||||
nn_fs_writeCost(fs, l, component);
|
nn_fs_writeCost(fs, l, component);
|
||||||
@ -189,9 +191,14 @@ void nn_fs_spaceTotal(nn_filesystem *fs, nn_componentMethod *_, nn_component *co
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nn_fs_isReadOnly(nn_filesystem *fs, nn_componentMethod *_, nn_component *component, nn_computer *computer) {
|
void nn_fs_isReadOnly(nn_filesystem *fs, nn_componentMethod *_, nn_component *component, nn_computer *computer) {
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_return_boolean(computer, fs->table.isReadOnly(fs->table.userdata));
|
nn_return_boolean(computer, fs->table.isReadOnly(fs->table.userdata, err));
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nn_fs_size(nn_filesystem *fs, nn_componentMethod *_, nn_component *component, nn_computer *computer) {
|
void nn_fs_size(nn_filesystem *fs, nn_componentMethod *_, nn_component *component, nn_computer *computer) {
|
||||||
@ -201,14 +208,20 @@ void nn_fs_size(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
nn_setCError(computer, "bad path (string expected)");
|
nn_setCError(computer, "bad path (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(path)) {
|
char canonical[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(path, canonical)) {
|
||||||
nn_setCError(computer, "bad path (illegal path)");
|
nn_setCError(computer, "bad path (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_size_t byteSize = fs->table.size(fs->table.userdata, path);
|
nn_size_t byteSize = fs->table.size(fs->table.userdata, canonical, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nn_return(computer, nn_values_integer(byteSize));
|
nn_return(computer, nn_values_integer(byteSize));
|
||||||
}
|
}
|
||||||
@ -220,14 +233,20 @@ void nn_fs_remove(nn_filesystem *fs, nn_componentMethod *_, nn_component *compon
|
|||||||
nn_setCError(computer, "bad path (string expected)");
|
nn_setCError(computer, "bad path (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(path)) {
|
char canonical[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(path, canonical)) {
|
||||||
nn_setCError(computer, "bad path (illegal path)");
|
nn_setCError(computer, "bad path (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_size_t removed = fs->table.remove(fs->table.userdata, path);
|
nn_size_t removed = fs->table.remove(fs->table.userdata, canonical, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
nn_return_boolean(computer, removed > 0);
|
nn_return_boolean(computer, removed > 0);
|
||||||
|
|
||||||
nn_fs_removeCost(fs, removed, component);
|
nn_fs_removeCost(fs, removed, component);
|
||||||
@ -240,14 +259,20 @@ void nn_fs_lastModified(nn_filesystem *fs, nn_componentMethod *_, nn_component *
|
|||||||
nn_setCError(computer, "bad path (string expected)");
|
nn_setCError(computer, "bad path (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(path)) {
|
char canonical[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(path, canonical)) {
|
||||||
nn_setCError(computer, "bad path (illegal path)");
|
nn_setCError(computer, "bad path (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_size_t t = fs->table.lastModified(fs->table.userdata, path);
|
nn_size_t t = fs->table.lastModified(fs->table.userdata, canonical, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// OpenOS does BULLSHIT with this thing, dividing it by 1000 and expecting it to be
|
// OpenOS does BULLSHIT with this thing, dividing it by 1000 and expecting it to be
|
||||||
// fucking usable as a date, meaning it needs to be an int.
|
// fucking usable as a date, meaning it needs to be an int.
|
||||||
@ -264,7 +289,8 @@ void nn_fs_rename(nn_filesystem *fs, nn_componentMethod *_, nn_component *compon
|
|||||||
nn_setCError(computer, "bad path #1 (string expected)");
|
nn_setCError(computer, "bad path #1 (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(from)) {
|
char canonicalFrom[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(from, canonicalFrom)) {
|
||||||
nn_setCError(computer, "bad path #1 (illegal path)");
|
nn_setCError(computer, "bad path #1 (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -275,14 +301,20 @@ void nn_fs_rename(nn_filesystem *fs, nn_componentMethod *_, nn_component *compon
|
|||||||
nn_setCError(computer, "bad path #2 (string expected)");
|
nn_setCError(computer, "bad path #2 (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(to)) {
|
char canonicalTo[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(to, canonicalTo)) {
|
||||||
nn_setCError(computer, "bad path #2 (illegal path)");
|
nn_setCError(computer, "bad path #2 (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_size_t movedCount = fs->table.rename(fs->table.userdata, from, to);
|
nn_size_t movedCount = fs->table.rename(fs->table.userdata, canonicalFrom, canonicalTo, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
nn_return(computer, nn_values_boolean(movedCount > 0));
|
nn_return(computer, nn_values_boolean(movedCount > 0));
|
||||||
|
|
||||||
nn_fs_removeCost(fs, movedCount, component);
|
nn_fs_removeCost(fs, movedCount, component);
|
||||||
@ -296,14 +328,20 @@ void nn_fs_exists(nn_filesystem *fs, nn_componentMethod *_, nn_component *compon
|
|||||||
nn_setCError(computer, "bad path (string expected)");
|
nn_setCError(computer, "bad path (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(path)) {
|
char canonical[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(path, canonical)) {
|
||||||
nn_setCError(computer, "bad path (illegal path)");
|
nn_setCError(computer, "bad path (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_return_boolean(computer, fs->table.exists(fs->table.userdata, path));
|
nn_return_boolean(computer, fs->table.exists(fs->table.userdata, canonical, err));
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nn_fs_isDirectory(nn_filesystem *fs, nn_componentMethod *_, nn_component *component, nn_computer *computer) {
|
void nn_fs_isDirectory(nn_filesystem *fs, nn_componentMethod *_, nn_component *component, nn_computer *computer) {
|
||||||
@ -313,14 +351,19 @@ void nn_fs_isDirectory(nn_filesystem *fs, nn_componentMethod *_, nn_component *c
|
|||||||
nn_setCError(computer, "bad path (string expected)");
|
nn_setCError(computer, "bad path (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(path)) {
|
char canonical[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(path, canonical)) {
|
||||||
nn_setCError(computer, "bad path (illegal path)");
|
nn_setCError(computer, "bad path (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_return_boolean(computer, fs->table.isDirectory(fs->table.userdata, path));
|
nn_return_boolean(computer, fs->table.isDirectory(fs->table.userdata, canonical, err));
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nn_fs_makeDirectory(nn_filesystem *fs, nn_componentMethod *_, nn_component *component, nn_computer *computer) {
|
void nn_fs_makeDirectory(nn_filesystem *fs, nn_componentMethod *_, nn_component *component, nn_computer *computer) {
|
||||||
@ -330,14 +373,19 @@ void nn_fs_makeDirectory(nn_filesystem *fs, nn_componentMethod *_, nn_component
|
|||||||
nn_setCError(computer, "bad path (string expected)");
|
nn_setCError(computer, "bad path (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(path)) {
|
char canonical[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(path, canonical)) {
|
||||||
nn_setCError(computer, "bad path (illegal path)");
|
nn_setCError(computer, "bad path (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, path));
|
nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, canonical, err));
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
}
|
||||||
|
|
||||||
nn_fs_createCost(fs, 1, component);
|
nn_fs_createCost(fs, 1, component);
|
||||||
}
|
}
|
||||||
@ -349,17 +397,28 @@ void nn_fs_list(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
nn_setCError(computer, "bad path (string expected)");
|
nn_setCError(computer, "bad path (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(path)) {
|
char canonical[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(path, canonical)) {
|
||||||
nn_setCError(computer, "bad path (illegal path)");
|
nn_setCError(computer, "bad path (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer));
|
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer));
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_size_t fileCount = 0;
|
nn_size_t fileCount = 0;
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
char **files = fs->table.list(alloc, fs->table.userdata, path, &fileCount);
|
char **files = fs->table.list(alloc, fs->table.userdata, canonical, &fileCount, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
if(files != NULL) {
|
||||||
|
for(nn_size_t i = 0; i < fileCount; i++) {
|
||||||
|
nn_deallocStr(alloc, files[i]);
|
||||||
|
}
|
||||||
|
nn_dealloc(alloc, files, sizeof(char *) * fileCount);
|
||||||
|
}
|
||||||
|
nn_setError(computer, err);
|
||||||
|
}
|
||||||
|
|
||||||
if(files != NULL) {
|
if(files != NULL) {
|
||||||
// operation succeeded
|
// operation succeeded
|
||||||
@ -380,7 +439,8 @@ void nn_fs_open(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
nn_setCError(computer, "bad path (string expected)");
|
nn_setCError(computer, "bad path (string expected)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nn_fs_illegalPath(path)) {
|
char canonical[NN_MAX_PATH];
|
||||||
|
if(nn_path_canonical(path, canonical)) {
|
||||||
nn_setCError(computer, "bad path (illegal path)");
|
nn_setCError(computer, "bad path (illegal path)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -391,11 +451,17 @@ void nn_fs_open(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
mode = "r";
|
mode = "r";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
// technically wrongfully
|
// technically wrongfully
|
||||||
if(!fs->table.exists(fs->table.userdata, path)) {
|
if(!fs->table.exists(fs->table.userdata, path, err)) {
|
||||||
nn_fs_createCost(fs, 1, component);
|
nn_fs_createCost(fs, 1, component);
|
||||||
}
|
}
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nn_size_t fd = 0;
|
nn_size_t fd = 0;
|
||||||
while(fs->files[fd] != NULL) {
|
while(fs->files[fd] != NULL) {
|
||||||
@ -406,13 +472,25 @@ void nn_fs_open(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void *file = fs->table.open(fs->table.userdata, path, mode);
|
void *file = fs->table.open(fs->table.userdata, canonical, mode, err);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
if(file != NULL) {
|
||||||
|
fs->table.close(fs->table.userdata, file, err);
|
||||||
|
}
|
||||||
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(file == NULL) {
|
if(file == NULL) {
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
nn_setCError(computer, "no such file or directory");
|
nn_setCError(computer, "no such file or directory");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
fs->files[fd] = file;
|
fs->files[fd] = file;
|
||||||
nn_return(computer, nn_values_integer(fd));
|
nn_return(computer, nn_values_integer(fd));
|
||||||
}
|
}
|
||||||
@ -426,12 +504,17 @@ void nn_fs_close(nn_filesystem *fs, nn_componentMethod *_, nn_component *compone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_bool_t closed = fs->table.close(fs->table.userdata, file);
|
nn_bool_t closed = fs->table.close(fs->table.userdata, file, err);
|
||||||
if(closed) {
|
if(closed) {
|
||||||
fs->files[fd] = NULL;
|
fs->files[fd] = NULL;
|
||||||
}
|
}
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
nn_return(computer, nn_values_boolean(closed));
|
nn_return(computer, nn_values_boolean(closed));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,6 +530,7 @@ void nn_fs_write(nn_filesystem *fs, nn_componentMethod *_, nn_component *compone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
nn_size_t spaceRemaining = nn_fs_getSpaceRemaining(fs);
|
nn_size_t spaceRemaining = nn_fs_getSpaceRemaining(fs);
|
||||||
|
|
||||||
@ -463,10 +547,14 @@ void nn_fs_write(nn_filesystem *fs, nn_componentMethod *_, nn_component *compone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nn_bool_t written = fs->table.write(fs->table.userdata, file, buf, len);
|
nn_bool_t written = fs->table.write(fs->table.userdata, file, buf, len, err);
|
||||||
nn_return(computer, nn_values_boolean(written));
|
nn_return(computer, nn_values_boolean(written));
|
||||||
if(written) nn_fs_invalidateSpaceUsed(fs);
|
if(written) nn_fs_invalidateSpaceUsed(fs);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nn_fs_writeCost(fs, len, component);
|
nn_fs_writeCost(fs, len, component);
|
||||||
}
|
}
|
||||||
@ -482,6 +570,7 @@ void nn_fs_read(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
if(len > capacity) len = capacity;
|
if(len > capacity) len = capacity;
|
||||||
nn_size_t byteLen = len;
|
nn_size_t byteLen = len;
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
void *file = nn_fs_unwrapFD(fs, fd);
|
void *file = nn_fs_unwrapFD(fs, fd);
|
||||||
if(file == NULL) {
|
if(file == NULL) {
|
||||||
@ -498,8 +587,12 @@ void nn_fs_read(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nn_size_t readLen = fs->table.read(fs->table.userdata, file, buf, byteLen);
|
nn_size_t readLen = fs->table.read(fs->table.userdata, file, buf, byteLen, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(readLen > 0) {
|
if(readLen > 0) {
|
||||||
// Nothing read means EoF.
|
// Nothing read means EoF.
|
||||||
nn_return_string(computer, buf, readLen);
|
nn_return_string(computer, buf, readLen);
|
||||||
@ -533,6 +626,7 @@ void nn_fs_seek(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_errorbuf_t err = "";
|
||||||
nn_lock(&fs->ctx, fs->lock);
|
nn_lock(&fs->ctx, fs->lock);
|
||||||
void *file = nn_fs_unwrapFD(fs, fd);
|
void *file = nn_fs_unwrapFD(fs, fd);
|
||||||
if(file == NULL) {
|
if(file == NULL) {
|
||||||
@ -541,8 +635,12 @@ void nn_fs_seek(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nn_size_t pos = fs->table.seek(fs->table.userdata, file, whence, off);
|
nn_size_t pos = fs->table.seek(fs->table.userdata, file, whence, off, err);
|
||||||
nn_unlock(&fs->ctx, fs->lock);
|
nn_unlock(&fs->ctx, fs->lock);
|
||||||
|
if(!nn_error_isEmpty(err)) {
|
||||||
|
nn_setError(computer, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nn_return_integer(computer, pos);
|
nn_return_integer(computer, pos);
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
typedef struct nn_vfnode {
|
typedef struct nn_vfnode {
|
||||||
struct nn_vfilesystem *fs;
|
struct nn_vfilesystem *fs;
|
||||||
struct nn_vfnode *parent;
|
|
||||||
char name[NN_MAX_PATH];
|
char name[NN_MAX_PATH];
|
||||||
|
struct nn_vfnode *parent;
|
||||||
nn_bool_t isDirectory;
|
nn_bool_t isDirectory;
|
||||||
union {
|
union {
|
||||||
// if directory
|
// if directory
|
||||||
@ -57,8 +57,8 @@ nn_vfnode *nn_vf_allocFile(nn_vfilesystem *fs, const char *name) {
|
|||||||
if(node == NULL) return NULL;
|
if(node == NULL) return NULL;
|
||||||
*node = (nn_vfnode) {
|
*node = (nn_vfnode) {
|
||||||
.fs = fs,
|
.fs = fs,
|
||||||
.parent = NULL,
|
|
||||||
.lastModified = nn_vf_now(fs),
|
.lastModified = nn_vf_now(fs),
|
||||||
|
.parent = NULL,
|
||||||
.isDirectory = false,
|
.isDirectory = false,
|
||||||
.data = NULL,
|
.data = NULL,
|
||||||
.len = 0,
|
.len = 0,
|
||||||
@ -81,8 +81,8 @@ nn_vfnode *nn_vf_allocDirectory(nn_vfilesystem *fs, const char *name) {
|
|||||||
}
|
}
|
||||||
*node = (nn_vfnode) {
|
*node = (nn_vfnode) {
|
||||||
.fs = fs,
|
.fs = fs,
|
||||||
.parent = NULL,
|
|
||||||
.lastModified = nn_vf_now(fs),
|
.lastModified = nn_vf_now(fs),
|
||||||
|
.parent = NULL,
|
||||||
.isDirectory = false,
|
.isDirectory = false,
|
||||||
.entries = buffer,
|
.entries = buffer,
|
||||||
.len = 0,
|
.len = 0,
|
||||||
@ -121,6 +121,66 @@ nn_size_t nn_vf_spaceUsedByNode(nn_vfnode *node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_vfnode *nn_vf_find(nn_vfnode *parent, const char *name) {
|
||||||
|
if(parent->isDirectory) return NULL;
|
||||||
|
for(nn_size_t i = 0; i < parent->len; i++) {
|
||||||
|
nn_vfnode *entry = parent->entries[i];
|
||||||
|
|
||||||
|
if(nn_strcmp(entry->name, name) == 0) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_bool_t nn_vf_ensureFileCapacity(nn_vfnode *file, nn_size_t capacity) {
|
||||||
|
if(file->isDirectory) return false;
|
||||||
|
nn_Alloc *alloc = &file->fs->ctx.allocator;
|
||||||
|
|
||||||
|
if(file->cap >= capacity) return true; // already at that point
|
||||||
|
|
||||||
|
char *newData = nn_resize(alloc, file->data, file->cap, capacity);
|
||||||
|
if(newData == NULL) {
|
||||||
|
return false; // OOM
|
||||||
|
}
|
||||||
|
file->data = newData;
|
||||||
|
file->cap = capacity;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is used to compute exponential backoff
|
||||||
|
// TODO: add an option to select either a slower growth rate or
|
||||||
|
// linear backoff to reduce memory usage at the cost of speed
|
||||||
|
nn_size_t nn_vf_getIdealCapacity(nn_vfnode *file, nn_size_t spaceNeeded) {
|
||||||
|
nn_size_t cap = file->cap;
|
||||||
|
if(cap == 0) cap = 1;
|
||||||
|
while(cap < spaceNeeded) cap *= 2; // this would mean a file with 1,048,577 bytes takes up 2,097,152 bytes, potentially wasting 1,048,575 bytes
|
||||||
|
return cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nn_vf_clampHandlePosition(nn_vfhandle *handle) {
|
||||||
|
nn_size_t len = handle->node->len;
|
||||||
|
if(handle->position < 0) handle->position = 0;
|
||||||
|
if(handle->position > len) handle->position = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_vfnode *nn_vf_resolvePathFromNode(nn_vfnode *node, const char *path) {
|
||||||
|
if(path[0] == 0) return node;
|
||||||
|
char firstDirectory[NN_MAX_PATH];
|
||||||
|
char subpath[NN_MAX_PATH];
|
||||||
|
if(nn_path_firstName(path, firstDirectory, subpath)) {
|
||||||
|
return nn_vf_find(node, firstDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_vfnode *dir = nn_vf_find(node, firstDirectory);
|
||||||
|
return nn_vf_resolvePathFromNode(dir, subpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_vfnode *nn_vf_resolvePath(nn_vfilesystem *fs, const char *path) {
|
||||||
|
return nn_vf_resolvePathFromNode(fs->root, path);
|
||||||
|
}
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
|
|
||||||
void nn_vfs_deinit(nn_vfilesystem *fs) {
|
void nn_vfs_deinit(nn_vfilesystem *fs) {
|
||||||
|
@ -197,7 +197,7 @@ nn_size_t ne_fs_setLabel(void *_, const char *buf, size_t buflen) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nn_bool_t ne_fs_isReadOnly(void *_) {
|
nn_bool_t ne_fs_isReadOnly(void *_, nn_errorbuf_t err) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ const char *ne_fs_diskPath(nn_address addr, const char *path) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ne_fs_open(nn_address address, const char *path, const char *mode) {
|
void *ne_fs_open(nn_address address, const char *path, const char *mode, nn_errorbuf_t err) {
|
||||||
const char *trueMode = "rb";
|
const char *trueMode = "rb";
|
||||||
if(strcmp(mode, "w") == 0) {
|
if(strcmp(mode, "w") == 0) {
|
||||||
trueMode = "wb";
|
trueMode = "wb";
|
||||||
@ -228,28 +228,32 @@ void *ne_fs_open(nn_address address, const char *path, const char *mode) {
|
|||||||
|
|
||||||
const char *p = ne_fs_diskPath(address, path);
|
const char *p = ne_fs_diskPath(address, path);
|
||||||
if(p[0] == '/') p++;
|
if(p[0] == '/') p++;
|
||||||
|
if(DirectoryExists(p)) {
|
||||||
|
nn_error_write(err, "Is a directory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
FILE *f = fopen(p, trueMode);
|
FILE *f = fopen(p, trueMode);
|
||||||
if(f == NULL) {
|
if(f == NULL) {
|
||||||
printf("open(%s) failure: %s\n", path, strerror(errno));
|
nn_error_write(err, strerror(errno));
|
||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ne_fs_close(nn_address addr, FILE *f) {
|
bool ne_fs_close(nn_address addr, FILE *f, nn_errorbuf_t err) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ne_fs_write(nn_address addr, FILE *f, const char *buf, size_t len) {
|
bool ne_fs_write(nn_address addr, FILE *f, const char *buf, size_t len, nn_errorbuf_t err) {
|
||||||
return fwrite(buf, sizeof(char), len, f) > 0;
|
return fwrite(buf, sizeof(char), len, f) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ne_fs_read(nn_address addr, FILE *f, char *buf, size_t required) {
|
size_t ne_fs_read(nn_address addr, FILE *f, char *buf, size_t required, nn_errorbuf_t err) {
|
||||||
if(feof(f)) return 0;
|
if(feof(f)) return 0;
|
||||||
return fread(buf, sizeof(char), required, f);
|
return fread(buf, sizeof(char), required, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ne_fs_seek(nn_address addr, FILE *f, const char *whence, int off) {
|
size_t ne_fs_seek(nn_address addr, FILE *f, const char *whence, int off, nn_errorbuf_t err) {
|
||||||
int w = SEEK_SET;
|
int w = SEEK_SET;
|
||||||
if(strcmp(whence, "cur") == 0) {
|
if(strcmp(whence, "cur") == 0) {
|
||||||
w = SEEK_CUR;
|
w = SEEK_CUR;
|
||||||
@ -261,7 +265,7 @@ size_t ne_fs_seek(nn_address addr, FILE *f, const char *whence, int off) {
|
|||||||
return ftell(f);
|
return ftell(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
char **ne_fs_list(nn_Alloc *alloc, nn_address addr, const char *path, size_t *len) {
|
char **ne_fs_list(nn_Alloc *alloc, nn_address addr, const char *path, size_t *len, nn_errorbuf_t err) {
|
||||||
const char *p = ne_fs_diskPath(addr, path);
|
const char *p = ne_fs_diskPath(addr, path);
|
||||||
if(p[0] == '/') p++;
|
if(p[0] == '/') p++;
|
||||||
|
|
||||||
@ -278,7 +282,7 @@ char **ne_fs_list(nn_Alloc *alloc, nn_address addr, const char *path, size_t *le
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ne_fs_size(nn_address addr, const char *path) {
|
size_t ne_fs_size(nn_address addr, const char *path, nn_errorbuf_t err) {
|
||||||
const char *p = ne_fs_diskPath(addr, path);
|
const char *p = ne_fs_diskPath(addr, path);
|
||||||
if(p[0] == '/') p++;
|
if(p[0] == '/') p++;
|
||||||
|
|
||||||
@ -287,28 +291,28 @@ size_t ne_fs_size(nn_address addr, const char *path) {
|
|||||||
return GetFileLength(p);
|
return GetFileLength(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ne_fs_lastModified(nn_address addr, const char *path) {
|
size_t ne_fs_lastModified(nn_address addr, const char *path, nn_errorbuf_t err) {
|
||||||
const char *p = ne_fs_diskPath(addr, path);
|
const char *p = ne_fs_diskPath(addr, path);
|
||||||
if(p[0] == '/') p++;
|
if(p[0] == '/') p++;
|
||||||
|
|
||||||
return GetFileModTime(p);
|
return GetFileModTime(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ne_fs_isDirectory(nn_address addr, const char *path) {
|
bool ne_fs_isDirectory(nn_address addr, const char *path, nn_errorbuf_t err) {
|
||||||
const char *p = ne_fs_diskPath(addr, path);
|
const char *p = ne_fs_diskPath(addr, path);
|
||||||
if(p[0] == '/') p++;
|
if(p[0] == '/') p++;
|
||||||
|
|
||||||
return DirectoryExists(p);
|
return DirectoryExists(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ne_fs_makeDirectory(nn_address addr, const char *path) {
|
bool ne_fs_makeDirectory(nn_address addr, const char *path, nn_errorbuf_t err) {
|
||||||
const char *p = ne_fs_diskPath(addr, path);
|
const char *p = ne_fs_diskPath(addr, path);
|
||||||
if(p[0] == '/') p++;
|
if(p[0] == '/') p++;
|
||||||
|
|
||||||
return MakeDirectory(p) == 0;
|
return MakeDirectory(p) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ne_fs_exists(nn_address addr, const char *path) {
|
bool ne_fs_exists(nn_address addr, const char *path, nn_errorbuf_t err) {
|
||||||
const char *p = ne_fs_diskPath(addr, path);
|
const char *p = ne_fs_diskPath(addr, path);
|
||||||
if(p[0] == '/') p++;
|
if(p[0] == '/') p++;
|
||||||
|
|
||||||
@ -647,8 +651,8 @@ int main() {
|
|||||||
nn_filesystemTable genericFSTable = {
|
nn_filesystemTable genericFSTable = {
|
||||||
.userdata = fsFolder,
|
.userdata = fsFolder,
|
||||||
.deinit = NULL,
|
.deinit = NULL,
|
||||||
.getLabel = ne_fs_getLabel,
|
.getLabel = ne_eeprom_getLabel,
|
||||||
.setLabel = ne_fs_setLabel,
|
.setLabel = ne_eeprom_setLabel,
|
||||||
.spaceUsed = ne_fs_spaceUsed,
|
.spaceUsed = ne_fs_spaceUsed,
|
||||||
.spaceTotal = 1*1024*1024,
|
.spaceTotal = 1*1024*1024,
|
||||||
.isReadOnly = ne_fs_isReadOnly,
|
.isReadOnly = ne_fs_isReadOnly,
|
||||||
|
@ -682,37 +682,37 @@ typedef struct nn_filesystemTable {
|
|||||||
void *userdata;
|
void *userdata;
|
||||||
void (*deinit)(void *userdata);
|
void (*deinit)(void *userdata);
|
||||||
|
|
||||||
void (*getLabel)(void *userdata, char *buf, nn_size_t *buflen);
|
void (*getLabel)(void *userdata, char *buf, nn_size_t *buflen, nn_errorbuf_t err);
|
||||||
nn_size_t (*setLabel)(void *userdata, const char *buf, nn_size_t buflen);
|
nn_size_t (*setLabel)(void *userdata, const char *buf, nn_size_t buflen, nn_errorbuf_t err);
|
||||||
|
|
||||||
nn_size_t (*spaceUsed)(void *userdata);
|
nn_size_t (*spaceUsed)(void *userdata);
|
||||||
nn_size_t spaceTotal;
|
nn_size_t spaceTotal;
|
||||||
nn_bool_t (*isReadOnly)(void *userdata);
|
nn_bool_t (*isReadOnly)(void *userdata, nn_errorbuf_t err);
|
||||||
|
|
||||||
// general operations
|
// general operations
|
||||||
nn_size_t (*size)(void *userdata, const char *path);
|
nn_size_t (*size)(void *userdata, const char *path, nn_errorbuf_t err);
|
||||||
nn_size_t (*remove)(void *userdata, const char *path);
|
nn_size_t (*remove)(void *userdata, const char *path, nn_errorbuf_t err);
|
||||||
nn_size_t (*lastModified)(void *userdata, const char *path);
|
nn_size_t (*lastModified)(void *userdata, const char *path, nn_errorbuf_t err);
|
||||||
nn_size_t (*rename)(void *userdata, const char *from, const char *to);
|
nn_size_t (*rename)(void *userdata, const char *from, const char *to, nn_errorbuf_t err);
|
||||||
nn_bool_t (*exists)(void *userdata, const char *path);
|
nn_bool_t (*exists)(void *userdata, const char *path, nn_errorbuf_t err);
|
||||||
|
|
||||||
// directory operations
|
// directory operations
|
||||||
nn_bool_t (*isDirectory)(void *userdata, const char *path);
|
nn_bool_t (*isDirectory)(void *userdata, const char *path, nn_errorbuf_t err);
|
||||||
nn_bool_t (*makeDirectory)(void *userdata, const char *path);
|
nn_bool_t (*makeDirectory)(void *userdata, const char *path, nn_errorbuf_t err);
|
||||||
// The returned array should be allocated with the supplied allocator.
|
// The returned array should be allocated with the supplied allocator.
|
||||||
// The strings should be null terminated. Use nn_strdup for the allocation to guarantee nn_deallocStr deallocates it correctly.
|
// The strings should be null terminated. Use nn_strdup for the allocation to guarantee nn_deallocStr deallocates it correctly.
|
||||||
// For the array, the *exact* size of the allocation should be sizeof(char *) * (*len),
|
// For the array, the *exact* size of the allocation should be sizeof(char *) * (*len),
|
||||||
// If it is not, the behavior is undefined.
|
// If it is not, the behavior is undefined.
|
||||||
// We recommend first computing len then allocating, though if that is not doable or practical,
|
// We recommend first computing len then allocating, though if that is not doable or practical,
|
||||||
// consider nn_resize()ing it to the correct size to guarantee a correct deallocation.
|
// consider nn_resize()ing it to the correct size to guarantee a correct deallocation.
|
||||||
char **(*list)(nn_Alloc *alloc, void *userdata, const char *path, nn_size_t *len);
|
char **(*list)(nn_Alloc *alloc, void *userdata, const char *path, nn_size_t *len, nn_errorbuf_t err);
|
||||||
|
|
||||||
// file operations
|
// file operations
|
||||||
void *(*open)(void *userdata, const char *path, const char *mode);
|
void *(*open)(void *userdata, const char *path, const char *mode, nn_errorbuf_t err);
|
||||||
nn_bool_t (*close)(void *userdata, void *fd);
|
nn_bool_t (*close)(void *userdata, void *fd, nn_errorbuf_t err);
|
||||||
nn_bool_t (*write)(void *userdata, void *fd, const char *buf, nn_size_t len);
|
nn_bool_t (*write)(void *userdata, void *fd, const char *buf, nn_size_t len, nn_errorbuf_t err);
|
||||||
nn_size_t (*read)(void *userdata, void *fd, char *buf, nn_size_t required);
|
nn_size_t (*read)(void *userdata, void *fd, char *buf, nn_size_t required, nn_errorbuf_t err);
|
||||||
nn_size_t (*seek)(void *userdata, void *fd, const char *whence, int off);
|
nn_size_t (*seek)(void *userdata, void *fd, const char *whence, int off, nn_errorbuf_t err);
|
||||||
} nn_filesystemTable;
|
} nn_filesystemTable;
|
||||||
|
|
||||||
typedef struct nn_filesystem nn_filesystem;
|
typedef struct nn_filesystem nn_filesystem;
|
||||||
|
@ -408,7 +408,7 @@ sandbox = {
|
|||||||
lower = string.lower,
|
lower = string.lower,
|
||||||
wtrunc = function (str,space)
|
wtrunc = function (str,space)
|
||||||
space = space - 1
|
space = space - 1
|
||||||
return str:sub(1,(space >= utf8.len(str)) and (#str) or (utf8.offset(str,space+1)-1))
|
return unicode.sub(str, 1, space)
|
||||||
end,
|
end,
|
||||||
}),
|
}),
|
||||||
checkArg = checkArg,
|
checkArg = checkArg,
|
||||||
|
53
src/utils.c
53
src/utils.c
@ -388,7 +388,14 @@ nn_bool_t nn_path_isValid(const char *path) {
|
|||||||
return nn_strlen(path) < NN_MAX_PATH; // less then because we depend on the terminator
|
return nn_strlen(path) < NN_MAX_PATH; // less then because we depend on the terminator
|
||||||
}
|
}
|
||||||
|
|
||||||
nn_bool_t nn_path_canonical(const char path[NN_MAX_PATH], char canonical[NN_MAX_PATH]) {
|
static nn_bool_t nni_path_isAllDots(const char *path, nn_size_t len) {
|
||||||
|
for(nn_size_t i = 0; i < len; i++) {
|
||||||
|
if(path[i] != '.') return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_bool_t nn_path_canonical(const char *path, char canonical[NN_MAX_PATH]) {
|
||||||
// attempts to convert a random barely legal path
|
// attempts to convert a random barely legal path
|
||||||
// if this shit is ever bugged and a sandbox escape is done
|
// if this shit is ever bugged and a sandbox escape is done
|
||||||
// by tricking it into sneaking some .. in there
|
// by tricking it into sneaking some .. in there
|
||||||
@ -396,23 +403,49 @@ nn_bool_t nn_path_canonical(const char path[NN_MAX_PATH], char canonical[NN_MAX_
|
|||||||
|
|
||||||
if(!nn_path_isValid(path)) {
|
if(!nn_path_isValid(path)) {
|
||||||
// HELL NO
|
// HELL NO
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tmp shit because lazy, maybe the optimizer be with us
|
|
||||||
char junk[NN_MAX_PATH];
|
|
||||||
|
|
||||||
// 0'd out because it fills it up with terminators, simplifying the rest of the code
|
// 0'd out because it fills it up with terminators, simplifying the rest of the code
|
||||||
// in theory this is suboptimal, however, I'm lazy
|
// in theory this is suboptimal, however, I'm lazy
|
||||||
nn_memset(canonical, 0, NN_MAX_PATH);
|
nn_memset(canonical, 0, NN_MAX_PATH);
|
||||||
size_t ptr = 0;
|
nn_size_t ptr = 0;
|
||||||
|
nn_size_t i = 0;
|
||||||
|
|
||||||
// TODO: burn it with fire and get banned from programming
|
// TODO: burn it with fire and get banned from programming
|
||||||
for(nn_size_t i = 0; path[i]; i++) {
|
while(true) {
|
||||||
// all of this is very slow
|
while(path[i] == '/') i++; // just do not ask
|
||||||
|
if(path[i] == 0) break;
|
||||||
|
|
||||||
while(path[i] == '/') continue; // just do not ask
|
const char *subpath = path + i;
|
||||||
|
nn_size_t len = nn_path_firstSlash(subpath);
|
||||||
|
|
||||||
|
if(len == 0) {
|
||||||
|
len = nn_strlen(path) - i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if(nni_path_isAllDots(subpath, len)) {
|
||||||
|
// we don't actually resolve them because they shouldn't be there
|
||||||
|
// to begin with
|
||||||
|
i += len;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ptr == 0) {
|
||||||
|
// at the start
|
||||||
|
nn_memcpy(canonical, subpath, len);
|
||||||
|
ptr = len;
|
||||||
|
i += len;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// just append to it
|
||||||
|
canonical[ptr] = '/';
|
||||||
|
ptr++;
|
||||||
|
nn_memcpy(canonical + ptr, subpath, len);
|
||||||
|
ptr += len;
|
||||||
|
i += len;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user