diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | Src/hist.c | 32 | ||||
-rw-r--r-- | configure.ac | 3 |
3 files changed, 37 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog index 5a94fae95..500257248 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-12-18 Wayne Davison <wayned@users.sourceforge.net> + + * users/14659: Src/hist.c: Add symlink-based hist-file locking. + 2009-12-17 Peter Stephenson <pws@csr.com> * Greg: 27529: Completion/Unix/Command/_subversion: make URL @@ -12514,5 +12518,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.4847 $ +* $Revision: 1.4848 $ ***************************************************** diff --git a/Src/hist.c b/Src/hist.c index 86b08bd45..b1e4e82c4 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -2600,11 +2600,38 @@ lockhistfile(char *fn, int keep_trying) int fd; char *lockfile; #ifdef HAVE_LINK +# ifdef HAVE_SYMLINK + char pidbuf[32], *lnk; +# else char *tmpfile; +# endif #endif lockfile = bicat(unmeta(fn), ".LOCK"); + /* NOTE: only use symlink locking on a link()-having host in order to + * avoid a change from open()-based locking to symlink()-based. */ #ifdef HAVE_LINK +# ifdef HAVE_SYMLINK + sprintf(pidbuf, "/pid-%ld/host-", (long)mypid); + lnk = bicat(pidbuf, getsparam("HOST")); + /* We'll abuse fd as our success flag. */ + while ((fd = symlink(lnk, lockfile)) < 0) { + if (errno != EEXIST || !keep_trying) + break; + if (lstat(lockfile, &sb) < 0) { + if (errno == ENOENT) + continue; + break; + } + if (time(NULL) - sb.st_mtime < 10) + sleep(1); + else + unlink(lockfile); + } + if (fd < 0) + lockhistct--; + free(lnk); +# else /* not HAVE_SYMLINK */ if ((fd = gettempfile(fn, 0, &tmpfile)) >= 0) { FILE *out = fdopen(fd, "w"); if (out) { @@ -2618,7 +2645,7 @@ lockhistfile(char *fn, int keep_trying) lockfile, errno); else if (!keep_trying) ; - else if (stat(lockfile, &sb) < 0) { + else if (lstat(lockfile, &sb) < 0) { if (errno == ENOENT) continue; zerr("failed to stat lock file %s: %e", lockfile, errno); @@ -2635,11 +2662,12 @@ lockhistfile(char *fn, int keep_trying) unlink(tmpfile); free(tmpfile); } +# endif /* not HAVE_SYMLINK */ #else /* not HAVE_LINK */ while ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { if (errno != EEXIST || !keep_trying) break; - if (stat(lockfile, &sb) < 0) { + if (lstat(lockfile, &sb) < 0) { if (errno == ENOENT) continue; break; diff --git a/configure.ac b/configure.ac index 569300765..262fe5d14 100644 --- a/configure.ac +++ b/configure.ac @@ -1169,7 +1169,8 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \ htons ntohs \ regcomp regexec regerror regfree \ gdbm_open getxattr \ - realpath canonicalize_file_name) + realpath canonicalize_file_name \ + symlink) AC_FUNC_STRCOLL if test x$enable_cap = xyes; then |