diff options
Diffstat (limited to '')
-rw-r--r-- | src/lfs.c | 141 |
1 files changed, 97 insertions, 44 deletions
@@ -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); |