aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/us/manual.html6
-rw-r--r--src/lfs.c139
-rw-r--r--tests/test.lua13
3 files changed, 113 insertions, 45 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 dd0b6af..aeaa8b4 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>
@@ -85,22 +89,6 @@
85#define strerror(_) "System unable to describe the error" 89#define strerror(_) "System unable to describe the error"
86#endif 90#endif
87 91
88/* Define 'getcwd' for systems that do not implement it */
89#ifdef NO_GETCWD
90#define getcwd(p,s) NULL
91#define getcwd_error "Function 'getcwd' not provided by system"
92#else
93#define getcwd_error strerror(errno)
94 #ifdef _WIN32
95 /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
96 #define LFS_MAXPATHLEN MAX_PATH
97 #else
98 /* For MAXPATHLEN: */
99 #include <sys/param.h>
100 #define LFS_MAXPATHLEN MAXPATHLEN
101 #endif
102#endif
103
104#define DIR_METATABLE "directory metatable" 92#define DIR_METATABLE "directory metatable"
105typedef struct dir_data { 93typedef struct dir_data {
106 int closed; 94 int closed;
@@ -186,18 +174,35 @@ static int change_dir (lua_State *L) {
186** and a string describing the error 174** and a string describing the error
187*/ 175*/
188static int get_dir (lua_State *L) { 176static int get_dir (lua_State *L) {
189 char *path; 177#ifdef NO_GETCWD
190 /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
191 char buf[LFS_MAXPATHLEN];
192 if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) {
193 lua_pushnil(L); 178 lua_pushnil(L);
194 lua_pushstring(L, getcwd_error); 179 lua_pushstring(L, "Function 'getcwd' not provided by system");
195 return 2; 180 return 2;
196 } 181#else
197 else { 182 char *path = NULL;
198 lua_pushstring(L, path); 183 /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
199 return 1; 184 size_t size = LFS_MAXPATHLEN; /* initial buffer size */
200 } 185 int result;
186 while (1) {
187 path = realloc(path, size);
188 if (!path) /* failed to allocate */
189 return pusherror(L, "get_dir realloc() failed");
190 if (getcwd(path, size) != NULL) {
191 /* success, push the path to the Lua stack */
192 lua_pushstring(L, path);
193 result = 1;
194 break;
195 }
196 if (errno != ERANGE) { /* unexpected error */
197 result = pusherror(L, "get_dir getcwd() failed");
198 break;
199 }
200 /* ERANGE = insufficient buffer capacity, double size and retry */
201 size *= 2;
202 }
203 free(path);
204 return result;
205#endif
201} 206}
202 207
203/* 208/*
@@ -815,7 +820,8 @@ static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
815 /* member not found */ 820 /* member not found */
816 return luaL_error(L, "invalid attribute name '%s'", member); 821 return luaL_error(L, "invalid attribute name '%s'", member);
817 } 822 }
818 /* creates a table if none is given */ 823 /* creates a table if none is given, removes extra arguments */
824 lua_settop(L, 2);
819 if (!lua_istable (L, 2)) { 825 if (!lua_istable (L, 2)) {
820 lua_newtable (L); 826 lua_newtable (L);
821 } 827 }
@@ -838,10 +844,57 @@ static int file_info (lua_State *L) {
838 844
839 845
840/* 846/*
847** Push the symlink target to the top of the stack.
848** Assumes the file name is at position 1 of the stack.
849** Returns 1 if successful (with the target on top of the stack),
850** 0 on failure (with stack unchanged, and errno set).
851*/
852static int push_link_target(lua_State *L) {
853#ifdef _WIN32
854 errno = ENOSYS;
855 return 0;
856#else
857 const char *file = luaL_checkstring(L, 1);
858 char *target = NULL;
859 int tsize, size = 256; /* size = initial buffer capacity */
860 while (1) {
861 target = realloc(target, size);
862 if (!target) /* failed to allocate */
863 return 0;
864 tsize = readlink(file, target, size);
865 if (tsize < 0) { /* a readlink() error occurred */
866 free(target);
867 return 0;
868 }
869 if (tsize < size)
870 break;
871 /* possibly truncated readlink() result, double size and retry */
872 size *= 2;
873 }
874 target[tsize] = '\0';
875 lua_pushlstring(L, target, tsize);
876 free(target);
877 return 1;
878#endif
879}
880
881/*
841** Get symbolic link information using lstat. 882** Get symbolic link information using lstat.
842*/ 883*/
843static int link_info (lua_State *L) { 884static int link_info (lua_State *L) {
844 return _file_info_ (L, LSTAT_FUNC); 885 int ret;
886 if (lua_isstring (L, 2) && (strcmp(lua_tostring(L, 2), "target") == 0)) {
887 int ok = push_link_target(L);
888 return ok ? 1 : pusherror(L, "could not obtain link target");
889 }
890 ret = _file_info_ (L, LSTAT_FUNC);
891 if (ret == 1 && lua_type(L, -1) == LUA_TTABLE) {
892 int ok = push_link_target(L);
893 if (ok) {
894 lua_setfield(L, -2, "target");
895 }
896 }
897 return ret;
845} 898}
846 899
847 900
diff --git a/tests/test.lua b/tests/test.lua
index 193e0bd..591ee25 100644
--- a/tests/test.lua
+++ b/tests/test.lua
@@ -91,6 +91,8 @@ io.flush()
91if lfs.link (tmpfile, "_a_link_for_test_", true) then 91if lfs.link (tmpfile, "_a_link_for_test_", true) then
92 assert (lfs.attributes"_a_link_for_test_".mode == "file") 92 assert (lfs.attributes"_a_link_for_test_".mode == "file")
93 assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link") 93 assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link")
94 assert (lfs.symlinkattributes"_a_link_for_test_".target == tmpfile)
95 assert (lfs.symlinkattributes("_a_link_for_test_", "target") == tmpfile)
94 assert (lfs.link (tmpfile, "_a_hard_link_for_test_")) 96 assert (lfs.link (tmpfile, "_a_hard_link_for_test_"))
95 assert (lfs.attributes (tmpfile, "nlink") == 2) 97 assert (lfs.attributes (tmpfile, "nlink") == 2)
96 assert (os.remove"_a_link_for_test_") 98 assert (os.remove"_a_link_for_test_")
@@ -130,6 +132,17 @@ for key, value in pairs(attr) do
130 "lfs.attributes values not consistent") 132 "lfs.attributes values not consistent")
131end 133end
132 134
135-- Check that lfs.attributes accepts a table as second argument
136local attr2 = {}
137lfs.attributes(tmpfile, attr2)
138for key, value in pairs(attr2) do
139 assert (value == lfs.attributes (tmpfile, key),
140 "lfs.attributes values with table argument not consistent")
141end
142
143-- Check that extra arguments are ignored
144lfs.attributes(tmpfile, attr2, nil)
145
133-- Remove new file and directory 146-- Remove new file and directory
134assert (os.remove (tmpfile), "could not remove new file") 147assert (os.remove (tmpfile), "could not remove new file")
135assert (lfs.rmdir (tmpdir), "could not remove new directory") 148assert (lfs.rmdir (tmpdir), "could not remove new directory")