more work on FS

This commit is contained in:
2026-03-31 13:13:11 +02:00
parent 5c854e5c4a
commit 76b14524c5
10 changed files with 191 additions and 45 deletions

View File

@@ -269,9 +269,6 @@ local function writeEntry(entry, levelStack)
if opts.Q then io.write('"') end if opts.Q then io.write('"') end
if opts.color == "always" then if opts.color == "always" then
if not entry.extension then
print("entry:", entry)
end
io.write("\27[" .. colorize(entry) .. "m") io.write("\27[" .. colorize(entry) .. "m")
end end

View File

@@ -7,4 +7,3 @@ require("event").listen("init", function()
dofile(require("shell").resolve("rc", "lua")) dofile(require("shell").resolve("rc", "lua"))
return false return false
end) end)

View File

@@ -40,6 +40,5 @@ shell.setWorkingDirectory(os.getenv("HOME"))
local home_shrc = shell.resolve(".shrc") local home_shrc = shell.resolve(".shrc")
if fs.exists(home_shrc) then if fs.exists(home_shrc) then
local resolved = shell.resolve("source", "lua") loadfile(shell.resolve("source", "lua"))(home_shrc)
assert(loadfile(resolved))(home_shrc)
end end

View File

@@ -73,7 +73,7 @@ local function dofile(file)
status("> " .. file) status("> " .. file)
local program, reason = raw_loadfile(file) local program, reason = raw_loadfile(file)
if program then if program then
local result = table.pack(xpcall(program, debug.traceback)) local result = table.pack(pcall(program))
if result[1] then if result[1] then
return table.unpack(result, 2, result.n) return table.unpack(result, 2, result.n)
else else

View File

@@ -16,7 +16,7 @@ Most blocks act as 'cables' - use relays and power distributors to create separa
Welcome to the dark side - here, have some cookies. Welcome to the dark side - here, have some cookies.
Screens can display Unicode - paste the special chars or use unicode.char. Screens can display Unicode - paste the special chars or use unicode.char.
Run `help` or `man programname` for ingame help on programs shipped with OpenOS - start with `man man`. Run `help` or `man programname` for ingame help on programs shipped with OpenOS - start with `man man`.
For more help, there's a wiki at https://ocdoc.cil.li/ - or find the IRC loot disk and join #oc. For more help, there's a wiki at http://ocdoc.cil.li/ - or find the IRC loot disk and join #oc.
Computers have a very basic, built-in speaker - control it using computer.beep(). Computers have a very basic, built-in speaker - control it using computer.beep().
Many component methods have a short documentation - use `=component.componentName.methodName` in the Lua interpreter to see it. Many component methods have a short documentation - use `=component.componentName.methodName` in the Lua interpreter to see it.
You can get a list of all attached components using the `components` program. You can get a list of all attached components using the `components` program.

View File

