1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/profile/dirserviceprovider/src/nsProfileLock.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,649 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsProfileStringTypes.h" 1.10 +#include "nsProfileLock.h" 1.11 +#include "nsCOMPtr.h" 1.12 + 1.13 +#if defined(XP_MACOSX) 1.14 +#include <Carbon/Carbon.h> 1.15 +#include <CoreFoundation/CoreFoundation.h> 1.16 +#endif 1.17 + 1.18 +#ifdef XP_UNIX 1.19 +#include <unistd.h> 1.20 +#include <fcntl.h> 1.21 +#include <errno.h> 1.22 +#include <signal.h> 1.23 +#include <stdlib.h> 1.24 +#include "prnetdb.h" 1.25 +#include "prsystem.h" 1.26 +#include "prprf.h" 1.27 +#include "prenv.h" 1.28 +#endif 1.29 + 1.30 +#ifdef VMS 1.31 +#include <rmsdef.h> 1.32 +#endif 1.33 + 1.34 +// ********************************************************************** 1.35 +// class nsProfileLock 1.36 +// 1.37 +// This code was moved from profile/src/nsProfileAccess. 1.38 +// ********************************************************************** 1.39 + 1.40 +#if defined (XP_UNIX) 1.41 +static bool sDisableSignalHandling = false; 1.42 +#endif 1.43 + 1.44 +nsProfileLock::nsProfileLock() : 1.45 + mHaveLock(false), 1.46 + mReplacedLockTime(0) 1.47 +#if defined (XP_WIN) 1.48 + ,mLockFileHandle(INVALID_HANDLE_VALUE) 1.49 +#elif defined (XP_UNIX) 1.50 + ,mPidLockFileName(nullptr) 1.51 + ,mLockFileDesc(-1) 1.52 +#endif 1.53 +{ 1.54 +#if defined (XP_UNIX) 1.55 + next = prev = this; 1.56 + sDisableSignalHandling = PR_GetEnv("MOZ_DISABLE_SIG_HANDLER") ? true : false; 1.57 +#endif 1.58 +} 1.59 + 1.60 + 1.61 +nsProfileLock::nsProfileLock(nsProfileLock& src) 1.62 +{ 1.63 + *this = src; 1.64 +} 1.65 + 1.66 + 1.67 +nsProfileLock& nsProfileLock::operator=(nsProfileLock& rhs) 1.68 +{ 1.69 + Unlock(); 1.70 + 1.71 + mHaveLock = rhs.mHaveLock; 1.72 + rhs.mHaveLock = false; 1.73 + 1.74 +#if defined (XP_WIN) 1.75 + mLockFileHandle = rhs.mLockFileHandle; 1.76 + rhs.mLockFileHandle = INVALID_HANDLE_VALUE; 1.77 +#elif defined (XP_UNIX) 1.78 + mLockFileDesc = rhs.mLockFileDesc; 1.79 + rhs.mLockFileDesc = -1; 1.80 + mPidLockFileName = rhs.mPidLockFileName; 1.81 + rhs.mPidLockFileName = nullptr; 1.82 + if (mPidLockFileName) 1.83 + { 1.84 + // rhs had a symlink lock, therefore it was on the list. 1.85 + PR_REMOVE_LINK(&rhs); 1.86 + PR_APPEND_LINK(this, &mPidLockList); 1.87 + } 1.88 +#endif 1.89 + 1.90 + return *this; 1.91 +} 1.92 + 1.93 + 1.94 +nsProfileLock::~nsProfileLock() 1.95 +{ 1.96 + Unlock(); 1.97 +} 1.98 + 1.99 + 1.100 +#if defined (XP_UNIX) 1.101 + 1.102 +static int setupPidLockCleanup; 1.103 + 1.104 +PRCList nsProfileLock::mPidLockList = 1.105 + PR_INIT_STATIC_CLIST(&nsProfileLock::mPidLockList); 1.106 + 1.107 +void nsProfileLock::RemovePidLockFiles(bool aFatalSignal) 1.108 +{ 1.109 + while (!PR_CLIST_IS_EMPTY(&mPidLockList)) 1.110 + { 1.111 + nsProfileLock *lock = static_cast<nsProfileLock*>(mPidLockList.next); 1.112 + lock->Unlock(aFatalSignal); 1.113 + } 1.114 +} 1.115 + 1.116 +static struct sigaction SIGHUP_oldact; 1.117 +static struct sigaction SIGINT_oldact; 1.118 +static struct sigaction SIGQUIT_oldact; 1.119 +static struct sigaction SIGILL_oldact; 1.120 +static struct sigaction SIGABRT_oldact; 1.121 +static struct sigaction SIGSEGV_oldact; 1.122 +static struct sigaction SIGTERM_oldact; 1.123 + 1.124 +void nsProfileLock::FatalSignalHandler(int signo 1.125 +#ifdef SA_SIGINFO 1.126 + , siginfo_t *info, void *context 1.127 +#endif 1.128 + ) 1.129 +{ 1.130 + // Remove any locks still held. 1.131 + RemovePidLockFiles(true); 1.132 + 1.133 + // Chain to the old handler, which may exit. 1.134 + struct sigaction *oldact = nullptr; 1.135 + 1.136 + switch (signo) { 1.137 + case SIGHUP: 1.138 + oldact = &SIGHUP_oldact; 1.139 + break; 1.140 + case SIGINT: 1.141 + oldact = &SIGINT_oldact; 1.142 + break; 1.143 + case SIGQUIT: 1.144 + oldact = &SIGQUIT_oldact; 1.145 + break; 1.146 + case SIGILL: 1.147 + oldact = &SIGILL_oldact; 1.148 + break; 1.149 + case SIGABRT: 1.150 + oldact = &SIGABRT_oldact; 1.151 + break; 1.152 + case SIGSEGV: 1.153 + oldact = &SIGSEGV_oldact; 1.154 + break; 1.155 + case SIGTERM: 1.156 + oldact = &SIGTERM_oldact; 1.157 + break; 1.158 + default: 1.159 + NS_NOTREACHED("bad signo"); 1.160 + break; 1.161 + } 1.162 + 1.163 + if (oldact) { 1.164 + if (oldact->sa_handler == SIG_DFL) { 1.165 + // Make sure the default sig handler is executed 1.166 + // We need it to get Mozilla to dump core. 1.167 + sigaction(signo,oldact, nullptr); 1.168 + 1.169 + // Now that we've restored the default handler, unmask the 1.170 + // signal and invoke it. 1.171 + 1.172 + sigset_t unblock_sigs; 1.173 + sigemptyset(&unblock_sigs); 1.174 + sigaddset(&unblock_sigs, signo); 1.175 + 1.176 + sigprocmask(SIG_UNBLOCK, &unblock_sigs, nullptr); 1.177 + 1.178 + raise(signo); 1.179 + } 1.180 +#ifdef SA_SIGINFO 1.181 + else if (oldact->sa_sigaction && 1.182 + (oldact->sa_flags & SA_SIGINFO) == SA_SIGINFO) { 1.183 + oldact->sa_sigaction(signo, info, context); 1.184 + } 1.185 +#endif 1.186 + else if (oldact->sa_handler && oldact->sa_handler != SIG_IGN) 1.187 + { 1.188 + oldact->sa_handler(signo); 1.189 + } 1.190 + } 1.191 + 1.192 + // Backstop exit call, just in case. 1.193 + _exit(signo); 1.194 +} 1.195 + 1.196 +nsresult nsProfileLock::LockWithFcntl(nsIFile *aLockFile) 1.197 +{ 1.198 + nsresult rv = NS_OK; 1.199 + 1.200 + nsAutoCString lockFilePath; 1.201 + rv = aLockFile->GetNativePath(lockFilePath); 1.202 + if (NS_FAILED(rv)) { 1.203 + NS_ERROR("Could not get native path"); 1.204 + return rv; 1.205 + } 1.206 + 1.207 + aLockFile->GetLastModifiedTime(&mReplacedLockTime); 1.208 + 1.209 + mLockFileDesc = open(lockFilePath.get(), O_WRONLY | O_CREAT | O_TRUNC, 0666); 1.210 + if (mLockFileDesc != -1) 1.211 + { 1.212 + struct flock lock; 1.213 + lock.l_start = 0; 1.214 + lock.l_len = 0; // len = 0 means entire file 1.215 + lock.l_type = F_WRLCK; 1.216 + lock.l_whence = SEEK_SET; 1.217 + 1.218 + // If fcntl(F_GETLK) fails then the server does not support/allow fcntl(), 1.219 + // return failure rather than access denied in this case so we fallback 1.220 + // to using a symlink lock, bug 303633. 1.221 + struct flock testlock = lock; 1.222 + if (fcntl(mLockFileDesc, F_GETLK, &testlock) == -1) 1.223 + { 1.224 + close(mLockFileDesc); 1.225 + mLockFileDesc = -1; 1.226 + rv = NS_ERROR_FAILURE; 1.227 + } 1.228 + else if (fcntl(mLockFileDesc, F_SETLK, &lock) == -1) 1.229 + { 1.230 + close(mLockFileDesc); 1.231 + mLockFileDesc = -1; 1.232 + 1.233 + // With OS X, on NFS, errno == ENOTSUP 1.234 + // XXX Check for that and return specific rv for it? 1.235 +#ifdef DEBUG 1.236 + printf("fcntl(F_SETLK) failed. errno = %d\n", errno); 1.237 +#endif 1.238 + if (errno == EAGAIN || errno == EACCES) 1.239 + rv = NS_ERROR_FILE_ACCESS_DENIED; 1.240 + else 1.241 + rv = NS_ERROR_FAILURE; 1.242 + } 1.243 + else 1.244 + mHaveLock = true; 1.245 + } 1.246 + else 1.247 + { 1.248 + NS_ERROR("Failed to open lock file."); 1.249 + rv = NS_ERROR_FAILURE; 1.250 + } 1.251 + return rv; 1.252 +} 1.253 + 1.254 +static bool IsSymlinkStaleLock(struct in_addr* aAddr, const char* aFileName, 1.255 + bool aHaveFcntlLock) 1.256 +{ 1.257 + // the link exists; see if it's from this machine, and if 1.258 + // so if the process is still active 1.259 + char buf[1024]; 1.260 + int len = readlink(aFileName, buf, sizeof buf - 1); 1.261 + if (len > 0) 1.262 + { 1.263 + buf[len] = '\0'; 1.264 + char *colon = strchr(buf, ':'); 1.265 + if (colon) 1.266 + { 1.267 + *colon++ = '\0'; 1.268 + unsigned long addr = inet_addr(buf); 1.269 + if (addr != (unsigned long) -1) 1.270 + { 1.271 + if (colon[0] == '+' && aHaveFcntlLock) { 1.272 + // This lock was placed by a Firefox build which would have 1.273 + // taken the fnctl lock, and we've already taken the fcntl lock, 1.274 + // so the process that created this obsolete lock must be gone 1.275 + return true; 1.276 + } 1.277 + 1.278 + char *after = nullptr; 1.279 + pid_t pid = strtol(colon, &after, 0); 1.280 + if (pid != 0 && *after == '\0') 1.281 + { 1.282 + if (addr != aAddr->s_addr) 1.283 + { 1.284 + // Remote lock: give up even if stuck. 1.285 + return false; 1.286 + } 1.287 + 1.288 + // kill(pid,0) is a neat trick to check if a 1.289 + // process exists 1.290 + if (kill(pid, 0) == 0 || errno != ESRCH) 1.291 + { 1.292 + // Local process appears to be alive, ass-u-me it 1.293 + // is another Mozilla instance, or a compatible 1.294 + // derivative, that's currently using the profile. 1.295 + // XXX need an "are you Mozilla?" protocol 1.296 + return false; 1.297 + } 1.298 + } 1.299 + } 1.300 + } 1.301 + } 1.302 + return true; 1.303 +} 1.304 + 1.305 +nsresult nsProfileLock::LockWithSymlink(nsIFile *aLockFile, bool aHaveFcntlLock) 1.306 +{ 1.307 + nsresult rv; 1.308 + nsAutoCString lockFilePath; 1.309 + rv = aLockFile->GetNativePath(lockFilePath); 1.310 + if (NS_FAILED(rv)) { 1.311 + NS_ERROR("Could not get native path"); 1.312 + return rv; 1.313 + } 1.314 + 1.315 + // don't replace an existing lock time if fcntl already got one 1.316 + if (!mReplacedLockTime) 1.317 + aLockFile->GetLastModifiedTimeOfLink(&mReplacedLockTime); 1.318 + 1.319 + struct in_addr inaddr; 1.320 + inaddr.s_addr = htonl(INADDR_LOOPBACK); 1.321 + 1.322 + char hostname[256]; 1.323 + PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname); 1.324 + if (status == PR_SUCCESS) 1.325 + { 1.326 + char netdbbuf[PR_NETDB_BUF_SIZE]; 1.327 + PRHostEnt hostent; 1.328 + status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent); 1.329 + if (status == PR_SUCCESS) 1.330 + memcpy(&inaddr, hostent.h_addr, sizeof inaddr); 1.331 + } 1.332 + 1.333 + char *signature = 1.334 + PR_smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "", 1.335 + (unsigned long)getpid()); 1.336 + const char *fileName = lockFilePath.get(); 1.337 + int symlink_rv, symlink_errno = 0, tries = 0; 1.338 + 1.339 + // use ns4.x-compatible symlinks if the FS supports them 1.340 + while ((symlink_rv = symlink(signature, fileName)) < 0) 1.341 + { 1.342 + symlink_errno = errno; 1.343 + if (symlink_errno != EEXIST) 1.344 + break; 1.345 + 1.346 + if (!IsSymlinkStaleLock(&inaddr, fileName, aHaveFcntlLock)) 1.347 + break; 1.348 + 1.349 + // Lock seems to be bogus: try to claim it. Give up after a large 1.350 + // number of attempts (100 comes from the 4.x codebase). 1.351 + (void) unlink(fileName); 1.352 + if (++tries > 100) 1.353 + break; 1.354 + } 1.355 + 1.356 + PR_smprintf_free(signature); 1.357 + signature = nullptr; 1.358 + 1.359 + if (symlink_rv == 0) 1.360 + { 1.361 + // We exclusively created the symlink: record its name for eventual 1.362 + // unlock-via-unlink. 1.363 + rv = NS_OK; 1.364 + mHaveLock = true; 1.365 + mPidLockFileName = strdup(fileName); 1.366 + if (mPidLockFileName) 1.367 + { 1.368 + PR_APPEND_LINK(this, &mPidLockList); 1.369 + if (!setupPidLockCleanup++) 1.370 + { 1.371 + // Clean up on normal termination. 1.372 + // This instanciates a dummy class, and will trigger the class 1.373 + // destructor when libxul is unloaded. This is equivalent to atexit(), 1.374 + // but gracefully handles dlclose(). 1.375 + static RemovePidLockFilesExiting r; 1.376 + 1.377 + // Clean up on abnormal termination, using POSIX sigaction. 1.378 + // Don't arm a handler if the signal is being ignored, e.g., 1.379 + // because mozilla is run via nohup. 1.380 + if (!sDisableSignalHandling) { 1.381 + struct sigaction act, oldact; 1.382 +#ifdef SA_SIGINFO 1.383 + act.sa_sigaction = FatalSignalHandler; 1.384 + act.sa_flags = SA_SIGINFO; 1.385 +#else 1.386 + act.sa_handler = FatalSignalHandler; 1.387 +#endif 1.388 + sigfillset(&act.sa_mask); 1.389 + 1.390 +#define CATCH_SIGNAL(signame) \ 1.391 +PR_BEGIN_MACRO \ 1.392 + if (sigaction(signame, nullptr, &oldact) == 0 && \ 1.393 + oldact.sa_handler != SIG_IGN) \ 1.394 + { \ 1.395 + sigaction(signame, &act, &signame##_oldact); \ 1.396 + } \ 1.397 + PR_END_MACRO 1.398 + 1.399 + CATCH_SIGNAL(SIGHUP); 1.400 + CATCH_SIGNAL(SIGINT); 1.401 + CATCH_SIGNAL(SIGQUIT); 1.402 + CATCH_SIGNAL(SIGILL); 1.403 + CATCH_SIGNAL(SIGABRT); 1.404 + CATCH_SIGNAL(SIGSEGV); 1.405 + CATCH_SIGNAL(SIGTERM); 1.406 + 1.407 +#undef CATCH_SIGNAL 1.408 + } 1.409 + } 1.410 + } 1.411 + } 1.412 + else if (symlink_errno == EEXIST) 1.413 + rv = NS_ERROR_FILE_ACCESS_DENIED; 1.414 + else 1.415 + { 1.416 +#ifdef DEBUG 1.417 + printf("symlink() failed. errno = %d\n", errno); 1.418 +#endif 1.419 + rv = NS_ERROR_FAILURE; 1.420 + } 1.421 + return rv; 1.422 +} 1.423 +#endif /* XP_UNIX */ 1.424 + 1.425 +nsresult nsProfileLock::GetReplacedLockTime(PRTime *aResult) { 1.426 + *aResult = mReplacedLockTime; 1.427 + return NS_OK; 1.428 +} 1.429 + 1.430 +nsresult nsProfileLock::Lock(nsIFile* aProfileDir, 1.431 + nsIProfileUnlocker* *aUnlocker) 1.432 +{ 1.433 +#if defined (XP_MACOSX) 1.434 + NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock"); 1.435 + NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "parent.lock"); 1.436 +#elif defined (XP_UNIX) 1.437 + NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "lock"); 1.438 + NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock"); 1.439 +#else 1.440 + NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, "parent.lock"); 1.441 +#endif 1.442 + 1.443 + nsresult rv; 1.444 + if (aUnlocker) 1.445 + *aUnlocker = nullptr; 1.446 + 1.447 + NS_ENSURE_STATE(!mHaveLock); 1.448 + 1.449 + bool isDir; 1.450 + rv = aProfileDir->IsDirectory(&isDir); 1.451 + if (NS_FAILED(rv)) 1.452 + return rv; 1.453 + if (!isDir) 1.454 + return NS_ERROR_FILE_NOT_DIRECTORY; 1.455 + 1.456 + nsCOMPtr<nsIFile> lockFile; 1.457 + rv = aProfileDir->Clone(getter_AddRefs(lockFile)); 1.458 + if (NS_FAILED(rv)) 1.459 + return rv; 1.460 + 1.461 + rv = lockFile->Append(LOCKFILE_NAME); 1.462 + if (NS_FAILED(rv)) 1.463 + return rv; 1.464 + 1.465 +#if defined(XP_MACOSX) 1.466 + // First, try locking using fcntl. It is more reliable on 1.467 + // a local machine, but may not be supported by an NFS server. 1.468 + 1.469 + rv = LockWithFcntl(lockFile); 1.470 + if (NS_FAILED(rv) && (rv != NS_ERROR_FILE_ACCESS_DENIED)) 1.471 + { 1.472 + // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED, 1.473 + // assume we tried an NFS that does not support it. Now, try with symlink. 1.474 + rv = LockWithSymlink(lockFile, false); 1.475 + } 1.476 + 1.477 + if (NS_SUCCEEDED(rv)) 1.478 + { 1.479 + // Check for the old-style lock used by pre-mozilla 1.3 builds. 1.480 + // Those builds used an earlier check to prevent the application 1.481 + // from launching if another instance was already running. Because 1.482 + // of that, we don't need to create an old-style lock as well. 1.483 + struct LockProcessInfo 1.484 + { 1.485 + ProcessSerialNumber psn; 1.486 + unsigned long launchDate; 1.487 + }; 1.488 + 1.489 + PRFileDesc *fd = nullptr; 1.490 + int32_t ioBytes; 1.491 + ProcessInfoRec processInfo; 1.492 + LockProcessInfo lockProcessInfo; 1.493 + 1.494 + rv = lockFile->SetLeafName(OLD_LOCKFILE_NAME); 1.495 + if (NS_FAILED(rv)) 1.496 + return rv; 1.497 + rv = lockFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); 1.498 + if (NS_SUCCEEDED(rv)) 1.499 + { 1.500 + ioBytes = PR_Read(fd, &lockProcessInfo, sizeof(LockProcessInfo)); 1.501 + PR_Close(fd); 1.502 + 1.503 + if (ioBytes == sizeof(LockProcessInfo)) 1.504 + { 1.505 +#ifdef __LP64__ 1.506 + processInfo.processAppRef = nullptr; 1.507 +#else 1.508 + processInfo.processAppSpec = nullptr; 1.509 +#endif 1.510 + processInfo.processName = nullptr; 1.511 + processInfo.processInfoLength = sizeof(ProcessInfoRec); 1.512 + if (::GetProcessInformation(&lockProcessInfo.psn, &processInfo) == noErr && 1.513 + processInfo.processLaunchDate == lockProcessInfo.launchDate) 1.514 + { 1.515 + return NS_ERROR_FILE_ACCESS_DENIED; 1.516 + } 1.517 + } 1.518 + else 1.519 + { 1.520 + NS_WARNING("Could not read lock file - ignoring lock"); 1.521 + } 1.522 + } 1.523 + rv = NS_OK; // Don't propagate error from OpenNSPRFileDesc. 1.524 + } 1.525 +#elif defined(XP_UNIX) 1.526 + // Get the old lockfile name 1.527 + nsCOMPtr<nsIFile> oldLockFile; 1.528 + rv = aProfileDir->Clone(getter_AddRefs(oldLockFile)); 1.529 + if (NS_FAILED(rv)) 1.530 + return rv; 1.531 + rv = oldLockFile->Append(OLD_LOCKFILE_NAME); 1.532 + if (NS_FAILED(rv)) 1.533 + return rv; 1.534 + 1.535 + // First, try locking using fcntl. It is more reliable on 1.536 + // a local machine, but may not be supported by an NFS server. 1.537 + rv = LockWithFcntl(lockFile); 1.538 + if (NS_SUCCEEDED(rv)) { 1.539 + // Check to see whether there is a symlink lock held by an older 1.540 + // Firefox build, and also place our own symlink lock --- but 1.541 + // mark it "obsolete" so that other newer builds can break the lock 1.542 + // if they obtain the fcntl lock 1.543 + rv = LockWithSymlink(oldLockFile, true); 1.544 + 1.545 + // If the symlink failed for some reason other than it already 1.546 + // exists, then something went wrong e.g. the file system 1.547 + // doesn't support symlinks, or we don't have permission to 1.548 + // create a symlink there. In such cases we should just 1.549 + // continue because it's unlikely there is an old build 1.550 + // running with a symlink there and we've already successfully 1.551 + // placed a fcntl lock. 1.552 + if (rv != NS_ERROR_FILE_ACCESS_DENIED) 1.553 + rv = NS_OK; 1.554 + } 1.555 + else if (rv != NS_ERROR_FILE_ACCESS_DENIED) 1.556 + { 1.557 + // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED, 1.558 + // assume we tried an NFS that does not support it. Now, try with symlink 1.559 + // using the old symlink path 1.560 + rv = LockWithSymlink(oldLockFile, false); 1.561 + } 1.562 + 1.563 +#elif defined(XP_WIN) 1.564 + nsAutoString filePath; 1.565 + rv = lockFile->GetPath(filePath); 1.566 + if (NS_FAILED(rv)) 1.567 + return rv; 1.568 + 1.569 + lockFile->GetLastModifiedTime(&mReplacedLockTime); 1.570 + 1.571 + // always create the profile lock and never delete it so we can use its 1.572 + // modification timestamp to detect startup crashes 1.573 + mLockFileHandle = CreateFileW(filePath.get(), 1.574 + GENERIC_READ | GENERIC_WRITE, 1.575 + 0, // no sharing - of course 1.576 + nullptr, 1.577 + CREATE_ALWAYS, 1.578 + 0, 1.579 + nullptr); 1.580 + if (mLockFileHandle == INVALID_HANDLE_VALUE) { 1.581 + // XXXbsmedberg: provide a profile-unlocker here! 1.582 + return NS_ERROR_FILE_ACCESS_DENIED; 1.583 + } 1.584 +#elif defined(VMS) 1.585 + nsAutoCString filePath; 1.586 + rv = lockFile->GetNativePath(filePath); 1.587 + if (NS_FAILED(rv)) 1.588 + return rv; 1.589 + 1.590 + lockFile->GetLastModifiedTime(&mReplacedLockTime); 1.591 + 1.592 + mLockFileDesc = open_noshr(filePath.get(), O_CREAT, 0666); 1.593 + if (mLockFileDesc == -1) 1.594 + { 1.595 + if ((errno == EVMSERR) && (vaxc$errno == RMS$_FLK)) 1.596 + { 1.597 + return NS_ERROR_FILE_ACCESS_DENIED; 1.598 + } 1.599 + else 1.600 + { 1.601 + NS_ERROR("Failed to open lock file."); 1.602 + return NS_ERROR_FAILURE; 1.603 + } 1.604 + } 1.605 +#endif 1.606 + 1.607 + mHaveLock = true; 1.608 + 1.609 + return rv; 1.610 +} 1.611 + 1.612 + 1.613 +nsresult nsProfileLock::Unlock(bool aFatalSignal) 1.614 +{ 1.615 + nsresult rv = NS_OK; 1.616 + 1.617 + if (mHaveLock) 1.618 + { 1.619 +#if defined (XP_WIN) 1.620 + if (mLockFileHandle != INVALID_HANDLE_VALUE) 1.621 + { 1.622 + CloseHandle(mLockFileHandle); 1.623 + mLockFileHandle = INVALID_HANDLE_VALUE; 1.624 + } 1.625 +#elif defined (XP_UNIX) 1.626 + if (mPidLockFileName) 1.627 + { 1.628 + PR_REMOVE_LINK(this); 1.629 + (void) unlink(mPidLockFileName); 1.630 + 1.631 + // Only free mPidLockFileName if we're not in the fatal signal 1.632 + // handler. The problem is that a call to free() might be the 1.633 + // cause of this fatal signal. If so, calling free() might cause 1.634 + // us to wait on the malloc implementation's lock. We're already 1.635 + // holding this lock, so we'll deadlock. See bug 522332. 1.636 + if (!aFatalSignal) 1.637 + free(mPidLockFileName); 1.638 + mPidLockFileName = nullptr; 1.639 + } 1.640 + if (mLockFileDesc != -1) 1.641 + { 1.642 + close(mLockFileDesc); 1.643 + mLockFileDesc = -1; 1.644 + // Don't remove it 1.645 + } 1.646 +#endif 1.647 + 1.648 + mHaveLock = false; 1.649 + } 1.650 + 1.651 + return rv; 1.652 +}