From 6e0dc7b27ce6e8a56d646071b69d7e46c85dd245 Mon Sep 17 00:00:00 2001 From: Eric Cosatto Date: Wed, 1 Jun 2016 16:52:07 -0400 Subject: Fix export of luaopen_lfs on Windows (#74) * Make lfs export luaopen_lfs under Windows --- src/lfs.c | 2 +- src/lfs.h | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/lfs.c b/src/lfs.c index 2b85d30..446373c 100644 --- a/src/lfs.c +++ b/src/lfs.c @@ -887,7 +887,7 @@ static const struct luaL_Reg fslib[] = { {NULL, NULL}, }; -int luaopen_lfs (lua_State *L) { +LFS_EXPORT int luaopen_lfs (lua_State *L) { dir_create_meta (L); lock_create_meta (L); luaL_newlib (L, fslib); diff --git a/src/lfs.h b/src/lfs.h index a621d04..7f7d2ab 100644 --- a/src/lfs.h +++ b/src/lfs.h @@ -5,27 +5,29 @@ /* Define 'chdir' for systems that do not implement it */ #ifdef NO_CHDIR -#define chdir(p) (-1) -#define chdir_error "Function 'chdir' not provided by system" + #define chdir(p) (-1) + #define chdir_error "Function 'chdir' not provided by system" #else -#define chdir_error strerror(errno) - + #define chdir_error strerror(errno) #endif #ifdef _WIN32 -#define chdir(p) (_chdir(p)) -#define getcwd(d, s) (_getcwd(d, s)) -#define rmdir(p) (_rmdir(p)) -#ifndef fileno -#define fileno(f) (_fileno(f)) -#endif + #define chdir(p) (_chdir(p)) + #define getcwd(d, s) (_getcwd(d, s)) + #define rmdir(p) (_rmdir(p)) + #define LFS_EXPORT __declspec (dllexport) + #ifndef fileno + #define fileno(f) (_fileno(f)) + #endif +#else + #define LFS_EXPORT #endif #ifdef __cplusplus extern "C" { #endif -int luaopen_lfs (lua_State *L); +LFS_EXPORT int luaopen_lfs (lua_State *L); #ifdef __cplusplus } -- cgit v1.2.3-55-g6feb From 7fae11cdb5a129ce798df462365b7ce60c5f4d62 Mon Sep 17 00:00:00 2001 From: Peter Melnichenko Date: Thu, 9 Jun 2016 13:28:56 +0300 Subject: Add a test for #52. --- tests/test.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test.lua b/tests/test.lua index abfbd4d..2842bc0 100644 --- a/tests/test.lua +++ b/tests/test.lua @@ -107,6 +107,9 @@ assert(result) -- on non-Windows platforms, mode is always returned as "binary" result, mode = lfs.setmode(f, "text") assert(result and mode == "binary") f:close() +local ok, err = pcall(lfs.setmode, f, "binary") +assert(not ok, "could setmode on closed file") +assert(err:find("closed file"), "bad error message for setmode on closed file") io.write(".") io.flush() -- cgit v1.2.3-55-g6feb From 080f74f785b2f30708ae797c15fca95a418b028a Mon Sep 17 00:00:00 2001 From: Peter Melnichenko Date: Thu, 30 Jun 2016 21:17:54 +0300 Subject: Fix anchor names in documentation --- doc/us/manual.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/us/manual.html b/doc/us/manual.html index 86c3406..f5fbaf6 100644 --- a/doc/us/manual.html +++ b/doc/us/manual.html @@ -177,7 +177,7 @@ LuaFileSystem offers the following functions: Returns true in case of success or nil plus an error string. -
lfs.lock_dir(path, [seconds_stale])
+
lfs.lock_dir(path, [seconds_stale])
Creates a lockfile (called lockfile.lfs) in path if it does not exist and returns the lock. If the lock already exists checks if it's stale, using the second parameter (default for the second @@ -187,7 +187,7 @@ LuaFileSystem offers the following functions: particular, if the lock exists and is not stale it returns the "File exists" message.
-
lfs.currentdir ()
+
lfs.currentdir ()
Returns a string with the current working directory or nil plus an error string.
-- cgit v1.2.3-55-g6feb From 32b355a9902e6ce7aae68926fc3f2d05856fc299 Mon Sep 17 00:00:00 2001 From: NiteHawk Date: Sat, 16 Jul 2016 15:35:27 +0200 Subject: Add a 'target' field for symlinkattributes. It returns the resolved path of the symlink. Original version by Hisham , modified to use a different strategy for sizing the readlink() buffer. --- doc/us/manual.html | 2 ++ src/lfs.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- tests/test.lua | 2 ++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/doc/us/manual.html b/doc/us/manual.html index f5fbaf6..0ecb625 100644 --- a/doc/us/manual.html +++ b/doc/us/manual.html @@ -242,6 +242,8 @@ LuaFileSystem offers the following functions:
lfs.symlinkattributes (filepath [, aname])
Identical to lfs.attributes except that it obtains information about the link itself (not the file it refers to). + It also adds a target field, containing + the file name that the symlink points to. On Windows this function does not yet support links, and is identical to lfs.attributes.
diff --git a/src/lfs.c b/src/lfs.c index 446373c..93c1419 100644 --- a/src/lfs.c +++ b/src/lfs.c @@ -849,11 +849,58 @@ static int file_info (lua_State *L) { } +/* +** 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). +*/ +static int push_link_target(lua_State *L) { +#ifdef _WIN32 + errno = ENOSYS; + return 0; +#else + const char *file = luaL_checkstring(L, 1); + char *target = NULL; + int tsize, size = 256; /* size = initial buffer capacity */ + while (1) { + target = realloc(target, size); + if (!target) /* failed to allocate */ + return 0; + tsize = readlink(file, target, size); + if (tsize < 0) { /* a readlink() error occurred */ + 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); + free(target); + return 1; +#endif +} + /* ** Get symbolic link information using lstat. */ static int link_info (lua_State *L) { - return _file_info_ (L, LSTAT_FUNC); + int ret; + if (lua_isstring (L, 2) && (strcmp(lua_tostring(L, 2), "target") == 0)) { + int ok = push_link_target(L); + return ok ? 1 : pusherror(L, "could not obtain link target"); + } + ret = _file_info_ (L, LSTAT_FUNC); + if (ret == 1 && lua_type(L, -1) == LUA_TTABLE) { + int ok = push_link_target(L); + if (ok) { + lua_setfield(L, -2, "target"); + } + } + return ret; } diff --git a/tests/test.lua b/tests/test.lua index 2842bc0..2331eec 100644 --- a/tests/test.lua +++ b/tests/test.lua @@ -91,6 +91,8 @@ io.flush() if lfs.link (tmpfile, "_a_link_for_test_", true) then assert (lfs.attributes"_a_link_for_test_".mode == "file") assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link") + assert (lfs.symlinkattributes"_a_link_for_test_".target == tmpfile) + assert (lfs.symlinkattributes("_a_link_for_test_", "target") == tmpfile) assert (lfs.link (tmpfile, "_a_hard_link_for_test_")) assert (lfs.attributes (tmpfile, "nlink") == 2) assert (os.remove"_a_link_for_test_") -- cgit v1.2.3-55-g6feb From 50919ed69ff64df51d8d586d00834fde3e901785 Mon Sep 17 00:00:00 2001 From: Peter Melnichenko Date: Thu, 25 Aug 2016 18:24:57 +0300 Subject: Fix lfs.attributes and lfs.symlinkattributes extra argument handling When the second argument is not a string, _file_info() wants to ensure that there is a table on top of the stack: the second argument or a new table. If a new table is pushed it's created on top immediately, but if a table is passed as the second argument it can be followed by extra arguments, with the last one ending up being used as a table, causing a crash. The fix is to remove any potential extra arguments using `lua_settop(L, 2)`. Also added a few tests for this case. Ref #80. --- src/lfs.c | 3 ++- tests/test.lua | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/lfs.c b/src/lfs.c index 93c1419..8154a46 100644 --- a/src/lfs.c +++ b/src/lfs.c @@ -827,7 +827,8 @@ static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) { /* member not found */ return luaL_error(L, "invalid attribute name '%s'", member); } - /* creates a table if none is given */ + /* creates a table if none is given, removes extra arguments */ + lua_settop(L, 2); if (!lua_istable (L, 2)) { lua_newtable (L); } diff --git a/tests/test.lua b/tests/test.lua index 2331eec..10810fe 100644 --- a/tests/test.lua +++ b/tests/test.lua @@ -132,6 +132,17 @@ for key, value in pairs(attr) do "lfs.attributes values not consistent") end +-- Check that lfs.attributes accepts a table as second argument +local attr2 = {} +lfs.attributes(tmpfile, attr2) +for key, value in pairs(attr2) do + assert (value == lfs.attributes (tmpfile, key), + "lfs.attributes values with table argument not consistent") +end + +-- Check that extra arguments are ignored +lfs.attributes(tmpfile, attr2, nil) + -- Remove new file and directory assert (os.remove (tmpfile), "could not remove new file") assert (lfs.rmdir (tmpdir), "could not remove new directory") -- cgit v1.2.3-55-g6feb From 3c4e563d9c140319e28c419f2710b51a2f6d6d24 Mon Sep 17 00:00:00 2001 From: NiteHawk Date: Sat, 15 Oct 2016 00:46:54 +0200 Subject: Dynamically size getcwd() buffer in get_dir function (#84) * Dynamically size getcwd() buffer in get_dir function This should fix issue 42. * Fixup: Properly respect NO_GETCWD * Fixup: Get rid of getcwd_error, handle NO_GETCWD in a single place --- src/lfs.c | 87 +++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/src/lfs.c b/src/lfs.c index 8154a46..25122a3 100644 --- a/src/lfs.c +++ b/src/lfs.c @@ -41,22 +41,26 @@ #include #ifdef _WIN32 -#include -#include -#include -#include -#ifdef __BORLANDC__ - #include -#else - #include -#endif -#include + #include + #include + #include + #include + #ifdef __BORLANDC__ + #include + #else + #include + #endif + #include + /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */ + #define LFS_MAXPATHLEN MAX_PATH #else -#include -#include -#include -#include -#include + #include + #include + #include + #include + #include + #include /* for MAXPATHLEN */ + #define LFS_MAXPATHLEN MAXPATHLEN #endif #include @@ -85,22 +89,6 @@ #define strerror(_) "System unable to describe the error" #endif -/* Define 'getcwd' for systems that do not implement it */ -#ifdef NO_GETCWD -#define getcwd(p,s) NULL -#define getcwd_error "Function 'getcwd' not provided by system" -#else -#define getcwd_error strerror(errno) - #ifdef _WIN32 - /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */ - #define LFS_MAXPATHLEN MAX_PATH - #else - /* For MAXPATHLEN: */ - #include - #define LFS_MAXPATHLEN MAXPATHLEN - #endif -#endif - #define DIR_METATABLE "directory metatable" typedef struct dir_data { int closed; @@ -178,18 +166,35 @@ static int change_dir (lua_State *L) { ** and a string describing the error */ static int get_dir (lua_State *L) { - char *path; - /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */ - char buf[LFS_MAXPATHLEN]; - if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) { +#ifdef NO_GETCWD lua_pushnil(L); - lua_pushstring(L, getcwd_error); + lua_pushstring(L, "Function 'getcwd' not provided by system"); return 2; - } - else { - lua_pushstring(L, path); - return 1; - } +#else + char *path = NULL; + /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */ + size_t size = LFS_MAXPATHLEN; /* initial buffer size */ + int result; + while (1) { + path = realloc(path, size); + if (!path) /* failed to allocate */ + return pusherror(L, "get_dir realloc() failed"); + if (getcwd(path, size) != NULL) { + /* success, push the path to the Lua stack */ + lua_pushstring(L, path); + result = 1; + break; + } + if (errno != ERANGE) { /* unexpected error */ + result = pusherror(L, "get_dir getcwd() failed"); + break; + } + /* ERANGE = insufficient buffer capacity, double size and retry */ + size *= 2; + } + free(path); + return result; +#endif } /* -- cgit v1.2.3-55-g6feb