diff options
-rw-r--r-- | doc/us/manual.html | 6 | ||||
-rw-r--r-- | src/lfs.c | 139 | ||||
-rw-r--r-- | tests/test.lua | 13 |
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> |
@@ -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" |
105 | typedef struct dir_data { | 93 | typedef 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 | */ |
188 | static int get_dir (lua_State *L) { | 176 | static 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 | */ | ||
852 | static 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 | */ |
843 | static int link_info (lua_State *L) { | 884 | static 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() | |||
91 | if lfs.link (tmpfile, "_a_link_for_test_", true) then | 91 | if 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") |
131 | end | 133 | end |
132 | 134 | ||
135 | -- Check that lfs.attributes accepts a table as second argument | ||
136 | local attr2 = {} | ||
137 | lfs.attributes(tmpfile, attr2) | ||
138 | for key, value in pairs(attr2) do | ||
139 | assert (value == lfs.attributes (tmpfile, key), | ||
140 | "lfs.attributes values with table argument not consistent") | ||
141 | end | ||
142 | |||
143 | -- Check that extra arguments are ignored | ||
144 | lfs.attributes(tmpfile, attr2, nil) | ||
145 | |||
133 | -- Remove new file and directory | 146 | -- Remove new file and directory |
134 | assert (os.remove (tmpfile), "could not remove new file") | 147 | assert (os.remove (tmpfile), "could not remove new file") |
135 | assert (lfs.rmdir (tmpdir), "could not remove new directory") | 148 | assert (lfs.rmdir (tmpdir), "could not remove new directory") |