forked from izaya/LuPPC
Implement filesystem component
This commit is contained in:
parent
54631f1e79
commit
03f4203fa2
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-g -std=c99 -Isrc/lib/lua -Iinclude
|
CFLAGS=-g -std=gnu99 -Isrc/lib/lua -Iinclude
|
||||||
|
|
||||||
BUILD = bin/
|
BUILD = bin/
|
||||||
SOURCE = src/c/
|
SOURCE = src/c/
|
||||||
|
@ -5,6 +5,7 @@ extern char lua_component[];
|
|||||||
extern char lua_computer[];
|
extern char lua_computer[];
|
||||||
extern char lua_eepromDefault[];
|
extern char lua_eepromDefault[];
|
||||||
extern char lua_eeprom[];
|
extern char lua_eeprom[];
|
||||||
|
extern char lua_filesystem[];
|
||||||
extern char lua_init[];
|
extern char lua_init[];
|
||||||
extern char lua_sandbox[];
|
extern char lua_sandbox[];
|
||||||
extern char lua_textgpu[];
|
extern char lua_textgpu[];
|
||||||
|
262
src/c/lnative.c
262
src/c/lnative.c
@ -1,19 +1,279 @@
|
|||||||
|
#define _XOPEN_SOURCE 500
|
||||||
|
|
||||||
#include "lupi.h"
|
#include "lupi.h"
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
#include <lualib.h>
|
#include <lualib.h>
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <linux/kd.h>
|
||||||
|
|
||||||
static int l_sleep (lua_State *L) {
|
static int l_sleep (lua_State *L) {
|
||||||
int t = lua_tonumber(L, 1);
|
unsigned int t = lua_tonumber(L, 1);
|
||||||
usleep(t);
|
usleep(t);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filesystem methods
|
||||||
|
static int l_fs_exists (lua_State *L) {
|
||||||
|
const char* fname = lua_tostring(L, 1);
|
||||||
|
if( access( fname, F_OK ) != -1 ) {
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
} else {
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_mkdir (lua_State *L) {
|
||||||
|
const char* fname = lua_tostring(L, 1);
|
||||||
|
if( mkdir( fname, 0755 ) != -1 ) {
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
} else {
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_isdir (lua_State *L) {
|
||||||
|
const char* fname = lua_tostring(L, 1);
|
||||||
|
struct stat s;
|
||||||
|
int err = stat(fname, &s);
|
||||||
|
if(-1 == err) {
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
} else {
|
||||||
|
if(S_ISDIR(s.st_mode)) {
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
} else {
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_spaceUsed (lua_State *L) {
|
||||||
|
const char* fname = lua_tostring(L, 1);
|
||||||
|
struct statvfs s;
|
||||||
|
if( statvfs(fname, &s) != -1 ) {
|
||||||
|
lua_pushnumber(L, s.f_bsize * s.f_bfree);
|
||||||
|
} else {
|
||||||
|
lua_pushnumber(L, -1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_open (lua_State *L) {
|
||||||
|
const char* fname = lua_tostring(L, 1);
|
||||||
|
const char* mode = lua_tostring(L, 2);
|
||||||
|
int m = 0;
|
||||||
|
if(mode[0] == 'r') m = O_RDONLY;
|
||||||
|
else if(mode[0] == 'w') m = O_WRONLY | O_CREAT /*| O_DIRECT*/;
|
||||||
|
else if(mode[0] == 'a') m = O_WRONLY | O_APPEND | O_CREAT /*| O_DIRECT*/;
|
||||||
|
else return 0;
|
||||||
|
int fd = open(fname, m, 644);
|
||||||
|
if(fd == -1) return 0;
|
||||||
|
|
||||||
|
lua_pushnumber(L, fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_seek (lua_State *L) {
|
||||||
|
int fd = lua_tonumber(L, 1);
|
||||||
|
int whence = lua_tonumber(L, 2);
|
||||||
|
long offset = lua_tonumber(L, 3);
|
||||||
|
|
||||||
|
int w = 0;
|
||||||
|
if(whence == 0) w = SEEK_CUR;
|
||||||
|
else if(whence == 1) w = SEEK_SET;
|
||||||
|
else if(whence == 2) w = SEEK_END;
|
||||||
|
else return 0;
|
||||||
|
int res = lseek(fd, w, offset);
|
||||||
|
lua_pushnumber(L, res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_write (lua_State *L) {
|
||||||
|
int fd = lua_tonumber(L, 1);
|
||||||
|
size_t len = 0;
|
||||||
|
const char* data = lua_tolstring(L, 2, &len);
|
||||||
|
|
||||||
|
//TODO: May not all data be written?
|
||||||
|
if(write(fd, data, len) == -1) {
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
} else {
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_spaceTotal (lua_State *L) {
|
||||||
|
const char* fname = lua_tostring(L, 1);
|
||||||
|
struct statvfs s;
|
||||||
|
if( statvfs(fname, &s) != -1 ) {
|
||||||
|
lua_pushnumber(L, s.f_frsize * s.f_blocks);
|
||||||
|
} else {
|
||||||
|
lua_pushnumber(L, -1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_rename (lua_State *L) {
|
||||||
|
const char* from = lua_tostring(L, 1);
|
||||||
|
const char* to = lua_tostring(L, 1);
|
||||||
|
if( rename( from, to ) != -1 ) {
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
} else {
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_list (lua_State *L) {
|
||||||
|
const char* path = lua_tostring(L, 1);
|
||||||
|
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
if ((dir = opendir(path)) != NULL) {
|
||||||
|
lua_newtable(L);
|
||||||
|
int n = 1;
|
||||||
|
while ((ent = readdir(dir)) != NULL) { //TODO: Check if it should be freed
|
||||||
|
lua_pushstring(L, ent->d_name);
|
||||||
|
lua_rawseti(L, -2, n++);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_lastModified (lua_State *L) {
|
||||||
|
const char* path = lua_tostring(L, 1);
|
||||||
|
struct stat s;
|
||||||
|
if( stat(path, &s) != -1 ) {
|
||||||
|
lua_pushnumber(L, s.st_mtime);
|
||||||
|
} else {
|
||||||
|
return 0; //TODO: No error?
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rm(const char *path, const struct stat *s, int flag, struct FTW *f) {
|
||||||
|
int status;
|
||||||
|
int (*rm_func)(const char *);
|
||||||
|
|
||||||
|
switch(flag) {
|
||||||
|
default: rm_func = unlink; break;
|
||||||
|
case FTW_DP: rm_func = rmdir;
|
||||||
|
}
|
||||||
|
if(status = rm_func(path), status != 0)
|
||||||
|
perror(path);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_remove (lua_State *L) {
|
||||||
|
const char* path = lua_tostring(L, 1);
|
||||||
|
|
||||||
|
if( nftw( path, rm, FOPEN_MAX, FTW_DEPTH )) {
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
} else {
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_close (lua_State *L) {
|
||||||
|
int fd = lua_tonumber(L, 1);
|
||||||
|
|
||||||
|
if(close(fd) == -1) {
|
||||||
|
lua_pushboolean(L, 0);
|
||||||
|
} else {
|
||||||
|
lua_pushboolean(L, 1);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_size (lua_State *L) {
|
||||||
|
const char* path = lua_tostring(L, 1);
|
||||||
|
struct stat s;
|
||||||
|
if( stat(path, &s) != -1 ) {
|
||||||
|
lua_pushnumber(L, s.st_size);
|
||||||
|
} else {
|
||||||
|
return 0; //TODO: No error?
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_fs_read (lua_State *L) {
|
||||||
|
int fd = lua_tonumber(L, 1);
|
||||||
|
int count = lua_tonumber(L, 2);
|
||||||
|
void* buf = malloc(count);
|
||||||
|
size_t res = read(fd, buf, count);
|
||||||
|
if(res != -1) {
|
||||||
|
lua_pushlstring(L, buf, res);
|
||||||
|
free(buf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CLOCK_TICK_RATE
|
||||||
|
#define CLOCK_TICK_RATE 1193180
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Filesystem end
|
||||||
|
static int l_beep (lua_State *L) {
|
||||||
|
int freq = lua_tonumber(L, 1);
|
||||||
|
int btime = lua_tonumber(L, 2);
|
||||||
|
int console_fd = -1;
|
||||||
|
|
||||||
|
if((console_fd = open("/dev/console", O_WRONLY)) == -1) {
|
||||||
|
//fprintf(stderr, "Could not open /dev/console for writing.\n");
|
||||||
|
printf("\a");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ioctl(console_fd, KIOCSOUND, (int)(CLOCK_TICK_RATE/freq)) < 0) {
|
||||||
|
printf("\a");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(1000 * btime);
|
||||||
|
ioctl(console_fd, KIOCSOUND, 0);
|
||||||
|
close(console_fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void luanative_start(lua_State *L) {
|
void luanative_start(lua_State *L) {
|
||||||
lua_createtable (L, 0, 1);
|
lua_createtable (L, 0, 1);
|
||||||
|
|
||||||
pushctuple(L, "sleep", l_sleep);
|
pushctuple(L, "sleep", l_sleep);
|
||||||
|
|
||||||
|
pushctuple(L, "fs_exists", l_fs_exists);
|
||||||
|
pushctuple(L, "fs_mkdir", l_fs_mkdir);
|
||||||
|
pushctuple(L, "fs_isdir", l_fs_isdir);
|
||||||
|
pushctuple(L, "fs_spaceUsed", l_fs_spaceUsed);
|
||||||
|
pushctuple(L, "fs_open", l_fs_open);
|
||||||
|
pushctuple(L, "fs_seek", l_fs_seek);
|
||||||
|
pushctuple(L, "fs_write", l_fs_write);
|
||||||
|
pushctuple(L, "fs_spaceTotal", l_fs_spaceTotal);
|
||||||
|
pushctuple(L, "fs_rename", l_fs_rename);
|
||||||
|
pushctuple(L, "fs_lastModified", l_fs_lastModified);
|
||||||
|
pushctuple(L, "fs_remove", l_fs_remove);
|
||||||
|
pushctuple(L, "fs_close", l_fs_close);
|
||||||
|
pushctuple(L, "fs_size", l_fs_size);
|
||||||
|
pushctuple(L, "fs_read", l_fs_read);
|
||||||
|
|
||||||
|
pushctuple(L, "beep", l_beep);
|
||||||
|
|
||||||
lua_setglobal(L, "native");
|
lua_setglobal(L, "native");
|
||||||
}
|
}
|
@ -13,6 +13,7 @@ void setup_modules(lua_State *L) {
|
|||||||
pushstuple(L, "computer", lua_computer);
|
pushstuple(L, "computer", lua_computer);
|
||||||
pushstuple(L, "eeprom", lua_eeprom);
|
pushstuple(L, "eeprom", lua_eeprom);
|
||||||
pushstuple(L, "eepromDefault", lua_eepromDefault);
|
pushstuple(L, "eepromDefault", lua_eepromDefault);
|
||||||
|
pushstuple(L, "filesystem", lua_filesystem);
|
||||||
pushstuple(L, "sandbox", lua_sandbox);
|
pushstuple(L, "sandbox", lua_sandbox);
|
||||||
pushstuple(L, "textgpu", lua_textgpu);
|
pushstuple(L, "textgpu", lua_textgpu);
|
||||||
pushstuple(L, "color", lua_util_color);
|
pushstuple(L, "color", lua_util_color);
|
||||||
|
12
src/c/run.c
12
src/c/run.c
@ -5,6 +5,15 @@
|
|||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
void run_init() {
|
void run_init() {
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
L = luaL_newstate();
|
L = luaL_newstate();
|
||||||
@ -14,7 +23,8 @@ void run_init() {
|
|||||||
luanative_start (L);
|
luanative_start (L);
|
||||||
termutils_start (L);
|
termutils_start (L);
|
||||||
|
|
||||||
int status = luaL_loadstring(L, lua_init);
|
//int status = luaL_loadstring(L, lua_init);
|
||||||
|
int status = luaL_loadbuffer(L, lua_init, strlen(lua_init), "=INIT");
|
||||||
if (status) {
|
if (status) {
|
||||||
fprintf(stderr, "Couldn't load init: %s\n", lua_tostring(L, -1));
|
fprintf(stderr, "Couldn't load init: %s\n", lua_tostring(L, -1));
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -4,39 +4,41 @@ function boot.boot()
|
|||||||
local gpu = modules.component.api.proxy(modules.component.api.list("gpu", true)())
|
local gpu = modules.component.api.proxy(modules.component.api.list("gpu", true)())
|
||||||
local w, h = gpu.getResolution()
|
local w, h = gpu.getResolution()
|
||||||
|
|
||||||
local function bsod(err)
|
local function bsod(...)
|
||||||
gpu.setBackground(0x0000FF)
|
gpu.setBackground(0x0000FF)
|
||||||
gpu.setForeground(0xFFFFFF)
|
gpu.setForeground(0xFFFFFF)
|
||||||
gpu.fill(0, 0, w, h, " ")
|
gpu.fill(1, 1, w, h, " ")
|
||||||
gpu.set(2, 2, "CRITICAL ERROR OCCURED")
|
gpu.set(2, 2, "CRITICAL ERROR OCCURED")
|
||||||
gpu.set(2, 3, "Lua BIOS Has failed:")
|
gpu.set(2, 3, "Lua BIOS has failed:")
|
||||||
gpu.set(2, 5, tostring(err))
|
for n, v in pairs({...}) do
|
||||||
io.flush()
|
gpu.set(2, 4 + n, tostring(v))
|
||||||
native.sleep(2000000)
|
end
|
||||||
|
gpu.set(2, h-1, "SYSTEM WILL STOP")
|
||||||
gpu.setForeground(0xFFFFFF)
|
gpu.setForeground(0xFFFFFF)
|
||||||
gpu.setBackground(0x000000)
|
gpu.setBackground(0x000000)
|
||||||
|
|
||||||
|
native.sleep(4000000)
|
||||||
|
os.exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
print("r= " .. tostring(w) .. " " .. tostring(h))
|
gpu.fill(1, 1, w, h, " ")
|
||||||
gpu.fill(0, 0, w, h, " ")
|
gpu.set(1, h - 2, "LuPI L2 INIT")
|
||||||
gpu.set(10, 5, "HHHHHHHHHHHHH")
|
|
||||||
gpu.set(11, 11, "VVVVVVVVVVVVVVVVV", true)
|
|
||||||
print("LuPI L2 INIT")
|
|
||||||
|
|
||||||
local code = modules.component.api.invoke(modules.component.api.list("eeprom", true)(), "get")
|
local code = modules.component.api.invoke(modules.component.api.list("eeprom", true)(), "get")
|
||||||
if not code then
|
if not code then
|
||||||
print("No bootcode")
|
bsod("No bootcode")
|
||||||
error("No bootcode")
|
|
||||||
end
|
end
|
||||||
local f, reason = load(code, "=BIOS", nil, modules.sandbox)
|
local f, reason = load(code, "=USERBIOS", nil, modules.sandbox)
|
||||||
if not f then
|
if not f then
|
||||||
print(reason)
|
|
||||||
else
|
|
||||||
local e, reason = pcall(f)
|
|
||||||
if not e then
|
|
||||||
bsod(reason)
|
bsod(reason)
|
||||||
|
else
|
||||||
|
xpcall(f, function(e)
|
||||||
|
local trace = {}
|
||||||
|
for s in string.gmatch(debug.traceback(e, 2), "[^\r\n]+") do
|
||||||
|
trace[#trace + 1] = s
|
||||||
end
|
end
|
||||||
print("System quit, Panic")
|
bsod("System crashed", "Stack traceback:", table.unpack(trace))
|
||||||
|
end)
|
||||||
|
bsod("System quit")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ function api.register(address, ctype, proxy, doc)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
modules.computer.api.pushSignal("component_added", address, ctype)
|
modules.computer.api.pushSignal("component_added", address, ctype)
|
||||||
return true
|
return address
|
||||||
end
|
end
|
||||||
|
|
||||||
function api.unregister(address)
|
function api.unregister(address)
|
||||||
@ -65,7 +65,7 @@ function api.invoke(address, method, ...)
|
|||||||
error("No such component")
|
error("No such component")
|
||||||
end
|
end
|
||||||
if not components[address].rawproxy[method] then
|
if not components[address].rawproxy[method] then
|
||||||
error("No such method")
|
error("No such method: " .. tostring(components[address].type) .. "." .. tostring(method))
|
||||||
end
|
end
|
||||||
return components[address].rawproxy[method](...)
|
return components[address].rawproxy[method](...)
|
||||||
end
|
end
|
||||||
|
@ -10,4 +10,10 @@ function api.pushSignal(...)
|
|||||||
--FIXME: ASAP: Implement
|
--FIXME: ASAP: Implement
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function api.beep(freq, time)
|
||||||
|
if not freq then freq = 1000 end
|
||||||
|
if not time then time = 0.2 end
|
||||||
|
native.beep(freq, time * 1000)
|
||||||
|
end
|
||||||
|
|
||||||
return computer
|
return computer
|
158
src/lua/core/filesystem.lua
Normal file
158
src/lua/core/filesystem.lua
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
--Native side at lnative.c
|
||||||
|
|
||||||
|
local filesystem = {}
|
||||||
|
|
||||||
|
local function segments(path)
|
||||||
|
path = path:gsub("\\", "/")
|
||||||
|
repeat local n; path, n = path:gsub("//", "/") until n == 0
|
||||||
|
local parts = {}
|
||||||
|
for part in path:gmatch("[^/]+") do
|
||||||
|
table.insert(parts, part)
|
||||||
|
end
|
||||||
|
local i = 1
|
||||||
|
while i <= #parts do
|
||||||
|
if parts[i] == "." then
|
||||||
|
table.remove(parts, i)
|
||||||
|
elseif parts[i] == ".." then
|
||||||
|
table.remove(parts, i)
|
||||||
|
i = i - 1
|
||||||
|
if i > 0 then
|
||||||
|
table.remove(parts, i)
|
||||||
|
else
|
||||||
|
i = 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return parts
|
||||||
|
end
|
||||||
|
|
||||||
|
local function canonical(path)
|
||||||
|
local result = table.concat(segments(path), "/")
|
||||||
|
if string.sub(path, 1, 1) == "/" then
|
||||||
|
return "/" .. result
|
||||||
|
else
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function concat(pathA, pathB, ...)
|
||||||
|
checkArg(1, pathA, "string")
|
||||||
|
checkArg(2, pathB, "string", "nil")
|
||||||
|
local function _concat(n, a, b, ...)
|
||||||
|
if not b then
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
checkArg(n, b, "string")
|
||||||
|
return _concat(n + 1, a .. "/" .. b, ...)
|
||||||
|
end
|
||||||
|
return canonical(_concat(2, pathA, pathB, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
function filesystem.register(basePath)
|
||||||
|
checkArg(1, basePath, "string")
|
||||||
|
|
||||||
|
if not native.fs_exists(basePath) then
|
||||||
|
native.fs_mkdir(basePath)
|
||||||
|
end
|
||||||
|
if not native.fs_isdir(basePath) then
|
||||||
|
error("Filesystem root is not a directory!")
|
||||||
|
end
|
||||||
|
local function realpath(path)
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
return concat(basePath, path)
|
||||||
|
end
|
||||||
|
|
||||||
|
--TODO: checkArg all
|
||||||
|
local fs = {}
|
||||||
|
function fs.spaceUsed()
|
||||||
|
return native.fs_spaceUsed(basePath)
|
||||||
|
end
|
||||||
|
function fs.open(path, mode)
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
checkArg(2, path, "string", "nil")
|
||||||
|
local m = "r"
|
||||||
|
if mode == "a" then m = "a"
|
||||||
|
elseif mode == "w" then m = "w" end
|
||||||
|
local fd = native.fs_open(realpath(path), m)
|
||||||
|
if not fd then
|
||||||
|
return nil, path
|
||||||
|
end
|
||||||
|
return fd
|
||||||
|
end
|
||||||
|
function fs.seek(handle, whence, offset) --TODO: Test
|
||||||
|
checkArg(1, handle, "number")
|
||||||
|
checkArg(2, whence, "string")
|
||||||
|
checkArg(3, offset, "number")
|
||||||
|
local w = 0
|
||||||
|
if whence == "cur" then w = 0
|
||||||
|
elseif whence == "set" then w = 1
|
||||||
|
elseif whence == "end" then w = 2
|
||||||
|
else error("Invalid whence") end
|
||||||
|
return native.fs_seek(handle, w, offset or 0)
|
||||||
|
end
|
||||||
|
function fs.makeDirectory(path) --TODO: check if creates parrent dirs
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
return native.fs_mkdir(realpath(path))
|
||||||
|
end
|
||||||
|
function fs.exists(path)
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
return native.fs_exists(realpath(path))
|
||||||
|
end
|
||||||
|
function fs.isReadOnly()
|
||||||
|
return false --TODO: Implement
|
||||||
|
end
|
||||||
|
function fs.write(handle, value) --TODO: check behaviour on invalid FDs
|
||||||
|
checkArg(1, handle, "number")
|
||||||
|
checkArg(2, value, "string")
|
||||||
|
return native.fs_write(handle, value)
|
||||||
|
end
|
||||||
|
function fs.spaceTotal()
|
||||||
|
return native.fs_spaceTotal(basePath)
|
||||||
|
end
|
||||||
|
function fs.isDirectory(path)
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
return native.fs_isdir(realpath(path))
|
||||||
|
end
|
||||||
|
function fs.rename(from, to)
|
||||||
|
checkArg(1, from, "string")
|
||||||
|
checkArg(2, to, "string")
|
||||||
|
return native.fs_rename(realpath(from), realpath(to))
|
||||||
|
end
|
||||||
|
function fs.list(path)
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
return native.fs_list(realpath(path)) --TODO: Test, check if dirs get / at end
|
||||||
|
end
|
||||||
|
function fs.lastModified(path)
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
return native.fs_lastModified(realpath(path))
|
||||||
|
end
|
||||||
|
function fs.getLabel()
|
||||||
|
return --TODO: Implement, use real labels
|
||||||
|
end
|
||||||
|
function fs.remove(path) --TODO: TEST!!
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
return native.fs_remove(realpath(path))
|
||||||
|
end
|
||||||
|
function fs.close(handle)
|
||||||
|
checkArg(1, handle, "number")
|
||||||
|
return native.fs_close()
|
||||||
|
end
|
||||||
|
function fs.size(path)
|
||||||
|
checkArg(1, path, "string")
|
||||||
|
return native.fs_size(realpath(path))
|
||||||
|
end
|
||||||
|
function fs.read(handle, count) --FIXME: Hudgeread, fix in general
|
||||||
|
checkArg(1, handle, "number")
|
||||||
|
checkArg(2, count, "number")
|
||||||
|
return native.fs_read(handle, count)
|
||||||
|
end
|
||||||
|
function fs.setLabel(value)
|
||||||
|
checkArg(1, value, "number")
|
||||||
|
return value --TODO: Implement, use real labels
|
||||||
|
end
|
||||||
|
return modules.component.api.register(nil, "filesystem", fs)
|
||||||
|
end
|
||||||
|
|
||||||
|
return filesystem
|
@ -18,6 +18,7 @@ end
|
|||||||
|
|
||||||
print("LuPI L1 INIT")
|
print("LuPI L1 INIT")
|
||||||
modules = {}
|
modules = {}
|
||||||
|
deadhooks = {}
|
||||||
|
|
||||||
local function loadModule(name)
|
local function loadModule(name)
|
||||||
print("LuPI L1 INIT > Load module > " .. name)
|
print("LuPI L1 INIT > Load module > " .. name)
|
||||||
@ -26,7 +27,7 @@ local function loadModule(name)
|
|||||||
if not moduleCode[name] then
|
if not moduleCode[name] then
|
||||||
error("No code for module " .. tostring(name))
|
error("No code for module " .. tostring(name))
|
||||||
end
|
end
|
||||||
local code, reason = load(moduleCode[name])
|
local code, reason = load(moduleCode[name], "=Module "..name)
|
||||||
if not code then
|
if not code then
|
||||||
print("Failed loading module " .. name .. ": " .. reason)
|
print("Failed loading module " .. name .. ": " .. reason)
|
||||||
else
|
else
|
||||||
@ -34,6 +35,7 @@ local function loadModule(name)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function main()
|
||||||
--Load modules
|
--Load modules
|
||||||
--Utils
|
--Utils
|
||||||
loadModule("random")
|
loadModule("random")
|
||||||
@ -46,6 +48,7 @@ loadModule("computer")
|
|||||||
--Components
|
--Components
|
||||||
loadModule("eeprom")
|
loadModule("eeprom")
|
||||||
loadModule("textgpu")
|
loadModule("textgpu")
|
||||||
|
loadModule("filesystem")
|
||||||
|
|
||||||
--Userspace
|
--Userspace
|
||||||
loadModule("sandbox")
|
loadModule("sandbox")
|
||||||
@ -56,6 +59,23 @@ modules.component.prepare()
|
|||||||
modules.computer.prepare()
|
modules.computer.prepare()
|
||||||
|
|
||||||
modules.eeprom.register()
|
modules.eeprom.register()
|
||||||
|
modules.filesystem.register("root")
|
||||||
modules.textgpu.start()
|
modules.textgpu.start()
|
||||||
|
|
||||||
modules.boot.boot()
|
modules.boot.boot()
|
||||||
|
end
|
||||||
|
|
||||||
|
local state, cause = pcall(main)
|
||||||
|
if not state then
|
||||||
|
print("LuPI finished with following error:")
|
||||||
|
print(cause)
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Running shutdown hooks")
|
||||||
|
for k, hook in ipairs(deadhooks) do
|
||||||
|
local state, cause = pcall(hook)
|
||||||
|
if not state then
|
||||||
|
print("Shutdown hook with following error:")
|
||||||
|
print(cause)
|
||||||
|
end
|
||||||
|
end
|
@ -160,7 +160,8 @@ sandbox = {
|
|||||||
len = utf8.len,
|
len = utf8.len,
|
||||||
offset = utf8.offset
|
offset = utf8.offset
|
||||||
},
|
},
|
||||||
checkArg = checkArg
|
checkArg = checkArg,
|
||||||
|
og = _G
|
||||||
}
|
}
|
||||||
|
|
||||||
sandbox._G = sandbox
|
sandbox._G = sandbox
|
||||||
|
@ -25,7 +25,8 @@ function textgpu.start()
|
|||||||
return --TODO: Maybe?
|
return --TODO: Maybe?
|
||||||
end
|
end
|
||||||
background = modules.color.nearest(color, mapping)
|
background = modules.color.nearest(color, mapping)
|
||||||
io.write("\x1b[4" .. background .. "m")
|
io.write("\x1b[4" .. math.floor(background) .. "m")
|
||||||
|
io.flush()
|
||||||
end
|
end
|
||||||
function gpu.setForeground(color, isPaletteIndex)
|
function gpu.setForeground(color, isPaletteIndex)
|
||||||
checkArg(1, color, "number")
|
checkArg(1, color, "number")
|
||||||
@ -33,8 +34,9 @@ function textgpu.start()
|
|||||||
if isPaletteIndex then
|
if isPaletteIndex then
|
||||||
return --TODO: Maybe?
|
return --TODO: Maybe?
|
||||||
end
|
end
|
||||||
background = modules.color.nearest(color, mapping)
|
foreground = modules.color.nearest(color, mapping)
|
||||||
io.write("\x1b[3" .. background .. "m")
|
io.write("\x1b[3" .. math.floor(foreground) .. "m")
|
||||||
|
io.flush()
|
||||||
end
|
end
|
||||||
function gpu.getBackground()
|
function gpu.getBackground()
|
||||||
return mapping[background], false
|
return mapping[background], false
|
||||||
@ -79,6 +81,8 @@ function textgpu.start()
|
|||||||
checkArg(2, y, "number")
|
checkArg(2, y, "number")
|
||||||
checkArg(3, value, "string")
|
checkArg(3, value, "string")
|
||||||
checkArg(4, vertical, "boolean", "nil")
|
checkArg(4, vertical, "boolean", "nil")
|
||||||
|
x = math.floor(x)
|
||||||
|
y = math.floor(y)
|
||||||
if not vertical then
|
if not vertical then
|
||||||
io.write("\x1b[" .. y .. ";" .. x .. "H" .. value)
|
io.write("\x1b[" .. y .. ";" .. x .. "H" .. value)
|
||||||
else
|
else
|
||||||
@ -87,6 +91,7 @@ function textgpu.start()
|
|||||||
io.write(c .. "\x1b[D\x1b[B")
|
io.write(c .. "\x1b[D\x1b[B")
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
io.flush()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
function gpu.copy(x, y, w, h, tx, ty)
|
function gpu.copy(x, y, w, h, tx, ty)
|
||||||
@ -112,10 +117,15 @@ function textgpu.start()
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
io.write("\x1b[?25l") --Disable cursor
|
||||||
gpu.setForeground(0xFFFFFF)
|
gpu.setForeground(0xFFFFFF)
|
||||||
gpu.setBackground(0x000000)
|
gpu.setBackground(0x000000)
|
||||||
|
|
||||||
modules.component.api.register(nil, "gpu", gpu)
|
modules.component.api.register(nil, "gpu", gpu)
|
||||||
|
|
||||||
|
deadhooks[#deadhooks + 1] = function()
|
||||||
|
io.write("\x1b[?25h") --Enable cursor on quit
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return textgpu
|
return textgpu
|
Loading…
Reference in New Issue
Block a user