12 changed files with 520 additions and 51 deletions
@ -1,19 +1,279 @@ |
|||
#define _XOPEN_SOURCE 500 |
|||
|
|||
#include "lupi.h" |
|||
#include <lua.h> |
|||
#include <lualib.h> |
|||
#include <lauxlib.h> |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/statvfs.h> |
|||
#include <string.h> |
|||
#include <stdlib.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) { |
|||
int t = lua_tonumber(L, 1); |
|||
unsigned int t = lua_tonumber(L, 1); |
|||
usleep(t); |
|||
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) { |
|||
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"); |
|||
} |
@ -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 |
Loading…
issues.context.reference_issue