Skip to content

Commit 9461e74

Browse files
committed
winio: Fix file locking
1 parent 0c39049 commit 9461e74

File tree

1 file changed

+49
-4
lines changed

1 file changed

+49
-4
lines changed

System/Win32/Types.hsc

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,20 @@ finiteBitSize = bitSize
5757
#endif
5858

5959
##if defined(__IO_MANAGER_WINIO__)
60-
import GHC.IO.Exception (ioException, IOException(..), IOErrorType(InappropriateType))
60+
import Control.Monad (when, liftM2)
61+
import Foreign.C.Types (CUIntPtr(..))
62+
import Foreign.Marshal.Utils (fromBool, with)
63+
import Foreign (peek)
64+
import Foreign.Ptr (ptrToWordPtr)
65+
import GHC.IO.Exception (ioException, IOException(..),
66+
IOErrorType(InappropriateType, ResourceBusy))
6167
import GHC.IO.SubSystem ((<!>))
6268
import GHC.IO.Handle.Windows
69+
import GHC.IO.IOMode
6370
import GHC.IO.Windows.Handle (fromHANDLE, Io(), NativeHandle(), ConsoleHandle(),
6471
toHANDLE, handleToMode, optimizeFileAccess)
6572
import qualified GHC.Event.Windows as Mgr
66-
import GHC.IO.Device (IODeviceType(..))
73+
import GHC.IO.Device (IODeviceType(..), devType)
6774
##endif
6875

6976
#include <fcntl.h>
@@ -264,15 +271,53 @@ hANDLEToHandle handle = posix
264271
-- Attach the handle to the I/O manager's CompletionPort. This allows the
265272
-- I/O manager to service requests for this Handle.
266273
Mgr.associateHandle' handle
267-
optimizeFileAccess handle
268274
let hwnd = fromHANDLE handle :: Io NativeHandle
269-
-- Not sure if I need to use devType here..
275+
_type <- devType hwnd
276+
277+
-- Use the rts to enforce any file locking we may need.
270278
mode <- handleToMode handle
279+
let write_lock = mode /= ReadMode
280+
281+
case _type of
282+
-- Regular files need to be locked.
283+
-- See also Note [RTS File locking]
284+
RegularFile -> do
285+
optimizeFileAccess handle -- Set a few optimization flags on file handles.
286+
(unique_dev, unique_ino) <- getUniqueFileInfo handle
287+
r <- internal_lockFile
288+
(fromIntegral $ ptrToWordPtr handle) unique_dev unique_ino
289+
(fromBool write_lock)
290+
when (r == -1) $
291+
ioException (IOError Nothing ResourceBusy "hANDLEToHandle"
292+
"file is locked" Nothing Nothing)
293+
294+
-- I don't see a reason for blocking directories. So unlike the FD
295+
-- implementation I'll allow it.
296+
_ -> return ()
271297
mkHandleFromHANDLE hwnd Stream ("hwnd:" ++ show handle) mode Nothing
298+
299+
-- | getUniqueFileInfo assumes the C call to getUniqueFileInfo
300+
-- succeeds.
301+
getUniqueFileInfo :: HANDLE -> IO (Word64, Word64)
302+
getUniqueFileInfo hnl = do
303+
with 0 $ \devptr -> do
304+
with 0 $ \inoptr -> do
305+
internal_getUniqueFileInfo hnl devptr inoptr
306+
liftM2 (,) (peek devptr) (peek inoptr)
272307
##endif
273308
posix = _open_osfhandle (fromIntegral (ptrToIntPtr handle))
274309
(#const _O_BINARY) >>= fdToHandle
275310

311+
##if defined(__IO_MANAGER_WINIO__)
312+
foreign import ccall unsafe "lockFile"
313+
internal_lockFile :: CUIntPtr -> Word64 -> Word64 -> CInt -> IO CInt
314+
315+
-- | Returns -1 on error. Otherwise writes two values representing
316+
-- the file into the given ptrs.
317+
foreign import ccall unsafe "get_unique_file_info_hwnd"
318+
internal_getUniqueFileInfo :: HANDLE -> Ptr Word64 -> Ptr Word64 -> IO ()
319+
##endif
320+
276321
foreign import ccall unsafe "_get_osfhandle"
277322
c_get_osfhandle :: CInt -> IO HANDLE
278323

0 commit comments

Comments
 (0)