2 * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * Portions derived from https://github.com/keplerproject/luafilesystem under
27 * the terms of the MIT license:
29 * Copyright (c) 2003-2014 Kepler Project.
31 * Permission is hereby granted, free of charge, to any person
32 * obtaining a copy of this software and associated documentation
33 * files (the "Software"), to deal in the Software without
34 * restriction, including without limitation the rights to use, copy,
35 * modify, merge, publish, distribute, sublicense, and/or sell copies
36 * of the Software, and to permit persons to whom the Software is
37 * furnished to do so, subject to the following conditions:
39 * The above copyright notice and this permission notice shall be
40 * included in all copies or substantial portions of the Software.
42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
45 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
46 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
47 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
48 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
52 #include <sys/cdefs.h>
53 __FBSDID("$FreeBSD$");
71 #include "bootstrap.h"
75 #define nitems(x) (sizeof((x)) / sizeof((x)[0]))
79 * The goal is to emulate a subset of the upstream Lua FileSystem library, as
80 * faithfully as possible in the boot environment. Only APIs that seem useful
85 * for file in lfs.dir("/boot") do
94 * The other available API is lfs.attributes(), which functions somewhat like
95 * stat(2) and returns a table of values. Example code:
97 * attrs, errormsg, errorcode = lfs.attributes("/boot")
98 * if attrs == nil then
103 * for k, v in pairs(attrs) do
104 * print(k .. ":\t" .. v)
108 * Prints (on success):
110 * change: 140737488342640
114 * dev: 140737488342544
115 * modification: 140737488342576
117 * access: 140737488342560
123 #define DIR_METATABLE "directory iterator metatable"
126 lua_dir_iter_next(lua_State *L)
128 struct dirent *entry;
131 dpp = (DIR **)luaL_checkudata(L, 1, DIR_METATABLE);
133 luaL_argcheck(L, dp != NULL, 1, "closed directory");
136 entry = readdirfd(dp->fd);
146 lua_pushstring(L, entry->d_name);
151 lua_dir_iter_close(lua_State *L)
155 dpp = (DIR **)lua_touserdata(L, 1);
166 lua_dir(lua_State *L)
171 if (lua_gettop(L) != 1) {
176 path = luaL_checkstring(L, 1);
183 lua_pushcfunction(L, lua_dir_iter_next);
184 *(DIR **)lua_newuserdata(L, sizeof(DIR **)) = dp;
185 luaL_getmetatable(L, DIR_METATABLE);
186 lua_setmetatable(L, -2);
191 register_metatable(lua_State *L)
194 * Create so-called metatable for iterator object returned by
197 luaL_newmetatable(L, DIR_METATABLE);
200 lua_pushcfunction(L, lua_dir_iter_next);
201 lua_setfield(L, -2, "next");
202 lua_pushcfunction(L, lua_dir_iter_close);
203 lua_setfield(L, -2, "close");
205 /* Magically associate anonymous method table with metatable. */
206 lua_setfield(L, -2, "__index");
207 /* Implement magic destructor method */
208 lua_pushcfunction(L, lua_dir_iter_close);
209 lua_setfield(L, -2, "__gc");
214 #define PUSH_INTEGER(lname, stname) \
216 push_st_ ## lname (lua_State *L, struct stat *sb) \
218 lua_pushinteger(L, (lua_Integer)sb->st_ ## stname); \
220 PUSH_INTEGER(dev, dev)
221 PUSH_INTEGER(ino, ino)
222 PUSH_INTEGER(nlink, nlink)
223 PUSH_INTEGER(uid, uid)
224 PUSH_INTEGER(gid, gid)
225 PUSH_INTEGER(rdev, rdev)
226 PUSH_INTEGER(access, atime)
227 PUSH_INTEGER(modification, mtime)
228 PUSH_INTEGER(change, ctime)
229 PUSH_INTEGER(size, size)
233 push_st_mode(lua_State *L, struct stat *sb)
238 mode = (sb->st_mode & S_IFMT);
241 else if (S_ISDIR(mode))
242 mode_s = "directory";
243 else if (S_ISLNK(mode))
245 else if (S_ISSOCK(mode))
247 else if (S_ISFIFO(mode))
249 else if (S_ISCHR(mode))
250 mode_s = "char device";
251 else if (S_ISBLK(mode))
252 mode_s = "block device";
256 lua_pushstring(L, mode_s);
260 push_st_permissions(lua_State *L, struct stat *sb)
266 * Could actually format as "-rwxrwxrwx" -- do we care?
268 snprintf(buf, sizeof(buf), "%o", sb->st_mode & ~S_IFMT);
269 lua_pushstring(L, buf);
272 #define PUSH_ENTRY(n) { #n, push_st_ ## n }
273 struct stat_members {
275 void (*push)(lua_State *, struct stat *);
285 PUSH_ENTRY(modification),
288 PUSH_ENTRY(permissions),
293 lua_attributes(lua_State *L)
296 const char *path, *member;
300 path = luaL_checkstring(L, 1);
303 lua_pushfstring(L, "cannot convert first argument to string");
304 lua_pushinteger(L, EINVAL);
308 rc = stat(path, &sb);
312 "cannot obtain information from file '%s': %s", path,
314 lua_pushinteger(L, errno);
318 if (lua_isstring(L, 2)) {
319 member = lua_tostring(L, 2);
320 for (i = 0; i < nitems(members); i++) {
321 if (strcmp(members[i].name, member) != 0)
324 members[i].push(L, &sb);
327 return luaL_error(L, "invalid attribute name '%s'", member);
330 /* Create or reuse existing table */
332 if (!lua_istable(L, 2))
335 /* Export all stat data to caller */
336 for (i = 0; i < nitems(members); i++) {
337 lua_pushstring(L, members[i].name);
338 members[i].push(L, &sb);
345 #define lfs_mkdir_impl(path) (mkdir((path), \
346 S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | \
350 lua_mkdir(lua_State *L)
355 path = luaL_checkstring(L, 1);
358 lua_pushfstring(L, "cannot convert first argument to string");
359 lua_pushinteger(L, EINVAL);
363 error = lfs_mkdir_impl(path);
365 /* Save it; unclear what other libc functions may be invoked */
368 lua_pushfstring(L, strerror(serrno));
369 lua_pushinteger(L, serrno);
373 lua_pushboolean(L, 1);
378 lua_rmdir(lua_State *L)
383 path = luaL_checkstring(L, 1);
386 lua_pushfstring(L, "cannot convert first argument to string");
387 lua_pushinteger(L, EINVAL);
393 /* Save it; unclear what other libc functions may be invoked */
396 lua_pushfstring(L, strerror(serrno));
397 lua_pushinteger(L, serrno);
401 lua_pushboolean(L, 1);
406 #define REG_SIMPLE(n) { #n, lua_ ## n }
407 static const struct luaL_Reg fslib[] = {
408 REG_SIMPLE(attributes),
419 luaopen_lfs(lua_State *L)
421 register_metatable(L);
422 luaL_newlib(L, fslib);