diff mbox series

lua: add stat() function

Message ID 20220811162535.617583-1-sbabic@denx.de
State Accepted
Headers show
Series lua: add stat() function | expand

Commit Message

Stefano Babic Aug. 11, 2022, 4:25 p.m. UTC
It is sometimes useful to get more information inside a Lua script about
a file. Lua does  not provide direct access, so this is a wrapper for
the stat() function and creates a table that can be parsed by the
caller. Reference for the implementation was luafilesystem (MIT), but
return values were changed to made it more easy to use inside SWUpdate.

Signed-off-by: Stefano Babic <sbabic@denx.de>
---
 corelib/lua_interface.c | 170 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 170 insertions(+)
diff mbox series

Patch

diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
index ef1622e..4d59e7b 100644
--- a/corelib/lua_interface.c
+++ b/corelib/lua_interface.c
@@ -11,6 +11,9 @@ 
 #include <unistd.h>
 #include <stdbool.h>
 #include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
 
 #include "lua.h"
 #include "lauxlib.h"
@@ -53,6 +56,12 @@  extern const char EMBEDDED_LUA_SRC_END[];
 	lua_settable(L, -3);			\
 } while (0)
 
+typedef void (*stat_push_function) (lua_State *L, struct stat *info);
+struct stat_fields {
+	const char *name;
+	stat_push_function push;
+};
+
 #ifdef CONFIG_HANDLER_IN_LUA
 static int l_register_handler( lua_State *L );
 static int l_call_handler(lua_State *L);
@@ -993,6 +1002,166 @@  int lua_get_swupdate_version(lua_State *L)
 	return 1;
 }
 
+/*
+ * permssions string - convert st_mode
+ * into a rwx string.
+ *
+ */
+static void push_st_perm (lua_State *L, struct stat *info) {
+	char perms[10];
+	mode_t mode = info->st_mode;
+
+	memset(perms, '-', sizeof(perms) - 1);
+	perms[9] = '\0';
+	if (mode & S_IRUSR) perms[0] = 'r';
+	if (mode & S_IWUSR) perms[1] = 'w';
+	if (mode & S_IXUSR) perms[2] = 'x';
+	if (mode & S_IRGRP) perms[3] = 'r';
+	if (mode & S_IWGRP) perms[4] = 'w';
+	if (mode & S_IXGRP) perms[5] = 'x';
+	if (mode & S_IROTH) perms[6] = 'r';
+	if (mode & S_IWOTH) perms[7] = 'w';
+	if (mode & S_IXOTH) perms[8] = 'x';
+
+	lua_pushstring (L, perms);
+}
+
+static const char *mode2string (mode_t mode)
+{
+	switch (mode & S_IFMT) {
+		case S_IFDIR:
+			return "directory";
+		case S_IFIFO:
+			return "named pipe";
+		case S_IFLNK:
+			return "link";
+		case S_IFREG:
+			return "regular file";
+		case S_IFSOCK:
+			return "socket";
+		case S_IFBLK:
+			return "block device";
+		case S_IFCHR:
+			return "char device";
+		default:
+			return "unknown";
+	}
+}
+
+/*
+ * Push a new table with major and minor fields
+ */
+static void push_device(lua_State *L, dev_t dev) {
+	lua_newtable (L);
+        lua_pushstring (L, "major");
+        lua_pushinteger (L, (lua_Integer) major(dev));
+        lua_settable(L, -3);
+        lua_pushstring (L, "minor");
+        lua_pushinteger (L, (lua_Integer) minor(dev));
+        lua_settable(L, -3);
+}
+
+/* Inode type */
+static void push_st_mode(lua_State *L, struct stat *info) {
+        lua_pushstring (L, mode2string (info->st_mode));
+}
+
+/* device inode resides on */
+static void push_st_dev(lua_State *L, struct stat *info) {
+	push_device(L, info->st_dev);
+}
+
+/* inode's number */
+static void push_st_ino (lua_State *L, struct stat *info) {
+        lua_pushinteger(L, (lua_Integer) info->st_ino);
+}
+
+/* number of hard links to the file */
+static void push_st_nlink(lua_State *L, struct stat *info) {
+        lua_pushinteger(L, (lua_Integer)info->st_nlink);
+}
+
+/* user-id of owner */
+static void push_st_uid(lua_State *L, struct stat *info) {
+        lua_pushinteger(L, (lua_Integer)info->st_uid);
+}
+
+/* group-id of owner */
+static void push_st_gid(lua_State *L, struct stat *info) {
+        lua_pushinteger(L, (lua_Integer)info->st_gid);
+}
+
+/* device type, for special file inode */
+static void push_st_rdev(lua_State *L, struct stat *info) {
+	push_device(L, info->st_rdev);
+}
+/* time of last access */
+static void push_st_atime(lua_State *L, struct stat *info) {
+        lua_pushstring(L, ctime(&info->st_atime));
+}
+/* time of last data modification */
+static void push_st_mtime(lua_State *L, struct stat *info) {
+        lua_pushstring(L, ctime(&info->st_mtime));
+}
+/* time of last file status change */
+static void push_st_ctime(lua_State *L, struct stat *info) {
+        lua_pushstring(L, ctime(&info->st_ctime));
+}
+/* file size, in bytes */
+static void push_st_size(lua_State *L, struct stat *info) {
+        lua_pushinteger(L, (lua_Integer)info->st_size);
+}
+/* blocks allocated for file */
+static void push_st_blocks(lua_State *L, struct stat *info) {
+        lua_pushinteger(L, (lua_Integer)info->st_blocks);
+}
+/* optimal file system I/O blocksize */
+static void push_st_blksize(lua_State *L, struct stat *info) {
+        lua_pushinteger(L, (lua_Integer)info->st_blksize);
+}
+
+struct stat_fields statfields[] = {
+        { "mode",         push_st_mode },
+        { "dev",          push_st_dev },
+        { "ino",          push_st_ino },
+        { "nlink",        push_st_nlink },
+        { "uid",          push_st_uid },
+        { "gid",          push_st_gid },
+        { "rdev",         push_st_rdev },
+        { "access",       push_st_atime },
+        { "modification", push_st_mtime },
+        { "change",       push_st_ctime },
+        { "size",         push_st_size },
+        { "permissions",  push_st_perm },
+        { "blocks",       push_st_blocks },
+        { "blksize",      push_st_blksize },
+        { NULL, NULL }
+};
+
+static int l_stat(lua_State *L)
+{
+	struct stat st;
+        const char *file = luaL_checkstring (L, 1);
+
+	/* Clean up stack */
+	lua_pop(L, 1);
+        if (stat(file, &st)) {
+                lua_pushnil(L);
+		return 1;
+	}
+	/*
+	 * Return a table with all value
+	 */
+	lua_newtable (L);
+        /* stores all members in table on top of the stack */
+        for (int i = 0; statfields[i].name; i++) {
+                lua_pushstring (L, statfields[i].name);
+                statfields[i].push(L, &st);
+                lua_settable(L, -3);
+        }
+        return 1;
+}
+
 /**
  * @brief Dispatch a message to the progress interface.
  *
@@ -1021,6 +1190,7 @@  static const luaL_Reg l_swupdate[] = {
         { "warn", lua_notify_warn },
         { "debug", lua_notify_debug },
         { "mount", l_mount },
+        { "stat", l_stat },
         { "umount", l_umount },
         { "getroot", l_getroot },
         { "get_hw", l_get_hw },