@@ -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 ))
6167import GHC.IO.SubSystem ((<!>) )
6268import GHC.IO.Handle.Windows
69+ import GHC.IO.IOMode
6370import GHC.IO.Windows.Handle (fromHANDLE , Io (), NativeHandle (), ConsoleHandle (),
6471 toHANDLE , handleToMode , optimizeFileAccess )
6572import 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+
276321foreign import ccall unsafe " _get_osfhandle"
277322 c_get_osfhandle :: CInt -> IO HANDLE
278323
0 commit comments