diff options
Diffstat (limited to 'libraries/ghc-boot/GHC/PackageDb.hs')
-rw-r--r-- | libraries/ghc-boot/GHC/PackageDb.hs | 49 |
1 files changed, 21 insertions, 28 deletions
diff --git a/libraries/ghc-boot/GHC/PackageDb.hs b/libraries/ghc-boot/GHC/PackageDb.hs index bf83d25baa..5de3a5fc74 100644 --- a/libraries/ghc-boot/GHC/PackageDb.hs +++ b/libraries/ghc-boot/GHC/PackageDb.hs @@ -64,6 +64,7 @@ module GHC.PackageDb ( writePackageDb ) where +import Prelude -- See note [Why do we import Prelude here?] import Data.Version (Version(..)) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BS.Char8 @@ -80,9 +81,7 @@ import System.FilePath import System.IO import System.IO.Error import GHC.IO.Exception (IOErrorType(InappropriateType)) -#if MIN_VERSION_base(4,10,0) import GHC.IO.Handle.Lock -#endif import System.Directory @@ -209,12 +208,7 @@ emptyInstalledPackageInfo = } -- | Represents a lock of a package db. -newtype PackageDbLock = PackageDbLock -#if MIN_VERSION_base(4,10,0) - Handle -#else - () -- no locking primitives available in base < 4.10 -#endif +newtype PackageDbLock = PackageDbLock Handle -- | Acquire an exclusive lock related to package DB under given location. lockPackageDb :: FilePath -> IO PackageDbLock @@ -222,8 +216,6 @@ lockPackageDb :: FilePath -> IO PackageDbLock -- | Release the lock related to package DB. unlockPackageDb :: PackageDbLock -> IO () -#if MIN_VERSION_base(4,10,0) - -- | Acquire a lock of given type related to package DB under given location. lockPackageDbWith :: LockMode -> FilePath -> IO PackageDbLock lockPackageDbWith mode file = do @@ -239,15 +231,21 @@ lockPackageDbWith mode file = do -- DB for reading then we will require that the installer/packaging has -- included the lock file. -- - -- Thus the logic here is to first try opening in read-only mode (to handle - -- global read-only DBs) and if the file does not exist then try opening in - -- read/write mode to create the lock file. If either succeed then lock the - -- file. IO exceptions (other than the first open attempt failing due to the - -- file not existing) simply propagate. + -- Thus the logic here is to first try opening in read-write mode + -- and if that fails we try read-only (to handle global read-only DBs). + -- If either succeed then lock the file. IO exceptions (other than the first + -- open attempt failing due to the file not existing) simply propagate. + -- + -- Note that there is a complexity here which was discovered in #13945: some + -- filesystems (e.g. NFS) will only allow exclusive locking if the fd was + -- opened for write access. We would previously try opening the lockfile for + -- read-only access first, however this failed when run on such filesystems. + -- Consequently, we now try read-write access first, falling back to read-only + -- if we are denied permission (e.g. in the case of a global database). catchJust - (\e -> if isDoesNotExistError e then Just () else Nothing) - (lockFileOpenIn ReadMode) - (const $ lockFileOpenIn ReadWriteMode) + (\e -> if isPermissionError e then Just () else Nothing) + (lockFileOpenIn ReadWriteMode) + (const $ lockFileOpenIn ReadMode) where lock = file <.> "lock" @@ -261,16 +259,11 @@ lockPackageDbWith mode file = do return $ PackageDbLock hnd lockPackageDb = lockPackageDbWith ExclusiveLock -unlockPackageDb (PackageDbLock hnd) = hClose hnd - --- MIN_VERSION_base(4,10,0) -#else - -lockPackageDb _file = return $ PackageDbLock () -unlockPackageDb _lock = return () - --- MIN_VERSION_base(4,10,0) +unlockPackageDb (PackageDbLock hnd) = do +#if MIN_VERSION_base(4,11,0) + hUnlock hnd #endif + hClose hnd -- | Mode to open a package db in. data DbMode = DbReadOnly | DbReadWrite @@ -400,7 +393,7 @@ decodeFromFile file mode decoder = case mode of -- shared lock on non-Windows platform because we update the database with an -- atomic rename, so readers will always see the database in a consistent -- state. -#if MIN_VERSION_base(4,10,0) && defined(mingw32_HOST_OS) +#if defined(mingw32_HOST_OS) bracket (lockPackageDbWith SharedLock file) unlockPackageDb $ \_ -> do #endif (, DbOpenReadOnly) <$> decodeFileContents |