forked from justincormack/ljsyscall
-
Notifications
You must be signed in to change notification settings - Fork 5
/
lfs.lua
133 lines (113 loc) · 3 KB
/
lfs.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
-- this is intended to be compatible with luafilesystem https://github.com/keplerproject/luafilesystem
-- currently does not implement locks
local require, error, assert, tonumber, tostring,
setmetatable, pairs, ipairs, unpack, rawget, rawset,
pcall, type, table, string =
require, error, assert, tonumber, tostring,
setmetatable, pairs, ipairs, unpack, rawget, rawset,
pcall, type, table, string
-- TODO allow use eg with rump kernel, needs an initialisation option
-- maybe return a table with a metatable that allows init or uses default if no init?
local S = require "syscall"
-- TODO not implemented
-- lfs.lock_dir
-- lfs.lock
-- unlock
local function lfswrap(f)
return function(...)
local ret, err = f(...)
if not ret then return nil, tostring(err) end
return ret
end
end
local lfs = {}
lfs._VERSION = "ljsyscall lfs 1"
local attributes = {
dev = "dev",
ino = "ino",
mode = "typename", -- not sure why lfs insists on calling this mode
nlink = "nlink",
uid = "uid",
gid = "gid",
rdev = "rdev",
access = "access",
modification = "modification",
change = "change",
size = "size",
blocks = "blocks",
blksize = "blksize",
}
local function attr(st, aname)
if aname then
aname = attributes[aname]
return st[aname]
end
local ret = {}
for k, v in pairs(attributes) do ret[k] = st[v] end
return ret
end
function lfs.attributes(filepath, aname)
local st, err = S.stat(filepath)
if not st then return nil, tostring(err) end
return attr(st, aname)
end
function lfs.symlinkattributes(filepath, aname)
local st, err = S.lstat(filepath)
if not st then return nil, tostring(err) end
return attr(st, aname)
end
lfs.chdir = lfswrap(S.chdir)
lfs.currentdir = lfswrap(S.getcwd)
lfs.rmdir = lfswrap(S.rmdir)
lfs.touch = lfswrap(S.utime)
function lfs.mkdir(path)
local ret, err = S.mkdir(path, "0777")
if not ret then return nil, tostring(err) end
return ret
end
local function dir_close(dir)
dir.fd:close()
dir.fd = nil
end
local function dir_next(dir)
if not dir.fd then error "dir ended" end
local d
repeat
if not dir.di then
local err
dir.di, err = dir.fd:getdents(dir.buf, dir.size)
if not dir.di then
dir_close(dir)
error(tostring(err)) -- not sure how we are suppose to handle errors
end
dir.first = true
end
d = dir.di()
if not d then
dir.di = nil
if dir.first then
dir_close(dir)
return nil
end
end
dir.first = false
until d
return d.name
end
function lfs.dir(path)
local size = 4096
local buf = S.t.buffer(size)
local fd, err = S.open(path, "directory, rdonly")
if err then return nil, tostring(err) end
return dir_next, {size = size, buf = buf, fd = fd, next = dir_next, close = dir_close}
end
local flink, fsymlink = lfswrap(S.link), lfswrap(S.symlink)
function lfs.link(old, new, symlink)
if symlink then
return fsymlink(old, new)
else
return flink(old, new)
end
end
function lfs.setmode(file, mode) return true, "binary" end
return lfs