diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lfs.c | 351 | ||||
| -rw-r--r-- | src/lfs.h | 10 |
2 files changed, 361 insertions, 0 deletions
diff --git a/src/lfs.c b/src/lfs.c new file mode 100644 index 0000000..d494dd3 --- /dev/null +++ b/src/lfs.c | |||
| @@ -0,0 +1,351 @@ | |||
| 1 | /* | ||
| 2 | ** File system manipulation library. | ||
| 3 | ** This library offers these functions: | ||
| 4 | ** lfs.attributes (filepath [, attributename]) | ||
| 5 | ** lfs.chdir (path) | ||
| 6 | ** lfs.currentdir () | ||
| 7 | ** lfs.dir (path) | ||
| 8 | ** lfs.mkdir (path) | ||
| 9 | ** lfs.lock (fh, mode) | ||
| 10 | ** lfs.unlock (fh) | ||
| 11 | ** | ||
| 12 | ** $Id: lfs.c,v 1.1 2004/07/29 14:26:33 tomas Exp $ | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <errno.h> | ||
| 16 | #include <stdio.h> | ||
| 17 | #include <string.h> | ||
| 18 | #include <time.h> | ||
| 19 | |||
| 20 | #ifdef WIN32 | ||
| 21 | #include <direct.h> | ||
| 22 | #include <io.h> | ||
| 23 | #include <sys/locking.h> | ||
| 24 | #else | ||
| 25 | #include <unistd.h> | ||
| 26 | #include <dirent.h> | ||
| 27 | #include <fcntl.h> | ||
| 28 | #include <sys/types.h> | ||
| 29 | #include <sys/stat.h> | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #include <lua.h> | ||
| 33 | #include <lauxlib.h> | ||
| 34 | #include <lualib.h> | ||
| 35 | |||
| 36 | #include "lfs.h" | ||
| 37 | |||
| 38 | /* Define 'strerror' for systems that do not implement it */ | ||
| 39 | #ifdef NO_STRERROR | ||
| 40 | #define strerror(_) "System unable to describe the error" | ||
| 41 | #endif | ||
| 42 | |||
| 43 | /* Define 'getcwd' for systems that do not implement it */ | ||
| 44 | #ifdef NO_GETCWD | ||
| 45 | #define getcwd(p,s) NULL | ||
| 46 | #define getcwd_error "Function 'getcwd' not provided by system" | ||
| 47 | #else | ||
| 48 | #define getcwd_error strerror(errno) | ||
| 49 | #endif | ||
| 50 | |||
| 51 | #define DIR_METATABLE "directory metatable" | ||
| 52 | #define MAX_DIR_LENGTH 1023 | ||
| 53 | #ifdef _WIN32 | ||
| 54 | typedef struct dir_data { | ||
| 55 | long hFile; | ||
| 56 | char pattern[MAX_DIR_LENGTH+1]; | ||
| 57 | } dir_data; | ||
| 58 | #endif | ||
| 59 | |||
| 60 | |||
| 61 | /* | ||
| 62 | ** This function changes the working (current) directory | ||
| 63 | */ | ||
| 64 | static int change_dir (lua_State *L) { | ||
| 65 | const char *path = luaL_checkstring(L, 1); | ||
| 66 | if (chdir(path)) | ||
| 67 | luaL_error(L,"Unable to change working directory to '%s'\n%s\n", | ||
| 68 | path, chdir_error); | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | /* | ||
| 73 | ** This function returns the current directory | ||
| 74 | ** If unable to get the current directory, it returns nil | ||
| 75 | ** and a string describing the error | ||
| 76 | */ | ||
| 77 | static int get_dir (lua_State *L) { | ||
| 78 | char path[255+2]; | ||
| 79 | if (getcwd(path, 255) == NULL) { | ||
| 80 | lua_pushnil(L); | ||
| 81 | lua_pushstring(L, getcwd_error); | ||
| 82 | return 2; | ||
| 83 | } | ||
| 84 | else { | ||
| 85 | lua_pushstring(L, path); | ||
| 86 | return 1; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | ** Check if the given element on the stack is a file and returns it. | ||
| 92 | */ | ||
| 93 | static FILE *check_file (lua_State *L, int idx, const char *funcname) { | ||
| 94 | FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*"); | ||
| 95 | if (fh == NULL) { | ||
| 96 | luaL_error (L, "%s: not a file", funcname); | ||
| 97 | return 0; | ||
| 98 | } else if (*fh == NULL) { | ||
| 99 | luaL_error (L, "%s: closed file", funcname); | ||
| 100 | return 0; | ||
| 101 | } else | ||
| 102 | return *fh; | ||
| 103 | } | ||
| 104 | |||
| 105 | |||
| 106 | /* | ||
| 107 | ** | ||
| 108 | */ | ||
| 109 | static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) { | ||
| 110 | int code; | ||
| 111 | #ifdef WIN32 | ||
| 112 | /* lkmode valid values are: | ||
| 113 | _LK_LOCK Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error. | ||
| 114 | _LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error. | ||
| 115 | _LK_NBRLCK Same as _LK_NBLCK. | ||
| 116 | _LK_RLCK Same as _LK_LOCK. | ||
| 117 | _LK_UNLCK Unlocks the specified bytes, which must have been previously locked. | ||
| 118 | |||
| 119 | Regions should be locked only briefly and should be unlocked before closing a file or exiting the program. | ||
| 120 | |||
| 121 | http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp | ||
| 122 | */ | ||
| 123 | int lkmode; | ||
| 124 | switch (*mode) { | ||
| 125 | case 'r': lkmode = _LK_NBLCK; break; | ||
| 126 | case 'w': lkmode = _LK_NBLCK; break; | ||
| 127 | case 'u': lkmode = _LK_UNLCK; break; | ||
| 128 | default : luaL_error (L, "%s: invalid mode", funcname); | ||
| 129 | } | ||
| 130 | if (!len) { | ||
| 131 | fseek (fh, 0L, SEEK_END); | ||
| 132 | len = ftell (fh); | ||
| 133 | } | ||
| 134 | fseek (fh, start, SEEK_SET); | ||
| 135 | code = _locking (fileno(fh), lkmode, len); | ||
| 136 | #else | ||
| 137 | struct flock f; | ||
| 138 | switch (*mode) { | ||
| 139 | case 'w': f.l_type = F_WRLCK; break; | ||
| 140 | case 'r': f.l_type = F_RDLCK; break; | ||
| 141 | case 'u': f.l_type = F_UNLCK; break; | ||
| 142 | default : luaL_error (L, "%s: invalid mode", funcname); | ||
| 143 | } | ||
| 144 | f.l_whence = SEEK_SET; | ||
| 145 | f.l_start = (off_t)start; | ||
| 146 | f.l_len = (off_t)len; | ||
| 147 | code = fcntl (fileno(fh), F_SETLK, &f); | ||
| 148 | #endif | ||
| 149 | return (code != -1); | ||
| 150 | } | ||
| 151 | |||
| 152 | |||
| 153 | /* | ||
| 154 | ** Locks a file. | ||
| 155 | ** @param #1 File handle. | ||
| 156 | ** @param #2 String with lock mode ('w'rite, 'r'ead). | ||
| 157 | ** @param #3 Number with start position (optional). | ||
| 158 | ** @param #4 Number with length (optional). | ||
| 159 | */ | ||
| 160 | static int file_lock (lua_State *L) { | ||
| 161 | FILE *fh = check_file (L, 1, "lock"); | ||
| 162 | const char *mode = luaL_checkstring (L, 2); | ||
| 163 | const long start = luaL_optlong (L, 3, 0); | ||
| 164 | long len = luaL_optlong (L, 4, 0); | ||
| 165 | if (_file_lock (L, fh, mode, start, len, "lock")) { | ||
| 166 | lua_pushboolean (L, 1); | ||
| 167 | return 1; | ||
| 168 | } else { | ||
| 169 | lua_pushboolean (L, 0); | ||
| 170 | lua_pushfstring (L, "%s", strerror(errno)); | ||
| 171 | return 2; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | |||
| 176 | /* | ||
| 177 | ** Unlocks a file. | ||
| 178 | ** @param #1 File handle. | ||
| 179 | ** @param #2 Number with start position (optional). | ||
| 180 | ** @param #3 Number with length (optional). | ||
| 181 | */ | ||
| 182 | static int file_unlock (lua_State *L) { | ||
| 183 | FILE *fh = check_file (L, 1, "unlock"); | ||
| 184 | const long start = luaL_optlong (L, 2, 0); | ||
| 185 | long len = luaL_optlong (L, 3, 0); | ||
| 186 | if (_file_lock (L, fh, "u", start, len, "unlock")) { | ||
| 187 | lua_pushboolean (L, 1); | ||
| 188 | return 1; | ||
| 189 | } else { | ||
| 190 | lua_pushboolean (L, 0); | ||
| 191 | lua_pushfstring (L, "%s", strerror(errno)); | ||
| 192 | return 2; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | /* | ||
| 198 | static void cgilua_sleep( lua_State *L ) | ||
| 199 | { | ||
| 200 | unsigned int usec = (unsigned int)luaL_check_number( L, 1 ); | ||
| 201 | |||
| 202 | #ifndef WIN32 | ||
| 203 | sleep( (unsigned int)ceil( usec/1000.0 )); | ||
| 204 | #else | ||
| 205 | Sleep( (DWORD)usec ); | ||
| 206 | #endif | ||
| 207 | } | ||
| 208 | |||
| 209 | static void cgilua_filesize( lua_State *L ) | ||
| 210 | { | ||
| 211 | struct stat info; | ||
| 212 | char *file = luaL_check_string( L, 1 ); | ||
| 213 | |||
| 214 | if (stat(file, &info)) | ||
| 215 | { | ||
| 216 | lua_pushnil( L ); | ||
| 217 | lua_pushstring( L, "Cannot retrieve stat info from file" ); | ||
| 218 | return; | ||
| 219 | } | ||
| 220 | lua_pushnumber(L, info.st_size); | ||
| 221 | } | ||
| 222 | */ | ||
| 223 | |||
| 224 | static int make_dir (lua_State *L) { | ||
| 225 | const char *path = luaL_checkstring (L, 1); | ||
| 226 | int fail; | ||
| 227 | #ifdef WIN32 | ||
| 228 | int oldmask = umask (0); | ||
| 229 | fail = _mkdir (path); | ||
| 230 | #else | ||
| 231 | mode_t oldmask = umask( (mode_t)0 ); | ||
| 232 | fail = mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | | ||
| 233 | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH ); | ||
| 234 | #endif | ||
| 235 | lua_pushboolean (L, fail); | ||
| 236 | umask (oldmask); | ||
| 237 | return 1; | ||
| 238 | } | ||
| 239 | |||
| 240 | |||
| 241 | /* | ||
| 242 | ** Directory iterator | ||
| 243 | */ | ||
| 244 | static int dir_iter (lua_State *L) { | ||
| 245 | #ifdef _WIN32 | ||
| 246 | dir_data *d = (dir_data *)lua_touserdata (L, lua_upvalueindex (1)); | ||
| 247 | struct _finddata_t c_file; | ||
| 248 | if (d->hFile == 0L) { /* first entry */ | ||
| 249 | if ((d->hFile = _findfirst (d->pattern, &c_file)) == -1L) { | ||
| 250 | lua_pushnil (L); | ||
| 251 | lua_pushstring (L, strerror (errno)); | ||
| 252 | return 2; | ||
| 253 | } else { | ||
| 254 | lua_pushstring (L, c_file.name); | ||
| 255 | return 1; | ||
| 256 | } | ||
| 257 | } else { /* next entry */ | ||
| 258 | if (_findnext (d->hFile, &c_file) == -1L) | ||
| 259 | return 0; | ||
| 260 | else { | ||
| 261 | lua_pushstring (L, c_file.name); | ||
| 262 | return 1; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | #else | ||
| 266 | DIR *d = *(DIR **) lua_touserdata (L, lua_upvalueindex (1)); | ||
| 267 | struct dirent *entry; | ||
| 268 | if ((entry = readdir (d)) != NULL) { | ||
| 269 | lua_pushstring (L, entry->d_name); | ||
| 270 | return 1; | ||
| 271 | } | ||
| 272 | else | ||
| 273 | return 0; | ||
| 274 | #endif | ||
| 275 | } | ||
| 276 | |||
| 277 | |||
| 278 | /* | ||
| 279 | ** Closes directory iterators | ||
| 280 | */ | ||
| 281 | static int dir_close (lua_State *L) { | ||
| 282 | #ifdef _WIN32 | ||
| 283 | dir_data *d = (dir_data *)lua_touserdata (L, 1); | ||
| 284 | if (d->hFile) { | ||
| 285 | _findclose (d->hFile); | ||
| 286 | } | ||
| 287 | #else | ||
| 288 | DIR *d = *(DIR **)lua_touserdata (L, 1); | ||
| 289 | if (d) | ||
| 290 | closedir (d); | ||
| 291 | #endif | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | |||
| 296 | /* | ||
| 297 | ** Factory of directory iterators | ||
| 298 | */ | ||
| 299 | static int dir_iter_factory (lua_State *L) { | ||
| 300 | const char *path = luaL_checkstring (L, 1); | ||
| 301 | #ifdef _WIN32 | ||
| 302 | dir_data *dir = (dir_data *) lua_newuserdata (L, sizeof(dir_data)); | ||
| 303 | dir->hFile = 0L; | ||
| 304 | if (strlen(path) > MAX_DIR_LENGTH) | ||
| 305 | luaL_error (L, "path too long: %s", path); | ||
| 306 | else | ||
| 307 | sprintf (dir->pattern, "%s/*", path); | ||
| 308 | luaL_getmetatable (L, DIR_METATABLE); | ||
| 309 | lua_setmetatable (L, -2); | ||
| 310 | #else | ||
| 311 | DIR **d = (DIR **) lua_newuserdata (L, sizeof(DIR *)); | ||
| 312 | luaL_getmetatable (L, DIR_METATABLE); | ||
| 313 | lua_setmetatable (L, -2); | ||
| 314 | *d = opendir (path); | ||
| 315 | if (*d == NULL) | ||
| 316 | luaL_error (L, "cannot open %s: %s", path, strerror (errno)); | ||
| 317 | #endif | ||
| 318 | lua_pushcclosure (L, dir_iter, 1); | ||
| 319 | return 1; | ||
| 320 | } | ||
| 321 | |||
| 322 | |||
| 323 | /* | ||
| 324 | ** Creates directory metatable. | ||
| 325 | */ | ||
| 326 | static int dir_create_meta (lua_State *L) { | ||
| 327 | luaL_newmetatable (L, DIR_METATABLE); | ||
| 328 | /* set its __gc field */ | ||
| 329 | lua_pushstring (L, "__gc"); | ||
| 330 | lua_pushcfunction (L, dir_close); | ||
| 331 | lua_settable (L, -3); | ||
| 332 | |||
| 333 | return 1; | ||
| 334 | } | ||
| 335 | |||
| 336 | |||
| 337 | static const struct luaL_reg fslib[] = { | ||
| 338 | {"chdir", change_dir}, | ||
| 339 | {"currentdir", get_dir}, | ||
| 340 | {"dir", dir_iter_factory}, | ||
| 341 | {"lock", file_lock}, | ||
| 342 | {"mkdir", make_dir}, | ||
| 343 | {"unlock", file_unlock}, | ||
| 344 | {NULL, NULL}, | ||
| 345 | }; | ||
| 346 | |||
| 347 | int luaopen_lfs (lua_State *L) { | ||
| 348 | dir_create_meta (L); | ||
| 349 | luaL_openlib (L, "lfs", fslib, 0); | ||
| 350 | return 1; | ||
| 351 | } | ||
diff --git a/src/lfs.h b/src/lfs.h new file mode 100644 index 0000000..67871f2 --- /dev/null +++ b/src/lfs.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | /* Define 'chdir' for systems that do not implement it */ | ||
| 2 | /* $Id: lfs.h,v 1.1 2004/07/29 14:26:33 tomas Exp $ */ | ||
| 3 | #ifdef NO_CHDIR | ||
| 4 | #define chdir(p) (-1) | ||
| 5 | #define chdir_error "Function 'chdir' not provided by system" | ||
| 6 | #else | ||
| 7 | #define chdir_error strerror(errno) | ||
| 8 | #endif | ||
| 9 | |||
| 10 | int luaopen_lfs (lua_State *L); | ||