@@ -10,6 +10,7 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <raylib.h> #include <raylib.h>
#include <errno.h>
nn_Architecture getLuaArch(); nn_Architecture getLuaArch();
@@ -379,7 +380,7 @@ int main(int argc, char **argv) {
printf("%zu bytes logically used by OpenOS\n", ncl_spaceUsedIn(ncl_defaultFS, "data/OpenOS")); printf("%zu bytes logically used by OpenOS\n", ncl_spaceUsedIn(ncl_defaultFS, "data/OpenOS"));
printf("%zu bytes physically used by OpenOS\n", ncl_spaceUsedBy(ncl_defaultFS, "data/OpenOS")); printf("%zu bytes physically used by OpenOS\n", ncl_spaceUsedBy(ncl_defaultFS, "data/OpenOS"));
nn_Component *eepromCard = nn_createVEEPROM(u, "eeprom", &veeprom, &nn_defaultEEPROMs[3]); nn_Component *eepromCard = nn_createVEEPROM(u, "eeprom", &veeprom, &nn_defaultEEPROMs[3]);
nn_Component *managedfs = ncl_createFilesystem(u, "mainFS", "data/OpenOS", &nn_defaultFilesystems[3], true); nn_Component *managedfs = ncl_createFilesystem(u, "mainFS", "data/OpenOS", &nn_defaultFilesystems[3], true);

View File

@@ -95,25 +95,12 @@ bool ncl_defaultHandler(ncl_VFSRequest *request) {
ncl_Stat *stat = request->stat.stat; ncl_Stat *stat = request->stat.stat;
stat->isDirectory = S_ISDIR(s.st_mode); stat->isDirectory = S_ISDIR(s.st_mode);
stat->diskSize = s.st_blocks * 512; stat->diskSize = s.st_blocks * 512;
stat->size = 0; stat->size = stat->isDirectory ? 0 : s.st_size;
if(!stat->isDirectory) {
FILE *f = fopen(request->stat.path, "r");
if(f == NULL) {
// horribly off but don't care atp
stat->size = s.st_size;
} else {
fseek(f, SEEK_END, 0);
stat->size = ftell(f);
fclose(f);
}
}
stat->lastModified = s.st_mtime; stat->lastModified = s.st_mtime;
return true; return true;
} }
if(request->action == NCL_VFS_MKDIR) { if(request->action == NCL_VFS_MKDIR) {
// we're not meant to have executables. return mkdir(request->mkdir, 0777) == 0;
int mode = 6*64 + 6*8 + 6;
return mkdir(request->mkdir, mode) == 0;
} }
#endif #endif
return false; // not supported return false; // not supported
@@ -232,11 +219,9 @@ size_t ncl_spaceUsedIn(ncl_VFS vfs, const char *path) {
if(dir == NULL) return spaceUsed; if(dir == NULL) return spaceUsed;
char name[NN_MAX_PATH]; char name[NN_MAX_PATH];
while(ncl_readdir(vfs, dir, name)) { while(ncl_readdir(vfs, dir, name)) {
if(strcmp(name, ".") != 0 && strcmp(name, "..") != 0) { char subpath[NN_MAX_PATH];
char subpath[NN_MAX_PATH]; snprintf(subpath, sizeof(subpath), "%s%c%s", path, vfs.pathsep, name);
snprintf(subpath, sizeof(subpath), "%s%c%s", path, vfs.pathsep, name); spaceUsed += ncl_spaceUsedIn(vfs, subpath);
spaceUsed += ncl_spaceUsedIn(vfs, subpath);
}
} }
ncl_closedir(vfs, dir); ncl_closedir(vfs, dir);
return spaceUsed; return spaceUsed;
@@ -251,11 +236,9 @@ size_t ncl_spaceUsedBy(ncl_VFS vfs, const char *path) {
if(dir == NULL) return spaceUsed; if(dir == NULL) return spaceUsed;
char name[NN_MAX_PATH]; char name[NN_MAX_PATH];
while(ncl_readdir(vfs, dir, name)) { while(ncl_readdir(vfs, dir, name)) {
if(strcmp(name, ".") != 0 && strcmp(name, "..") != 0) { char subpath[NN_MAX_PATH];
char subpath[NN_MAX_PATH]; snprintf(subpath, sizeof(subpath), "%s%c%s", path, vfs.pathsep, name);
snprintf(subpath, sizeof(subpath), "%s%c%s", path, vfs.pathsep, name); spaceUsed += ncl_spaceUsedBy(vfs, subpath);
spaceUsed += ncl_spaceUsedBy(vfs, subpath);
}
} }
ncl_closedir(vfs, dir); ncl_closedir(vfs, dir);
return spaceUsed; return spaceUsed;
@@ -298,7 +281,94 @@ bool ncl_mkdir(ncl_VFS vfs, const char *path) {
return vfs.handler(&req); return vfs.handler(&req);
} }
bool ncl_mkdirRecursive(ncl_VFS vfs, const char *path); bool ncl_mkdirRecursive(ncl_VFS vfs, const char *path) {
ncl_Stat s;
if(ncl_stat(vfs, path, &s)) {
return s.isDirectory;
}
char buf[NN_MAX_PATH];
// use snprintf instead of strncpy cuz NULL terminator
snprintf(buf, NN_MAX_PATH, "%s", path);
char *sep = strrchr(buf, '/');
if(sep == NULL) {
return ncl_mkdir(vfs, path);
}
*sep = '\0';
if(!ncl_mkdirRecursive(vfs, buf)) return false;
return ncl_mkdir(vfs, path);
}
static bool ncl_copydir(ncl_VFS vfs, const char *from, const char *to) {
bool created = ncl_mkdir(vfs, to);
if(!created) return false;
void *dir = ncl_opendir(vfs, from);
if(dir == NULL) goto fail;
char name[NN_MAX_PATH];
while(ncl_readdir(vfs, dir, name)) {
char subpath[NN_MAX_PATH];
snprintf(subpath, NN_MAX_PATH, "%s%c%s", from, vfs.pathsep, name);
char subdest[NN_MAX_PATH];
snprintf(subdest, NN_MAX_PATH, "%s%c%s", to, vfs.pathsep, name);
printf("%s -> %s\n", subpath, subdest);
if(!ncl_copyto(vfs, subpath, subdest)) goto fail;
}
ncl_closedir(vfs, dir);
return true;
fail:
if(dir != NULL) ncl_closedir(vfs, dir);
// erase all evidence
//ncl_removeRecursive(vfs, to);
return false;
}
static bool ncl_copyfile(ncl_VFS vfs, const char *from, const char *to) {
// copy some files!
void *src = NULL;
void *dest = NULL;
src = ncl_openfile(vfs, from, "r");
if(src == NULL) goto fail;
dest = ncl_openfile(vfs, to, "w");
if(dest == NULL) goto fail;
char buf[NN_MAX_READ];
size_t len = NN_MAX_READ;
while(ncl_readfile(vfs, src, buf, &len)) {
if(!ncl_writefile(vfs, dest, buf, len)) goto fail;
len = NN_MAX_READ;
}
ncl_closefile(vfs, src);
ncl_closefile(vfs, dest);
return true;
fail:
if(src != NULL) ncl_closefile(vfs, src);
if(dest != NULL) ncl_closefile(vfs, dest);
//ncl_remove(vfs, to);
return false;
}
static bool ncl_isIllegalCopy(const char *from, const char *to) {
// check if to starts with from, or from starts with to
if(strncmp(from, to, strlen(from)) == 0) return true;
if(strncmp(to, from, strlen(to)) == 0) return true;
return false;
}
bool ncl_copyto(ncl_VFS vfs, const char *from, const char *to) {
if(strcmp(from, to) == 0) return true;
if(ncl_isIllegalCopy(from, to)) return false;
// already exists
if(ncl_exists(vfs, to)) return false;
ncl_Stat s;
// missing
if(!ncl_stat(vfs, from, &s)) return false;
if(s.isDirectory) return ncl_copydir(vfs, from, to);
return ncl_copyfile(vfs, from, to);
}
typedef struct ncl_ScreenPixel { typedef struct ncl_ScreenPixel {
nn_codepoint codepoint; nn_codepoint codepoint;
@@ -533,6 +603,8 @@ static nn_Exit ncl_fsHandler(nn_FSRequest *req) {
return NN_EBADCALL; return NN_EBADCALL;
} }
state->fds[fd] = NULL; state->fds[fd] = NULL;
state->spaceUsed = 0;
state->realSpaceUsed = 0;
volatile ncl_VFS vfs = state->vfs; volatile ncl_VFS vfs = state->vfs;
nn_unlock(ctx, state->lock); nn_unlock(ctx, state->lock);
// out of lock for the most minimal of performance // out of lock for the most minimal of performance
@@ -571,6 +643,8 @@ static nn_Exit ncl_fsHandler(nn_FSRequest *req) {
return NN_EBADCALL; return NN_EBADCALL;
} }
bool ok = ncl_writefile(state->vfs, file, req->write.buf, req->write.len); bool ok = ncl_writefile(state->vfs, file, req->write.buf, req->write.len);
state->spaceUsed = 0;
state->realSpaceUsed = 0;
nn_unlock(ctx, state->lock); nn_unlock(ctx, state->lock);
if(ok) return NN_OK; if(ok) return NN_OK;
nn_setError(C, "write failed"); nn_setError(C, "write failed");
@@ -655,13 +729,14 @@ static nn_Exit ncl_fsHandler(nn_FSRequest *req) {
} }
if(req->action == NN_FS_STAT) { if(req->action == NN_FS_STAT) {
nn_lock(ctx, state->lock); nn_lock(ctx, state->lock);
state->usage++;
char path[NN_MAX_PATH]; char path[NN_MAX_PATH];
ncl_fixPath(state, req->stat.path, path); ncl_fixPath(state, req->stat.path, path);
ncl_Stat s; ncl_Stat s;
if(!ncl_stat(state->vfs, path, &s)) { if(!ncl_stat(state->vfs, path, &s)) {
nn_unlock(ctx, state->lock); nn_unlock(ctx, state->lock);
nn_setError(C, "no such file or directory"); req->stat.path = NULL;
return NN_EBADCALL; return NN_OK;
} }
req->stat.isDirectory = s.isDirectory; req->stat.isDirectory = s.isDirectory;
req->stat.size = s.size; req->stat.size = s.size;
@@ -669,7 +744,80 @@ static nn_Exit ncl_fsHandler(nn_FSRequest *req) {
nn_unlock(ctx, state->lock); nn_unlock(ctx, state->lock);
return NN_OK; return NN_OK;
} }
// TODO: mkdir, rename if(req->action == NN_FS_MKDIR) {
nn_lock(ctx, state->lock);
state->usage++;
char path[NN_MAX_PATH];
ncl_fixPath(state, req->mkdir, path);
ncl_Stat s;
if(ncl_stat(state->vfs, path, &s)) {
nn_unlock(ctx, state->lock);
if(s.isDirectory) {
return NN_OK;
}
nn_setError(C, "not a directory");
return NN_EBADCALL;
}
if(!ncl_mkdirRecursive(state->vfs, path)) {
nn_unlock(ctx, state->lock);
nn_setError(C, "operation failed");
return NN_EBADCALL;
}
size_t newSpaceUsed = ncl_spaceUsedIn(state->vfs, state->path);
if(newSpaceUsed > state->conf.spaceTotal) {
ncl_removeRecursive(state->vfs, path);
nn_unlock(ctx, state->lock);
nn_setError(C, "out of space");
return NN_EBADCALL;
}
state->spaceUsed = newSpaceUsed;
state->realSpaceUsed = 0;
nn_unlock(ctx, state->lock);
return NN_OK;
}
if(req->action == NN_FS_RENAME) {
if(req->rename.from[0] == '\0') {
nn_setError(C, "root is forbidden");
return NN_EBADCALL;
}
if(req->rename.to != NULL && req->rename.to[0] == '\0') {
nn_setError(C, "root is forbidden");
return NN_EBADCALL;
}
nn_lock(ctx, state->lock);
state->usage++;
char from[NN_MAX_PATH];
ncl_fixPath(state, req->rename.from, from);
if(req->rename.to == NULL) {
bool ok = ncl_removeRecursive(state->vfs, from);
nn_unlock(ctx, state->lock);
if(!ok) {
nn_setError(C, "operation failed");
return NN_EBADCALL;
}
return NN_OK;
}
char to[NN_MAX_PATH];
ncl_fixPath(state, req->rename.to, to);
// copy a to a is illegal btw
if(ncl_isIllegalCopy(from, to)) {
nn_unlock(ctx, state->lock);
nn_setError(C, "illegal copy operation");
return NN_EBADCALL;
}
bool ok = ncl_copyto(state->vfs, from, to);
if(ok) {
ncl_removeRecursive(state->vfs, from);
}
state->spaceUsed = 0;
state->realSpaceUsed = 0;
nn_unlock(ctx, state->lock);
if(!ok) {
nn_setError(C, "operation failed");
return NN_EBADCALL;
}
return NN_OK;
}
if(C) nn_setError(C, "not implemented yet"); if(C) nn_setError(C, "not implemented yet");
return NN_EBADCALL; return NN_EBADCALL;

