1*b11a5709SKyle Evans /*-
2*b11a5709SKyle Evans * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org>
3*b11a5709SKyle Evans * All rights reserved.
4*b11a5709SKyle Evans *
5*b11a5709SKyle Evans * Redistribution and use in source and binary forms, with or without
6*b11a5709SKyle Evans * modification, are permitted provided that the following conditions
7*b11a5709SKyle Evans * are met:
8*b11a5709SKyle Evans * 1. Redistributions of source code must retain the above copyright
9*b11a5709SKyle Evans * notice, this list of conditions and the following disclaimer.
10*b11a5709SKyle Evans * 2. Redistributions in binary form must reproduce the above copyright
11*b11a5709SKyle Evans * notice, this list of conditions and the following disclaimer in the
12*b11a5709SKyle Evans * documentation and/or other materials provided with the distribution.
13*b11a5709SKyle Evans *
14*b11a5709SKyle Evans * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*b11a5709SKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*b11a5709SKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*b11a5709SKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*b11a5709SKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*b11a5709SKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*b11a5709SKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*b11a5709SKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*b11a5709SKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*b11a5709SKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*b11a5709SKyle Evans * SUCH DAMAGE.
25*b11a5709SKyle Evans *
26*b11a5709SKyle Evans * Portions derived from https://github.com/keplerproject/luafilesystem under
27*b11a5709SKyle Evans * the terms of the MIT license:
28*b11a5709SKyle Evans *
29*b11a5709SKyle Evans * Copyright (c) 2003-2014 Kepler Project.
30*b11a5709SKyle Evans *
31*b11a5709SKyle Evans * Permission is hereby granted, free of charge, to any person
32*b11a5709SKyle Evans * obtaining a copy of this software and associated documentation
33*b11a5709SKyle Evans * files (the "Software"), to deal in the Software without
34*b11a5709SKyle Evans * restriction, including without limitation the rights to use, copy,
35*b11a5709SKyle Evans * modify, merge, publish, distribute, sublicense, and/or sell copies
36*b11a5709SKyle Evans * of the Software, and to permit persons to whom the Software is
37*b11a5709SKyle Evans * furnished to do so, subject to the following conditions:
38*b11a5709SKyle Evans *
39*b11a5709SKyle Evans * The above copyright notice and this permission notice shall be
40*b11a5709SKyle Evans * included in all copies or substantial portions of the Software.
41*b11a5709SKyle Evans *
42*b11a5709SKyle Evans * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43*b11a5709SKyle Evans * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44*b11a5709SKyle Evans * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
45*b11a5709SKyle Evans * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
46*b11a5709SKyle Evans * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
47*b11a5709SKyle Evans * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
48*b11a5709SKyle Evans * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
49*b11a5709SKyle Evans * SOFTWARE.
50*b11a5709SKyle Evans */
51*b11a5709SKyle Evans
52*b11a5709SKyle Evans #include <sys/cdefs.h>
53*b11a5709SKyle Evans #ifndef _STANDALONE
54*b11a5709SKyle Evans #include <sys/stat.h>
55*b11a5709SKyle Evans #include <dirent.h>
56*b11a5709SKyle Evans #include <errno.h>
57*b11a5709SKyle Evans #include <unistd.h>
58*b11a5709SKyle Evans #include <stdio.h>
59*b11a5709SKyle Evans #include <string.h>
60*b11a5709SKyle Evans #endif
61*b11a5709SKyle Evans
62*b11a5709SKyle Evans #include <lua.h>
63*b11a5709SKyle Evans #include "lauxlib.h"
64*b11a5709SKyle Evans #include "lfs.h"
65*b11a5709SKyle Evans
66*b11a5709SKyle Evans #ifdef _STANDALONE
67*b11a5709SKyle Evans #include "lstd.h"
68*b11a5709SKyle Evans #include "lutils.h"
69*b11a5709SKyle Evans #endif
70*b11a5709SKyle Evans
71*b11a5709SKyle Evans #include "bootstrap.h"
72*b11a5709SKyle Evans
73*b11a5709SKyle Evans #ifndef nitems
74*b11a5709SKyle Evans #define nitems(x) (sizeof((x)) / sizeof((x)[0]))
75*b11a5709SKyle Evans #endif
76*b11a5709SKyle Evans
77*b11a5709SKyle Evans /*
78*b11a5709SKyle Evans * The goal is to emulate a subset of the upstream Lua FileSystem library, as
79*b11a5709SKyle Evans * faithfully as possible in the boot environment. Only APIs that seem useful
80*b11a5709SKyle Evans * need to emulated.
81*b11a5709SKyle Evans *
82*b11a5709SKyle Evans * Example usage:
83*b11a5709SKyle Evans *
84*b11a5709SKyle Evans * for file in lfs.dir("/boot") do
85*b11a5709SKyle Evans * print("\t"..file)
86*b11a5709SKyle Evans * end
87*b11a5709SKyle Evans *
88*b11a5709SKyle Evans * Prints:
89*b11a5709SKyle Evans * .
90*b11a5709SKyle Evans * ..
91*b11a5709SKyle Evans * (etc.)
92*b11a5709SKyle Evans *
93*b11a5709SKyle Evans * The other available API is lfs.attributes(), which functions somewhat like
94*b11a5709SKyle Evans * stat(2) and returns a table of values. Example code:
95*b11a5709SKyle Evans *
96*b11a5709SKyle Evans * attrs, errormsg, errorcode = lfs.attributes("/boot")
97*b11a5709SKyle Evans * if attrs == nil then
98*b11a5709SKyle Evans * print(errormsg)
99*b11a5709SKyle Evans * return errorcode
100*b11a5709SKyle Evans * end
101*b11a5709SKyle Evans *
102*b11a5709SKyle Evans * for k, v in pairs(attrs) do
103*b11a5709SKyle Evans * print(k .. ":\t" .. v)
104*b11a5709SKyle Evans * end
105*b11a5709SKyle Evans * return 0
106*b11a5709SKyle Evans *
107*b11a5709SKyle Evans * Prints (on success):
108*b11a5709SKyle Evans * gid: 0
109*b11a5709SKyle Evans * change: 140737488342640
110*b11a5709SKyle Evans * mode: directory
111*b11a5709SKyle Evans * rdev: 0
112*b11a5709SKyle Evans * ino: 4199275
113*b11a5709SKyle Evans * dev: 140737488342544
114*b11a5709SKyle Evans * modification: 140737488342576
115*b11a5709SKyle Evans * size: 512
116*b11a5709SKyle Evans * access: 140737488342560
117*b11a5709SKyle Evans * permissions: 755
118*b11a5709SKyle Evans * nlink: 58283552
119*b11a5709SKyle Evans * uid: 1001
120*b11a5709SKyle Evans */
121*b11a5709SKyle Evans
122*b11a5709SKyle Evans #define DIR_METATABLE "directory iterator metatable"
123*b11a5709SKyle Evans
124*b11a5709SKyle Evans static int
lua_dir_iter_pushtype(lua_State * L __unused,const struct dirent * ent __unused)125*b11a5709SKyle Evans lua_dir_iter_pushtype(lua_State *L __unused, const struct dirent *ent __unused)
126*b11a5709SKyle Evans {
127*b11a5709SKyle Evans
128*b11a5709SKyle Evans /*
129*b11a5709SKyle Evans * This is a non-standard extension to luafilesystem for loader's
130*b11a5709SKyle Evans * benefit. The extra stat() calls to determine the entry type can
131*b11a5709SKyle Evans * be quite expensive on some systems, so this speeds up enumeration of
132*b11a5709SKyle Evans * /boot greatly by providing the type up front.
133*b11a5709SKyle Evans *
134*b11a5709SKyle Evans * This extension is compatible enough with luafilesystem, in that we're
135*b11a5709SKyle Evans * just using an extra return value for the iterator.
136*b11a5709SKyle Evans */
137*b11a5709SKyle Evans #ifdef _STANDALONE
138*b11a5709SKyle Evans lua_pushinteger(L, ent->d_type);
139*b11a5709SKyle Evans return 1;
140*b11a5709SKyle Evans #else
141*b11a5709SKyle Evans return 0;
142*b11a5709SKyle Evans #endif
143*b11a5709SKyle Evans }
144*b11a5709SKyle Evans
145*b11a5709SKyle Evans static int
lua_dir_iter_next(lua_State * L)146*b11a5709SKyle Evans lua_dir_iter_next(lua_State *L)
147*b11a5709SKyle Evans {
148*b11a5709SKyle Evans struct dirent *entry;
149*b11a5709SKyle Evans DIR *dp, **dpp;
150*b11a5709SKyle Evans
151*b11a5709SKyle Evans dpp = (DIR **)luaL_checkudata(L, 1, DIR_METATABLE);
152*b11a5709SKyle Evans dp = *dpp;
153*b11a5709SKyle Evans luaL_argcheck(L, dp != NULL, 1, "closed directory");
154*b11a5709SKyle Evans
155*b11a5709SKyle Evans #ifdef _STANDALONE
156*b11a5709SKyle Evans entry = readdirfd(dp->fd);
157*b11a5709SKyle Evans #else
158*b11a5709SKyle Evans entry = readdir(dp);
159*b11a5709SKyle Evans #endif
160*b11a5709SKyle Evans if (entry == NULL) {
161*b11a5709SKyle Evans closedir(dp);
162*b11a5709SKyle Evans *dpp = NULL;
163*b11a5709SKyle Evans return 0;
164*b11a5709SKyle Evans }
165*b11a5709SKyle Evans
166*b11a5709SKyle Evans lua_pushstring(L, entry->d_name);
167*b11a5709SKyle Evans return 1 + lua_dir_iter_pushtype(L, entry);
168*b11a5709SKyle Evans }
169*b11a5709SKyle Evans
170*b11a5709SKyle Evans static int
lua_dir_iter_close(lua_State * L)171*b11a5709SKyle Evans lua_dir_iter_close(lua_State *L)
172*b11a5709SKyle Evans {
173*b11a5709SKyle Evans DIR *dp, **dpp;
174*b11a5709SKyle Evans
175*b11a5709SKyle Evans dpp = (DIR **)lua_touserdata(L, 1);
176*b11a5709SKyle Evans dp = *dpp;
177*b11a5709SKyle Evans if (dp == NULL)
178*b11a5709SKyle Evans return 0;
179*b11a5709SKyle Evans
180*b11a5709SKyle Evans closedir(dp);
181*b11a5709SKyle Evans *dpp = NULL;
182*b11a5709SKyle Evans return 0;
183*b11a5709SKyle Evans }
184*b11a5709SKyle Evans
185*b11a5709SKyle Evans static int
lua_dir(lua_State * L)186*b11a5709SKyle Evans lua_dir(lua_State *L)
187*b11a5709SKyle Evans {
188*b11a5709SKyle Evans const char *path;
189*b11a5709SKyle Evans DIR *dp;
190*b11a5709SKyle Evans
191*b11a5709SKyle Evans if (lua_gettop(L) != 1) {
192*b11a5709SKyle Evans lua_pushnil(L);
193*b11a5709SKyle Evans return 1;
194*b11a5709SKyle Evans }
195*b11a5709SKyle Evans
196*b11a5709SKyle Evans path = luaL_checkstring(L, 1);
197*b11a5709SKyle Evans dp = opendir(path);
198*b11a5709SKyle Evans if (dp == NULL) {
199*b11a5709SKyle Evans lua_pushnil(L);
200*b11a5709SKyle Evans return 1;
201*b11a5709SKyle Evans }
202*b11a5709SKyle Evans
203*b11a5709SKyle Evans lua_pushcfunction(L, lua_dir_iter_next);
204*b11a5709SKyle Evans *(DIR **)lua_newuserdata(L, sizeof(DIR **)) = dp;
205*b11a5709SKyle Evans luaL_getmetatable(L, DIR_METATABLE);
206*b11a5709SKyle Evans lua_setmetatable(L, -2);
207*b11a5709SKyle Evans return 2;
208*b11a5709SKyle Evans }
209*b11a5709SKyle Evans
210*b11a5709SKyle Evans static void
register_metatable(lua_State * L)211*b11a5709SKyle Evans register_metatable(lua_State *L)
212*b11a5709SKyle Evans {
213*b11a5709SKyle Evans /*
214*b11a5709SKyle Evans * Create so-called metatable for iterator object returned by
215*b11a5709SKyle Evans * lfs.dir().
216*b11a5709SKyle Evans */
217*b11a5709SKyle Evans luaL_newmetatable(L, DIR_METATABLE);
218*b11a5709SKyle Evans
219*b11a5709SKyle Evans lua_newtable(L);
220*b11a5709SKyle Evans lua_pushcfunction(L, lua_dir_iter_next);
221*b11a5709SKyle Evans lua_setfield(L, -2, "next");
222*b11a5709SKyle Evans lua_pushcfunction(L, lua_dir_iter_close);
223*b11a5709SKyle Evans lua_setfield(L, -2, "close");
224*b11a5709SKyle Evans
225*b11a5709SKyle Evans /* Magically associate anonymous method table with metatable. */
226*b11a5709SKyle Evans lua_setfield(L, -2, "__index");
227*b11a5709SKyle Evans /* Implement magic destructor method */
228*b11a5709SKyle Evans lua_pushcfunction(L, lua_dir_iter_close);
229*b11a5709SKyle Evans lua_setfield(L, -2, "__gc");
230*b11a5709SKyle Evans
231*b11a5709SKyle Evans lua_pop(L, 1);
232*b11a5709SKyle Evans }
233*b11a5709SKyle Evans
234*b11a5709SKyle Evans #define PUSH_INTEGER(lname, stname) \
235*b11a5709SKyle Evans static void \
236*b11a5709SKyle Evans push_st_ ## lname (lua_State *L, struct stat *sb) \
237*b11a5709SKyle Evans { \
238*b11a5709SKyle Evans lua_pushinteger(L, (lua_Integer)sb->st_ ## stname); \
239*b11a5709SKyle Evans }
PUSH_INTEGER(dev,dev)240*b11a5709SKyle Evans PUSH_INTEGER(dev, dev)
241*b11a5709SKyle Evans PUSH_INTEGER(ino, ino)
242*b11a5709SKyle Evans PUSH_INTEGER(nlink, nlink)
243*b11a5709SKyle Evans PUSH_INTEGER(uid, uid)
244*b11a5709SKyle Evans PUSH_INTEGER(gid, gid)
245*b11a5709SKyle Evans PUSH_INTEGER(rdev, rdev)
246*b11a5709SKyle Evans PUSH_INTEGER(access, atime)
247*b11a5709SKyle Evans PUSH_INTEGER(modification, mtime)
248*b11a5709SKyle Evans PUSH_INTEGER(change, ctime)
249*b11a5709SKyle Evans PUSH_INTEGER(size, size)
250*b11a5709SKyle Evans #undef PUSH_INTEGER
251*b11a5709SKyle Evans
252*b11a5709SKyle Evans static void
253*b11a5709SKyle Evans push_st_mode(lua_State *L, struct stat *sb)
254*b11a5709SKyle Evans {
255*b11a5709SKyle Evans const char *mode_s;
256*b11a5709SKyle Evans mode_t mode;
257*b11a5709SKyle Evans
258*b11a5709SKyle Evans mode = (sb->st_mode & S_IFMT);
259*b11a5709SKyle Evans if (S_ISREG(mode))
260*b11a5709SKyle Evans mode_s = "file";
261*b11a5709SKyle Evans else if (S_ISDIR(mode))
262*b11a5709SKyle Evans mode_s = "directory";
263*b11a5709SKyle Evans else if (S_ISLNK(mode))
264*b11a5709SKyle Evans mode_s = "link";
265*b11a5709SKyle Evans else if (S_ISSOCK(mode))
266*b11a5709SKyle Evans mode_s = "socket";
267*b11a5709SKyle Evans else if (S_ISFIFO(mode))
268*b11a5709SKyle Evans mode_s = "fifo";
269*b11a5709SKyle Evans else if (S_ISCHR(mode))
270*b11a5709SKyle Evans mode_s = "char device";
271*b11a5709SKyle Evans else if (S_ISBLK(mode))
272*b11a5709SKyle Evans mode_s = "block device";
273*b11a5709SKyle Evans else
274*b11a5709SKyle Evans mode_s = "other";
275*b11a5709SKyle Evans
276*b11a5709SKyle Evans lua_pushstring(L, mode_s);
277*b11a5709SKyle Evans }
278*b11a5709SKyle Evans
279*b11a5709SKyle Evans static void
push_st_permissions(lua_State * L,struct stat * sb)280*b11a5709SKyle Evans push_st_permissions(lua_State *L, struct stat *sb)
281*b11a5709SKyle Evans {
282*b11a5709SKyle Evans char buf[20];
283*b11a5709SKyle Evans
284*b11a5709SKyle Evans /*
285*b11a5709SKyle Evans * XXX
286*b11a5709SKyle Evans * Could actually format as "-rwxrwxrwx" -- do we care?
287*b11a5709SKyle Evans */
288*b11a5709SKyle Evans snprintf(buf, sizeof(buf), "%o", sb->st_mode & ~S_IFMT);
289*b11a5709SKyle Evans lua_pushstring(L, buf);
290*b11a5709SKyle Evans }
291*b11a5709SKyle Evans
292*b11a5709SKyle Evans #define PUSH_ENTRY(n) { #n, push_st_ ## n }
293*b11a5709SKyle Evans struct stat_members {
294*b11a5709SKyle Evans const char *name;
295*b11a5709SKyle Evans void (*push)(lua_State *, struct stat *);
296*b11a5709SKyle Evans } members[] = {
297*b11a5709SKyle Evans PUSH_ENTRY(mode),
298*b11a5709SKyle Evans PUSH_ENTRY(dev),
299*b11a5709SKyle Evans PUSH_ENTRY(ino),
300*b11a5709SKyle Evans PUSH_ENTRY(nlink),
301*b11a5709SKyle Evans PUSH_ENTRY(uid),
302*b11a5709SKyle Evans PUSH_ENTRY(gid),
303*b11a5709SKyle Evans PUSH_ENTRY(rdev),
304*b11a5709SKyle Evans PUSH_ENTRY(access),
305*b11a5709SKyle Evans PUSH_ENTRY(modification),
306*b11a5709SKyle Evans PUSH_ENTRY(change),
307*b11a5709SKyle Evans PUSH_ENTRY(size),
308*b11a5709SKyle Evans PUSH_ENTRY(permissions),
309*b11a5709SKyle Evans };
310*b11a5709SKyle Evans #undef PUSH_ENTRY
311*b11a5709SKyle Evans
312*b11a5709SKyle Evans static int
lua_attributes(lua_State * L)313*b11a5709SKyle Evans lua_attributes(lua_State *L)
314*b11a5709SKyle Evans {
315*b11a5709SKyle Evans struct stat sb;
316*b11a5709SKyle Evans const char *path, *member;
317*b11a5709SKyle Evans size_t i;
318*b11a5709SKyle Evans int rc;
319*b11a5709SKyle Evans
320*b11a5709SKyle Evans path = luaL_checkstring(L, 1);
321*b11a5709SKyle Evans if (path == NULL) {
322*b11a5709SKyle Evans lua_pushnil(L);
323*b11a5709SKyle Evans lua_pushfstring(L, "cannot convert first argument to string");
324*b11a5709SKyle Evans lua_pushinteger(L, EINVAL);
325*b11a5709SKyle Evans return 3;
326*b11a5709SKyle Evans }
327*b11a5709SKyle Evans
328*b11a5709SKyle Evans rc = stat(path, &sb);
329*b11a5709SKyle Evans if (rc != 0) {
330*b11a5709SKyle Evans lua_pushnil(L);
331*b11a5709SKyle Evans lua_pushfstring(L,
332*b11a5709SKyle Evans "cannot obtain information from file '%s': %s", path,
333*b11a5709SKyle Evans strerror(errno));
334*b11a5709SKyle Evans lua_pushinteger(L, errno);
335*b11a5709SKyle Evans return 3;
336*b11a5709SKyle Evans }
337*b11a5709SKyle Evans
338*b11a5709SKyle Evans if (lua_isstring(L, 2)) {
339*b11a5709SKyle Evans member = lua_tostring(L, 2);
340*b11a5709SKyle Evans for (i = 0; i < nitems(members); i++) {
341*b11a5709SKyle Evans if (strcmp(members[i].name, member) != 0)
342*b11a5709SKyle Evans continue;
343*b11a5709SKyle Evans
344*b11a5709SKyle Evans members[i].push(L, &sb);
345*b11a5709SKyle Evans return 1;
346*b11a5709SKyle Evans }
347*b11a5709SKyle Evans return luaL_error(L, "invalid attribute name '%s'", member);
348*b11a5709SKyle Evans }
349*b11a5709SKyle Evans
350*b11a5709SKyle Evans /* Create or reuse existing table */
351*b11a5709SKyle Evans lua_settop(L, 2);
352*b11a5709SKyle Evans if (!lua_istable(L, 2))
353*b11a5709SKyle Evans lua_newtable(L);
354*b11a5709SKyle Evans
355*b11a5709SKyle Evans /* Export all stat data to caller */
356*b11a5709SKyle Evans for (i = 0; i < nitems(members); i++) {
357*b11a5709SKyle Evans lua_pushstring(L, members[i].name);
358*b11a5709SKyle Evans members[i].push(L, &sb);
359*b11a5709SKyle Evans lua_rawset(L, -3);
360*b11a5709SKyle Evans }
361*b11a5709SKyle Evans return 1;
362*b11a5709SKyle Evans }
363*b11a5709SKyle Evans
364*b11a5709SKyle Evans #ifndef _STANDALONE
365*b11a5709SKyle Evans #define lfs_mkdir_impl(path) (mkdir((path), \
366*b11a5709SKyle Evans S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | \
367*b11a5709SKyle Evans S_IROTH | S_IXOTH))
368*b11a5709SKyle Evans
369*b11a5709SKyle Evans static int
lua_mkdir(lua_State * L)370*b11a5709SKyle Evans lua_mkdir(lua_State *L)
371*b11a5709SKyle Evans {
372*b11a5709SKyle Evans const char *path;
373*b11a5709SKyle Evans int error, serrno;
374*b11a5709SKyle Evans
375*b11a5709SKyle Evans path = luaL_checkstring(L, 1);
376*b11a5709SKyle Evans if (path == NULL) {
377*b11a5709SKyle Evans lua_pushnil(L);
378*b11a5709SKyle Evans lua_pushfstring(L, "cannot convert first argument to string");
379*b11a5709SKyle Evans lua_pushinteger(L, EINVAL);
380*b11a5709SKyle Evans return 3;
381*b11a5709SKyle Evans }
382*b11a5709SKyle Evans
383*b11a5709SKyle Evans error = lfs_mkdir_impl(path);
384*b11a5709SKyle Evans if (error == -1) {
385*b11a5709SKyle Evans /* Save it; unclear what other libc functions may be invoked */
386*b11a5709SKyle Evans serrno = errno;
387*b11a5709SKyle Evans lua_pushnil(L);
388*b11a5709SKyle Evans lua_pushfstring(L, strerror(serrno));
389*b11a5709SKyle Evans lua_pushinteger(L, serrno);
390*b11a5709SKyle Evans return 3;
391*b11a5709SKyle Evans }
392*b11a5709SKyle Evans
393*b11a5709SKyle Evans lua_pushboolean(L, 1);
394*b11a5709SKyle Evans return 1;
395*b11a5709SKyle Evans }
396*b11a5709SKyle Evans
397*b11a5709SKyle Evans static int
lua_rmdir(lua_State * L)398*b11a5709SKyle Evans lua_rmdir(lua_State *L)
399*b11a5709SKyle Evans {
400*b11a5709SKyle Evans const char *path;
401*b11a5709SKyle Evans int error, serrno;
402*b11a5709SKyle Evans
403*b11a5709SKyle Evans path = luaL_checkstring(L, 1);
404*b11a5709SKyle Evans if (path == NULL) {
405*b11a5709SKyle Evans lua_pushnil(L);
406*b11a5709SKyle Evans lua_pushfstring(L, "cannot convert first argument to string");
407*b11a5709SKyle Evans lua_pushinteger(L, EINVAL);
408*b11a5709SKyle Evans return 3;
409*b11a5709SKyle Evans }
410*b11a5709SKyle Evans
411*b11a5709SKyle Evans error = rmdir(path);
412*b11a5709SKyle Evans if (error == -1) {
413*b11a5709SKyle Evans /* Save it; unclear what other libc functions may be invoked */
414*b11a5709SKyle Evans serrno = errno;
415*b11a5709SKyle Evans lua_pushnil(L);
416*b11a5709SKyle Evans lua_pushfstring(L, strerror(serrno));
417*b11a5709SKyle Evans lua_pushinteger(L, serrno);
418*b11a5709SKyle Evans return 3;
419*b11a5709SKyle Evans }
420*b11a5709SKyle Evans
421*b11a5709SKyle Evans lua_pushboolean(L, 1);
422*b11a5709SKyle Evans return 1;
423*b11a5709SKyle Evans }
424*b11a5709SKyle Evans #endif
425*b11a5709SKyle Evans
426*b11a5709SKyle Evans #define REG_SIMPLE(n) { #n, lua_ ## n }
427*b11a5709SKyle Evans static const struct luaL_Reg fslib[] = {
428*b11a5709SKyle Evans REG_SIMPLE(attributes),
429*b11a5709SKyle Evans REG_SIMPLE(dir),
430*b11a5709SKyle Evans #ifndef _STANDALONE
431*b11a5709SKyle Evans REG_SIMPLE(mkdir),
432*b11a5709SKyle Evans REG_SIMPLE(rmdir),
433*b11a5709SKyle Evans #endif
434*b11a5709SKyle Evans { NULL, NULL },
435*b11a5709SKyle Evans };
436*b11a5709SKyle Evans #undef REG_SIMPLE
437*b11a5709SKyle Evans
438*b11a5709SKyle Evans int
luaopen_lfs(lua_State * L)439*b11a5709SKyle Evans luaopen_lfs(lua_State *L)
440*b11a5709SKyle Evans {
441*b11a5709SKyle Evans register_metatable(L);
442*b11a5709SKyle Evans luaL_newlib(L, fslib);
443*b11a5709SKyle Evans #ifdef _STANDALONE
444*b11a5709SKyle Evans /* Non-standard extension for loader, used with lfs.dir(). */
445*b11a5709SKyle Evans lua_pushinteger(L, DT_DIR);
446*b11a5709SKyle Evans lua_setfield(L, -2, "DT_DIR");
447*b11a5709SKyle Evans #endif
448*b11a5709SKyle Evans return 1;
449*b11a5709SKyle Evans }
450*b11a5709SKyle Evans
451*b11a5709SKyle Evans #ifndef _STANDALONE
452*b11a5709SKyle Evans FLUA_MODULE(lfs);
453*b11a5709SKyle Evans #endif
454