* On Windows we cannot delete open (lock) files, so we delete lock

files after we've closed them.  Since this only succeeds if the lock
  is no longer opened by any process, the token trick used on Unix is
  not necessary.
This commit is contained in:
Eelco Dolstra 2006-06-19 14:43:13 +00:00
parent 0e783e5579
commit b35735d8b2

View file

@ -6,6 +6,11 @@
#include "pathlocks.hh" #include "pathlocks.hh"
#ifdef __CYGWIN__
#include <windows.h>
#include <sys/cygwin.h>
#endif
bool lockFile(int fd, LockType lockType, bool wait) bool lockFile(int fd, LockType lockType, bool wait)
{ {
@ -89,9 +94,26 @@ void PathLocks::lockPaths(const PathSet & _paths, const string & waitMsg)
while (1) { while (1) {
/* Open/create the lock file. */ /* Open/create the lock file. */
#ifdef __CYGWIN__
char win32Path[MAX_PATH];
cygwin_conv_to_full_win32_path(lockPath.c_str(), win32Path);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = TRUE;
HANDLE h = CreateFile(win32Path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE)
throw Error(format("opening lock file `%1%'") % lockPath);
fd = cygwin_attach_handle_to_fd((char *) lockPath.c_str(), -1, h, 1, O_RDWR);
#else
fd = open(lockPath.c_str(), O_WRONLY | O_CREAT, 0666); fd = open(lockPath.c_str(), O_WRONLY | O_CREAT, 0666);
if (fd == -1) if (fd == -1)
throw SysError(format("opening lock file `%1%'") % lockPath); throw SysError(format("opening lock file `%1%'") % lockPath);
#endif
/* Acquire an exclusive lock. */ /* Acquire an exclusive lock. */
if (!lockFile(fd, ltWrite, false)) { if (!lockFile(fd, ltWrite, false)) {
@ -126,19 +148,40 @@ void PathLocks::lockPaths(const PathSet & _paths, const string & waitMsg)
PathLocks::~PathLocks() PathLocks::~PathLocks()
{ {
for (list<FDPair>::iterator i = fds.begin(); i != fds.end(); i++) { for (list<FDPair>::iterator i = fds.begin(); i != fds.end(); i++) {
#ifndef __CYGWIN__
if (deletePaths) { if (deletePaths) {
/* Write a (meaningless) token to the file to indicate to /* Get rid of the lock file. Have to be careful not to
other processes waiting on this lock that the lock is introduce races. */
stale (deleted). */ /* On Unix, write a (meaningless) token to the file to
indicate to other processes waiting on this lock that
the lock is stale (deleted). */
unlink(i->second.c_str()); unlink(i->second.c_str());
writeFull(i->first, (const unsigned char *) "d", 1); writeFull(i->first, (const unsigned char *) "d", 1);
/* Note that the result of unlink() is ignored; removing /* Note that the result of unlink() is ignored; removing
the lock file is an optimisation, not a necessity. */ the lock file is an optimisation, not a necessity. */
} }
#endif
lockedPaths.erase(i->second); lockedPaths.erase(i->second);
if (close(i->first) == -1) if (close(i->first) == -1)
printMsg(lvlError, printMsg(lvlError,
format("error (ignored): cannot close lock file on `%1%'") % i->second); format("error (ignored): cannot close lock file on `%1%'") % i->second);
#ifdef __CYGWIN__
if (deletePaths) {
/* On Windows, just try to delete the lock file. This
will fail if anybody still has the file open. We
cannot use unlink() here, because Cygwin emulates Unix
semantics of allowing an open file to be deleted (but
fakes it - the file isn't actually deleted until later,
so a file with the same name cannot be created in the
meantime). */
char win32Path[MAX_PATH];
cygwin_conv_to_full_win32_path(i->second.c_str(), win32Path);
if (DeleteFile(win32Path))
debug(format("delete of `%1%' succeeded") % i->second.c_str());
else
debug(format("delete of `%1%' failed: %2%") % i->second.c_str() % GetLastError());
}
#endif
debug(format("lock released on `%1%'") % i->second); debug(format("lock released on `%1%'") % i->second);
} }
} }