Back to index

lightning-sunbird  0.9+nobinonly
nsProfileLock.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Conrad Carlen <ccarlen@netscape.com>
00024  *   Brendan Eich <brendan@mozilla.org>
00025  *   Colin Blake <colin@theblakes.com>
00026  *   Javier Pedemonte <pedemont@us.ibm.com>
00027  *   Mats Palmgren <mats.palmgren@bredband.net>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either the GNU General Public License Version 2 or later (the "GPL"), or
00031  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #include "nsProfileStringTypes.h"
00044 #include "nsProfileLock.h"
00045 #include "nsCOMPtr.h"
00046 
00047 #if defined(XP_MAC) || defined(XP_MACOSX)
00048 #include <Processes.h>
00049 #include <CFBundle.h>
00050 #endif
00051 
00052 #ifdef XP_UNIX
00053 #include <unistd.h>
00054 #include <fcntl.h>
00055 #include <errno.h>
00056 #include <signal.h>
00057 #include <stdlib.h>
00058 #include "prnetdb.h"
00059 #include "prsystem.h"
00060 #include "prprf.h"
00061 #endif
00062 
00063 #ifdef VMS
00064 #include <rmsdef.h>
00065 #endif
00066 
00067 // **********************************************************************
00068 // class nsProfileLock
00069 //
00070 // This code was moved from profile/src/nsProfileAccess.
00071 // **********************************************************************
00072 
00073 nsProfileLock::nsProfileLock() :
00074     mHaveLock(PR_FALSE)
00075 #if defined (XP_WIN)
00076     ,mLockFileHandle(INVALID_HANDLE_VALUE)
00077 #elif defined (XP_OS2)
00078     ,mLockFileHandle(-1)
00079 #elif defined (XP_UNIX)
00080     ,mPidLockFileName(nsnull)
00081     ,mLockFileDesc(-1)
00082 #endif
00083 {
00084 #if defined (XP_UNIX)
00085     next = prev = this;
00086 #endif
00087 }
00088 
00089 
00090 nsProfileLock::nsProfileLock(nsProfileLock& src)
00091 {
00092     *this = src;
00093 }
00094 
00095 
00096 nsProfileLock& nsProfileLock::operator=(nsProfileLock& rhs)
00097 {
00098     Unlock();
00099 
00100     mHaveLock = rhs.mHaveLock;
00101     rhs.mHaveLock = PR_FALSE;
00102 
00103 #if defined (XP_WIN)
00104     mLockFileHandle = rhs.mLockFileHandle;
00105     rhs.mLockFileHandle = INVALID_HANDLE_VALUE;
00106 #elif defined (XP_OS2)
00107     mLockFileHandle = rhs.mLockFileHandle;
00108     rhs.mLockFileHandle = -1;
00109 #elif defined (XP_UNIX)
00110     mLockFileDesc = rhs.mLockFileDesc;
00111     rhs.mLockFileDesc = -1;
00112     mPidLockFileName = rhs.mPidLockFileName;
00113     rhs.mPidLockFileName = nsnull;
00114     if (mPidLockFileName)
00115     {
00116         // rhs had a symlink lock, therefore it was on the list.
00117         PR_REMOVE_LINK(&rhs);
00118         PR_APPEND_LINK(this, &mPidLockList);
00119     }
00120 #endif
00121 
00122     return *this;
00123 }
00124 
00125 
00126 nsProfileLock::~nsProfileLock()
00127 {
00128     Unlock();
00129 }
00130 
00131 
00132 #if defined (XP_UNIX)
00133 
00134 static int setupPidLockCleanup;
00135 
00136 PRCList nsProfileLock::mPidLockList =
00137     PR_INIT_STATIC_CLIST(&nsProfileLock::mPidLockList);
00138 
00139 void nsProfileLock::RemovePidLockFiles()
00140 {
00141     while (!PR_CLIST_IS_EMPTY(&mPidLockList))
00142     {
00143         nsProfileLock *lock = NS_STATIC_CAST(nsProfileLock*, mPidLockList.next);
00144         lock->Unlock();
00145     }
00146 }
00147 
00148 static struct sigaction SIGHUP_oldact;
00149 static struct sigaction SIGINT_oldact;
00150 static struct sigaction SIGQUIT_oldact;
00151 static struct sigaction SIGILL_oldact;
00152 static struct sigaction SIGABRT_oldact;
00153 static struct sigaction SIGSEGV_oldact;
00154 static struct sigaction SIGTERM_oldact;
00155 
00156 void nsProfileLock::FatalSignalHandler(int signo)
00157 {
00158     // Remove any locks still held.
00159     RemovePidLockFiles();
00160 
00161     // Chain to the old handler, which may exit.
00162     struct sigaction *oldact = nsnull;
00163 
00164     switch (signo) {
00165       case SIGHUP:
00166         oldact = &SIGHUP_oldact;
00167         break;
00168       case SIGINT:
00169         oldact = &SIGINT_oldact;
00170         break;
00171       case SIGQUIT:
00172         oldact = &SIGQUIT_oldact;
00173         break;
00174       case SIGILL:
00175         oldact = &SIGILL_oldact;
00176         break;
00177       case SIGABRT:
00178         oldact = &SIGABRT_oldact;
00179         break;
00180       case SIGSEGV:
00181         oldact = &SIGSEGV_oldact;
00182         break;
00183       case SIGTERM:
00184         oldact = &SIGTERM_oldact;
00185         break;
00186       default:
00187         NS_NOTREACHED("bad signo");
00188         break;
00189     }
00190 
00191     if (oldact) {
00192         if (oldact->sa_handler == SIG_DFL) {
00193             // Make sure the default sig handler is executed
00194             // We need it to get Mozilla to dump core.
00195             sigaction(signo,oldact,NULL);
00196 
00197             // Now that we've restored the default handler, unmask the
00198             // signal and invoke it.
00199 
00200             sigset_t unblock_sigs;
00201             sigemptyset(&unblock_sigs);
00202             sigaddset(&unblock_sigs, signo);
00203 
00204             sigprocmask(SIG_UNBLOCK, &unblock_sigs, NULL);
00205 
00206             raise(signo);
00207         }
00208         else if (oldact->sa_handler && oldact->sa_handler != SIG_IGN)
00209         {
00210             oldact->sa_handler(signo);
00211         }
00212     }
00213 
00214     // Backstop exit call, just in case.
00215     _exit(signo);
00216 }
00217 
00218 nsresult nsProfileLock::LockWithFcntl(const nsACString& lockFilePath)
00219 {
00220     nsresult rv = NS_OK;
00221 
00222     mLockFileDesc = open(PromiseFlatCString(lockFilePath).get(),
00223                           O_WRONLY | O_CREAT | O_TRUNC, 0666);
00224     if (mLockFileDesc != -1)
00225     {
00226         struct flock lock;
00227         lock.l_start = 0;
00228         lock.l_len = 0; // len = 0 means entire file
00229         lock.l_type = F_WRLCK;
00230         lock.l_whence = SEEK_SET;
00231 
00232         // If fcntl(F_GETLK) fails then the server does not support/allow fcntl(),
00233         // return failure rather than access denied in this case so we fallback
00234         // to using a symlink lock, bug 303633.
00235         struct flock testlock = lock;
00236         if (fcntl(mLockFileDesc, F_GETLK, &testlock) == -1)
00237         {
00238             close(mLockFileDesc);
00239             mLockFileDesc = -1;
00240             rv = NS_ERROR_FAILURE;
00241         }
00242         else if (fcntl(mLockFileDesc, F_SETLK, &lock) == -1)
00243         {
00244             close(mLockFileDesc);
00245             mLockFileDesc = -1;
00246 
00247             // With OS X, on NFS, errno == ENOTSUP
00248             // XXX Check for that and return specific rv for it?
00249 #ifdef DEBUG
00250             printf("fcntl(F_SETLK) failed. errno = %d\n", errno);
00251 #endif
00252             if (errno == EAGAIN || errno == EACCES)
00253                 rv = NS_ERROR_FILE_ACCESS_DENIED;
00254             else
00255                 rv = NS_ERROR_FAILURE;
00256         }
00257         else
00258             mHaveLock = PR_TRUE;
00259     }
00260     else
00261     {
00262         NS_ERROR("Failed to open lock file.");
00263         rv = NS_ERROR_FAILURE;
00264     }
00265     return rv;
00266 }
00267 
00268 static PRBool IsSymlinkStaleLock(struct in_addr* aAddr, const char* aFileName,
00269                                  PRBool aHaveFcntlLock)
00270 {
00271     // the link exists; see if it's from this machine, and if
00272     // so if the process is still active
00273     char buf[1024];
00274     int len = readlink(aFileName, buf, sizeof buf - 1);
00275     if (len > 0)
00276     {
00277         buf[len] = '\0';
00278         char *colon = strchr(buf, ':');
00279         if (colon)
00280         {
00281             *colon++ = '\0';
00282             unsigned long addr = inet_addr(buf);
00283             if (addr != (unsigned long) -1)
00284             {
00285                 if (colon[0] == '+' && aHaveFcntlLock) {
00286                     // This lock was placed by a Firefox build which would have
00287                     // taken the fnctl lock, and we've already taken the fcntl lock,
00288                     // so the process that created this obsolete lock must be gone
00289                     return PR_TRUE;
00290                 }
00291                     
00292                 char *after = nsnull;
00293                 pid_t pid = strtol(colon, &after, 0);
00294                 if (pid != 0 && *after == '\0')
00295                 {
00296                     if (addr != aAddr->s_addr)
00297                     {
00298                         // Remote lock: give up even if stuck.
00299                         return PR_FALSE;
00300                     }
00301     
00302                     // kill(pid,0) is a neat trick to check if a
00303                     // process exists
00304                     if (kill(pid, 0) == 0 || errno != ESRCH)
00305                     {
00306                         // Local process appears to be alive, ass-u-me it
00307                         // is another Mozilla instance, or a compatible
00308                         // derivative, that's currently using the profile.
00309                         // XXX need an "are you Mozilla?" protocol
00310                         return PR_FALSE;
00311                     }
00312                 }
00313             }
00314         }
00315     }
00316     return PR_TRUE;
00317 }
00318 
00319 nsresult nsProfileLock::LockWithSymlink(const nsACString& lockFilePath, PRBool aHaveFcntlLock)
00320 {
00321     nsresult rv;
00322 
00323     struct in_addr inaddr;
00324     inaddr.s_addr = htonl(INADDR_LOOPBACK);
00325 
00326     char hostname[256];
00327     PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname);
00328     if (status == PR_SUCCESS)
00329     {
00330         char netdbbuf[PR_NETDB_BUF_SIZE];
00331         PRHostEnt hostent;
00332         status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent);
00333         if (status == PR_SUCCESS)
00334             memcpy(&inaddr, hostent.h_addr, sizeof inaddr);
00335     }
00336 
00337     char *signature =
00338         PR_smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "",
00339                     (unsigned long)getpid());
00340     const nsPromiseFlatCString& flat = PromiseFlatCString(lockFilePath);
00341     const char *fileName = flat.get();
00342     int symlink_rv, symlink_errno = 0, tries = 0;
00343 
00344     // use ns4.x-compatible symlinks if the FS supports them
00345     while ((symlink_rv = symlink(signature, fileName)) < 0)
00346     {
00347         symlink_errno = errno;
00348         if (symlink_errno != EEXIST)
00349             break;
00350 
00351         if (!IsSymlinkStaleLock(&inaddr, fileName, aHaveFcntlLock))
00352             break;
00353 
00354         // Lock seems to be bogus: try to claim it.  Give up after a large
00355         // number of attempts (100 comes from the 4.x codebase).
00356         (void) unlink(fileName);
00357         if (++tries > 100)
00358             break;
00359     }
00360 
00361     PR_smprintf_free(signature);
00362     signature = nsnull;
00363 
00364     if (symlink_rv == 0)
00365     {
00366         // We exclusively created the symlink: record its name for eventual
00367         // unlock-via-unlink.
00368         rv = NS_OK;
00369         mHaveLock = PR_TRUE;
00370         mPidLockFileName = strdup(fileName);
00371         if (mPidLockFileName)
00372         {
00373             PR_APPEND_LINK(this, &mPidLockList);
00374             if (!setupPidLockCleanup++)
00375             {
00376                 // Clean up on normal termination.
00377                 atexit(RemovePidLockFiles);
00378 
00379                 // Clean up on abnormal termination, using POSIX sigaction.
00380                 // Don't arm a handler if the signal is being ignored, e.g.,
00381                 // because mozilla is run via nohup.
00382                 struct sigaction act, oldact;
00383                 act.sa_handler = FatalSignalHandler;
00384                 act.sa_flags = 0;
00385                 sigfillset(&act.sa_mask);
00386 
00387 #define CATCH_SIGNAL(signame)                                           \
00388 PR_BEGIN_MACRO                                                          \
00389   if (sigaction(signame, NULL, &oldact) == 0 &&                         \
00390       oldact.sa_handler != SIG_IGN)                                     \
00391   {                                                                     \
00392       sigaction(signame, &act, &signame##_oldact);                      \
00393   }                                                                     \
00394   PR_END_MACRO
00395 
00396                 CATCH_SIGNAL(SIGHUP);
00397                 CATCH_SIGNAL(SIGINT);
00398                 CATCH_SIGNAL(SIGQUIT);
00399                 CATCH_SIGNAL(SIGILL);
00400                 CATCH_SIGNAL(SIGABRT);
00401                 CATCH_SIGNAL(SIGSEGV);
00402                 CATCH_SIGNAL(SIGTERM);
00403 
00404 #undef CATCH_SIGNAL
00405             }
00406         }
00407     }
00408     else if (symlink_errno == EEXIST)
00409         rv = NS_ERROR_FILE_ACCESS_DENIED;
00410     else
00411     {
00412 #ifdef DEBUG
00413         printf("symlink() failed. errno = %d\n", errno);
00414 #endif
00415         rv = NS_ERROR_FAILURE;
00416     }
00417     return rv;
00418 }
00419 #endif /* XP_UNIX */
00420 
00421 nsresult nsProfileLock::Lock(nsILocalFile* aProfileDir,
00422                              nsIProfileUnlocker* *aUnlocker)
00423 {
00424 #if defined (XP_MACOSX)
00425     NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock");
00426     NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "parent.lock");
00427 #elif defined (XP_UNIX)
00428     NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "lock");
00429     NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock");
00430 #else
00431     NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, "parent.lock");
00432 #endif
00433 
00434     nsresult rv;
00435     if (aUnlocker)
00436         *aUnlocker = nsnull;
00437 
00438     NS_ENSURE_STATE(!mHaveLock);
00439 
00440     PRBool isDir;
00441     rv = aProfileDir->IsDirectory(&isDir);
00442     if (NS_FAILED(rv))
00443         return rv;
00444     if (!isDir)
00445         return NS_ERROR_FILE_NOT_DIRECTORY;
00446 
00447     nsCOMPtr<nsILocalFile> lockFile;
00448     rv = aProfileDir->Clone((nsIFile **)((void **)getter_AddRefs(lockFile)));
00449     if (NS_FAILED(rv))
00450         return rv;
00451 
00452     rv = lockFile->Append(LOCKFILE_NAME);
00453     if (NS_FAILED(rv))
00454         return rv;
00455         
00456 #if defined(XP_MACOSX)
00457     // First, try locking using fcntl. It is more reliable on
00458     // a local machine, but may not be supported by an NFS server.
00459     nsCAutoString filePath;
00460     rv = lockFile->GetNativePath(filePath);
00461     if (NS_FAILED(rv))
00462         return rv;
00463 
00464     rv = LockWithFcntl(filePath);
00465     if (NS_FAILED(rv) && (rv != NS_ERROR_FILE_ACCESS_DENIED))
00466     {
00467         // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED,
00468         // assume we tried an NFS that does not support it. Now, try with symlink.
00469         rv = LockWithSymlink(filePath, PR_FALSE);
00470     }
00471     
00472     if (NS_SUCCEEDED(rv))
00473     {
00474         // Check for the old-style lock used by pre-mozilla 1.3 builds.
00475         // Those builds used an earlier check to prevent the application
00476         // from launching if another instance was already running. Because
00477         // of that, we don't need to create an old-style lock as well.
00478         struct LockProcessInfo
00479         {
00480             ProcessSerialNumber psn;
00481             unsigned long launchDate;
00482         };
00483 
00484         PRFileDesc *fd = nsnull;
00485         PRInt32 ioBytes;
00486         ProcessInfoRec processInfo;
00487         LockProcessInfo lockProcessInfo;
00488 
00489         rv = lockFile->SetLeafName(OLD_LOCKFILE_NAME);
00490         if (NS_FAILED(rv))
00491             return rv;
00492         rv = lockFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
00493         if (NS_SUCCEEDED(rv))
00494         {
00495             ioBytes = PR_Read(fd, &lockProcessInfo, sizeof(LockProcessInfo));
00496             PR_Close(fd);
00497 
00498             if (ioBytes == sizeof(LockProcessInfo))
00499             {
00500                 processInfo.processAppSpec = nsnull;
00501                 processInfo.processName = nsnull;
00502                 processInfo.processInfoLength = sizeof(ProcessInfoRec);
00503                 if (::GetProcessInformation(&lockProcessInfo.psn, &processInfo) == noErr &&
00504                     processInfo.processLaunchDate == lockProcessInfo.launchDate)
00505                 {
00506                     return NS_ERROR_FILE_ACCESS_DENIED;
00507                 }
00508             }
00509             else
00510             {
00511                 NS_WARNING("Could not read lock file - ignoring lock");
00512             }
00513         }
00514         rv = NS_OK; // Don't propagate error from OpenNSPRFileDesc.
00515     }
00516 #elif defined(XP_UNIX)
00517     nsCAutoString filePath;
00518     rv = lockFile->GetNativePath(filePath);
00519     if (NS_FAILED(rv))
00520         return rv;
00521 
00522     // Get the old lockfile name
00523     nsCOMPtr<nsIFile> oldLockFile;
00524     rv = aProfileDir->Clone(getter_AddRefs(oldLockFile));
00525     if (NS_FAILED(rv))
00526         return rv;
00527     rv = oldLockFile->Append(OLD_LOCKFILE_NAME);
00528     if (NS_FAILED(rv))
00529         return rv;
00530     nsCAutoString oldFilePath;
00531     rv = oldLockFile->GetNativePath(oldFilePath);
00532     if (NS_FAILED(rv))
00533         return rv;
00534 
00535     // First, try locking using fcntl. It is more reliable on
00536     // a local machine, but may not be supported by an NFS server.
00537     rv = LockWithFcntl(filePath);
00538     if (NS_SUCCEEDED(rv)) {
00539         // Check to see whether there is a symlink lock held by an older
00540         // Firefox build, and also place our own symlink lock --- but
00541         // mark it "obsolete" so that other newer builds can break the lock
00542         // if they obtain the fcntl lock
00543         rv = LockWithSymlink(oldFilePath, PR_TRUE);
00544 
00545         // If the symlink failed for some reason other than it already
00546         // exists, then something went wrong e.g. the file system
00547         // doesn't support symlinks, or we don't have permission to
00548         // create a symlink there.  In such cases we should just
00549         // continue because it's unlikely there is an old build
00550         // running with a symlink there and we've already successfully
00551         // placed a fcntl lock.
00552         if (rv != NS_ERROR_FILE_ACCESS_DENIED)
00553             rv = NS_OK;
00554     }
00555     else if (rv != NS_ERROR_FILE_ACCESS_DENIED)
00556     {
00557         // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED,
00558         // assume we tried an NFS that does not support it. Now, try with symlink
00559         // using the old symlink path
00560         rv = LockWithSymlink(oldFilePath, PR_FALSE);
00561     }
00562 
00563 #elif defined(XP_WIN)
00564     nsCAutoString filePath;
00565     rv = lockFile->GetNativePath(filePath);
00566     if (NS_FAILED(rv))
00567         return rv;
00568     mLockFileHandle = CreateFile(filePath.get(),
00569                                  GENERIC_READ | GENERIC_WRITE,
00570                                  0, // no sharing - of course
00571                                  nsnull,
00572                                  OPEN_ALWAYS,
00573                                  FILE_FLAG_DELETE_ON_CLOSE,
00574                                  nsnull);
00575     if (mLockFileHandle == INVALID_HANDLE_VALUE) {
00576         // XXXbsmedberg: provide a profile-unlocker here!
00577         return NS_ERROR_FILE_ACCESS_DENIED;
00578     }
00579 #elif defined(XP_OS2)
00580     nsCAutoString filePath;
00581     rv = lockFile->GetNativePath(filePath);
00582     if (NS_FAILED(rv))
00583         return rv;
00584 
00585     ULONG   ulAction = 0;
00586     APIRET  rc;
00587     rc = DosOpen(filePath.get(),
00588                   &mLockFileHandle,
00589                   &ulAction,
00590                   0,
00591                   FILE_NORMAL,
00592                   OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
00593                   OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE | OPEN_FLAGS_NOINHERIT,
00594                   0 );
00595     if (rc != NO_ERROR)
00596     {
00597         mLockFileHandle = -1;
00598         return NS_ERROR_FILE_ACCESS_DENIED;
00599     }
00600 #elif defined(VMS)
00601     nsCAutoString filePath;
00602     rv = lockFile->GetNativePath(filePath);
00603     if (NS_FAILED(rv))
00604         return rv;
00605 
00606     mLockFileDesc = open_noshr(filePath.get(), O_CREAT, 0666);
00607     if (mLockFileDesc == -1)
00608     {
00609        if ((errno == EVMSERR) && (vaxc$errno == RMS$_FLK))
00610        {
00611            return NS_ERROR_FILE_ACCESS_DENIED;
00612        }
00613        else
00614        {
00615            NS_ERROR("Failed to open lock file.");
00616            return NS_ERROR_FAILURE;
00617        }
00618     }
00619 #endif
00620 
00621     mHaveLock = PR_TRUE;
00622 
00623     return rv;
00624 }
00625 
00626 
00627 nsresult nsProfileLock::Unlock()
00628 {
00629     nsresult rv = NS_OK;
00630 
00631     if (mHaveLock)
00632     {
00633 #if defined (XP_WIN)
00634         if (mLockFileHandle != INVALID_HANDLE_VALUE)
00635         {
00636             CloseHandle(mLockFileHandle);
00637             mLockFileHandle = INVALID_HANDLE_VALUE;
00638         }
00639 #elif defined (XP_OS2)
00640         if (mLockFileHandle != -1)
00641         {
00642             DosClose(mLockFileHandle);
00643             mLockFileHandle = -1;
00644         }
00645 #elif defined (XP_UNIX)
00646         if (mPidLockFileName)
00647         {
00648             PR_REMOVE_LINK(this);
00649             (void) unlink(mPidLockFileName);
00650             free(mPidLockFileName);
00651             mPidLockFileName = nsnull;
00652         }
00653         else if (mLockFileDesc != -1)
00654         {
00655             close(mLockFileDesc);
00656             mLockFileDesc = -1;
00657             // Don't remove it
00658         }
00659 #endif
00660 
00661         mHaveLock = PR_FALSE;
00662     }
00663 
00664     return rv;
00665 }