~n-muench/ubuntu/precise/open-vm-tools/open-vm-tools.raring-precise.backport

« back to all changes in this revision

Viewing changes to lib/file/fileLockPrimitive.c

  • Committer: Package Import Robot
  • Author(s): Nate Muench
  • Date: 2012-01-23 16:09:45 UTC
  • mfrom: (1.4.6) (2.4.26 sid)
  • Revision ID: package-import@ubuntu.com-20120123160945-b6s0r1vkcovucpf3
Tags: 2011.12.20-562307-0ubuntu1
* Merge latest upstream git tag. Fixes building on Precise
  (LP: #898289, LP: #905612)

* Items merged from Debian unstable:
  - debian/control:
    + open-vm-tools recommends open-vm-dkms. (LP: #598933)
    + open-vm-tools now suggests open-vm-toolbox. (LP: #604998)
  (From 2011.08.21-471295-1 release)
  - Updating maintainer and uploaders fields.
  - Removing vcs fields.
  - Removing references to Daniel's old email address.
  - Updating years in copyright file.
  - Updating to standards version 3.9.2.
  - Updating to debhelper version 8.
  - Switching to source format 3.0 (quilt).
  - Removing manual chrpath setting.
  - Removing exclusion from plugins from debhelper shlibs.
  - Rediffing kvers.patch.
  (From 2011.09.23-491607-1 release)
  - Marking binary architecture-dependend packages as linux and kfreebsd
  only.
  - Removing liburiparser-dev from build-depends as upstream dropped
  unity support.
  - Building with libproc-dev on amd64 again.
  - Dropping disabling of dnet support.
  (From 2011.09.23-491607-2 release)
  - Adding doxygen to build-depends for api documentation.
  - Adding libcunit1-dev to build-depends for test suites.
  - Minimizing rules file.
  - Adding open-vm-tools-dev package, containing only the api
    documentation for now.
  (From 2011.09.23-491607-3 release)
  - Sorting overrides in rules alphabetically.
  - Compacting copyright file.
  - Adding udev rule to set timeout for vmware scsi devices
  (From 2011.12.20-562307-1 release)
  - Adding patch to correct typo in upstreams dkms configuration

* Remaining Changes:
  - Remove Stable part of version numbering.
  - debian folder:
    + Re-added open-vm-dkms.postinst & open-vm-dkms.prerm.
      * Allows dkms modules to compile upon installation.
  - debian/control:
    + Re-add open-vm-source and make into a transitional package
      for open-vm-toolbox.
    + Return dependancies that were moved to open-vm-tools back to
      open-vm-toolbox.
  - debian/rules and debian/open-vm-toolbox.lintian-overrides:
    + Make vmware-user-suid-wrapper suid-root
  - debian/rules:
    + Added CFLAGS field with -Wno-deprecated-declarations
      * Will suppress issues with glib 2.31 or later.
    + Add line to copy vmware-xdg-detect-de into place.
    + Install vmware-user.desktop through toolbox package.
  - debian/open-vm-tools.init:
    + Re-add 'modprobe [-r] vmblock'.
    + Add 'modprobe [-r] vmxnet'.
      * Incase it's not loaded during boot.
    + Remove and re-add pcnet32 module
      * Will be done before (remove) and after (readd) vmxnet module
        is added.
      * If vmxnet doesn't exist (aka modules fail to build), pcnet32 can be
        still used for network connectivity.
      * Workaround until a better fix can be done.
  - Re-add gnome-session to debian/local/xautostart.conf
  - Manpages removed (from debian/manpages):
    + vmmemctl.9
    + vmxnet3.9
    + Remove references to manpages that have been removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
#include "random.h"
54
54
#include "vm_atomic.h"
55
55
#include "util.h"
 
56
#include "hostType.h"
56
57
 
57
58
#include "unicodeOperations.h"
58
59
 
86
87
struct FileLockToken
87
88
{
88
89
   uint32  signature;
 
90
   Bool    portable;
89
91
   Unicode pathName;
90
 
   Unicode lockFilePath;  // &implicitReadToken for implicit read locks
 
92
   union {
 
93
      struct {
 
94
         FileIODescriptor lockFd;
 
95
      } mandatory;
 
96
      struct {
 
97
         Unicode lockFilePath;  // &implicitReadToken for implicit read locks
 
98
      } portable;
 
99
   } u;
91
100
};
92
101
 
93
102
 
979
988
int
980
989
FileUnlockIntrinsic(FileLockToken *tokenPtr)  // IN:
981
990
{
982
 
   int err;
 
991
   int err = 0;
983
992
 
984
993
   ASSERT(tokenPtr && (tokenPtr->signature == FILELOCK_TOKEN_SIGNATURE));
985
994
 
986
995
   LOG(1, ("Requesting unlock on %s\n", UTF8(tokenPtr->pathName)));
987
996
 
988
 
   /*
989
 
    * If the lockFilePath (a pointer) is the fixed-address token representing
990
 
    * an implicit read lock, there is no lock file and the token can simply
991
 
    * be discarded.
992
 
    */
993
 
 
994
 
   if (tokenPtr->lockFilePath == &implicitReadToken) {
995
 
      err = 0;
996
 
 
997
 
      free(tokenPtr->pathName);
 
997
   if (tokenPtr->portable) {
 
998
 
 
999
      /*
 
1000
       * If the lockFilePath (a pointer) is the fixed-address token representing
 
1001
       * an implicit read lock, there is no lock file and the token can simply
 
1002
       * be discarded.
 
1003
       */
 
1004
 
 
1005
      if (tokenPtr->u.portable.lockFilePath != &implicitReadToken) {
 
1006
         Unicode lockDir;
 
1007
 
 
1008
         /* The lock directory path */
 
1009
         lockDir = Unicode_Append(tokenPtr->pathName, FILELOCK_SUFFIX);
 
1010
 
 
1011
         /*
 
1012
          * TODO: under vmx86_debug validate the contents of the lock file as
 
1013
          *       matching the machineID and executionID.
 
1014
          */
 
1015
 
 
1016
         err = FileDeletionRobust(tokenPtr->u.portable.lockFilePath, FALSE);
 
1017
 
 
1018
         FileRemoveDirectoryRobust(lockDir); // just in case we can clean up
 
1019
 
 
1020
         if (err && vmx86_debug) {
 
1021
            Log(LGPFX" %s failed for '%s': %s\n", __FUNCTION__,
 
1022
                UTF8(tokenPtr->u.portable.lockFilePath), strerror(err));
 
1023
         }
 
1024
         Unicode_Free(lockDir);
 
1025
         Unicode_Free(tokenPtr->u.portable.lockFilePath);
 
1026
      }
 
1027
 
 
1028
      tokenPtr->u.portable.lockFilePath = NULL;  // Just in case...
998
1029
   } else {
999
 
      Unicode lockDir;
1000
 
 
1001
 
      /* The lock directory path */
1002
 
      lockDir = Unicode_Append(tokenPtr->pathName, FILELOCK_SUFFIX);
1003
 
 
1004
 
      /*
1005
 
       * TODO: under vmx86_debug validate the contents of the lock file as
1006
 
       *       matching the machineID and executionID.
1007
 
       */
1008
 
 
1009
 
      err = FileDeletionRobust(tokenPtr->lockFilePath, FALSE);
1010
 
 
1011
 
      if (err && vmx86_debug) {
1012
 
         Log(LGPFX" %s failed for '%s': %s\n", __FUNCTION__,
1013
 
             UTF8(tokenPtr->lockFilePath), strerror(err));
 
1030
      ASSERT(FileIO_IsValid(&tokenPtr->u.mandatory.lockFd));
 
1031
 
 
1032
     if (FileIO_CloseAndUnlink(&tokenPtr->u.mandatory.lockFd)) {
 
1033
        /*
 
1034
         * Should succeed, but there is an unavoidable race:
 
1035
         * close() must preceed unlink(), but another locker could acquire
 
1036
         * lock between close() and unlink(). Solution: treat EBUSY as
 
1037
         * success.
 
1038
         */
 
1039
        if (Err_Errno() == EBUSY) {
 
1040
           LOG(0, ("Tolerating EBUSY on unlink of advisory lock at %s\n",
 
1041
                   UTF8(tokenPtr->pathName)));
 
1042
        } else {
 
1043
           err = Err_Errno();
 
1044
        }
1014
1045
      }
1015
 
 
1016
 
      /*
1017
 
       * Attempt to clean up the locking directory.
1018
 
       */
1019
 
 
1020
 
      FileRemoveDirectoryRobust(lockDir); // just in case we can clean up
1021
 
 
1022
 
      Unicode_Free(lockDir);
1023
 
      Unicode_Free(tokenPtr->pathName);
1024
 
      Unicode_Free(tokenPtr->lockFilePath);
1025
1046
   }
1026
1047
 
 
1048
   Unicode_Free(tokenPtr->pathName);
1027
1049
   tokenPtr->signature = 0;        // Just in case...
1028
1050
   tokenPtr->pathName = NULL;      // Just in case...
1029
 
   tokenPtr->lockFilePath = NULL;  // Just in case...
1030
1051
   free(tokenPtr);
1031
1052
 
1032
1053
   return err;
1263
1284
            Log(LGPFX" %s: '%s' exists; an old style lock file?\n",
1264
1285
                      __FUNCTION__, UTF8(lockDir));
1265
1286
 
1266
 
            err = EAGAIN;
 
1287
            err = EBUSY;
1267
1288
            break;
1268
1289
        }
1269
1290
 
1474
1495
      return EIO;
1475
1496
   }
1476
1497
 
1477
 
   err = FileRename(entryFilePath, memberFilePath);
 
1498
   err = File_Rename(entryFilePath, memberFilePath);
1478
1499
 
1479
1500
   if (err != 0) {
1480
1501
      Warning(LGPFX" %s FileRename of '%s' to '%s' failed: %s\n",
1501
1522
/*
1502
1523
 *-----------------------------------------------------------------------------
1503
1524
 *
1504
 
 * FileLockIntrinsic --
 
1525
 * FileLockIntrinsicMandatory --
1505
1526
 *
1506
1527
 *      Obtain a lock on a file; shared or exclusive access.
1507
1528
 *
 
1529
 *      This implementation uses the FILEIO_OPEN_LOCK_MANDATORY flag,
 
1530
 *      which requires kernel support for mandatory locking. Such locks
 
1531
 *      are automatically broken if the host holding the lock fails.
 
1532
 *
1508
1533
 *      msecMaxWaitTime specifies the maximum amount of time, in
1509
1534
 *      milliseconds, to wait for the lock before returning the "not
1510
1535
 *      acquired" status. A value of FILELOCK_TRYLOCK_WAIT is the
1524
1549
 *-----------------------------------------------------------------------------
1525
1550
 */
1526
1551
 
1527
 
FileLockToken *
1528
 
FileLockIntrinsic(ConstUnicode pathName,   // IN:
1529
 
                  Bool exclusivity,        // IN:
1530
 
                  uint32 msecMaxWaitTime,  // IN:
1531
 
                  int *err)                // OUT:
1532
 
{
1533
 
   int access;
1534
 
   LockValues myValues;
 
1552
static FileLockToken *
 
1553
FileLockIntrinsicMandatory(ConstUnicode pathName,   // IN:
 
1554
                           ConstUnicode lockFile,   // IN:
 
1555
                           LockValues *myValues,    // IN/OUT:
 
1556
                           int *err)                // OUT:
 
1557
{
 
1558
   int access;
 
1559
   int loopCount = 0;
 
1560
   FileIOResult result;
 
1561
   FileLockToken *tokenPtr = Util_SafeMalloc(sizeof(FileLockToken));
 
1562
 
 
1563
   tokenPtr->signature = FILELOCK_TOKEN_SIGNATURE;
 
1564
   tokenPtr->portable = FALSE;
 
1565
   tokenPtr->pathName = Unicode_Duplicate(pathName);
 
1566
   FileIO_Invalidate(&tokenPtr->u.mandatory.lockFd);
 
1567
 
 
1568
   access = myValues->exclusivity ? FILEIO_OPEN_ACCESS_WRITE
 
1569
                                  : FILEIO_OPEN_ACCESS_READ;
 
1570
   access |= FILEIO_OPEN_EXCLUSIVE_LOCK;
 
1571
 
 
1572
   do {
 
1573
      result = FileIOCreateRetry(&tokenPtr->u.mandatory.lockFd,
 
1574
                                 lockFile, access,
 
1575
                                 FILEIO_OPEN_CREATE, 0600,
 
1576
                                 0);
 
1577
      if (result != FILEIO_LOCK_FAILED) {
 
1578
         break;
 
1579
      }
 
1580
   } while (FileLockSleeper(myValues, &loopCount) == 0);
 
1581
 
 
1582
   if (FileIO_IsSuccess(result)) {
 
1583
      ASSERT(FileIO_IsValid(&tokenPtr->u.mandatory.lockFd));
 
1584
      *err = 0;
 
1585
 
 
1586
      return tokenPtr;
 
1587
   } else {
 
1588
      *err = FileMapErrorToErrno(__FUNCTION__, Err_Errno());
 
1589
      Unicode_Free(tokenPtr->pathName);
 
1590
      ASSERT(!FileIO_IsValid(&tokenPtr->u.mandatory.lockFd));
 
1591
      free(tokenPtr);
 
1592
 
 
1593
      return NULL;
 
1594
   }
 
1595
}
 
1596
 
 
1597
 
 
1598
/*
 
1599
 *-----------------------------------------------------------------------------
 
1600
 *
 
1601
 * FileLockIntrinsicPortable --
 
1602
 *
 
1603
 *      Obtain a lock on a file; shared or exclusive access.
 
1604
 *
 
1605
 *      This implementation uses a HIGHLY portable directory-namespace +
 
1606
 *      Lamport bakery scheme that works on all filesystems that provide atomicity
 
1607
 *      of the directory namespace. (That is, all known filesystems.)
 
1608
 *      The various files involved are hidden within a "pathName.lck/"
 
1609
 *      subdirectory.
 
1610
 *
 
1611
 *      The lock can be broken by removing the subdirectory. The lock
 
1612
 *      is self-cleaning on the same host (e.g. will detect a dead process
 
1613
 *      and will break the lock), but NOT self-cleaning across hosts. The
 
1614
 *      lock does not require any sort of time-based leases or heartbeats.
 
1615
 *
 
1616
 * Results:
 
1617
 *      NULL    Lock not acquired. Check err.
 
1618
 *              err     0       Lock Timed Out
 
1619
 *              err     > 0     errno
 
1620
 *      !NULL   Lock Acquired. This is the "lockToken" for an unlock.
 
1621
 *
 
1622
 * Side effects:
 
1623
 *      None.
 
1624
 *
 
1625
 *-----------------------------------------------------------------------------
 
1626
 */
 
1627
 
 
1628
static FileLockToken *
 
1629
FileLockIntrinsicPortable(ConstUnicode pathName,   // IN:
 
1630
                          ConstUnicode lockDir,    // IN:
 
1631
                          LockValues *myValues,    // IN/OUT:
 
1632
                          int *err)                // OUT:
 
1633
{
 
1634
   int access;
1535
1635
   FileIOResult result;
1536
1636
   FileIODescriptor desc;
1537
1637
   FileLockToken *tokenPtr;
1538
1638
 
1539
 
   Unicode lockDir = NULL;
1540
1639
   Unicode entryFilePath = NULL;
1541
1640
   Unicode memberFilePath = NULL;
1542
1641
   Unicode entryDirectory = NULL;
1544
1643
   ASSERT(pathName);
1545
1644
   ASSERT(err);
1546
1645
 
1547
 
   /* Construct the locking directory path */
1548
 
   lockDir = Unicode_Append(pathName, FILELOCK_SUFFIX);
1549
 
 
1550
 
   /* establish our values */
1551
 
 
1552
 
   myValues.machineID = (char *) FileLockGetMachineID(); // don't free this!
1553
 
   myValues.executionID = FileLockGetExecutionID();      // free this!
1554
 
   myValues.lockType = exclusivity ? LOCK_EXCLUSIVE : LOCK_SHARED;
1555
 
   myValues.lamportNumber = 0;
1556
 
   myValues.locationChecksum = FileLockLocationChecksum(lockDir); // free this!
1557
 
   myValues.waitTime = 0;
1558
 
   myValues.msecMaxWaitTime = msecMaxWaitTime;
1559
 
   myValues.memberName = NULL;
1560
 
 
1561
 
   LOG(1, ("Requesting %s lock on %s (%s, %s, %u).\n",
1562
 
       myValues.lockType, UTF8(pathName), myValues.machineID,
1563
 
       myValues.executionID, myValues.msecMaxWaitTime));
1564
 
 
1565
1646
   /*
1566
1647
    * Attempt to create the locking and entry directories; obtain the
1567
1648
    * entry and member path names.
1569
1650
 
1570
1651
   *err = FileLockCreateEntryDirectory(lockDir, &entryDirectory,
1571
1652
                                       &entryFilePath, &memberFilePath,
1572
 
                                       &myValues.memberName);
 
1653
                                       &myValues->memberName);
1573
1654
 
1574
1655
   switch (*err) {
1575
1656
   case 0:
1578
1659
   case EROFS:
1579
1660
      /* FALL THROUGH */
1580
1661
   case EACCES:
1581
 
      if (!exclusivity) {
 
1662
      if (!myValues->exclusivity) {
1582
1663
         /*
1583
1664
          * Lock is for read/shared access however the lock directory could
1584
1665
          * not be created. Grant an implicit read lock whenever possible.
1626
1707
   }
1627
1708
 
1628
1709
   /* what is max(Number[1]... Number[all lockers])? */
1629
 
   *err = FileLockScanner(lockDir, FileLockNumberScan, &myValues, FALSE);
 
1710
   *err = FileLockScanner(lockDir, FileLockNumberScan, myValues, FALSE);
1630
1711
 
1631
1712
   if (*err != 0) {
1632
1713
      /* clean up */
1639
1720
   }
1640
1721
 
1641
1722
   /* Number[i] = 1 + max([Number[1]... Number[all lockers]) */
1642
 
   myValues.lamportNumber++;
 
1723
   myValues->lamportNumber++;
1643
1724
 
1644
1725
   /* Attempt to create the member file */
1645
 
   *err = FileLockCreateMemberFile(&desc, &myValues, entryFilePath,
 
1726
   *err = FileLockCreateMemberFile(&desc, myValues, entryFilePath,
1646
1727
                                   memberFilePath);
1647
1728
 
1648
1729
   /* Remove entry directory; it has done its job */
1659
1740
 
1660
1741
   /* Attempt to acquire the lock */
1661
1742
   *err = FileLockScanner(lockDir, FileLockWaitForPossession,
1662
 
                          &myValues, TRUE);
 
1743
                          myValues, TRUE);
1663
1744
 
1664
1745
   switch (*err) {
1665
1746
   case 0:
1677
1758
 
1678
1759
bail:
1679
1760
 
1680
 
   Unicode_Free(lockDir);
1681
1761
   Unicode_Free(entryDirectory);
1682
1762
   Unicode_Free(entryFilePath);
1683
 
   Unicode_Free(myValues.memberName);
1684
 
   free(myValues.locationChecksum);
1685
 
   free(myValues.executionID);
1686
1763
 
1687
1764
   if (*err == 0) {
1688
1765
      tokenPtr = Util_SafeMalloc(sizeof(FileLockToken));
1689
1766
 
1690
1767
      tokenPtr->signature = FILELOCK_TOKEN_SIGNATURE;
 
1768
      tokenPtr->portable = TRUE;
1691
1769
      tokenPtr->pathName = Unicode_Duplicate(pathName);
1692
 
      tokenPtr->lockFilePath = memberFilePath;
 
1770
      tokenPtr->u.portable.lockFilePath = memberFilePath;
1693
1771
   } else {
1694
1772
      Unicode_Free(memberFilePath);
1695
1773
      tokenPtr = NULL;
1706
1784
/*
1707
1785
 *-----------------------------------------------------------------------------
1708
1786
 *
1709
 
 * FileLockIsLocked --
1710
 
 *
1711
 
 *      Is a file currently locked (at the time of the call)?
1712
 
 *
1713
 
 * Results:
1714
 
 *      TRUE    YES
1715
 
 *      FALSE   NO; if err is not NULL may check *err for an error
1716
 
 *
1717
 
 * Side effects:
1718
 
 *      None.
1719
 
 *
1720
 
 *-----------------------------------------------------------------------------
1721
 
 */
1722
 
 
1723
 
Bool
1724
 
FileLockIsLocked(ConstUnicode pathName,  // IN:
1725
 
                 int *err)               // OUT:
 
1787
 * FileLockIntrinsic --
 
1788
 *
 
1789
 *      Obtain a lock on a file; shared or exclusive access.
 
1790
 *
 
1791
 *      All FileLock_-based locks are advisory locks (i.e. the
 
1792
 *      lock is maintained separately from the file so only FileLock_
 
1793
 *      callers experience locking). Advisory locks have an inherent problem
 
1794
 *      that they are difficult to break in the event one of the cooperating
 
1795
 *      entities fails, particularly across distributed filesystems.
 
1796
 *
 
1797
 *      This wrapper function will adaptively switch between a scheme
 
1798
 *      implemented via mandatory locks and a more portable scheme depending
 
1799
 *      on host OS support.
 
1800
 *
 
1801
 *      msecMaxWaitTime specifies the maximum amount of time, in
 
1802
 *      milliseconds, to wait for the lock before returning the "not
 
1803
 *      acquired" status. A value of FILELOCK_TRYLOCK_WAIT is the
 
1804
 *      equivalent of a "try lock" - the lock will be acquired only if
 
1805
 *      there is no contention. A value of FILELOCK_INFINITE_WAIT
 
1806
 *      specifies "waiting forever" to acquire the lock.
 
1807
 *
 
1808
 * Results:
 
1809
 *      NULL    Lock not acquired. Check err.
 
1810
 *              err     0       Lock Timed Out
 
1811
 *              err     > 0     errno
 
1812
 *      !NULL   Lock Acquired. This is the "lockToken" for an unlock.
 
1813
 *
 
1814
 * Side effects:
 
1815
 *      None.
 
1816
 *
 
1817
 *-----------------------------------------------------------------------------
 
1818
 */
 
1819
 
 
1820
FileLockToken *
 
1821
FileLockIntrinsic(ConstUnicode pathName,   // IN:
 
1822
                  Bool exclusivity,        // IN:
 
1823
                  uint32 msecMaxWaitTime,  // IN:
 
1824
                  int *err)                // OUT:
 
1825
{
 
1826
   Unicode lockBase;
 
1827
   LockValues myValues = { 0 };
 
1828
   FileLockToken *tokenPtr;
 
1829
 
 
1830
   /* Construct the locking directory path */
 
1831
   lockBase = Unicode_Append(pathName, FILELOCK_SUFFIX);
 
1832
 
 
1833
   myValues.lockType = exclusivity ? LOCK_EXCLUSIVE : LOCK_SHARED;
 
1834
   myValues.waitTime = 0;
 
1835
   myValues.msecMaxWaitTime = msecMaxWaitTime;
 
1836
 
 
1837
   if (File_SupportsMandatoryLock(pathName)) {
 
1838
      LOG(1, ("Requesting %s lock on %s (mandatory, %u).\n",
 
1839
          myValues.lockType, UTF8(pathName), myValues.msecMaxWaitTime));
 
1840
 
 
1841
      tokenPtr = FileLockIntrinsicMandatory(pathName, lockBase, &myValues, err);
 
1842
   } else {
 
1843
      myValues.machineID = (char *) FileLockGetMachineID(); // don't free this!
 
1844
      myValues.executionID = FileLockGetExecutionID();      // free this!
 
1845
      myValues.lamportNumber = 0;
 
1846
      myValues.locationChecksum = FileLockLocationChecksum(lockBase); // free this!
 
1847
      myValues.memberName = NULL;
 
1848
 
 
1849
      LOG(1, ("Requesting %s lock on %s (%s, %s, %u).\n",
 
1850
          myValues.lockType, UTF8(pathName), myValues.machineID,
 
1851
          myValues.executionID, myValues.msecMaxWaitTime));
 
1852
 
 
1853
      tokenPtr = FileLockIntrinsicPortable(pathName, lockBase, &myValues, err);
 
1854
 
 
1855
      Unicode_Free(myValues.memberName);
 
1856
      free(myValues.locationChecksum);
 
1857
      free(myValues.executionID);
 
1858
   }
 
1859
 
 
1860
   Unicode_Free(lockBase);
 
1861
 
 
1862
   return tokenPtr;
 
1863
}
 
1864
 
 
1865
 
 
1866
/*
 
1867
 *-----------------------------------------------------------------------------
 
1868
 *
 
1869
 * FileLockIsLockedMandatory --
 
1870
 *
 
1871
 *      Is a file currently locked (at the time of the call)?
 
1872
 *
 
1873
 *      The only way to check for a mandatory lock is to try opening
 
1874
 *      the file (and quickly closing it again). If the lock is held,
 
1875
 *      attempting to open the file will return FILEIO_LOCK_FAILED.
 
1876
 *
 
1877
 * Results:
 
1878
 *      TRUE    YES
 
1879
 *      FALSE   NO; if err is not NULL may check *err for an error
 
1880
 *
 
1881
 * Side effects:
 
1882
 *      None.
 
1883
 *
 
1884
 *-----------------------------------------------------------------------------
 
1885
 */
 
1886
 
 
1887
static Bool
 
1888
FileLockIsLockedMandatory(ConstUnicode lockFile,  // IN:
 
1889
                          int *err)               // OUT/OPT:
 
1890
{
 
1891
   int access;
 
1892
   FileIOResult result;
 
1893
   FileIODescriptor desc;
 
1894
 
 
1895
   FileIO_Invalidate(&desc);
 
1896
 
 
1897
   /*
 
1898
    * Check for lock by actually locking file, and dropping
 
1899
    * lock quickly if open was successful.
 
1900
    */
 
1901
 
 
1902
   access = FILEIO_OPEN_ACCESS_READ | FILEIO_OPEN_ACCESS_WRITE |
 
1903
            FILEIO_OPEN_EXCLUSIVE_LOCK;
 
1904
 
 
1905
   result = FileIOCreateRetry(&desc, lockFile, access, FILEIO_OPEN, 0644, 0);
 
1906
 
 
1907
   if (FileIO_IsSuccess(result)) {
 
1908
      Bool ret;
 
1909
 
 
1910
      ret = FileIO_Close(&desc);
 
1911
 
 
1912
      ASSERT(!ret);
 
1913
      return FALSE;
 
1914
   } else if (result == FILEIO_LOCK_FAILED) {
 
1915
      return TRUE;   // locked
 
1916
   } else if (result == FILEIO_FILE_NOT_FOUND) {
 
1917
      return FALSE;  // no lock file means unlocked
 
1918
   } else {
 
1919
      if (err != NULL) {
 
1920
         *err = FileMapErrorToErrno(__FUNCTION__, Err_Errno());
 
1921
      }
 
1922
 
 
1923
      return FALSE;
 
1924
   }
 
1925
}
 
1926
 
 
1927
 
 
1928
/*
 
1929
 *-----------------------------------------------------------------------------
 
1930
 *
 
1931
 * FileLockIsLockedPortable --
 
1932
 *
 
1933
 *      Is a file currently locked (at the time of the call)?
 
1934
 *
 
1935
 *      The "portable" lock is held if the lock directory exists and
 
1936
 *      there are any "M" entries (representing held locks).
 
1937
 *
 
1938
 *      FileLocks implemented via mandatory locking are reported
 
1939
 *      as held locks (errno == ENOTDIR).
 
1940
 *
 
1941
 * Results:
 
1942
 *      TRUE    YES
 
1943
 *      FALSE   NO; if err is not NULL may check *err for an error
 
1944
 *
 
1945
 * Side effects:
 
1946
 *      None.
 
1947
 *
 
1948
 *-----------------------------------------------------------------------------
 
1949
 */
 
1950
 
 
1951
static Bool
 
1952
FileLockIsLockedPortable(ConstUnicode lockDir,  // IN:
 
1953
                         int *err)              // OUT/OPT:
1726
1954
{
1727
1955
   uint32 i;
1728
1956
   int numEntries;
1729
 
   Unicode lockDir;
1730
 
 
1731
 
   int errValue = 0;
1732
1957
   Bool isLocked = FALSE;
1733
1958
   Unicode *fileList = NULL;
1734
1959
 
1735
 
   lockDir = Unicode_Append(pathName, FILELOCK_SUFFIX);
1736
 
 
1737
1960
   numEntries = FileListDirectoryRobust(lockDir, &fileList);
1738
1961
 
1739
1962
   if (numEntries == -1) {
1741
1964
       * If the lock directory doesn't exist, we should not count this
1742
1965
       * as an error.  This is expected if the file isn't locked.
1743
1966
       */
1744
 
      if (errno != ENOENT) {
1745
 
         errValue = errno;
 
1967
 
 
1968
      if (err != NULL) {
 
1969
         *err = (errno == ENOENT) ? 0 : errno;
1746
1970
      }
1747
1971
 
1748
 
      goto bail;
 
1972
      return FALSE;
1749
1973
   }
1750
1974
 
1751
1975
   for (i = 0; i < numEntries; i++) {
1761
1985
 
1762
1986
   free(fileList);
1763
1987
 
1764
 
bail:
1765
 
   Unicode_Free(lockDir);
1766
 
 
1767
 
   if (err != NULL) {
1768
 
      *err = errValue;
 
1988
   return isLocked;
 
1989
}
 
1990
 
 
1991
 
 
1992
/*
 
1993
 *-----------------------------------------------------------------------------
 
1994
 *
 
1995
 * FileLockIsLocked --
 
1996
 *
 
1997
 *      Is a file currently locked (at the time of the call)?
 
1998
 *
 
1999
 * Results:
 
2000
 *      TRUE    YES
 
2001
 *      FALSE   NO; if err is not NULL may check *err for an error
 
2002
 *
 
2003
 * Side effects:
 
2004
 *      None.
 
2005
 *
 
2006
 *-----------------------------------------------------------------------------
 
2007
 */
 
2008
 
 
2009
Bool
 
2010
FileLockIsLocked(ConstUnicode pathName,  // IN:
 
2011
                 int *err)               // OUT/OPT:
 
2012
{
 
2013
   Bool isLocked;
 
2014
   Unicode lockBase;
 
2015
 
 
2016
   ASSERT(pathName);
 
2017
 
 
2018
   lockBase = Unicode_Append(pathName, FILELOCK_SUFFIX);
 
2019
 
 
2020
   if (File_SupportsMandatoryLock(pathName)) {
 
2021
      isLocked = FileLockIsLockedMandatory(lockBase, err);
 
2022
   } else {
 
2023
      isLocked = FileLockIsLockedPortable(lockBase, err);
1769
2024
   }
1770
2025
 
 
2026
   Unicode_Free(lockBase);
 
2027
 
1771
2028
   return isLocked;
1772
2029
}
1773
2030