diff options
| author | mascarenhas <mascarenhas> | 2009-03-25 19:14:17 +0000 |
|---|---|---|
| committer | mascarenhas <mascarenhas> | 2009-03-25 19:14:17 +0000 |
| commit | d21c4ae194f84338cbcd85a878fdeefa46fff4f7 (patch) | |
| tree | 4efaccb5521e3deb4cadb68b21cc56f254cde560 | |
| parent | 342df4a5a3c67c4ff2567090d203280b6505f580 (diff) | |
| download | luafilesystem-d21c4ae194f84338cbcd85a878fdeefa46fff4f7.tar.gz luafilesystem-d21c4ae194f84338cbcd85a878fdeefa46fff4f7.tar.bz2 luafilesystem-d21c4ae194f84338cbcd85a878fdeefa46fff4f7.zip | |
locking via lockfiles in posix systems. API:
lock, err = lfs.lock_dir(path, [seconds_stale])
Creates a lockfile (called lockfile.lfs) in <path> if it does not
exist and returns the lock. If the lock already exists checks it
it's stale, using the second parameter (default for the second
parameter is INT_MAX, which in practice means the lock will never
be stale. To free the the lock call lock:free().
In case of any errors it returns nil and the error message. In
particular, if the lock exists and is not stale it returns the
"File exists" message.
| -rw-r--r-- | src/lfs.c | 82 |
1 files changed, 81 insertions, 1 deletions
| @@ -16,7 +16,7 @@ | |||
| 16 | ** lfs.touch (filepath [, atime [, mtime]]) | 16 | ** lfs.touch (filepath [, atime [, mtime]]) |
| 17 | ** lfs.unlock (fh) | 17 | ** lfs.unlock (fh) |
| 18 | ** | 18 | ** |
| 19 | ** $Id: lfs.c,v 1.56 2009/02/03 22:05:48 carregal Exp $ | 19 | ** $Id: lfs.c,v 1.57 2009/03/25 19:14:17 mascarenhas Exp $ |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #ifndef _WIN32 | 22 | #ifndef _WIN32 |
| @@ -84,6 +84,11 @@ typedef struct dir_data { | |||
| 84 | #endif | 84 | #endif |
| 85 | } dir_data; | 85 | } dir_data; |
| 86 | 86 | ||
| 87 | #define LOCK_METATABLE "lock metatable" | ||
| 88 | typedef struct lfs_Lock { | ||
| 89 | int fd; | ||
| 90 | char *ln; | ||
| 91 | } lfs_Lock; | ||
| 87 | 92 | ||
| 88 | #ifdef _WIN32 | 93 | #ifdef _WIN32 |
| 89 | #ifdef __BORLANDC__ | 94 | #ifdef __BORLANDC__ |
| @@ -206,6 +211,64 @@ static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long star | |||
| 206 | } | 211 | } |
| 207 | 212 | ||
| 208 | #ifdef _WIN32 | 213 | #ifdef _WIN32 |
| 214 | static int lfs_lock_dir(lua_State *L) { | ||
| 215 | luaL_error(L, "not implemented for Windows"); | ||
| 216 | } | ||
| 217 | static int lfs_unlock_dir(lua_State *L) { | ||
| 218 | luaL_error(L, "not implemented for Windows"); | ||
| 219 | } | ||
| 220 | #else | ||
| 221 | static int lfs_lock_dir(lua_State *L) { | ||
| 222 | struct stat statbuf; | ||
| 223 | lfs_Lock *lock; | ||
| 224 | size_t pathl; int fd; | ||
| 225 | char *tmpln, *ln; | ||
| 226 | const char *template = "/lockfile.XXXXXX"; | ||
| 227 | const char *lockfile = "/lockfile.lfs"; | ||
| 228 | const char *path = luaL_checklstring(L, 1, &pathl); | ||
| 229 | time_t expires = (time_t)luaL_optint(L, 2, INT_MAX); | ||
| 230 | tmpln = (char*)malloc(pathl + strlen(template) + 1); | ||
| 231 | if(!tmpln) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; } | ||
| 232 | strcpy(tmpln, path); strcat(tmpln, template); | ||
| 233 | fd = mkstemp(tmpln); | ||
| 234 | if(fd == -1) { | ||
| 235 | free(tmpln); lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; | ||
| 236 | } | ||
| 237 | ln = (char*)malloc(pathl + strlen(lockfile) + 1); | ||
| 238 | if(!ln) { | ||
| 239 | unlink(tmpln); free(tmpln); close(fd); lua_pushnil(L); | ||
| 240 | lua_pushstring(L, strerror(errno)); return 2; | ||
| 241 | } | ||
| 242 | strcpy(ln, path); strcat(ln, lockfile); | ||
| 243 | while(symlink(tmpln, ln) == -1) { | ||
| 244 | if(errno == EEXIST) { | ||
| 245 | if(lstat(ln, &statbuf) == -1) goto fail; | ||
| 246 | if(time(NULL) - statbuf.st_mtimespec.tv_sec > expires) { | ||
| 247 | unlink(ln); | ||
| 248 | continue; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | fail: | ||
| 252 | unlink(tmpln); free(tmpln); free(ln); close(fd); | ||
| 253 | lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; | ||
| 254 | } | ||
| 255 | unlink(tmpln); free(tmpln); | ||
| 256 | lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock)); | ||
| 257 | lock->fd = fd; lock->ln = ln; | ||
| 258 | luaL_getmetatable (L, LOCK_METATABLE); | ||
| 259 | lua_setmetatable (L, -2); | ||
| 260 | return 1; | ||
| 261 | } | ||
| 262 | static int lfs_unlock_dir(lua_State *L) { | ||
| 263 | lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE); | ||
| 264 | unlink(lock->ln); | ||
| 265 | close(lock->fd); | ||
| 266 | free(lock->ln); | ||
| 267 | return 0; | ||
| 268 | } | ||
| 269 | #endif | ||
| 270 | |||
| 271 | #ifdef _WIN32 | ||
| 209 | static int lfs_g_setmode (lua_State *L, FILE *f, int arg) { | 272 | static int lfs_g_setmode (lua_State *L, FILE *f, int arg) { |
| 210 | static const int mode[] = {_O_TEXT, _O_BINARY}; | 273 | static const int mode[] = {_O_TEXT, _O_BINARY}; |
| 211 | static const char *const modenames[] = {"text", "binary", NULL}; | 274 | static const char *const modenames[] = {"text", "binary", NULL}; |
| @@ -433,6 +496,21 @@ static int dir_create_meta (lua_State *L) { | |||
| 433 | return 1; | 496 | return 1; |
| 434 | } | 497 | } |
| 435 | 498 | ||
| 499 | /* | ||
| 500 | ** Creates lock metatable. | ||
| 501 | */ | ||
| 502 | static int lock_create_meta (lua_State *L) { | ||
| 503 | luaL_newmetatable (L, LOCK_METATABLE); | ||
| 504 | /* set its __gc field */ | ||
| 505 | lua_newtable(L); | ||
| 506 | lua_pushcfunction(L, lfs_unlock_dir); | ||
| 507 | lua_setfield(L, -2, "free"); | ||
| 508 | lua_setfield(L, -2, "__index"); | ||
| 509 | lua_pushcfunction(L, lfs_unlock_dir); | ||
| 510 | lua_setfield(L, -2, "__gc"); | ||
| 511 | return 1; | ||
| 512 | } | ||
| 513 | |||
| 436 | 514 | ||
| 437 | #ifdef _WIN32 | 515 | #ifdef _WIN32 |
| 438 | #ifndef S_ISDIR | 516 | #ifndef S_ISDIR |
| @@ -688,11 +766,13 @@ static const struct luaL_reg fslib[] = { | |||
| 688 | {"setmode", lfs_f_setmode}, | 766 | {"setmode", lfs_f_setmode}, |
| 689 | {"touch", file_utime}, | 767 | {"touch", file_utime}, |
| 690 | {"unlock", file_unlock}, | 768 | {"unlock", file_unlock}, |
| 769 | {"lock_dir", lfs_lock_dir}, | ||
| 691 | {NULL, NULL}, | 770 | {NULL, NULL}, |
| 692 | }; | 771 | }; |
| 693 | 772 | ||
| 694 | int luaopen_lfs (lua_State *L) { | 773 | int luaopen_lfs (lua_State *L) { |
| 695 | dir_create_meta (L); | 774 | dir_create_meta (L); |
| 775 | lock_create_meta (L); | ||
| 696 | luaL_register (L, "lfs", fslib); | 776 | luaL_register (L, "lfs", fslib); |
| 697 | set_info (L); | 777 | set_info (L); |
| 698 | return 1; | 778 | return 1; |
