File: LockFileEx.hsc

package info (click to toggle)
haskell-filelock 0.1.1.8-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 88 kB
  • sloc: haskell: 148; makefile: 2
file content (67 lines) | stat: -rw-r--r-- 1,964 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
module System.FileLock.Internal.LockFileEx
#ifndef USE_LOCKFILEEX
  () where
#else
  (Lock, lock, tryLock, unlock) where

#include <windows.h>

import Control.Applicative
import qualified Control.Exception as E
import Data.Bits
import Foreign.Marshal.Alloc
import System.Win32.File
import System.Win32.Mem
import System.Win32.Types

type Lock = HANDLE

lock :: FilePath -> Bool -> IO Lock
lock path exclusive = do
  file <- open path
  (`E.onException` closeHandle file) $ do
    True <- lockFirstByte file exclusive True
    return file

tryLock :: FilePath -> Bool -> IO (Maybe Lock)
tryLock path exclusive = do
  file <- open path
  (`E.onException` closeHandle file) $ do
    r <- lockFirstByte file exclusive False
    if r
      then return $ Just file
      else Nothing <$ closeHandle file

unlock :: Lock -> IO ()
unlock = closeHandle

open :: FilePath -> IO HANDLE
open path =
  createFile path gENERIC_WRITE (fILE_SHARE_READ .|. fILE_SHARE_WRITE)
    Nothing oPEN_ALWAYS fILE_ATTRIBUTE_NORMAL Nothing

lockFirstByte :: HANDLE -> Bool -> Bool -> IO Bool
lockFirstByte handle exclusive block
    = allocaBytes sizeof_OVERLAPPED $ \op -> do
  zeroMemory op $ fromIntegral sizeof_OVERLAPPED
  -- Offset and OffsetHigh fields are set to 0 by zeroMemory.
  r <- c_lockFileEx handle (exFlag .|. blockFlag) 0{-reserved-}
    1{-number of bytes, lower dword-}
    0{-number of bytes, higher dword-}
    op
  if r
    then return True -- success
    else do
      code <- getLastError
      if code == #{const ERROR_LOCK_VIOLATION}
        then return False -- already taken
        else failWith "LockFileEx" code
  where
    exFlag = if exclusive then #{const LOCKFILE_EXCLUSIVE_LOCK} else 0
    blockFlag = if block then 0 else #{const LOCKFILE_FAIL_IMMEDIATELY}
    sizeof_OVERLAPPED = #{size OVERLAPPED}

foreign import stdcall "LockFileEx" c_lockFileEx
  :: HANDLE -> DWORD -> DWORD -> DWORD -> DWORD -> LPOVERLAPPED -> IO BOOL

#endif /* USE_LOCKFILEEX */