1506f3640SKyle Evans /*-
2506f3640SKyle Evans * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org>
3506f3640SKyle Evans * All rights reserved.
4506f3640SKyle Evans *
5506f3640SKyle Evans * Redistribution and use in source and binary forms, with or without
6506f3640SKyle Evans * modification, are permitted provided that the following conditions
7506f3640SKyle Evans * are met:
8506f3640SKyle Evans * 1. Redistributions of source code must retain the above copyright
9506f3640SKyle Evans * notice, this list of conditions and the following disclaimer.
10506f3640SKyle Evans * 2. Redistributions in binary form must reproduce the above copyright
11506f3640SKyle Evans * notice, this list of conditions and the following disclaimer in the
12506f3640SKyle Evans * documentation and/or other materials provided with the distribution.
13506f3640SKyle Evans *
14506f3640SKyle Evans * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15506f3640SKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16506f3640SKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17506f3640SKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18506f3640SKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19506f3640SKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20506f3640SKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21506f3640SKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22506f3640SKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23506f3640SKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24506f3640SKyle Evans * SUCH DAMAGE.
25506f3640SKyle Evans *
26506f3640SKyle Evans * Portions derived from https://github.com/keplerproject/luafilesystem under
27506f3640SKyle Evans * the terms of the MIT license:
28506f3640SKyle Evans *
29506f3640SKyle Evans * Copyright (c) 2003-2014 Kepler Project.
30506f3640SKyle Evans *
31506f3640SKyle Evans * Permission is hereby granted, free of charge, to any person
32506f3640SKyle Evans * obtaining a copy of this software and associated documentation
33506f3640SKyle Evans * files (the "Software"), to deal in the Software without
34506f3640SKyle Evans * restriction, including without limitation the rights to use, copy,
35506f3640SKyle Evans * modify, merge, publish, distribute, sublicense, and/or sell copies
36506f3640SKyle Evans * of the Software, and to permit persons to whom the Software is
37506f3640SKyle Evans * furnished to do so, subject to the following conditions:
38506f3640SKyle Evans *
39506f3640SKyle Evans * The above copyright notice and this permission notice shall be
40506f3640SKyle Evans * included in all copies or substantial portions of the Software.
41506f3640SKyle Evans *
42506f3640SKyle Evans * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43506f3640SKyle Evans * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44506f3640SKyle Evans * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
45506f3640SKyle Evans * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
46506f3640SKyle Evans * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
47506f3640SKyle Evans * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
48506f3640SKyle Evans * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
49506f3640SKyle Evans * SOFTWARE.
50506f3640SKyle Evans */
51506f3640SKyle Evans
52506f3640SKyle Evans #include <sys/cdefs.h>
53506f3640SKyle Evans #ifndef _STANDALONE
54506f3640SKyle Evans #include <sys/stat.h>
55506f3640SKyle Evans #include <dirent.h>
56506f3640SKyle Evans #include <errno.h>
57506f3640SKyle Evans #include <unistd.h>
58506f3640SKyle Evans #include <stdio.h>
59506f3640SKyle Evans #include <string.h>
60506f3640SKyle Evans #endif
61506f3640SKyle Evans
62506f3640SKyle Evans #include <lua.h>
63506f3640SKyle Evans #include "lauxlib.h"
64506f3640SKyle Evans #include "lfs.h"
65506f3640SKyle Evans
66506f3640SKyle Evans #ifdef _STANDALONE
67506f3640SKyle Evans #include "lstd.h"
68506f3640SKyle Evans #include "lutils.h"
69506f3640SKyle Evans #include "bootstrap.h"
70506f3640SKyle Evans #endif
71506f3640SKyle Evans
72506f3640SKyle Evans #ifndef nitems
73506f3640SKyle Evans #define nitems(x) (sizeof((x)) / sizeof((x)[0]))
74506f3640SKyle Evans #endif
75506f3640SKyle Evans
76506f3640SKyle Evans /*
77506f3640SKyle Evans * The goal is to emulate a subset of the upstream Lua FileSystem library, as
78506f3640SKyle Evans * faithfully as possible in the boot environment. Only APIs that seem useful
79506f3640SKyle Evans * need to emulated.
80506f3640SKyle Evans *
81506f3640SKyle Evans * Example usage:
82506f3640SKyle Evans *
83506f3640SKyle Evans * for file in lfs.dir("/boot") do
84506f3640SKyle Evans * print("\t"..file)
85506f3640SKyle Evans * end
86506f3640SKyle Evans *
87506f3640SKyle Evans * Prints:
88506f3640SKyle Evans * .
89506f3640SKyle Evans * ..
90506f3640SKyle Evans * (etc.)
91506f3640SKyle Evans *
92506f3640SKyle Evans * The other available API is lfs.attributes(), which functions somewhat like
93506f3640SKyle Evans * stat(2) and returns a table of values. Example code:
94506f3640SKyle Evans *
95506f3640SKyle Evans * attrs, errormsg, errorcode = lfs.attributes("/boot")
96506f3640SKyle Evans * if attrs == nil then
97506f3640SKyle Evans * print(errormsg)
98506f3640SKyle Evans * return errorcode
99506f3640SKyle Evans * end
100506f3640SKyle Evans *
101506f3640SKyle Evans * for k, v in pairs(attrs) do
102506f3640SKyle Evans * print(k .. ":\t" .. v)
103506f3640SKyle Evans * end
104506f3640SKyle Evans * return 0
105506f3640SKyle Evans *
106506f3640SKyle Evans * Prints (on success):
107506f3640SKyle Evans * gid: 0
108506f3640SKyle Evans * change: 140737488342640
109506f3640SKyle Evans * mode: directory
110506f3640SKyle Evans * rdev: 0
111506f3640SKyle Evans * ino: 4199275
112506f3640SKyle Evans * dev: 140737488342544
113506f3640SKyle Evans * modification: 140737488342576
114506f3640SKyle Evans * size: 512
115506f3640SKyle Evans * access: 140737488342560
116506f3640SKyle Evans * permissions: 755
117506f3640SKyle Evans * nlink: 58283552
118506f3640SKyle Evans * uid: 1001
119506f3640SKyle Evans */
120506f3640SKyle Evans
121506f3640SKyle Evans #define DIR_METATABLE "directory iterator metatable"
122506f3640SKyle Evans
123506f3640SKyle Evans static int
lua_dir_iter_pushtype(lua_State * L __unused,const struct dirent * ent __unused)124*e25ee296SKyle Evans lua_dir_iter_pushtype(lua_State *L __unused, const struct dirent *ent __unused)
125*e25ee296SKyle Evans {
126*e25ee296SKyle Evans
127*e25ee296SKyle Evans /*
128*e25ee296SKyle Evans * This is a non-standard extension to luafilesystem for loader's
129*e25ee296SKyle Evans * benefit. The extra stat() calls to determine the entry type can
130*e25ee296SKyle Evans * be quite expensive on some systems, so this speeds up enumeration of
131*e25ee296SKyle Evans * /boot greatly by providing the type up front.
132*e25ee296SKyle Evans *
133*e25ee296SKyle Evans * This extension is compatible enough with luafilesystem, in that we're
134*e25ee296SKyle Evans * just using an extra return value for the iterator.
135*e25ee296SKyle Evans */
136*e25ee296SKyle Evans #ifdef _STANDALONE
137*e25ee296SKyle Evans lua_pushinteger(L, ent->d_type);
138*e25ee296SKyle Evans return 1;
139*e25ee296SKyle Evans #else
140*e25ee296SKyle Evans return 0;
141*e25ee296SKyle Evans #endif
142*e25ee296SKyle Evans }
143*e25ee296SKyle Evans
144*e25ee296SKyle Evans static int
lua_dir_iter_next(lua_State * L)145506f3640SKyle Evans lua_dir_iter_next(lua_State *L)
146506f3640SKyle Evans {
147506f3640SKyle Evans struct dirent *entry;
148506f3640SKyle Evans DIR *dp, **dpp;
149506f3640SKyle Evans
150506f3640SKyle Evans dpp = (DIR **)luaL_checkudata(L, 1, DIR_METATABLE);
151506f3640SKyle Evans dp = *dpp;
152506f3640SKyle Evans luaL_argcheck(L, dp != NULL, 1, "closed directory");
153506f3640SKyle Evans
154506f3640SKyle Evans #ifdef _STANDALONE
155506f3640SKyle Evans entry = readdirfd(dp->fd);
156506f3640SKyle Evans #else
157506f3640SKyle Evans entry = readdir(dp);
158506f3640SKyle Evans #endif
159506f3640SKyle Evans if (entry == NULL) {
160506f3640SKyle Evans closedir(dp);
161506f3640SKyle Evans *dpp = NULL;
162506f3640SKyle Evans return 0;
163506f3640SKyle Evans }
164506f3640SKyle Evans
165506f3640SKyle Evans lua_pushstring(L, entry->d_name);
166*e25ee296SKyle Evans return 1 + lua_dir_iter_pushtype(L, entry);
167506f3640SKyle Evans }
168506f3640SKyle Evans
169506f3640SKyle Evans static int
lua_dir_iter_close(lua_State * L)170506f3640SKyle Evans lua_dir_iter_close(lua_State *L)
171506f3640SKyle Evans {
172506f3640SKyle Evans DIR *dp, **dpp;
173506f3640SKyle Evans
174506f3640SKyle Evans dpp = (DIR **)lua_touserdata(L, 1);
175506f3640SKyle Evans dp = *dpp;
176506f3640SKyle Evans if (dp == NULL)
177506f3640SKyle Evans return 0;
178506f3640SKyle Evans
179506f3640SKyle Evans closedir(dp);
180506f3640SKyle Evans *dpp = NULL;
181506f3640SKyle Evans return 0;
182506f3640SKyle Evans }
183506f3640SKyle Evans
184506f3640SKyle Evans static int
lua_dir(lua_State * L)185506f3640SKyle Evans lua_dir(lua_State *L)
186506f3640SKyle Evans {
187506f3640SKyle Evans const char *path;
188506f3640SKyle Evans DIR *dp;
189506f3640SKyle Evans
190506f3640SKyle Evans if (lua_gettop(L) != 1) {
191506f3640SKyle Evans lua_pushnil(L);
192506f3640SKyle Evans return 1;
193506f3640SKyle Evans }
194506f3640SKyle Evans
195506f3640SKyle Evans path = luaL_checkstring(L, 1);
196506f3640SKyle Evans dp = opendir(path);
197506f3640SKyle Evans if (dp == NULL) {
198506f3640SKyle Evans lua_pushnil(L);
199506f3640SKyle Evans return 1;
200506f3640SKyle Evans }
201506f3640SKyle Evans
202506f3640SKyle Evans lua_pushcfunction(L, lua_dir_iter_next);
203506f3640SKyle Evans *(DIR **)lua_newuserdata(L, sizeof(DIR **)) = dp;
204506f3640SKyle Evans luaL_getmetatable(L, DIR_METATABLE);
205506f3640SKyle Evans lua_setmetatable(L, -2);
206506f3640SKyle Evans return 2;
207506f3640SKyle Evans }
208506f3640SKyle Evans
209506f3640SKyle Evans static void
register_metatable(lua_State * L)210506f3640SKyle Evans register_metatable(lua_State *L)
211506f3640SKyle Evans {
212506f3640SKyle Evans /*
213506f3640SKyle Evans * Create so-called metatable for iterator object returned by
214506f3640SKyle Evans * lfs.dir().
215506f3640SKyle Evans */
216506f3640SKyle Evans luaL_newmetatable(L, DIR_METATABLE);
217506f3640SKyle Evans
218506f3640SKyle Evans lua_newtable(L);
219506f3640SKyle Evans lua_pushcfunction(L, lua_dir_iter_next);
220506f3640SKyle Evans lua_setfield(L, -2, "next");
221506f3640SKyle Evans lua_pushcfunction(L, lua_dir_iter_close);
222506f3640SKyle Evans lua_setfield(L, -2, "close");
223506f3640SKyle Evans
224506f3640SKyle Evans /* Magically associate anonymous method table with metatable. */
225506f3640SKyle Evans lua_setfield(L, -2, "__index");
226506f3640SKyle Evans /* Implement magic destructor method */
227506f3640SKyle Evans lua_pushcfunction(L, lua_dir_iter_close);
228506f3640SKyle Evans lua_setfield(L, -2, "__gc");
229506f3640SKyle Evans
230506f3640SKyle Evans lua_pop(L, 1);
231506f3640SKyle Evans }
232506f3640SKyle Evans
233506f3640SKyle Evans #define PUSH_INTEGER(lname, stname) \
234506f3640SKyle Evans static void \
235506f3640SKyle Evans push_st_ ## lname (lua_State *L, struct stat *sb) \
236506f3640SKyle Evans { \
237506f3640SKyle Evans lua_pushinteger(L, (lua_Integer)sb->st_ ## stname); \
238506f3640SKyle Evans }
PUSH_INTEGER(dev,dev)239506f3640SKyle Evans PUSH_INTEGER(dev, dev)
240506f3640SKyle Evans PUSH_INTEGER(ino, ino)
241506f3640SKyle Evans PUSH_INTEGER(nlink, nlink)
242506f3640SKyle Evans PUSH_INTEGER(uid, uid)
243506f3640SKyle Evans PUSH_INTEGER(gid, gid)
244506f3640SKyle Evans PUSH_INTEGER(rdev, rdev)
245506f3640SKyle Evans PUSH_INTEGER(access, atime)
246506f3640SKyle Evans PUSH_INTEGER(modification, mtime)
247506f3640SKyle Evans PUSH_INTEGER(change, ctime)
248506f3640SKyle Evans PUSH_INTEGER(size, size)
249506f3640SKyle Evans #undef PUSH_INTEGER
250506f3640SKyle Evans
251506f3640SKyle Evans static void
252506f3640SKyle Evans push_st_mode(lua_State *L, struct stat *sb)
253506f3640SKyle Evans {
254506f3640SKyle Evans const char *mode_s;
255506f3640SKyle Evans mode_t mode;
256506f3640SKyle Evans
257506f3640SKyle Evans mode = (sb->st_mode & S_IFMT);
258506f3640SKyle Evans if (S_ISREG(mode))
259506f3640SKyle Evans mode_s = "file";
260506f3640SKyle Evans else if (S_ISDIR(mode))
261506f3640SKyle Evans mode_s = "directory";
262506f3640SKyle Evans else if (S_ISLNK(mode))
263506f3640SKyle Evans mode_s = "link";
264506f3640SKyle Evans else if (S_ISSOCK(mode))
265506f3640SKyle Evans mode_s = "socket";
266506f3640SKyle Evans else if (S_ISFIFO(mode))
267506f3640SKyle Evans mode_s = "fifo";
268506f3640SKyle Evans else if (S_ISCHR(mode))
269506f3640SKyle Evans mode_s = "char device";
270506f3640SKyle Evans else if (S_ISBLK(mode))
271506f3640SKyle Evans mode_s = "block device";
272506f3640SKyle Evans else
273506f3640SKyle Evans mode_s = "other";
274506f3640SKyle Evans
275506f3640SKyle Evans lua_pushstring(L, mode_s);
276506f3640SKyle Evans }
277506f3640SKyle Evans
278506f3640SKyle Evans static void
push_st_permissions(lua_State * L,struct stat * sb)279506f3640SKyle Evans push_st_permissions(lua_State *L, struct stat *sb)
280506f3640SKyle Evans {
281506f3640SKyle Evans char buf[20];
282506f3640SKyle Evans
283506f3640SKyle Evans /*
284506f3640SKyle Evans * XXX
285506f3640SKyle Evans * Could actually format as "-rwxrwxrwx" -- do we care?
286506f3640SKyle Evans */
287506f3640SKyle Evans snprintf(buf, sizeof(buf), "%o", sb->st_mode & ~S_IFMT);
288506f3640SKyle Evans lua_pushstring(L, buf);
289506f3640SKyle Evans }
290506f3640SKyle Evans
291506f3640SKyle Evans #define PUSH_ENTRY(n) { #n, push_st_ ## n }
292506f3640SKyle Evans struct stat_members {
293506f3640SKyle Evans const char *name;
294506f3640SKyle Evans void (*push)(lua_State *, struct stat *);
295506f3640SKyle Evans } members[] = {
296506f3640SKyle Evans PUSH_ENTRY(mode),
297506f3640SKyle Evans PUSH_ENTRY(dev),
298506f3640SKyle Evans PUSH_ENTRY(ino),
299506f3640SKyle Evans PUSH_ENTRY(nlink),
300506f3640SKyle Evans PUSH_ENTRY(uid),
301506f3640SKyle Evans PUSH_ENTRY(gid),
302506f3640SKyle Evans PUSH_ENTRY(rdev),
303506f3640SKyle Evans PUSH_ENTRY(access),
304506f3640SKyle Evans PUSH_ENTRY(modification),
305506f3640SKyle Evans PUSH_ENTRY(change),
306506f3640SKyle Evans PUSH_ENTRY(size),
307506f3640SKyle Evans PUSH_ENTRY(permissions),
308506f3640SKyle Evans };
309506f3640SKyle Evans #undef PUSH_ENTRY
310506f3640SKyle Evans
311506f3640SKyle Evans static int
lua_attributes(lua_State * L)312506f3640SKyle Evans lua_attributes(lua_State *L)
313506f3640SKyle Evans {
314506f3640SKyle Evans struct stat sb;
315506f3640SKyle Evans const char *path, *member;
316506f3640SKyle Evans size_t i;
317506f3640SKyle Evans int rc;
318506f3640SKyle Evans
319506f3640SKyle Evans path = luaL_checkstring(L, 1);
320506f3640SKyle Evans if (path == NULL) {
321506f3640SKyle Evans lua_pushnil(L);
322506f3640SKyle Evans lua_pushfstring(L, "cannot convert first argument to string");
323506f3640SKyle Evans lua_pushinteger(L, EINVAL);
324506f3640SKyle Evans return 3;
325506f3640SKyle Evans }
326506f3640SKyle Evans
327506f3640SKyle Evans rc = stat(path, &sb);
328506f3640SKyle Evans if (rc != 0) {
329506f3640SKyle Evans lua_pushnil(L);
330506f3640SKyle Evans lua_pushfstring(L,
331506f3640SKyle Evans "cannot obtain information from file '%s': %s", path,
332506f3640SKyle Evans strerror(errno));
333506f3640SKyle Evans lua_pushinteger(L, errno);
334506f3640SKyle Evans return 3;
335506f3640SKyle Evans }
336506f3640SKyle Evans
337506f3640SKyle Evans if (lua_isstring(L, 2)) {
338506f3640SKyle Evans member = lua_tostring(L, 2);
339506f3640SKyle Evans for (i = 0; i < nitems(members); i++) {
340506f3640SKyle Evans if (strcmp(members[i].name, member) != 0)
341506f3640SKyle Evans continue;
342506f3640SKyle Evans
343506f3640SKyle Evans members[i].push(L, &sb);
344506f3640SKyle Evans return 1;
345506f3640SKyle Evans }
346506f3640SKyle Evans return luaL_error(L, "invalid attribute name '%s'", member);
347506f3640SKyle Evans }
348506f3640SKyle Evans
349506f3640SKyle Evans /* Create or reuse existing table */
350506f3640SKyle Evans lua_settop(L, 2);
351506f3640SKyle Evans if (!lua_istable(L, 2))
352506f3640SKyle Evans lua_newtable(L);
353506f3640SKyle Evans
354506f3640SKyle Evans /* Export all stat data to caller */
355506f3640SKyle Evans for (i = 0; i < nitems(members); i++) {
356506f3640SKyle Evans lua_pushstring(L, members[i].name);
357506f3640SKyle Evans members[i].push(L, &sb);
358506f3640SKyle Evans lua_rawset(L, -3);
359506f3640SKyle Evans }
360506f3640SKyle Evans return 1;
361506f3640SKyle Evans }
362506f3640SKyle Evans
363506f3640SKyle Evans #ifndef _STANDALONE
364506f3640SKyle Evans #define lfs_mkdir_impl(path) (mkdir((path), \
365506f3640SKyle Evans S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | \
366506f3640SKyle Evans S_IROTH | S_IXOTH))
367506f3640SKyle Evans
368506f3640SKyle Evans static int
lua_mkdir(lua_State * L)369506f3640SKyle Evans lua_mkdir(lua_State *L)
370506f3640SKyle Evans {
371506f3640SKyle Evans const char *path;
372506f3640SKyle Evans int error, serrno;
373506f3640SKyle Evans
374506f3640SKyle Evans path = luaL_checkstring(L, 1);
375506f3640SKyle Evans if (path == NULL) {
376506f3640SKyle Evans lua_pushnil(L);
377506f3640SKyle Evans lua_pushfstring(L, "cannot convert first argument to string");
378506f3640SKyle Evans lua_pushinteger(L, EINVAL);
379506f3640SKyle Evans return 3;
380506f3640SKyle Evans }
381506f3640SKyle Evans
382506f3640SKyle Evans error = lfs_mkdir_impl(path);
383506f3640SKyle Evans if (error == -1) {
384506f3640SKyle Evans /* Save it; unclear what other libc functions may be invoked */
385506f3640SKyle Evans serrno = errno;
386506f3640SKyle Evans lua_pushnil(L);
387506f3640SKyle Evans lua_pushfstring(L, strerror(serrno));
388506f3640SKyle Evans lua_pushinteger(L, serrno);
389506f3640SKyle Evans return 3;
390506f3640SKyle Evans }
391506f3640SKyle Evans
392506f3640SKyle Evans lua_pushboolean(L, 1);
393506f3640SKyle Evans return 1;
394506f3640SKyle Evans }
395506f3640SKyle Evans
396506f3640SKyle Evans static int
lua_rmdir(lua_State * L)397506f3640SKyle Evans lua_rmdir(lua_State *L)
398506f3640SKyle Evans {
399506f3640SKyle Evans const char *path;
400506f3640SKyle Evans int error, serrno;
401506f3640SKyle Evans
402506f3640SKyle Evans path = luaL_checkstring(L, 1);
403506f3640SKyle Evans if (path == NULL) {
404506f3640SKyle Evans lua_pushnil(L);
405506f3640SKyle Evans lua_pushfstring(L, "cannot convert first argument to string");
406506f3640SKyle Evans lua_pushinteger(L, EINVAL);
407506f3640SKyle Evans return 3;
408506f3640SKyle Evans }
409506f3640SKyle Evans
410506f3640SKyle Evans error = rmdir(path);
411506f3640SKyle Evans if (error == -1) {
412506f3640SKyle Evans /* Save it; unclear what other libc functions may be invoked */
413506f3640SKyle Evans serrno = errno;
414506f3640SKyle Evans lua_pushnil(L);
415506f3640SKyle Evans lua_pushfstring(L, strerror(serrno));
416506f3640SKyle Evans lua_pushinteger(L, serrno);
417506f3640SKyle Evans return 3;
418506f3640SKyle Evans }
419506f3640SKyle Evans
420506f3640SKyle Evans lua_pushboolean(L, 1);
421506f3640SKyle Evans return 1;
422506f3640SKyle Evans }
423506f3640SKyle Evans #endif
424506f3640SKyle Evans
425506f3640SKyle Evans #define REG_SIMPLE(n) { #n, lua_ ## n }
426506f3640SKyle Evans static const struct luaL_Reg fslib[] = {
427506f3640SKyle Evans REG_SIMPLE(attributes),
428506f3640SKyle Evans REG_SIMPLE(dir),
429506f3640SKyle Evans #ifndef _STANDALONE
430506f3640SKyle Evans REG_SIMPLE(mkdir),
431506f3640SKyle Evans REG_SIMPLE(rmdir),
432506f3640SKyle Evans #endif
433506f3640SKyle Evans { NULL, NULL },
434506f3640SKyle Evans };
435506f3640SKyle Evans #undef REG_SIMPLE
436506f3640SKyle Evans
437506f3640SKyle Evans int
luaopen_lfs(lua_State * L)438506f3640SKyle Evans luaopen_lfs(lua_State *L)
439506f3640SKyle Evans {
440506f3640SKyle Evans register_metatable(L);
441506f3640SKyle Evans luaL_newlib(L, fslib);
442*e25ee296SKyle Evans #ifdef _STANDALONE
443*e25ee296SKyle Evans /* Non-standard extension for loader, used with lfs.dir(). */
444*e25ee296SKyle Evans lua_pushinteger(L, DT_DIR);
445*e25ee296SKyle Evans lua_setfield(L, -2, "DT_DIR");
446*e25ee296SKyle Evans #endif
447506f3640SKyle Evans return 1;
448506f3640SKyle Evans }
449