diff options
Diffstat (limited to 'source/luametatex/source/luarest/lmtfilelib.c')
-rw-r--r-- | source/luametatex/source/luarest/lmtfilelib.c | 877 |
1 files changed, 877 insertions, 0 deletions
diff --git a/source/luametatex/source/luarest/lmtfilelib.c b/source/luametatex/source/luarest/lmtfilelib.c new file mode 100644 index 000000000..8a814d713 --- /dev/null +++ b/source/luametatex/source/luarest/lmtfilelib.c @@ -0,0 +1,877 @@ +/* + + See license.txt in the root of this project. + + This is a replacement for lfs, a file system manipulation library from the Kepler project. I + started from the lfs.c file from luatex because we need to keep a similar interface. That + file mentioned: + + Copyright Kepler Project 2003 - 2017 (http://keplerproject.github.io/luafilesystem) + + The original library offers the following functions: + + lfs.attributes(filepath [, attributename | attributetable]) + lfs.chdir(path) + lfs.currentdir() + lfs.dir(path) + lfs.link(old, new[, symlink]) + -- lfs.lock(fh, mode) + -- lfs.lock_dir(path) + lfs.mkdir(path) + lfs.rmdir(path) + -- lfs.setmode(filepath, mode) + lfs.symlinkattributes(filepath [, attributename]) + lfs.touch(filepath [, atime [, mtime]]) + -- lfs.unlock(fh) + + We have additional code in other modules and the code was already adapted a little. In the + meantime the code looks quite different. + + Because \TEX| is multi-platform we try to provide a consistent interface. So, for instance + blocksize and inode number are not relevant for us, nor are user and group ids. The lock + functions have been removed as they serve no purpose in a \TEX\ system and devices make no + sense either. The iterator could be improved. I also fixed some anomalities. Permissions are + not useful either. + +*/ + +# include "../lua/lmtinterface.h" +# include "../utilities/auxmemory.h" + +# ifndef R_OK +# define F_OK 0x0 +# define W_OK 0x2 +# define R_OK 0x4 +# endif + +# define DIR_METATABLE "file.directory" + +# ifndef _WIN32 + # ifndef _FILE_OFFSET_BITS + # define _FILE_OFFSET_BITS 64 + # endif +# endif + +# ifdef _WIN32 + # ifndef WINVER + # define WINVER 0x0601 + # undef _WIN32_WINNT + # define _WIN32_WINNT 0x0601 + # endif +# endif + +// # ifndef _LARGEFILE64_SOURCE + # define _LARGEFILE64_SOURCE 1 +// # endif + +# include <errno.h> +# include <stdio.h> +# include <string.h> +# include <stdlib.h> +# include <time.h> +# include <sys/stat.h> + +// # ifdef _MSC_VER +// # ifndef MAX_PATH +// # define MAX_PATH 256 +// # endif +// # endif + +# ifdef _WIN32 + + # include <direct.h> + # include <windows.h> + # include <io.h> + # include <sys/locking.h> + # include <sys/utime.h> + # include <fcntl.h> + + # define MY_MAXPATHLEN MAX_PATH + +# else + + /* the next one is sensitive for c99 */ + + # include <unistd.h> + # include <dirent.h> + # include <fcntl.h> + # include <sys/types.h> + # include <utime.h> + # include <sys/param.h> + + # define MY_MAXPATHLEN MAXPATHLEN + +# endif + +/* This has to go to the h file. See luainit.c where it's also needed. */ + +# ifdef _WIN32 + + # include "../utilities/auxfile.h" + + # ifndef S_ISDIR + # define S_ISDIR(mode) (mode & _S_IFDIR) + # endif + + # ifndef S_ISREG + # define S_ISREG(mode) (mode & _S_IFREG) + # endif + + # ifndef S_ISLNK + # define S_ISLNK(mode) (0) + # endif + + # ifndef S_ISSUB + # define S_ISSUB(mode) (file_data.attrib & _A_SUBDIR) + # endif + + # define info_struct struct _stati64 + # define utime_struct struct __utimbuf64 + + # define exec_mode_flag _S_IEXEC + + /* + There is a difference between msvc and mingw wrt the daylight saving time correction being + applied toy the times. I couldn't figure it out and don't want to waste more time on it. + */ + + typedef struct dir_data { + intptr_t handle; + int closed; + char pattern[MY_MAXPATHLEN+1]; + } dir_data; + + static int get_stat(const char *s, info_struct *i) + { + LPWSTR w = aux_utf8_to_wide(s); + int r = _wstati64(w, i); + lmt_memory_free(w); + return r; + } + + static int mk_dir(const char *s) + { + LPWSTR w = aux_utf8_to_wide(s); + int r = _wmkdir(w); + lmt_memory_free(w); + return r; + } + + static int ch_dir(const char *s) + { + LPWSTR w = aux_utf8_to_wide(s); + int r = _wchdir(w); + lmt_memory_free(w); + return r; + } + + static int rm_dir(const char *s) + { + LPWSTR w = aux_utf8_to_wide(s); + int r = _wrmdir(w); + lmt_memory_free(w); + return r; + } + + static int mk_symlink(const char *t, const char *f) + { + LPWSTR wt = aux_utf8_to_wide(t); + LPWSTR wf = aux_utf8_to_wide(f); + int r = (CreateSymbolicLinkA(t, f, 0x2) != 0); + lmt_memory_free(wt); + lmt_memory_free(wf); + return r; + } + + static int mk_link(const char *t, const char *f) + { + LPWSTR wt = aux_utf8_to_wide(t); + LPWSTR wf = aux_utf8_to_wide(f); + int r = (CreateSymbolicLinkA(t, f, 0x3) != 0); + lmt_memory_free(wt); + lmt_memory_free(wf); + return r; + } + + static int ch_to_exec(const char *s, int n) + { + LPWSTR w = aux_utf8_to_wide(s); + int r = _wchmod(w, n); + lmt_memory_free(w); + return r; + } + + // # ifdef _MSC_VER + // + // static int set_utime(const char *s, utime_struct *b) + // { + // LPWSTR w = utf8_to_wide(s); + // HANDLE h = CreateFileW(w, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + // int r = -1; + // lmt_memory_free(w); + // if (h != INVALID_HANDLE_VALUE) { + // r = SetFileTime(h, (const struct _FILETIME *) b, (const struct _FILETIME *) b, (const struct _FILETIME *) b); + // CloseHandle(h); + // } + // return r; + // } + // + // # else + + static int set_utime(const char *s, utime_struct *b) + { + LPWSTR w = aux_utf8_to_wide(s); + int r = _wutime64(w, b); + lmt_memory_free(w); + return r; + } + + // # endif + +# else + + # define info_struct struct stat + # define utime_struct struct utimbuf + + typedef struct dir_data { + DIR *handle; + int closed; + char pattern[MY_MAXPATHLEN+1]; + } dir_data; + + # define get_stat stat + # define mk_dir(p) (mkdir((p), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH)) + # define ch_dir chdir + # define get_cwd getcwd + # define rm_dir rmdir + # define mk_symlink(f,t) (symlink(f,t) != -1) + # define mk_link(f,t) (link(f,t) != -1) + # define ch_to_exec(f,n) (chmod(f,n)) + # define exec_mode_flag S_IXUSR | S_IXGRP | S_IXOTH + # define set_utime(f,b) utime(f,b) + +# endif + +# include <lua.h> +# include <lauxlib.h> +# include <lualib.h> + +/* + This function changes the current directory. + + success = chdir(name) +*/ + +static int filelib_chdir(lua_State *L) { + if (lua_type(L, 1) == LUA_TSTRING) { + lua_pushboolean(L, ! ch_dir(luaL_checkstring(L, 1))); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +/* + This function returns the current directory or false. + + name = currentdir() +*/ + +# ifdef _WIN32 + + static int filelib_currentdir(lua_State *L) + { + LPWSTR wpath = NULL; + int size = 256; + while (1) { + LPWSTR temp = lmt_memory_realloc(wpath, size * sizeof(WCHAR)); + wpath = temp; + if (! wpath) { + lua_pushboolean(L, 0); + break; + } else if (_wgetcwd(wpath, size)) { + char * path = aux_utf8_from_wide(wpath); + lua_pushstring(L, path); + lmt_memory_free(path); + break; + } else if (errno != ERANGE) { + lua_pushboolean(L, 0); + break; + } else { + size *= 2; + } + } + lmt_memory_free(wpath); + return 1; + } + +# else + + static int filelib_currentdir(lua_State *L) + { + char *path = NULL; + size_t size = MY_MAXPATHLEN; + while (1) { + path = lmt_memory_realloc(path, size); + if (! path) { + lua_pushboolean(L,0); + break; + } + if (get_cwd(path, size)) { + lua_pushstring(L, path); + break; + } + if (errno != ERANGE) { + lua_pushboolean(L,0); + break; + } + size *= 2; + } + lmt_memory_free(path); + return 1; + } + +# endif + +/* + This functions create a link: + + success = link(target,name,[true=symbolic]) + success = symlink(target,name) +*/ + +static int filelib_link(lua_State *L) +{ + if (lua_type(L, 1) == LUA_TSTRING && lua_type(L, 2) == LUA_TSTRING) { + const char *oldpath = lua_tostring(L, 1); + const char *newpath = lua_tostring(L, 2); + lua_pushboolean(L, lua_toboolean(L, 3) ? mk_symlink(oldpath, newpath) : mk_link(oldpath, newpath)); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +static int filelib_symlink(lua_State *L) +{ + if (lua_type(L, 1) == LUA_TSTRING && lua_type(L, 2) == LUA_TSTRING) { + const char *oldpath = lua_tostring(L, 1); + const char *newpath = lua_tostring(L, 2); + lua_pushboolean(L, mk_symlink(oldpath, newpath)); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +/* + This function creates a directory. + + success = mkdir(name) +*/ + +static int filelib_mkdir(lua_State *L) +{ + if (lua_type(L, 1) == LUA_TSTRING) { + lua_pushboolean(L, mk_dir(lua_tostring(L, 1)) != -1); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +/* + This function removes a directory (non-recursive). + + success = mkdir(name) +*/ + +static int filelib_rmdir(lua_State *L) +{ + if (lua_type(L, 1) == LUA_TSTRING) { + lua_pushboolean(L, rm_dir(luaL_checkstring(L, 1)) != -1); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +/* + The directory iterator returns multiple values: + + for name, mode, size, mtime in dir(path) do ... end + + For practical reasons we keep the metatable the same. + +*/ + +# ifdef _WIN32 + + inline static int push_entry(lua_State *L, struct _wfinddata_t file_data, int details) + { + char *s = aux_utf8_from_wide(file_data.name); + lua_pushstring(L, s); + lmt_memory_free(s); + if (S_ISSUB(file_data.attrib)) { + lua_push_key(directory); + } else { + lua_push_key(file); + } + if (details) { + lua_pushinteger(L, file_data.size); + lua_pushinteger(L, file_data.time_write); + return 4; + } else { + return 2; + } + } + + static int filelib_aux_dir_iterator(lua_State *L) + { + struct _wfinddata_t file_data; + int details = 1; + dir_data *d = (dir_data *) luaL_checkudata(L, 1, DIR_METATABLE); + lua_getiuservalue(L, 1, 1); + details = lua_toboolean(L, -1); + lua_pop(L, 1); + luaL_argcheck(L, d->closed == 0, 1, "closed directory"); + if (d->handle == 0L) { + /* first entry */ + LPWSTR s = aux_utf8_to_wide(d->pattern); + if ((d->handle = _wfindfirst(s, &file_data)) == -1L) { + d->closed = 1; + lmt_memory_free(s); + return 0; + } else { + lmt_memory_free(s); + return push_entry(L, file_data, details); + } + } else if (_wfindnext(d->handle, &file_data) == -1L) { + /* no more entries */ + /* lmt_memory_free(d->handle); */ /* is done for us */ + _findclose(d->handle); + d->closed = 1; + return 0; + } else { + /* successive entries */ + return push_entry(L, file_data, details); + } + } + + static int filelib_aux_dir_close(lua_State *L) + { + dir_data *d = (dir_data *) lua_touserdata(L, 1); + if (!d->closed && d->handle) { + _findclose(d->handle); + } + d->closed = 1; + return 0; + } + + static int filelib_dir(lua_State *L) + { + const char *path = luaL_checkstring(L, 1); + int detail = lua_type(L, 2) == LUA_TBOOLEAN ? lua_toboolean(L, 2) : 1; + dir_data *d ; + lua_pushcfunction(L, filelib_aux_dir_iterator); + d = (dir_data *) lua_newuserdatauv(L, sizeof(dir_data), 1); + lua_pushboolean(L, detail); + lua_setiuservalue(L, -2, 1); + luaL_getmetatable(L, DIR_METATABLE); + lua_setmetatable(L, -2); + d->closed = 0; + d->handle = 0L; + if (path && strlen(path) > MY_MAXPATHLEN-2) { + luaL_error(L, "path too long: %s", path); + } else { + sprintf(d->pattern, "%s/*", path ? path : "."); /* brrr */ + } + return 2; + } + +# else + + /*tex + + On unix we cannot get the size and time in one go without interference. Also, not all file + systems return this field. So eventually we might not do this on unix and revert to the + slower method at the lua end when DT_DIR is undefined. After a report from the mailing + list about symbolic link issues this is what Taco and I came up with. The |_less| variant + is mainly there because in \UNIX\ we then can avoid a costly |stat| when we don't need the + details (only a symlink demands such a |stat|). + + */ + + static int filelib_aux_dir_iterator(lua_State *L) + { + struct dirent *entry; + dir_data *d; + int details = 1; + lua_pushcfunction(L, filelib_aux_dir_iterator); + d = (dir_data *) luaL_checkudata(L, 1, DIR_METATABLE); + lua_getiuservalue(L, 1, 1); + details = lua_toboolean(L, -1); + lua_pop(L, 1); + luaL_argcheck(L, d->closed == 0, 1, "closed directory"); + entry = readdir (d->handle); + if (entry) { + lua_pushstring(L, entry->d_name); +# ifdef _DIRENT_HAVE_D_TYPE + if (! details) { + if (entry->d_type == DT_DIR) { + lua_push_key(directory); + return 2; + } else if (entry->d_type == DT_REG) { + lua_push_key(file); + return 2; + } + } +# endif + /*tex We can have a symlink and/or we need the details an dfor both we need to |get_stat|. */ + { + info_struct info; + char file_path[2*MY_MAXPATHLEN]; + snprintf(file_path, 2*MY_MAXPATHLEN, "%s/%s", d->pattern, entry->d_name); + if (! get_stat(file_path, &info)) { + if (S_ISDIR(info.st_mode)) { + lua_push_key(directory); + } else if (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode)) { + lua_push_key(file); + } else { + lua_pushnil(L); + return 2; + } + if (details) { + lua_pushinteger(L, info.st_size); + lua_pushinteger(L, info.st_mtime); + return 4; + } + } else { + lua_pushnil(L); + } + return 2; + } + } else { + closedir(d->handle); + d->closed = 1; + return 0; + } + } + + static int filelib_aux_dir_close(lua_State *L) + { + dir_data *d = (dir_data *) lua_touserdata(L, 1); + if (!d->closed && d->handle) { + closedir(d->handle); + } + d->closed = 1; + return 0; + } + + static int filelib_dir(lua_State *L) + { + const char *path = luaL_checkstring(L, 1); + dir_data *d; + lua_pushcfunction(L, filelib_aux_dir_iterator); + d = (dir_data *) lua_newuserdatauv(L, sizeof(dir_data), 1); + lua_pushboolean(L, lua_type(L, 2) == LUA_TBOOLEAN ? lua_toboolean(L, 2) : 1); + lua_setiuservalue(L, -2, 1); + luaL_getmetatable(L, DIR_METATABLE); + lua_setmetatable(L, -2); + d->closed = 0; + d->handle = opendir(path ? path : "."); + if (! d->handle) { + luaL_error(L, "cannot open %s: %s", path, strerror(errno)); + } + snprintf(d->pattern, MY_MAXPATHLEN, "%s", path ? path : "."); + return 2; + } + +# endif + +static int dir_create_meta(lua_State *L) +{ + luaL_newmetatable(L, DIR_METATABLE); + lua_newtable(L); + lua_pushcfunction(L, filelib_aux_dir_iterator); + lua_setfield(L, -2, "next"); + lua_pushcfunction(L, filelib_aux_dir_close); + lua_setfield(L, -2, "close"); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, filelib_aux_dir_close); + lua_setfield(L, -2, "__gc"); + return 1; +} + +# define mode2string(mode) \ + ((S_ISREG(mode)) ? "file" : ((S_ISDIR(mode)) ? "directory" : ((S_ISLNK(mode)) ? "link" : "other"))) + +/* We keep this for a while: will change to { r, w, x hash } */ + +# ifdef _WIN32 + + static const char *perm2string(unsigned short mode) + { + static char perms[10] = "---------"; + /* persistent change hence the for loop */ + for (int i = 0; i < 9; i++) { + perms[i]='-'; + } + if (mode & _S_IREAD) { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; } + if (mode & _S_IWRITE) { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; } + if (mode & _S_IEXEC) { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; } + return perms; + } + +# else + + static const char *perm2string(mode_t mode) + { + static char perms[10] = "---------"; + /* persistent change hence the for loop */ + for (int i = 0; i < 9; i++) { + perms[i]='-'; + } + 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'; + return perms; + } + +# endif + +/* + The next one sets access time and modification values for a file: + + utime(filename) : current, current + utime(filename,acess) : access, access + utime(filename,acess,modification) : access, modification +*/ + +static int filelib_touch(lua_State *L) +{ + if (lua_type(L, 1) == LUA_TSTRING) { + const char *file = luaL_checkstring(L, 1); + utime_struct utb, *buf; + if (lua_gettop(L) == 1) { + buf = NULL; + } else { + utb.actime = (time_t) luaL_optinteger(L, 2, 0); + utb.modtime = (time_t) luaL_optinteger(L, 3, utb.actime); + buf = &utb; + } + lua_pushboolean(L, set_utime(file, buf) != -1); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +static void push_st_mode (lua_State *L, info_struct *info) { lua_pushstring (L, mode2string (info->st_mode)); } /* inode protection mode */ +static void push_st_size (lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_size); } /* file size, in bytes */ +static void push_st_mtime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_mtime); } /* time of last data modification */ +static void push_st_atime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_atime); } /* time of last access */ +static void push_st_ctime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_ctime); } /* time of last file status change */ +static void push_st_perm (lua_State *L, info_struct *info) { lua_pushstring (L, perm2string (info->st_mode)); } /* permissions string */ +static void push_st_nlink(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_nlink); } /* number of hard links to the file */ + +typedef void (*push_info_struct_function) (lua_State *L, info_struct *info); + +struct file_stat_members { + const char *name; + push_info_struct_function push; +}; + +static struct file_stat_members members[] = { + { "mode", push_st_mode }, + { "size", push_st_size }, + { "modification", push_st_mtime }, + { "access", push_st_atime }, + { "change", push_st_ctime }, + { "permissions", push_st_perm }, + { "nlink", push_st_nlink }, + { NULL, NULL }, +}; + +/* + Get file or symbolic link information. Returns a table or nil. +*/ + +static int filelib_attributes(lua_State *L) +{ + if (lua_type(L, 1) == LUA_TSTRING) { + info_struct info; + const char *file = luaL_checkstring(L, 1); + if (get_stat(file, &info)) { + /* bad news */ + } else if (lua_isstring(L, 2)) { + const char *member = lua_tostring(L, 2); + for (int i = 0; members[i].name; i++) { + if (strcmp(members[i].name, member) == 0) { + members[i].push(L, &info); + return 1; + } + } + } else { + lua_settop(L, 2); + if (! lua_istable(L, 2)) { + lua_createtable(L, 0, 6); + } + for (int i = 0; members[i].name; i++) { + lua_pushstring(L, members[i].name); + members[i].push(L, &info); + lua_rawset(L, -3); + } + return 1; + } + } + lua_pushnil(L); + return 1; +} + +# define is_whatever(L,IS_OK,okay) do { \ + if (lua_type(L, 1) == LUA_TSTRING) { \ + info_struct info; \ + const char *name = lua_tostring(L, 1); \ + if (get_stat(name, &info)) { \ + lua_pushboolean(L, 0); \ + } else { \ + lua_pushboolean(L, okay && ! access(name, IS_OK)); \ + } \ + } else { \ + lua_pushboolean(L, 0); \ + } \ + return 1; \ +} while(1) + +static int filelib_isdir (lua_State *L) { is_whatever(L, F_OK,(S_ISDIR(info.st_mode))); } +static int filelib_isreadabledir (lua_State *L) { is_whatever(L, R_OK,(S_ISDIR(info.st_mode))); } +static int filelib_iswriteabledir (lua_State *L) { is_whatever(L, W_OK,(S_ISDIR(info.st_mode))); } + +static int filelib_isfile (lua_State *L) { is_whatever(L, F_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); } +static int filelib_isreadablefile (lua_State *L) { is_whatever(L, R_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); } +static int filelib_iswriteablefile(lua_State *L) { is_whatever(L, W_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); } + +static int filelib_setexecutable(lua_State *L) +{ + int ok = 0; + if (lua_type(L, 1) == LUA_TSTRING) { + info_struct info; + const char *name = lua_tostring(L, 1); + if (! get_stat(name, &info) && S_ISREG(info.st_mode)) { + if (ch_to_exec(name, info.st_mode | exec_mode_flag)) { + /* the setting failed */ + } else { + ok = 1; + } + } else { + /* not a valid file */ + } + } + lua_pushboolean(L, ok); + return 1; +} + +/* + Push the symlink target to the top of the stack. Assumes the file name is at position 1 of the + stack. Returns 1 if successful (with the target on top of the stack), 0 on failure (with stack + unchanged, and errno set). + + link("name") : table + link("name","target") : targetname +*/ + +// # ifdef _WIN32 +// +// static int filelib_symlinkattributes(lua_State *L) +// { +// lua_pushnil(L); +// return 1; +// } +// +// # else +// +// static int push_link_target(lua_State *L) +// { +// const char *file = luaL_checkstring(L, 1); +// char *target = NULL; +// int tsize, size = 256; /* size = initial buffer capacity */ +// while (1) { +// target = lmt_memory_realloc(target, size); +// if (! target) { +// return 0; +// } +// tsize = readlink(file, target, size); +// if (tsize < 0) { +// /* error */ +// lmt_memory_free(target); +// return 0; +// } +// if (tsize < size) { +// break; +// } +// /* possibly truncated readlink() result, double size and retry */ +// size *= 2; +// } +// target[tsize] = '\0'; +// lua_pushlstring(L, target, tsize); +// lmt_memory_free(target); +// return 1; +// } +// +// static int filelib_symlinkattributes(lua_State *L) +// { +// if (lua_isstring(L, 2) && (strcmp(lua_tostring(L, 2), "target") == 0)) { +// if (! push_link_target(L)) { +// lua_pushnil(L); +// } +// } else { +// int ret = filelib_attributes(L); +// if (ret == 1 && lua_type(L, -1) == LUA_TTABLE) { +// if (push_link_target(L)) { +// lua_setfield(L, -2, "target"); +// } +// } else { +// lua_pushnil(L); +// } +// } +// return 1; +// } +// +// # endif + +static const struct luaL_Reg filelib_function_list[] = { + { "attributes", filelib_attributes }, + { "chdir", filelib_chdir }, + { "currentdir", filelib_currentdir }, + { "dir", filelib_dir }, + { "mkdir", filelib_mkdir }, + { "rmdir", filelib_rmdir }, + { "touch", filelib_touch }, + /* */ + { "link", filelib_link }, + { "symlink", filelib_symlink }, + { "setexecutable", filelib_setexecutable }, + /* { "symlinkattributes", filelib_symlinkattributes }, */ + /* */ + { "isdir", filelib_isdir }, + { "isfile", filelib_isfile }, + { "iswriteabledir", filelib_iswriteabledir }, + { "iswriteablefile", filelib_iswriteablefile }, + { "isreadabledir", filelib_isreadabledir }, + { "isreadablefile", filelib_isreadablefile }, + /* */ + { NULL, NULL }, +}; + +int luaopen_filelib(lua_State *L) { + dir_create_meta(L); + luaL_newlib(L,filelib_function_list); + return 1; +} |