aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormascarenhas <mascarenhas>2009-03-25 19:14:17 +0000
committermascarenhas <mascarenhas>2009-03-25 19:14:17 +0000
commitd21c4ae194f84338cbcd85a878fdeefa46fff4f7 (patch)
tree4efaccb5521e3deb4cadb68b21cc56f254cde560
parent342df4a5a3c67c4ff2567090d203280b6505f580 (diff)
downloadluafilesystem-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.c82
1 files changed, 81 insertions, 1 deletions
diff --git a/src/lfs.c b/src/lfs.c
index a3bce1d..45adf4a 100644
--- a/src/lfs.c
+++ b/src/lfs.c
@@ -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"
88typedef 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
214static int lfs_lock_dir(lua_State *L) {
215 luaL_error(L, "not implemented for Windows");
216}
217static int lfs_unlock_dir(lua_State *L) {
218 luaL_error(L, "not implemented for Windows");
219}
220#else
221static 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}
262static 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
209static int lfs_g_setmode (lua_State *L, FILE *f, int arg) { 272static 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*/
502static 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
694int luaopen_lfs (lua_State *L) { 773int 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;