LCOV - code coverage report
Current view: top level - toolkit/profile - nsProfileLock.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 87 217 40.1 %
Date: 2017-07-14 16:53:18 Functions: 5 13 38.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "nsProfileLock.h"
       7             : #include "nsCOMPtr.h"
       8             : #include "nsQueryObject.h"
       9             : #include "nsString.h"
      10             : 
      11             : #if defined(XP_WIN)
      12             : #include "ProfileUnlockerWin.h"
      13             : #include "nsAutoPtr.h"
      14             : #endif
      15             : 
      16             : #if defined(XP_MACOSX)
      17             : #include <Carbon/Carbon.h>
      18             : #include <CoreFoundation/CoreFoundation.h>
      19             : #endif
      20             : 
      21             : #ifdef XP_UNIX
      22             : #include <unistd.h>
      23             : #include <fcntl.h>
      24             : #include <errno.h>
      25             : #include <signal.h>
      26             : #include <stdlib.h>
      27             : #include "prnetdb.h"
      28             : #include "prsystem.h"
      29             : #include "prenv.h"
      30             : #include "mozilla/Printf.h"
      31             : #endif
      32             : 
      33             : #if defined(MOZ_WIDGET_GONK) && !defined(MOZ_CRASHREPORTER)
      34             : #include <sys/syscall.h>
      35             : #endif
      36             : 
      37             : // **********************************************************************
      38             : // class nsProfileLock
      39             : //
      40             : // This code was moved from profile/src/nsProfileAccess.
      41             : // **********************************************************************
      42             : 
      43             : #if defined (XP_UNIX)
      44             : static bool sDisableSignalHandling = false;
      45             : #endif
      46             : 
      47           2 : nsProfileLock::nsProfileLock() :
      48             :     mHaveLock(false),
      49             :     mReplacedLockTime(0)
      50             : #if defined (XP_WIN)
      51             :     ,mLockFileHandle(INVALID_HANDLE_VALUE)
      52             : #elif defined (XP_UNIX)
      53             :     ,mPidLockFileName(nullptr)
      54           2 :     ,mLockFileDesc(-1)
      55             : #endif
      56             : {
      57             : #if defined (XP_UNIX)
      58           2 :     next = prev = this;
      59           2 :     sDisableSignalHandling = PR_GetEnv("MOZ_DISABLE_SIG_HANDLER") ? true : false;
      60             : #endif
      61           2 : }
      62             : 
      63             : 
      64           0 : nsProfileLock::nsProfileLock(nsProfileLock& src)
      65             : {
      66           0 :     *this = src;
      67           0 : }
      68             : 
      69             : 
      70           0 : nsProfileLock& nsProfileLock::operator=(nsProfileLock& rhs)
      71             : {
      72           0 :     Unlock();
      73             : 
      74           0 :     mHaveLock = rhs.mHaveLock;
      75           0 :     rhs.mHaveLock = false;
      76             : 
      77             : #if defined (XP_WIN)
      78             :     mLockFileHandle = rhs.mLockFileHandle;
      79             :     rhs.mLockFileHandle = INVALID_HANDLE_VALUE;
      80             : #elif defined (XP_UNIX)
      81           0 :     mLockFileDesc = rhs.mLockFileDesc;
      82           0 :     rhs.mLockFileDesc = -1;
      83           0 :     mPidLockFileName = rhs.mPidLockFileName;
      84           0 :     rhs.mPidLockFileName = nullptr;
      85           0 :     if (mPidLockFileName)
      86             :     {
      87             :         // rhs had a symlink lock, therefore it was on the list.
      88           0 :         PR_REMOVE_LINK(&rhs);
      89           0 :         PR_APPEND_LINK(this, &mPidLockList);
      90             :     }
      91             : #endif
      92             : 
      93           0 :     return *this;
      94             : }
      95             : 
      96             : 
      97           0 : nsProfileLock::~nsProfileLock()
      98             : {
      99           0 :     Unlock();
     100           0 : }
     101             : 
     102             : 
     103             : #if defined (XP_UNIX)
     104             : 
     105             : static int setupPidLockCleanup;
     106             : 
     107             : PRCList nsProfileLock::mPidLockList =
     108             :     PR_INIT_STATIC_CLIST(&nsProfileLock::mPidLockList);
     109             : 
     110           0 : void nsProfileLock::RemovePidLockFiles(bool aFatalSignal)
     111             : {
     112           0 :     while (!PR_CLIST_IS_EMPTY(&mPidLockList))
     113             :     {
     114           0 :         nsProfileLock *lock = static_cast<nsProfileLock*>(mPidLockList.next);
     115           0 :         lock->Unlock(aFatalSignal);
     116             :     }
     117           0 : }
     118             : 
     119             : static struct sigaction SIGHUP_oldact;
     120             : static struct sigaction SIGINT_oldact;
     121             : static struct sigaction SIGQUIT_oldact;
     122             : static struct sigaction SIGILL_oldact;
     123             : static struct sigaction SIGABRT_oldact;
     124             : static struct sigaction SIGSEGV_oldact;
     125             : static struct sigaction SIGTERM_oldact;
     126             : 
     127           0 : void nsProfileLock::FatalSignalHandler(int signo
     128             : #ifdef SA_SIGINFO
     129             :                                        , siginfo_t *info, void *context
     130             : #endif
     131             :                                        )
     132             : {
     133             :     // Remove any locks still held.
     134           0 :     RemovePidLockFiles(true);
     135             : 
     136             :     // Chain to the old handler, which may exit.
     137           0 :     struct sigaction *oldact = nullptr;
     138             : 
     139           0 :     switch (signo) {
     140             :       case SIGHUP:
     141           0 :         oldact = &SIGHUP_oldact;
     142           0 :         break;
     143             :       case SIGINT:
     144           0 :         oldact = &SIGINT_oldact;
     145           0 :         break;
     146             :       case SIGQUIT:
     147           0 :         oldact = &SIGQUIT_oldact;
     148           0 :         break;
     149             :       case SIGILL:
     150           0 :         oldact = &SIGILL_oldact;
     151           0 :         break;
     152             :       case SIGABRT:
     153           0 :         oldact = &SIGABRT_oldact;
     154           0 :         break;
     155             :       case SIGSEGV:
     156           0 :         oldact = &SIGSEGV_oldact;
     157           0 :         break;
     158             :       case SIGTERM:
     159           0 :         oldact = &SIGTERM_oldact;
     160           0 :         break;
     161             :       default:
     162           0 :         NS_NOTREACHED("bad signo");
     163           0 :         break;
     164             :     }
     165             : 
     166           0 :     if (oldact) {
     167           0 :         if (oldact->sa_handler == SIG_DFL) {
     168             :             // Make sure the default sig handler is executed
     169             :             // We need it to get Mozilla to dump core.
     170           0 :             sigaction(signo,oldact, nullptr);
     171             : 
     172             :             // Now that we've restored the default handler, unmask the
     173             :             // signal and invoke it.
     174             : 
     175             :             sigset_t unblock_sigs;
     176           0 :             sigemptyset(&unblock_sigs);
     177           0 :             sigaddset(&unblock_sigs, signo);
     178             : 
     179           0 :             sigprocmask(SIG_UNBLOCK, &unblock_sigs, nullptr);
     180             : 
     181           0 :             raise(signo);
     182             :         }
     183             : #ifdef SA_SIGINFO
     184           0 :         else if (oldact->sa_sigaction &&
     185           0 :                  (oldact->sa_flags & SA_SIGINFO) == SA_SIGINFO) {
     186           0 :             oldact->sa_sigaction(signo, info, context);
     187             :         }
     188             : #endif
     189           0 :         else if (oldact->sa_handler && oldact->sa_handler != SIG_IGN)
     190             :         {
     191           0 :             oldact->sa_handler(signo);
     192             :         }
     193             :     }
     194             : 
     195             : #ifdef MOZ_WIDGET_GONK
     196             :     switch (signo) {
     197             :         case SIGQUIT:
     198             :         case SIGILL:
     199             :         case SIGABRT:
     200             :         case SIGSEGV:
     201             : #ifndef MOZ_CRASHREPORTER
     202             :             // Retrigger the signal for those that can generate a core dump
     203             :             signal(signo, SIG_DFL);
     204             :             if (info->si_code <= 0) {
     205             :                 if (syscall(__NR_tgkill, getpid(), syscall(__NR_gettid), signo) < 0) {
     206             :                     break;
     207             :                 }
     208             :             }
     209             : #endif
     210             :             return;
     211             :         default:
     212             :             break;
     213             :     }
     214             : #endif
     215             : 
     216             :     // Backstop exit call, just in case.
     217           0 :     _exit(signo);
     218             : }
     219             : 
     220           1 : nsresult nsProfileLock::LockWithFcntl(nsIFile *aLockFile)
     221             : {
     222           1 :     nsresult rv = NS_OK;
     223             : 
     224           2 :     nsAutoCString lockFilePath;
     225           1 :     rv = aLockFile->GetNativePath(lockFilePath);
     226           1 :     if (NS_FAILED(rv)) {
     227           0 :         NS_ERROR("Could not get native path");
     228           0 :         return rv;
     229             :     }
     230             : 
     231           1 :     aLockFile->GetLastModifiedTime(&mReplacedLockTime);
     232             : 
     233           1 :     mLockFileDesc = open(lockFilePath.get(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
     234           1 :     if (mLockFileDesc != -1)
     235             :     {
     236             :         struct flock lock;
     237           1 :         lock.l_start = 0;
     238           1 :         lock.l_len = 0; // len = 0 means entire file
     239           1 :         lock.l_type = F_WRLCK;
     240           1 :         lock.l_whence = SEEK_SET;
     241             : 
     242             :         // If fcntl(F_GETLK) fails then the server does not support/allow fcntl(),
     243             :         // return failure rather than access denied in this case so we fallback
     244             :         // to using a symlink lock, bug 303633.
     245           1 :         struct flock testlock = lock;
     246           1 :         if (fcntl(mLockFileDesc, F_GETLK, &testlock) == -1)
     247             :         {
     248           0 :             close(mLockFileDesc);
     249           0 :             mLockFileDesc = -1;
     250           0 :             rv = NS_ERROR_FAILURE;
     251             :         }
     252           1 :         else if (fcntl(mLockFileDesc, F_SETLK, &lock) == -1)
     253             :         {
     254           0 :             close(mLockFileDesc);
     255           0 :             mLockFileDesc = -1;
     256             : 
     257             :             // With OS X, on NFS, errno == ENOTSUP
     258             :             // XXX Check for that and return specific rv for it?
     259             : #ifdef DEBUG
     260           0 :             printf("fcntl(F_SETLK) failed. errno = %d\n", errno);
     261             : #endif
     262           0 :             if (errno == EAGAIN || errno == EACCES)
     263           0 :                 rv = NS_ERROR_FILE_ACCESS_DENIED;
     264             :             else
     265           0 :                 rv = NS_ERROR_FAILURE;
     266             :         }
     267             :     }
     268             :     else
     269             :     {
     270           0 :         NS_ERROR("Failed to open lock file.");
     271           0 :         rv = NS_ERROR_FAILURE;
     272             :     }
     273           1 :     return rv;
     274             : }
     275             : 
     276           0 : static bool IsSymlinkStaleLock(struct in_addr* aAddr, const char* aFileName,
     277             :                                  bool aHaveFcntlLock)
     278             : {
     279             :     // the link exists; see if it's from this machine, and if
     280             :     // so if the process is still active
     281             :     char buf[1024];
     282           0 :     int len = readlink(aFileName, buf, sizeof buf - 1);
     283           0 :     if (len > 0)
     284             :     {
     285           0 :         buf[len] = '\0';
     286           0 :         char *colon = strchr(buf, ':');
     287           0 :         if (colon)
     288             :         {
     289           0 :             *colon++ = '\0';
     290           0 :             unsigned long addr = inet_addr(buf);
     291           0 :             if (addr != (unsigned long) -1)
     292             :             {
     293           0 :                 if (colon[0] == '+' && aHaveFcntlLock) {
     294             :                     // This lock was placed by a Firefox build which would have
     295             :                     // taken the fnctl lock, and we've already taken the fcntl lock,
     296             :                     // so the process that created this obsolete lock must be gone
     297           0 :                     return true;
     298             :                 }
     299             : 
     300           0 :                 char *after = nullptr;
     301           0 :                 pid_t pid = strtol(colon, &after, 0);
     302           0 :                 if (pid != 0 && *after == '\0')
     303             :                 {
     304           0 :                     if (addr != aAddr->s_addr)
     305             :                     {
     306             :                         // Remote lock: give up even if stuck.
     307           0 :                         return false;
     308             :                     }
     309             : 
     310             :                     // kill(pid,0) is a neat trick to check if a
     311             :                     // process exists
     312           0 :                     if (kill(pid, 0) == 0 || errno != ESRCH)
     313             :                     {
     314             :                         // Local process appears to be alive, ass-u-me it
     315             :                         // is another Mozilla instance, or a compatible
     316             :                         // derivative, that's currently using the profile.
     317             :                         // XXX need an "are you Mozilla?" protocol
     318           0 :                         return false;
     319             :                     }
     320             :                 }
     321             :             }
     322             :         }
     323             :     }
     324           0 :     return true;
     325             : }
     326             : 
     327           1 : nsresult nsProfileLock::LockWithSymlink(nsIFile *aLockFile, bool aHaveFcntlLock)
     328             : {
     329             :     nsresult rv;
     330           2 :     nsAutoCString lockFilePath;
     331           1 :     rv = aLockFile->GetNativePath(lockFilePath);
     332           1 :     if (NS_FAILED(rv)) {
     333           0 :         NS_ERROR("Could not get native path");
     334           0 :         return rv;
     335             :     }
     336             : 
     337             :     // don't replace an existing lock time if fcntl already got one
     338           1 :     if (!mReplacedLockTime)
     339           0 :         aLockFile->GetLastModifiedTimeOfLink(&mReplacedLockTime);
     340             : 
     341             :     struct in_addr inaddr;
     342           1 :     inaddr.s_addr = htonl(INADDR_LOOPBACK);
     343             : 
     344             :     char hostname[256];
     345           1 :     PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname);
     346           1 :     if (status == PR_SUCCESS)
     347             :     {
     348             :         char netdbbuf[PR_NETDB_BUF_SIZE];
     349             :         PRHostEnt hostent;
     350           1 :         status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent);
     351           1 :         if (status == PR_SUCCESS)
     352           1 :             memcpy(&inaddr, hostent.h_addr, sizeof inaddr);
     353             :     }
     354             : 
     355             :     mozilla::SmprintfPointer signature =
     356             :         mozilla::Smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "",
     357           2 :                    (unsigned long)getpid());
     358           1 :     const char *fileName = lockFilePath.get();
     359           1 :     int symlink_rv, symlink_errno = 0, tries = 0;
     360             : 
     361             :     // use ns4.x-compatible symlinks if the FS supports them
     362           1 :     while ((symlink_rv = symlink(signature.get(), fileName)) < 0)
     363             :     {
     364           0 :         symlink_errno = errno;
     365           0 :         if (symlink_errno != EEXIST)
     366           0 :             break;
     367             : 
     368           0 :         if (!IsSymlinkStaleLock(&inaddr, fileName, aHaveFcntlLock))
     369           0 :             break;
     370             : 
     371             :         // Lock seems to be bogus: try to claim it.  Give up after a large
     372             :         // number of attempts (100 comes from the 4.x codebase).
     373           0 :         (void) unlink(fileName);
     374           0 :         if (++tries > 100)
     375           0 :             break;
     376             :     }
     377             : 
     378           1 :     if (symlink_rv == 0)
     379             :     {
     380             :         // We exclusively created the symlink: record its name for eventual
     381             :         // unlock-via-unlink.
     382           1 :         rv = NS_OK;
     383           1 :         mPidLockFileName = strdup(fileName);
     384           1 :         if (mPidLockFileName)
     385             :         {
     386           1 :             PR_APPEND_LINK(this, &mPidLockList);
     387           1 :             if (!setupPidLockCleanup++)
     388             :             {
     389             :                 // Clean up on normal termination.
     390             :                 // This instanciates a dummy class, and will trigger the class
     391             :                 // destructor when libxul is unloaded. This is equivalent to atexit(),
     392             :                 // but gracefully handles dlclose().
     393           1 :                 static RemovePidLockFilesExiting r;
     394             : 
     395             :                 // Clean up on abnormal termination, using POSIX sigaction.
     396             :                 // Don't arm a handler if the signal is being ignored, e.g.,
     397             :                 // because mozilla is run via nohup.
     398           1 :                 if (!sDisableSignalHandling) {
     399             :                     struct sigaction act, oldact;
     400             : #ifdef SA_SIGINFO
     401           1 :                     act.sa_sigaction = FatalSignalHandler;
     402           1 :                     act.sa_flags = SA_SIGINFO;
     403             : #else
     404             :                     act.sa_handler = FatalSignalHandler;
     405             : #endif
     406           1 :                     sigfillset(&act.sa_mask);
     407             : 
     408             : #define CATCH_SIGNAL(signame)                                           \
     409             : PR_BEGIN_MACRO                                                          \
     410             :   if (sigaction(signame, nullptr, &oldact) == 0 &&                      \
     411             :       oldact.sa_handler != SIG_IGN)                                     \
     412             :   {                                                                     \
     413             :       sigaction(signame, &act, &signame##_oldact);                      \
     414             :   }                                                                     \
     415             :   PR_END_MACRO
     416             : 
     417           1 :                     CATCH_SIGNAL(SIGHUP);
     418           1 :                     CATCH_SIGNAL(SIGINT);
     419           1 :                     CATCH_SIGNAL(SIGQUIT);
     420           1 :                     CATCH_SIGNAL(SIGILL);
     421           1 :                     CATCH_SIGNAL(SIGABRT);
     422           1 :                     CATCH_SIGNAL(SIGSEGV);
     423           1 :                     CATCH_SIGNAL(SIGTERM);
     424             : 
     425             : #undef CATCH_SIGNAL
     426             :                 }
     427             :             }
     428             :         }
     429             :     }
     430           0 :     else if (symlink_errno == EEXIST)
     431           0 :         rv = NS_ERROR_FILE_ACCESS_DENIED;
     432             :     else
     433             :     {
     434             : #ifdef DEBUG
     435           0 :         printf("symlink() failed. errno = %d\n", errno);
     436             : #endif
     437           0 :         rv = NS_ERROR_FAILURE;
     438             :     }
     439           1 :     return rv;
     440             : }
     441             : #endif /* XP_UNIX */
     442             : 
     443           2 : nsresult nsProfileLock::GetReplacedLockTime(PRTime *aResult) {
     444           2 :     *aResult = mReplacedLockTime;
     445           2 :     return NS_OK;
     446             : }
     447             : 
     448           1 : nsresult nsProfileLock::Lock(nsIFile* aProfileDir,
     449             :                              nsIProfileUnlocker* *aUnlocker)
     450             : {
     451             : #if defined (XP_MACOSX)
     452             :     NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock");
     453             :     NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "parent.lock");
     454             : #elif defined (XP_UNIX)
     455           1 :     NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "lock");
     456           1 :     NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock");
     457             : #else
     458             :     NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, "parent.lock");
     459             : #endif
     460             : 
     461             :     nsresult rv;
     462           1 :     if (aUnlocker)
     463           1 :         *aUnlocker = nullptr;
     464             : 
     465           1 :     NS_ENSURE_STATE(!mHaveLock);
     466             : 
     467             :     bool isDir;
     468           1 :     rv = aProfileDir->IsDirectory(&isDir);
     469           1 :     if (NS_FAILED(rv))
     470           0 :         return rv;
     471           1 :     if (!isDir)
     472           0 :         return NS_ERROR_FILE_NOT_DIRECTORY;
     473             : 
     474           2 :     nsCOMPtr<nsIFile> lockFile;
     475           1 :     rv = aProfileDir->Clone(getter_AddRefs(lockFile));
     476           1 :     if (NS_FAILED(rv))
     477           0 :         return rv;
     478             : 
     479           1 :     rv = lockFile->Append(LOCKFILE_NAME);
     480           1 :     if (NS_FAILED(rv))
     481           0 :         return rv;
     482             : 
     483             :     // Remember the name we're using so we can clean up
     484           1 :     rv = lockFile->Clone(getter_AddRefs(mLockFile));
     485           1 :     if (NS_FAILED(rv))
     486           0 :         return rv;
     487             : 
     488             : #if defined(XP_MACOSX)
     489             :     // First, try locking using fcntl. It is more reliable on
     490             :     // a local machine, but may not be supported by an NFS server.
     491             : 
     492             :     rv = LockWithFcntl(lockFile);
     493             :     if (NS_FAILED(rv) && (rv != NS_ERROR_FILE_ACCESS_DENIED))
     494             :     {
     495             :         // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED,
     496             :         // assume we tried an NFS that does not support it. Now, try with symlink.
     497             :         rv = LockWithSymlink(lockFile, false);
     498             :     }
     499             : 
     500             :     if (NS_SUCCEEDED(rv))
     501             :     {
     502             :         // Check for the old-style lock used by pre-mozilla 1.3 builds.
     503             :         // Those builds used an earlier check to prevent the application
     504             :         // from launching if another instance was already running. Because
     505             :         // of that, we don't need to create an old-style lock as well.
     506             :         struct LockProcessInfo
     507             :         {
     508             :             ProcessSerialNumber psn;
     509             :             unsigned long launchDate;
     510             :         };
     511             : 
     512             :         PRFileDesc *fd = nullptr;
     513             :         int32_t ioBytes;
     514             :         ProcessInfoRec processInfo;
     515             :         LockProcessInfo lockProcessInfo;
     516             : 
     517             :         rv = lockFile->SetLeafName(OLD_LOCKFILE_NAME);
     518             :         if (NS_FAILED(rv))
     519             :             return rv;
     520             :         rv = lockFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
     521             :         if (NS_SUCCEEDED(rv))
     522             :         {
     523             :             ioBytes = PR_Read(fd, &lockProcessInfo, sizeof(LockProcessInfo));
     524             :             PR_Close(fd);
     525             : 
     526             :             if (ioBytes == sizeof(LockProcessInfo))
     527             :             {
     528             : #ifdef __LP64__
     529             :                 processInfo.processAppRef = nullptr;
     530             : #else
     531             :                 processInfo.processAppSpec = nullptr;
     532             : #endif
     533             :                 processInfo.processName = nullptr;
     534             :                 processInfo.processInfoLength = sizeof(ProcessInfoRec);
     535             :                 if (::GetProcessInformation(&lockProcessInfo.psn, &processInfo) == noErr &&
     536             :                     processInfo.processLaunchDate == lockProcessInfo.launchDate)
     537             :                 {
     538             :                     return NS_ERROR_FILE_ACCESS_DENIED;
     539             :                 }
     540             :             }
     541             :             else
     542             :             {
     543             :                 NS_WARNING("Could not read lock file - ignoring lock");
     544             :             }
     545             :         }
     546             :         rv = NS_OK; // Don't propagate error from OpenNSPRFileDesc.
     547             :     }
     548             : #elif defined(XP_UNIX)
     549             :     // Get the old lockfile name
     550           2 :     nsCOMPtr<nsIFile> oldLockFile;
     551           1 :     rv = aProfileDir->Clone(getter_AddRefs(oldLockFile));
     552           1 :     if (NS_FAILED(rv))
     553           0 :         return rv;
     554           1 :     rv = oldLockFile->Append(OLD_LOCKFILE_NAME);
     555           1 :     if (NS_FAILED(rv))
     556           0 :         return rv;
     557             : 
     558             :     // First, try locking using fcntl. It is more reliable on
     559             :     // a local machine, but may not be supported by an NFS server.
     560           1 :     rv = LockWithFcntl(lockFile);
     561           1 :     if (NS_SUCCEEDED(rv)) {
     562             :         // Check to see whether there is a symlink lock held by an older
     563             :         // Firefox build, and also place our own symlink lock --- but
     564             :         // mark it "obsolete" so that other newer builds can break the lock
     565             :         // if they obtain the fcntl lock
     566           1 :         rv = LockWithSymlink(oldLockFile, true);
     567             : 
     568             :         // If the symlink failed for some reason other than it already
     569             :         // exists, then something went wrong e.g. the file system
     570             :         // doesn't support symlinks, or we don't have permission to
     571             :         // create a symlink there.  In such cases we should just
     572             :         // continue because it's unlikely there is an old build
     573             :         // running with a symlink there and we've already successfully
     574             :         // placed a fcntl lock.
     575           1 :         if (rv != NS_ERROR_FILE_ACCESS_DENIED)
     576           1 :             rv = NS_OK;
     577             :     }
     578           0 :     else if (rv != NS_ERROR_FILE_ACCESS_DENIED)
     579             :     {
     580             :         // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED,
     581             :         // assume we tried an NFS that does not support it. Now, try with symlink
     582             :         // using the old symlink path
     583           0 :         rv = LockWithSymlink(oldLockFile, false);
     584             :     }
     585             : 
     586             : #elif defined(XP_WIN)
     587             :     nsAutoString filePath;
     588             :     rv = lockFile->GetPath(filePath);
     589             :     if (NS_FAILED(rv))
     590             :         return rv;
     591             : 
     592             :     lockFile->GetLastModifiedTime(&mReplacedLockTime);
     593             : 
     594             :     // always create the profile lock and never delete it so we can use its
     595             :     // modification timestamp to detect startup crashes
     596             :     mLockFileHandle = CreateFileW(filePath.get(),
     597             :                                   GENERIC_READ | GENERIC_WRITE,
     598             :                                   0, // no sharing - of course
     599             :                                   nullptr,
     600             :                                   CREATE_ALWAYS,
     601             :                                   0,
     602             :                                   nullptr);
     603             :     if (mLockFileHandle == INVALID_HANDLE_VALUE) {
     604             :         if (aUnlocker) {
     605             :           RefPtr<mozilla::ProfileUnlockerWin> unlocker(
     606             :                                      new mozilla::ProfileUnlockerWin(filePath));
     607             :           if (NS_SUCCEEDED(unlocker->Init())) {
     608             :             nsCOMPtr<nsIProfileUnlocker> unlockerInterface(
     609             :                                                       do_QueryObject(unlocker));
     610             :             unlockerInterface.forget(aUnlocker);
     611             :           }
     612             :         }
     613             :         return NS_ERROR_FILE_ACCESS_DENIED;
     614             :     }
     615             : #endif
     616             : 
     617           1 :     if (NS_SUCCEEDED(rv))
     618           1 :         mHaveLock = true;
     619             : 
     620           1 :     return rv;
     621             : }
     622             : 
     623             : 
     624           0 : nsresult nsProfileLock::Unlock(bool aFatalSignal)
     625             : {
     626           0 :     nsresult rv = NS_OK;
     627             : 
     628           0 :     if (mHaveLock)
     629             :     {
     630             : #if defined (XP_WIN)
     631             :         if (mLockFileHandle != INVALID_HANDLE_VALUE)
     632             :         {
     633             :             CloseHandle(mLockFileHandle);
     634             :             mLockFileHandle = INVALID_HANDLE_VALUE;
     635             :         }
     636             : #elif defined (XP_UNIX)
     637           0 :         if (mPidLockFileName)
     638             :         {
     639           0 :             PR_REMOVE_LINK(this);
     640           0 :             (void) unlink(mPidLockFileName);
     641             : 
     642             :             // Only free mPidLockFileName if we're not in the fatal signal
     643             :             // handler.  The problem is that a call to free() might be the
     644             :             // cause of this fatal signal.  If so, calling free() might cause
     645             :             // us to wait on the malloc implementation's lock.  We're already
     646             :             // holding this lock, so we'll deadlock. See bug 522332.
     647           0 :             if (!aFatalSignal)
     648           0 :                 free(mPidLockFileName);
     649           0 :             mPidLockFileName = nullptr;
     650             :         }
     651           0 :         if (mLockFileDesc != -1)
     652             :         {
     653           0 :             close(mLockFileDesc);
     654           0 :             mLockFileDesc = -1;
     655             :             // Don't remove it
     656             :         }
     657             : #endif
     658             : 
     659           0 :         mHaveLock = false;
     660             :     }
     661             : 
     662           0 :     return rv;
     663             : }
     664             : 
     665           0 : nsresult nsProfileLock::Cleanup()
     666             : {
     667           0 :     if (mLockFile) {
     668           0 :         return mLockFile->Remove(false);
     669             :     }
     670             : 
     671           0 :     return NS_OK;
     672             : }

Generated by: LCOV version 1.13