diff options
| author | Hisham <hisham@gobolinux.org> | 2016-10-19 01:36:11 -0400 |
|---|---|---|
| committer | Hisham <hisham@gobolinux.org> | 2016-10-19 01:36:11 -0400 |
| commit | b1f0f80141fe4ddd622e7f525cd0da4d24ce72af (patch) | |
| tree | 270c8eb43212f0acc97f3dac4568542abc9a1acd | |
| parent | aa18f3e127b3d11344d6472fe3647cdf0e8a8f08 (diff) | |
| parent | 3c4e563d9c140319e28c419f2710b51a2f6d6d24 (diff) | |
| download | luafilesystem-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.html | 6 | ||||
| -rw-r--r-- | src/lfs.c | 141 | ||||
| -rw-r--r-- | src/lfs.h | 24 | ||||
| -rw-r--r-- | tests/test.lua | 16 |
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> |
| @@ -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" |
| 104 | typedef struct dir_data { | 92 | typedef 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 | */ |
| 187 | static int get_dir (lua_State *L) { | 175 | static 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 | */ | ||
| 845 | static 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 | */ |
| 836 | static int link_info (lua_State *L) { | 877 | static 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 | ||
| 871 | int luaopen_lfs (lua_State *L) { | 924 | LFS_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); |
| @@ -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 |
| 25 | extern "C" { | 27 | extern "C" { |
| 26 | #endif | 28 | #endif |
| 27 | 29 | ||
| 28 | int luaopen_lfs (lua_State *L); | 30 | LFS_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" | |||
| 109 | result, mode = lfs.setmode(f, "text") | 111 | result, mode = lfs.setmode(f, "text") |
| 110 | assert(result and mode == "binary") | 112 | assert(result and mode == "binary") |
| 111 | f:close() | 113 | f:close() |
| 114 | local ok, err = pcall(lfs.setmode, f, "binary") | ||
| 115 | assert(not ok, "could setmode on closed file") | ||
| 116 | assert(err:find("closed file"), "bad error message for setmode on closed file") | ||
| 112 | 117 | ||
| 113 | io.write(".") | 118 | io.write(".") |
| 114 | io.flush() | 119 | io.flush() |
| @@ -129,6 +134,17 @@ for key, value in pairs(attr) do | |||
| 129 | "lfs.attributes values not consistent") | 134 | "lfs.attributes values not consistent") |
| 130 | end | 135 | end |
| 131 | 136 | ||
| 137 | -- Check that lfs.attributes accepts a table as second argument | ||
| 138 | local attr2 = {} | ||
| 139 | lfs.attributes(tmpfile, attr2) | ||
| 140 | for key, value in pairs(attr2) do | ||
| 141 | assert (value == lfs.attributes (tmpfile, key), | ||
| 142 | "lfs.attributes values with table argument not consistent") | ||
| 143 | end | ||
| 144 | |||
| 145 | -- Check that extra arguments are ignored | ||
| 146 | lfs.attributes(tmpfile, attr2, nil) | ||
| 147 | |||
| 132 | -- Remove new file and directory | 148 | -- Remove new file and directory |
| 133 | assert (os.remove (tmpfile), "could not remove new file") | 149 | assert (os.remove (tmpfile), "could not remove new file") |
| 134 | assert (lfs.rmdir (tmpdir), "could not remove new directory") | 150 | assert (lfs.rmdir (tmpdir), "could not remove new directory") |
