aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHisham <hisham@gobolinux.org>2016-10-19 01:36:11 -0400
committerHisham <hisham@gobolinux.org>2016-10-19 01:36:11 -0400
commitb1f0f80141fe4ddd622e7f525cd0da4d24ce72af (patch)
tree270c8eb43212f0acc97f3dac4568542abc9a1acd
parentaa18f3e127b3d11344d6472fe3647cdf0e8a8f08 (diff)
parent3c4e563d9c140319e28c419f2710b51a2f6d6d24 (diff)
downloadluafilesystem-2.0.tar.gz
luafilesystem-2.0.tar.bz2
luafilesystem-2.0.zip
Merge branch 'master' into 2.02.0
-rw-r--r--doc/us/manual.html6
-rw-r--r--src/lfs.c141
-rw-r--r--src/lfs.h24
-rw-r--r--tests/test.lua16
4 files changed, 130 insertions, 57 deletions
diff --git a/doc/us/manual.html b/doc/us/manual.html
index beffe03..3555e3d 100644
--- a/doc/us/manual.html
+++ b/doc/us/manual.html
@@ -177,7 +177,7 @@ LuaFileSystem offers the following functions:
177 Returns <code>true</code> in case of success or <code>nil</code> plus an 177 Returns <code>true</code> in case of success or <code>nil</code> plus an
178 error string.</dd> 178 error string.</dd>
179 179
180 <dt><a name="chdir"></a><strong><code>lfs.lock_dir(path, [seconds_stale])</code></strong></dt> 180 <dt><a name="lock_dir"></a><strong><code>lfs.lock_dir(path, [seconds_stale])</code></strong></dt>
181 <dd>Creates a lockfile (called lockfile.lfs) in <code>path</code> if it does not 181 <dd>Creates a lockfile (called lockfile.lfs) in <code>path</code> if it does not
182 exist and returns the lock. If the lock already exists checks if 182 exist and returns the lock. If the lock already exists checks if
183 it's stale, using the second parameter (default for the second 183 it's stale, using the second parameter (default for the second
@@ -187,7 +187,7 @@ LuaFileSystem offers the following functions:
187 particular, if the lock exists and is not stale it returns the 187 particular, if the lock exists and is not stale it returns the
188 "File exists" message.</dd> 188 "File exists" message.</dd>
189 189
190 <dt><a name="getcwd"></a><strong><code>lfs.currentdir ()</code></strong></dt> 190 <dt><a name="currentdir"></a><strong><code>lfs.currentdir ()</code></strong></dt>
191 <dd>Returns a string with the current working directory or <code>nil</code> 191 <dd>Returns a string with the current working directory or <code>nil</code>
192 plus an error string.</dd> 192 plus an error string.</dd>
193 193
@@ -242,6 +242,8 @@ LuaFileSystem offers the following functions:
242 <dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, aname])</code></strong></dt> 242 <dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, aname])</code></strong></dt>
243 <dd>Identical to <a href="#attributes">lfs.attributes</a> except that 243 <dd>Identical to <a href="#attributes">lfs.attributes</a> except that
244 it obtains information about the link itself (not the file it refers to). 244 it obtains information about the link itself (not the file it refers to).
245 It also adds a <strong><code>target</code></strong> field, containing
246 the file name that the symlink points to.
245 On Windows this function does not yet support links, and is identical to 247 On Windows this function does not yet support links, and is identical to
246 <code>lfs.attributes</code>. 248 <code>lfs.attributes</code>.
247 </dd> 249 </dd>
diff --git a/src/lfs.c b/src/lfs.c
index 34e30a9..c45cae0 100644
--- a/src/lfs.c
+++ b/src/lfs.c
@@ -41,22 +41,26 @@
41#include <sys/stat.h> 41#include <sys/stat.h>
42 42
43#ifdef _WIN32 43#ifdef _WIN32
44#include <direct.h> 44 #include <direct.h>
45#include <windows.h> 45 #include <windows.h>
46#include <io.h> 46 #include <io.h>
47#include <sys/locking.h> 47 #include <sys/locking.h>
48#ifdef __BORLANDC__ 48 #ifdef __BORLANDC__
49 #include <utime.h> 49 #include <utime.h>
50#else 50 #else
51 #include <sys/utime.h> 51 #include <sys/utime.h>
52#endif 52 #endif
53#include <fcntl.h> 53 #include <fcntl.h>
54 /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
55 #define LFS_MAXPATHLEN MAX_PATH
54#else 56#else
55#include <unistd.h> 57 #include <unistd.h>
56#include <dirent.h> 58 #include <dirent.h>
57#include <fcntl.h> 59 #include <fcntl.h>
58#include <sys/types.h> 60 #include <sys/types.h>
59#include <utime.h> 61 #include <utime.h>
62 #include <sys/param.h> /* for MAXPATHLEN */
63 #define LFS_MAXPATHLEN MAXPATHLEN
60#endif 64#endif
61 65
62#include <lua.h> 66#include <lua.h>
@@ -84,22 +88,6 @@
84#define strerror(_) "System unable to describe the error" 88#define strerror(_) "System unable to describe the error"
85#endif 89#endif
86 90
87/* Define 'getcwd' for systems that do not implement it */
88#ifdef NO_GETCWD
89#define getcwd(p,s) NULL
90#define getcwd_error "Function 'getcwd' not provided by system"
91#else
92#define getcwd_error strerror(errno)
93 #ifdef _WIN32
94 /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
95 #define LFS_MAXPATHLEN MAX_PATH
96 #else
97 /* For MAXPATHLEN: */
98 #include <sys/param.h>
99 #define LFS_MAXPATHLEN MAXPATHLEN
100 #endif
101#endif
102
103#define DIR_METATABLE "directory metatable" 91#define DIR_METATABLE "directory metatable"
104typedef struct dir_data { 92typedef struct dir_data {
105 int closed; 93 int closed;
@@ -185,18 +173,35 @@ static int change_dir (lua_State *L) {
185** and a string describing the error 173** and a string describing the error
186*/ 174*/
187static int get_dir (lua_State *L) { 175static int get_dir (lua_State *L) {
188 char *path; 176#ifdef NO_GETCWD
189 /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
190 char buf[LFS_MAXPATHLEN];
191 if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) {
192 lua_pushnil(L); 177 lua_pushnil(L);
193 lua_pushstring(L, getcwd_error); 178 lua_pushstring(L, "Function 'getcwd' not provided by system");
194 return 2; 179 return 2;
195 } 180#else
196 else { 181 char *path = NULL;
197 lua_pushstring(L, path); 182 /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
198 return 1; 183 size_t size = LFS_MAXPATHLEN; /* initial buffer size */
199 } 184 int result;
185 while (1) {
186 path = realloc(path, size);
187 if (!path) /* failed to allocate */
188 return pusherror(L, "get_dir realloc() failed");
189 if (getcwd(path, size) != NULL) {
190 /* success, push the path to the Lua stack */
191 lua_pushstring(L, path);
192 result = 1;
193 break;
194 }
195 if (errno != ERANGE) { /* unexpected error */
196 result = pusherror(L, "get_dir getcwd() failed");
197 break;
198 }
199 /* ERANGE = insufficient buffer capacity, double size and retry */
200 size *= 2;
201 }
202 free(path);
203 return result;
204#endif
200} 205}
201 206
202/* 207/*
@@ -808,7 +813,8 @@ static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
808 /* member not found */ 813 /* member not found */
809 return luaL_error(L, "invalid attribute name '%s'", member); 814 return luaL_error(L, "invalid attribute name '%s'", member);
810 } 815 }
811 /* creates a table if none is given */ 816 /* creates a table if none is given, removes extra arguments */
817 lua_settop(L, 2);
812 if (!lua_istable (L, 2)) { 818 if (!lua_istable (L, 2)) {
813 lua_newtable (L); 819 lua_newtable (L);
814 } 820 }
@@ -831,10 +837,57 @@ static int file_info (lua_State *L) {
831 837
832 838
833/* 839/*
840** Push the symlink target to the top of the stack.
841** Assumes the file name is at position 1 of the stack.
842** Returns 1 if successful (with the target on top of the stack),
843** 0 on failure (with stack unchanged, and errno set).
844*/
845static int push_link_target(lua_State *L) {
846#ifdef _WIN32
847 errno = ENOSYS;
848 return 0;
849#else
850 const char *file = luaL_checkstring(L, 1);
851 char *target = NULL;
852 int tsize, size = 256; /* size = initial buffer capacity */
853 while (1) {
854 target = realloc(target, size);
855 if (!target) /* failed to allocate */
856 return 0;
857 tsize = readlink(file, target, size);
858 if (tsize < 0) { /* a readlink() error occurred */
859 free(target);
860 return 0;
861 }
862 if (tsize < size)
863 break;
864 /* possibly truncated readlink() result, double size and retry */
865 size *= 2;
866 }
867 target[tsize] = '\0';
868 lua_pushlstring(L, target, tsize);
869 free(target);
870 return 1;
871#endif
872}
873
874/*
834** Get symbolic link information using lstat. 875** Get symbolic link information using lstat.
835*/ 876*/
836static int link_info (lua_State *L) { 877static int link_info (lua_State *L) {
837 return _file_info_ (L, LSTAT_FUNC); 878 int ret;
879 if (lua_isstring (L, 2) && (strcmp(lua_tostring(L, 2), "target") == 0)) {
880 int ok = push_link_target(L);
881 return ok ? 1 : pusherror(L, "could not obtain link target");
882 }
883 ret = _file_info_ (L, LSTAT_FUNC);
884 if (ret == 1 && lua_type(L, -1) == LUA_TTABLE) {
885 int ok = push_link_target(L);
886 if (ok) {
887 lua_setfield(L, -2, "target");
888 }
889 }
890 return ret;
838} 891}
839 892
840 893
@@ -868,7 +921,7 @@ static const struct luaL_Reg fslib[] = {
868 {NULL, NULL}, 921 {NULL, NULL},
869}; 922};
870 923
871int luaopen_lfs (lua_State *L) { 924LFS_EXPORT int luaopen_lfs (lua_State *L) {
872 dir_create_meta (L); 925 dir_create_meta (L);
873 lock_create_meta (L); 926 lock_create_meta (L);
874 luaL_newlib (L, fslib); 927 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 @@
5 5
6/* Define 'chdir' for systems that do not implement it */ 6/* Define 'chdir' for systems that do not implement it */
7#ifdef NO_CHDIR 7#ifdef NO_CHDIR
8#define chdir(p) (-1) 8 #define chdir(p) (-1)
9#define chdir_error "Function 'chdir' not provided by system" 9 #define chdir_error "Function 'chdir' not provided by system"
10#else 10#else
11#define chdir_error strerror(errno) 11 #define chdir_error strerror(errno)
12
13#endif 12#endif
14 13
15#ifdef _WIN32 14#ifdef _WIN32
16#define chdir(p) (_chdir(p)) 15 #define chdir(p) (_chdir(p))
17#define getcwd(d, s) (_getcwd(d, s)) 16 #define getcwd(d, s) (_getcwd(d, s))
18#define rmdir(p) (_rmdir(p)) 17 #define rmdir(p) (_rmdir(p))
19#ifndef fileno 18 #define LFS_EXPORT __declspec (dllexport)
20#define fileno(f) (_fileno(f)) 19 #ifndef fileno
21#endif 20 #define fileno(f) (_fileno(f))
21 #endif
22#else
23 #define LFS_EXPORT
22#endif 24#endif
23 25
24#ifdef __cplusplus 26#ifdef __cplusplus
25extern "C" { 27extern "C" {
26#endif 28#endif
27 29
28int luaopen_lfs (lua_State *L); 30LFS_EXPORT int luaopen_lfs (lua_State *L);
29 31
30#ifdef __cplusplus 32#ifdef __cplusplus
31} 33}
diff --git a/tests/test.lua b/tests/test.lua
index 7876165..fd36ba7 100644
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -93,6 +93,8 @@ if link_ok then
93 assert (link_ok == true, "successful lfs.link did not return true") 93 assert (link_ok == true, "successful lfs.link did not return true")
94 assert (lfs.attributes"_a_link_for_test_".mode == "file") 94 assert (lfs.attributes"_a_link_for_test_".mode == "file")
95 assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link") 95 assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link")
96 assert (lfs.symlinkattributes"_a_link_for_test_".target == tmpfile)
97 assert (lfs.symlinkattributes("_a_link_for_test_", "target") == tmpfile)
96 assert (lfs.link (tmpfile, "_a_hard_link_for_test_")) 98 assert (lfs.link (tmpfile, "_a_hard_link_for_test_"))
97 assert (lfs.attributes (tmpfile, "nlink") == 2) 99 assert (lfs.attributes (tmpfile, "nlink") == 2)
98 assert (os.remove"_a_link_for_test_") 100 assert (os.remove"_a_link_for_test_")
@@ -109,6 +111,9 @@ assert(result) -- on non-Windows platforms, mode is always returned as "binary"
109result, mode = lfs.setmode(f, "text") 111result, mode = lfs.setmode(f, "text")
110assert(result and mode == "binary") 112assert(result and mode == "binary")
111f:close() 113f:close()
114local ok, err = pcall(lfs.setmode, f, "binary")
115assert(not ok, "could setmode on closed file")
116assert(err:find("closed file"), "bad error message for setmode on closed file")
112 117
113io.write(".") 118io.write(".")
114io.flush() 119io.flush()
@@ -129,6 +134,17 @@ for key, value in pairs(attr) do
129 "lfs.attributes values not consistent") 134 "lfs.attributes values not consistent")
130end 135end
131 136
137-- Check that lfs.attributes accepts a table as second argument
138local attr2 = {}
139lfs.attributes(tmpfile, attr2)
140for key, value in pairs(attr2) do
141 assert (value == lfs.attributes (tmpfile, key),
142 "lfs.attributes values with table argument not consistent")
143end
144
145-- Check that extra arguments are ignored
146lfs.attributes(tmpfile, attr2, nil)
147
132-- Remove new file and directory 148-- Remove new file and directory
133assert (os.remove (tmpfile), "could not remove new file") 149assert (os.remove (tmpfile), "could not remove new file")
134assert (lfs.rmdir (tmpdir), "could not remove new directory") 150assert (lfs.rmdir (tmpdir), "could not remove new directory")