Merge branch 'master' into 1.7

This commit is contained in:
Hisham
2016-10-19 01:35:24 -04:00
3 changed files with 113 additions and 45 deletions

View File

@@ -177,7 +177,7 @@ LuaFileSystem offers the following functions:
Returns <code>true</code> in case of success or <code>nil</code> plus an Returns <code>true</code> in case of success or <code>nil</code> plus an
error string.</dd> error string.</dd>
<dt><a name="chdir"></a><strong><code>lfs.lock_dir(path, [seconds_stale])</code></strong></dt> <dt><a name="lock_dir"></a><strong><code>lfs.lock_dir(path, [seconds_stale])</code></strong></dt>
<dd>Creates a lockfile (called lockfile.lfs) in <code>path</code> if it does not <dd>Creates a lockfile (called lockfile.lfs) in <code>path</code> if it does not
exist and returns the lock. If the lock already exists checks if exist and returns the lock. If the lock already exists checks if
it's stale, using the second parameter (default for the second 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 particular, if the lock exists and is not stale it returns the
"File exists" message.</dd> "File exists" message.</dd>
<dt><a name="getcwd"></a><strong><code>lfs.currentdir ()</code></strong></dt> <dt><a name="currentdir"></a><strong><code>lfs.currentdir ()</code></strong></dt>
<dd>Returns a string with the current working directory or <code>nil</code> <dd>Returns a string with the current working directory or <code>nil</code>
plus an error string.</dd> plus an error string.</dd>
@@ -242,6 +242,8 @@ LuaFileSystem offers the following functions:
<dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, aname])</code></strong></dt> <dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, aname])</code></strong></dt>
<dd>Identical to <a href="#attributes">lfs.attributes</a> except that <dd>Identical to <a href="#attributes">lfs.attributes</a> except that
it obtains information about the link itself (not the file it refers to). it obtains information about the link itself (not the file it refers to).
It also adds a <strong><code>target</code></strong> field, containing
the file name that the symlink points to.
On Windows this function does not yet support links, and is identical to On Windows this function does not yet support links, and is identical to
<code>lfs.attributes</code>. <code>lfs.attributes</code>.
</dd> </dd>

139
src/lfs.c
View File

@@ -41,22 +41,26 @@
#include <sys/stat.h> #include <sys/stat.h>
#ifdef _WIN32 #ifdef _WIN32
#include <direct.h> #include <direct.h>
#include <windows.h> #include <windows.h>
#include <io.h> #include <io.h>
#include <sys/locking.h> #include <sys/locking.h>
#ifdef __BORLANDC__ #ifdef __BORLANDC__
#include <utime.h> #include <utime.h>
#else
#include <sys/utime.h>
#endif
#include <fcntl.h>
/* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
#define LFS_MAXPATHLEN MAX_PATH
#else #else
#include <sys/utime.h> #include <unistd.h>
#endif #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#else #include <sys/types.h>
#include <unistd.h> #include <utime.h>
#include <dirent.h> #include <sys/param.h> /* for MAXPATHLEN */
#include <fcntl.h> #define LFS_MAXPATHLEN MAXPATHLEN
#include <sys/types.h>
#include <utime.h>
#endif #endif
#include <lua.h> #include <lua.h>
@@ -85,22 +89,6 @@
#define strerror(_) "System unable to describe the error" #define strerror(_) "System unable to describe the error"
#endif #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 <sys/param.h>
#define LFS_MAXPATHLEN MAXPATHLEN
#endif
#endif
#define DIR_METATABLE "directory metatable" #define DIR_METATABLE "directory metatable"
typedef struct dir_data { typedef struct dir_data {
int closed; int closed;
@@ -186,18 +174,35 @@ static int change_dir (lua_State *L) {
** and a string describing the error ** and a string describing the error
*/ */
static int get_dir (lua_State *L) { static int get_dir (lua_State *L) {
char *path; #ifdef NO_GETCWD
/* 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) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, getcwd_error); lua_pushstring(L, "Function 'getcwd' not provided by system");
return 2; return 2;
} #else
else { char *path = NULL;
lua_pushstring(L, path); /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
return 1; 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
} }
/* /*
@@ -815,7 +820,8 @@ static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
/* member not found */ /* member not found */
return luaL_error(L, "invalid attribute name '%s'", member); 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)) { if (!lua_istable (L, 2)) {
lua_newtable (L); lua_newtable (L);
} }
@@ -837,11 +843,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. ** Get symbolic link information using lstat.
*/ */
static int link_info (lua_State *L) { 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;
} }

View File

@@ -91,6 +91,8 @@ io.flush()
if lfs.link (tmpfile, "_a_link_for_test_", true) then if lfs.link (tmpfile, "_a_link_for_test_", true) then
assert (lfs.attributes"_a_link_for_test_".mode == "file") 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_".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.link (tmpfile, "_a_hard_link_for_test_"))
assert (lfs.attributes (tmpfile, "nlink") == 2) assert (lfs.attributes (tmpfile, "nlink") == 2)
assert (os.remove"_a_link_for_test_") assert (os.remove"_a_link_for_test_")
@@ -130,6 +132,17 @@ for key, value in pairs(attr) do
"lfs.attributes values not consistent") "lfs.attributes values not consistent")
end 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 -- Remove new file and directory
assert (os.remove (tmpfile), "could not remove new file") assert (os.remove (tmpfile), "could not remove new file")
assert (lfs.rmdir (tmpdir), "could not remove new directory") assert (lfs.rmdir (tmpdir), "could not remove new directory")