overhaul of lock_dir to remove staleness checks (due to race condition) and simplify the function

This commit is contained in:
mascarenhas
2009-07-04 02:10:16 +00:00
parent 327acf788f
commit c293392539

View File

@@ -17,7 +17,7 @@
** lfs.touch (filepath [, atime [, mtime]]) ** lfs.touch (filepath [, atime [, mtime]])
** lfs.unlock (fh) ** lfs.unlock (fh)
** **
** $Id: lfs.c,v 1.60 2009/06/03 20:49:18 mascarenhas Exp $ ** $Id: lfs.c,v 1.61 2009/07/04 02:10:16 mascarenhas Exp $
*/ */
#ifndef _WIN32 #ifndef _WIN32
@@ -247,55 +247,36 @@ static int lfs_unlock_dir(lua_State *L) {
} }
#else #else
typedef struct lfs_Lock { typedef struct lfs_Lock {
int fd;
char *ln; char *ln;
} lfs_Lock; } lfs_Lock;
static int lfs_lock_dir(lua_State *L) { static int lfs_lock_dir(lua_State *L) {
struct stat statbuf;
lfs_Lock *lock; lfs_Lock *lock;
size_t pathl; int fd; size_t pathl;
char *tmpln, *ln; char *ln;
const char *template = "/lockfile.XXXXXX";
const char *lockfile = "/lockfile.lfs"; const char *lockfile = "/lockfile.lfs";
const char *path = luaL_checklstring(L, 1, &pathl); const char *path = luaL_checklstring(L, 1, &pathl);
time_t expires = (time_t)luaL_optint(L, 2, INT_MAX); lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
tmpln = (char*)malloc(pathl + strlen(template) + 1);
if(!tmpln) { lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2; }
strcpy(tmpln, path); strcat(tmpln, template);
fd = mkstemp(tmpln);
if(fd == -1) {
free(tmpln); lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
}
ln = (char*)malloc(pathl + strlen(lockfile) + 1); ln = (char*)malloc(pathl + strlen(lockfile) + 1);
if(!ln) { if(!ln) {
unlink(tmpln); free(tmpln); close(fd); lua_pushnil(L); lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
lua_pushstring(L, strerror(errno)); return 2;
} }
strcpy(ln, path); strcat(ln, lockfile); strcpy(ln, path); strcat(ln, lockfile);
while(symlink(tmpln, ln) == -1) { if(symlink("lock", ln) == -1) {
if(errno == EEXIST) { free(ln); lua_pushnil(L);
if(lstat(ln, &statbuf) == -1) goto fail; lua_pushstring(L, strerror(errno)); return 2;
if(time(NULL) - statbuf.st_mtimespec.tv_sec > expires) {
unlink(ln);
continue;
}
}
fail:
unlink(tmpln); free(tmpln); free(ln); close(fd);
lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
} }
unlink(tmpln); free(tmpln); lock->ln = ln;
lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
lock->fd = fd; lock->ln = ln;
luaL_getmetatable (L, LOCK_METATABLE); luaL_getmetatable (L, LOCK_METATABLE);
lua_setmetatable (L, -2); lua_setmetatable (L, -2);
return 1; return 1;
} }
static int lfs_unlock_dir(lua_State *L) { static int lfs_unlock_dir(lua_State *L) {
lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE); lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE);
unlink(lock->ln); if(lock->ln) {
close(lock->fd); unlink(lock->ln);
free(lock->ln); free(lock->ln);
lock->ln = NULL;
}
return 0; return 0;
} }
#endif #endif