LCOV - code coverage report
Current view: directory - objdir/toolkit/profile - nsProfileLock.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 214 0 0.0 %
Date: 2012-06-02 Functions: 12 0 0.0 %

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

Generated by: LCOV version 1.7