Skip to content

T228 #232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed

T228 #232

wants to merge 6 commits into from

Conversation

phadej
Copy link
Contributor

@phadej phadej commented Oct 22, 2019

On top of #231, fixes #228

--- /code/ghc/libraries/base/GHC/IO/Handle/Lock.hsc	2019-04-03 01:58:28.555548614 +0300
+++ hackage-security/src/Hackage/Security/Util/FileLock.hsc	2019-10-22 21:31:28.072930649 +0300
@@ -1,9 +1,13 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE InterruptibleFFI #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE NoImplicitPrelude #-}
-module GHC.IO.Handle.Lock (
+{-# LANGUAGE DeriveDataTypeable #-}
+
+-- | This compat module can be removed once base-4.10 (ghc-8.2) is the minimum
+-- required version. Though note that the locking functionality is not in
+-- public modules in base-4.10, just in the "GHC.IO.Handle.Lock" module.
+--
+-- Copied from @cabal-install@ codebase "Distribution.Client.Compat.FileLock".
+module Hackage.Security.Util.FileLock (
     FileLockingNotSupported(..)
   , LockMode(..)
   , hLock
@@ -11,9 +15,38 @@
   , hUnlock
   ) where
 
-#include "HsBaseConfig.h"
+#if MIN_VERSION_base(4,11,0)
+
+import GHC.IO.Handle.Lock
 
-#if HAVE_FLOCK
+#elif MIN_VERSION_base(4,10,0)
+
+import GHC.IO.Handle.Lock
+
+-- N.B. base-4.10 (GHC 8.2) didn't have hUnlock. For the time being we simply
+-- define this to be a no-op since we generally close the lock handle anyways.
+--
+-- However, do note that on Windows it can take longer for an outstanding
+-- lock to be released after its handle is closed than if the lock were
+-- explicitly released.
+
+hUnlock :: Handle -> IO ()
+hUnlock hdl = return ()
+
+#else
+
+-- The remainder of this file is a modified copy
+-- of GHC.IO.Handle.Lock from ghc-8.9.x
+--
+-- The modifications were just to the imports and the CPP, since we do not have
+-- access to the HAVE_FLOCK from the ./configure script. We approximate the
+-- lack of HAVE_FLOCK with @defined(solaris2_HOST_OS) || defined(aix_HOST_OS)@
+-- instead since those are known major Unix platforms lacking @flock()@ or
+-- having broken one.
+
+-- We avoid using #define as it breaks older hsc2hs
+
+#if defined(solaris2_HOST_OS) || defined(aix_HOST_OS)
 
 #include <sys/file.h>
 
@@ -21,7 +54,6 @@
 import Data.Function
 import Foreign.C.Error
 import Foreign.C.Types
-import GHC.IO.Exception
 import GHC.IO.FD
 import GHC.IO.Handle.FD
 
@@ -52,20 +84,20 @@
 
 import GHC.IO (throwIO)
 
-#endif
+#endif /* HAVE_FLOCK */
 
 import Data.Functor
 import GHC.Base
 import GHC.Exception
 import GHC.IO.Handle.Types
 import GHC.Show
+import Data.Typeable (Typeable)
 
 -- | Exception thrown by 'hLock' on non-Windows platforms that don't support
 -- 'flock'.
 data FileLockingNotSupported = FileLockingNotSupported
-  deriving Show -- ^ @since 4.10.0.0
+  deriving (Typeable, Show)
 
--- ^ @since 4.10.0.0
 instance Exception FileLockingNotSupported
 
 -- | Indicates a mode in which a file should be locked.
@@ -147,10 +179,11 @@
       ret <- with flock $ fcntl fd mode flock_ptr
       case ret of
         0 -> return True
-        _ -> getErrno >>= \errno -> if
-          | not block && errno == eWOULDBLOCK -> return False
-          | errno == eINTR -> retry
-          | otherwise -> ioException $ errnoToIOError ctx errno (Just h) Nothing
+        _ -> getErrno >>= \errno ->
+          case () of
+            _ | not block && errno == eWOULDBLOCK -> return False
+              | errno == eINTR -> retry
+              | otherwise -> ioException $ errnoToIOError ctx errno (Just h) Nothing
   where
     flock = FLock { l_type = case mode of
                                SharedLock -> #{const F_RDLCK}
@@ -180,13 +213,16 @@
 lockImpl h ctx mode block = do
   FD{fdFD = fd} <- handleToFd h
   let flags = cmode .|. (if block then 0 else #{const LOCK_NB})
-  fix $ \retry -> c_flock fd flags >>= \case
-    0 -> return True
-    _ -> getErrno >>= \errno -> if
-      | not block
-      , errno == eAGAIN || errno == eACCES -> return False
-      | errno == eINTR -> retry
-      | otherwise -> ioException $ errnoToIOError ctx errno (Just h) Nothing
+  fix $ \retry -> do
+    ret <- c_flock fd flags
+    case ret of
+      0 -> return True
+      _ -> getErrno >>= \errno ->
+        case () of
+          _ | not block
+            , errno == eAGAIN || errno == eACCES -> return False
+            | errno == eINTR -> retry
+            | otherwise -> ioException $ errnoToIOError ctx errno (Just h) Nothing
   where
     cmode = case mode of
       SharedLock    -> #{const LOCK_SH}
@@ -214,12 +250,15 @@
     -- "locking a region that goes beyond the current end-of-file position is
     -- not an error", hence we pass maximum value as the number of bytes to
     -- lock.
-    fix $ \retry -> c_LockFileEx wh flags 0 0xffffffff 0xffffffff ovrlpd >>= \case
-      True  -> return True
-      False -> getLastError >>= \err -> if
-        | not block && err == #{const ERROR_LOCK_VIOLATION} -> return False
-        | err == #{const ERROR_OPERATION_ABORTED} -> retry
-        | otherwise -> failWith ctx err
+    fix $ \retry -> do
+      ret <- c_LockFileEx wh flags 0 0xffffffff 0xffffffff ovrlpd
+      case ret of
+        True  -> return True
+        False -> getLastError >>= \err ->
+          case () of
+            _ | not block && err == #{const ERROR_LOCK_VIOLATION} -> return False
+              | err == #{const ERROR_OPERATION_ABORTED} -> retry
+              | otherwise -> failWith ctx err
   where
     sizeof_OVERLAPPED = #{size OVERLAPPED}
 
@@ -233,7 +272,8 @@
   wh <- throwErrnoIf (== iNVALID_HANDLE_VALUE) "hUnlock" $ c_get_osfhandle fd
   allocaBytes sizeof_OVERLAPPED $ \ovrlpd -> do
     fillBytes ovrlpd 0 sizeof_OVERLAPPED
-    c_UnlockFileEx wh 0 0xffffffff 0xffffffff ovrlpd >>= \case
+    ret <- c_UnlockFileEx wh 0 0xffffffff 0xffffffff ovrlpd
+    case ret of
       True  -> return ()
       False -> getLastError >>= failWith "hUnlock"
   where
@@ -262,3 +302,5 @@
 unlockImpl _ = throwIO FileLockingNotSupported
 
 #endif
+
+#endif /* MIN_VERSION_base(4,10,0) */

@Avi-D-coder
Copy link

Is anything still blocking this?

@hvr
Copy link
Member

hvr commented Nov 2, 2019

This became moot with #235

@hvr hvr closed this Nov 2, 2019
@phadej phadej deleted the T228 branch November 2, 2019 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Sync up Hackage.Security.Util.FileLock with upstream
4 participants