View File

@@ -150,6 +150,8 @@ bool ncl_removeRecursive(ncl_VFS vfs, const char *path);
bool ncl_mkdir(ncl_VFS vfs, const char *path); bool ncl_mkdir(ncl_VFS vfs, const char *path);
bool ncl_mkdirRecursive(ncl_VFS vfs, const char *path); bool ncl_mkdirRecursive(ncl_VFS vfs, const char *path);
bool ncl_copyto(ncl_VFS vfs, const char *from, const char *to);
typedef struct ncl_EncodedState { typedef struct ncl_EncodedState {
char *buf; char *buf;
size_t len; size_t len;

View File

@@ -3272,10 +3272,10 @@ nn_Component *nn_createEEPROM(nn_Universe *universe, const char *address, const
[NN_EENUM_GETDATA] = {"getData", "function(): string - Get the data stored on the eeprom", NN_DIRECT}, [NN_EENUM_GETDATA] = {"getData", "function(): string - Get the data stored on the eeprom", NN_DIRECT},
[NN_EENUM_GETLABEL] = {"getLabel", "function(): string? - Get the label stored on the eeprom, if any", NN_DIRECT}, [NN_EENUM_GETLABEL] = {"getLabel", "function(): string? - Get the label stored on the eeprom, if any", NN_DIRECT},
[NN_EENUM_GETARCH] = {"getArchitecture", "function(): string? - Get the desired architecture stored on the eeprom, if any", NN_DIRECT}, [NN_EENUM_GETARCH] = {"getArchitecture", "function(): string? - Get the desired architecture stored on the eeprom, if any", NN_DIRECT},
[NN_EENUM_SET] = {"set", "function(code: string) - Set the code on the EEPROM", NN_DIRECT}, [NN_EENUM_SET] = {"set", "function(code: string) - Set the code on the EEPROM", NN_INDIRECT},
[NN_EENUM_SETDATA] = {"setData", "function(data: string) - Set the data on the EEPROM", NN_DIRECT}, [NN_EENUM_SETDATA] = {"setData", "function(data: string) - Set the data on the EEPROM", NN_INDIRECT},
[NN_EENUM_SETLABEL] = {"setLabel", "function(label?: string) - Set the label", NN_DIRECT}, [NN_EENUM_SETLABEL] = {"setLabel", "function(label?: string) - Set the label", NN_INDIRECT},
[NN_EENUM_SETARCH] = {"setArchitecture", "function(arch?: string) - Set the desired architecture", NN_DIRECT}, [NN_EENUM_SETARCH] = {"setArchitecture", "function(arch?: string) - Set the desired architecture", NN_INDIRECT},
}; };
nn_Exit e = nn_setComponentMethodsArray(c, methods, NN_EENUM_COUNT); nn_Exit e = nn_setComponentMethodsArray(c, methods, NN_EENUM_COUNT);
if(e) { if(e) {
@@ -3740,7 +3740,7 @@ nn_Component *nn_createFilesystem(nn_Universe *universe, const char *address, co
[NN_FSNUM_SPACETOTAL] = {"spaceTotal", "function(): integer - Capacity of the drive", NN_DIRECT}, [NN_FSNUM_SPACETOTAL] = {"spaceTotal", "function(): integer - Capacity of the drive", NN_DIRECT},
[NN_FSNUM_SPACEUSED] = {"spaceUsed", "function(): integer - Amount of space used", NN_DIRECT}, [NN_FSNUM_SPACEUSED] = {"spaceUsed", "function(): integer - Amount of space used", NN_DIRECT},
[NN_FSNUM_GETLABEL] = {"getLabel", "function(): string? - Gets the label of the drive, if any", NN_DIRECT}, [NN_FSNUM_GETLABEL] = {"getLabel", "function(): string? - Gets the label of the drive, if any", NN_DIRECT},
[NN_FSNUM_SETLABEL] = {"setLabel", "function(label?: string): string - Sets the label of the drive. Returns the new label, which may be truncated", NN_DIRECT}, [NN_FSNUM_SETLABEL] = {"setLabel", "function(label?: string): string - Sets the label of the drive. Returns the new label, which may be truncated", NN_INDIRECT},
[NN_FSNUM_ISRO] = {"isReadOnly", "function(): boolean - Returns whether the drive is read-only", NN_DIRECT}, [NN_FSNUM_ISRO] = {"isReadOnly", "function(): boolean - Returns whether the drive is read-only", NN_DIRECT},
[NN_FSNUM_OPEN] = {"open", "function(path: string, mode?: 'r'|'w'|'a'): integer - Open a file", NN_DIRECT}, [NN_FSNUM_OPEN] = {"open", "function(path: string, mode?: 'r'|'w'|'a'): integer - Open a file", NN_DIRECT},
[NN_FSNUM_READ] = {"read", "function(fd: integer, len?: integer): string? - Read from a file, returns nothing on EoF", NN_DIRECT}, [NN_FSNUM_READ] = {"read", "function(fd: integer, len?: integer): string? - Read from a file, returns nothing on EoF", NN_DIRECT},
@@ -3753,8 +3753,8 @@ nn_Component *nn_createFilesystem(nn_Universe *universe, const char *address, co
[NN_FSNUM_SIZE] = {"size", "function(path: string): integer - Returns the size of an entry", NN_DIRECT}, [NN_FSNUM_SIZE] = {"size", "function(path: string): integer - Returns the size of an entry", NN_DIRECT},
[NN_FSNUM_LASTMODIFIED] = {"lastModified", "function(path: string): integer - Returns the UNIX timestamp of the last modified time", NN_DIRECT}, [NN_FSNUM_LASTMODIFIED] = {"lastModified", "function(path: string): integer - Returns the UNIX timestamp of the last modified time", NN_DIRECT},
[NN_FSNUM_MKDIR] = {"makeDirectory", "function(path: string): boolean - Create a directory, recursively. Does not fail if directory already exists", NN_DIRECT}, [NN_FSNUM_MKDIR] = {"makeDirectory", "function(path: string): boolean - Create a directory, recursively. Does not fail if directory already exists", NN_DIRECT},
[NN_FSNUM_REMOVE] = {"remove", "function(path: string): boolean - Recursively deletes an entry", NN_DIRECT}, [NN_FSNUM_REMOVE] = {"remove", "function(path: string): boolean - Recursively deletes an entry", NN_INDIRECT},
[NN_FSNUM_RENAME] = {"rename", "function(from: string, to: string): boolean - Renames/moves an entry", NN_DIRECT}, [NN_FSNUM_RENAME] = {"rename", "function(from: string, to: string): boolean - Renames/moves an entry", NN_INDIRECT},
}; };
nn_Exit e = nn_setComponentMethodsArray(c, methods, NN_FSNUM_COUNT); nn_Exit e = nn_setComponentMethodsArray(c, methods, NN_FSNUM_COUNT);
if(e) { if(e) {