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 /src | |
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.
Diffstat (limited to 'src')
-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; |