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; |