{-# LINE 1 "libraries\Win32\System\Win32\File.hsc" #-}

{-# LINE 2 "libraries\Win32\System\Win32\File.hsc" #-}
{-# LANGUAGE Trustworthy #-}

{-# LINE 4 "libraries\Win32\System\Win32\File.hsc" #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  System.Win32.File
-- Copyright   :  (c) Alastair Reid, 1997-2003
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  Esa Ilari Vuokko <[email protected]>
-- Stability   :  provisional
-- Portability :  portable
--
-- A collection of FFI declarations for interfacing with Win32.
--
-----------------------------------------------------------------------------

module System.Win32.File
{-
	( AccessMode, ShareMode, CreateMode, FileAttributeOrFlag
	, CreateFile, CloseHandle, DeleteFile, CopyFile
	, MoveFileFlag, MoveFile, MoveFileEx,
	)
-}
where

import System.Win32.Types
import System.Win32.Time

import Foreign hiding (void)
import Control.Monad
import Control.Concurrent

#include "windows_cconv.h"


{-# LINE 37 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------
-- Enumeration types
----------------------------------------------------------------

type AccessMode   = UINT

gENERIC_NONE :: AccessMode
gENERIC_NONE = 0

gENERIC_READ              :: AccessMode
gENERIC_READ              =  2147483648
gENERIC_WRITE             :: AccessMode
gENERIC_WRITE             =  1073741824
gENERIC_EXECUTE           :: AccessMode
gENERIC_EXECUTE           =  536870912
gENERIC_ALL               :: AccessMode
gENERIC_ALL               =  268435456
dELETE                    :: AccessMode
dELETE                    =  65536
rEAD_CONTROL              :: AccessMode
rEAD_CONTROL              =  131072
wRITE_DAC                 :: AccessMode
wRITE_DAC                 =  262144
wRITE_OWNER               :: AccessMode
wRITE_OWNER               =  524288
sYNCHRONIZE               :: AccessMode
sYNCHRONIZE               =  1048576
sTANDARD_RIGHTS_REQUIRED  :: AccessMode
sTANDARD_RIGHTS_REQUIRED  =  983040
sTANDARD_RIGHTS_READ      :: AccessMode
sTANDARD_RIGHTS_READ      =  131072
sTANDARD_RIGHTS_WRITE     :: AccessMode
sTANDARD_RIGHTS_WRITE     =  131072
sTANDARD_RIGHTS_EXECUTE   :: AccessMode
sTANDARD_RIGHTS_EXECUTE   =  131072
sTANDARD_RIGHTS_ALL       :: AccessMode
sTANDARD_RIGHTS_ALL       =  2031616
sPECIFIC_RIGHTS_ALL       :: AccessMode
sPECIFIC_RIGHTS_ALL       =  65535
aCCESS_SYSTEM_SECURITY    :: AccessMode
aCCESS_SYSTEM_SECURITY    =  16777216
mAXIMUM_ALLOWED           :: AccessMode
mAXIMUM_ALLOWED           =  33554432

{-# LINE 66 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type ShareMode   = UINT

fILE_SHARE_NONE :: ShareMode
fILE_SHARE_NONE = 0

fILE_SHARE_READ       :: ShareMode
fILE_SHARE_READ       =  1
fILE_SHARE_WRITE      :: ShareMode
fILE_SHARE_WRITE      =  2

{-# LINE 78 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type CreateMode   = UINT

cREATE_NEW            :: CreateMode
cREATE_NEW            =  1
cREATE_ALWAYS         :: CreateMode
cREATE_ALWAYS         =  2
oPEN_EXISTING         :: CreateMode
oPEN_EXISTING         =  3
oPEN_ALWAYS           :: CreateMode
oPEN_ALWAYS           =  4
tRUNCATE_EXISTING     :: CreateMode
tRUNCATE_EXISTING     =  5

{-# LINE 90 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type FileAttributeOrFlag   = UINT

fILE_ATTRIBUTE_READONLY       :: FileAttributeOrFlag
fILE_ATTRIBUTE_READONLY       =  1
fILE_ATTRIBUTE_HIDDEN         :: FileAttributeOrFlag
fILE_ATTRIBUTE_HIDDEN         =  2
fILE_ATTRIBUTE_SYSTEM         :: FileAttributeOrFlag
fILE_ATTRIBUTE_SYSTEM         =  4
fILE_ATTRIBUTE_DIRECTORY      :: FileAttributeOrFlag
fILE_ATTRIBUTE_DIRECTORY      =  16
fILE_ATTRIBUTE_ARCHIVE        :: FileAttributeOrFlag
fILE_ATTRIBUTE_ARCHIVE        =  32
fILE_ATTRIBUTE_NORMAL         :: FileAttributeOrFlag
fILE_ATTRIBUTE_NORMAL         =  128
fILE_ATTRIBUTE_TEMPORARY      :: FileAttributeOrFlag
fILE_ATTRIBUTE_TEMPORARY      =  256
fILE_ATTRIBUTE_COMPRESSED     :: FileAttributeOrFlag
fILE_ATTRIBUTE_COMPRESSED     =  2048
fILE_FLAG_WRITE_THROUGH       :: FileAttributeOrFlag
fILE_FLAG_WRITE_THROUGH       =  2147483648
fILE_FLAG_OVERLAPPED          :: FileAttributeOrFlag
fILE_FLAG_OVERLAPPED          =  1073741824
fILE_FLAG_NO_BUFFERING        :: FileAttributeOrFlag
fILE_FLAG_NO_BUFFERING        =  536870912
fILE_FLAG_RANDOM_ACCESS       :: FileAttributeOrFlag
fILE_FLAG_RANDOM_ACCESS       =  268435456
fILE_FLAG_SEQUENTIAL_SCAN     :: FileAttributeOrFlag
fILE_FLAG_SEQUENTIAL_SCAN     =  134217728
fILE_FLAG_DELETE_ON_CLOSE     :: FileAttributeOrFlag
fILE_FLAG_DELETE_ON_CLOSE     =  67108864
fILE_FLAG_BACKUP_SEMANTICS    :: FileAttributeOrFlag
fILE_FLAG_BACKUP_SEMANTICS    =  33554432
fILE_FLAG_POSIX_SEMANTICS     :: FileAttributeOrFlag
fILE_FLAG_POSIX_SEMANTICS     =  16777216

{-# LINE 113 "libraries\Win32\System\Win32\File.hsc" #-}

{-# LINE 114 "libraries\Win32\System\Win32\File.hsc" #-}
sECURITY_ANONYMOUS            :: FileAttributeOrFlag
sECURITY_ANONYMOUS            =  0
sECURITY_IDENTIFICATION       :: FileAttributeOrFlag
sECURITY_IDENTIFICATION       =  65536
sECURITY_IMPERSONATION        :: FileAttributeOrFlag
sECURITY_IMPERSONATION        =  131072
sECURITY_DELEGATION           :: FileAttributeOrFlag
sECURITY_DELEGATION           =  196608
sECURITY_CONTEXT_TRACKING     :: FileAttributeOrFlag
sECURITY_CONTEXT_TRACKING     =  262144
sECURITY_EFFECTIVE_ONLY       :: FileAttributeOrFlag
sECURITY_EFFECTIVE_ONLY       =  524288
sECURITY_SQOS_PRESENT         :: FileAttributeOrFlag
sECURITY_SQOS_PRESENT         =  1048576
sECURITY_VALID_SQOS_FLAGS     :: FileAttributeOrFlag
sECURITY_VALID_SQOS_FLAGS     =  2031616

{-# LINE 124 "libraries\Win32\System\Win32\File.hsc" #-}

{-# LINE 125 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type MoveFileFlag   = DWORD

mOVEFILE_REPLACE_EXISTING	 :: MoveFileFlag
mOVEFILE_REPLACE_EXISTING	 =  1
mOVEFILE_COPY_ALLOWED	 :: MoveFileFlag
mOVEFILE_COPY_ALLOWED	 =  2
mOVEFILE_DELAY_UNTIL_REBOOT	 :: MoveFileFlag
mOVEFILE_DELAY_UNTIL_REBOOT	 =  4

{-# LINE 135 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type FilePtrDirection   = DWORD

fILE_BEGIN    :: FilePtrDirection
fILE_BEGIN    =  0
fILE_CURRENT  :: FilePtrDirection
fILE_CURRENT  =  1
fILE_END      :: FilePtrDirection
fILE_END      =  2

{-# LINE 145 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type DriveType = UINT

dRIVE_UNKNOWN         :: DriveType
dRIVE_UNKNOWN         =  0
dRIVE_NO_ROOT_DIR     :: DriveType
dRIVE_NO_ROOT_DIR     =  1
dRIVE_REMOVABLE       :: DriveType
dRIVE_REMOVABLE       =  2
dRIVE_FIXED           :: DriveType
dRIVE_FIXED           =  3
dRIVE_REMOTE          :: DriveType
dRIVE_REMOTE          =  4
dRIVE_CDROM           :: DriveType
dRIVE_CDROM           =  5
dRIVE_RAMDISK         :: DriveType
dRIVE_RAMDISK         =  6

{-# LINE 159 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type DefineDosDeviceFlags = DWORD

dDD_RAW_TARGET_PATH           :: DefineDosDeviceFlags
dDD_RAW_TARGET_PATH           =  1
dDD_REMOVE_DEFINITION         :: DefineDosDeviceFlags
dDD_REMOVE_DEFINITION         =  2
dDD_EXACT_MATCH_ON_REMOVE     :: DefineDosDeviceFlags
dDD_EXACT_MATCH_ON_REMOVE     =  4

{-# LINE 169 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type BinaryType = DWORD

sCS_32BIT_BINARY      :: BinaryType
sCS_32BIT_BINARY      =  0
sCS_DOS_BINARY        :: BinaryType
sCS_DOS_BINARY        =  1
sCS_WOW_BINARY        :: BinaryType
sCS_WOW_BINARY        =  2
sCS_PIF_BINARY        :: BinaryType
sCS_PIF_BINARY        =  3
sCS_POSIX_BINARY      :: BinaryType
sCS_POSIX_BINARY      =  4
sCS_OS216_BINARY      :: BinaryType
sCS_OS216_BINARY      =  5

{-# LINE 182 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type FileNotificationFlag = DWORD

fILE_NOTIFY_CHANGE_FILE_NAME   :: FileNotificationFlag
fILE_NOTIFY_CHANGE_FILE_NAME   =  1
fILE_NOTIFY_CHANGE_DIR_NAME    :: FileNotificationFlag
fILE_NOTIFY_CHANGE_DIR_NAME    =  2
fILE_NOTIFY_CHANGE_ATTRIBUTES  :: FileNotificationFlag
fILE_NOTIFY_CHANGE_ATTRIBUTES  =  4
fILE_NOTIFY_CHANGE_SIZE        :: FileNotificationFlag
fILE_NOTIFY_CHANGE_SIZE        =  8
fILE_NOTIFY_CHANGE_LAST_WRITE  :: FileNotificationFlag
fILE_NOTIFY_CHANGE_LAST_WRITE  =  16
fILE_NOTIFY_CHANGE_SECURITY    :: FileNotificationFlag
fILE_NOTIFY_CHANGE_SECURITY    =  256

{-# LINE 195 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type FileType = DWORD

fILE_TYPE_UNKNOWN     :: FileType
fILE_TYPE_UNKNOWN     =  0
fILE_TYPE_DISK        :: FileType
fILE_TYPE_DISK        =  1
fILE_TYPE_CHAR        :: FileType
fILE_TYPE_CHAR        =  2
fILE_TYPE_PIPE        :: FileType
fILE_TYPE_PIPE        =  3
fILE_TYPE_REMOTE      :: FileType
fILE_TYPE_REMOTE      =  32768

{-# LINE 207 "libraries\Win32\System\Win32\File.hsc" #-}

----------------------------------------------------------------

type LPSECURITY_ATTRIBUTES = Ptr ()
type MbLPSECURITY_ATTRIBUTES = Maybe LPSECURITY_ATTRIBUTES

----------------------------------------------------------------
-- Other types
----------------------------------------------------------------

data BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION
    { bhfiFileAttributes :: FileAttributeOrFlag
    , bhfiCreationTime, bhfiLastAccessTime, bhfiLastWriteTime :: FILETIME
    , bhfiVolumeSerialNumber :: DWORD
    , bhfiSize :: DDWORD
    , bhfiNumberOfLinks :: DWORD
    , bhfiFileIndex :: DDWORD
    } deriving (Show)

instance Storable BY_HANDLE_FILE_INFORMATION where
    sizeOf = const ((52))
{-# LINE 228 "libraries\Win32\System\Win32\File.hsc" #-}
    alignment = sizeOf
    poke buf bhi = do
        ((\hsc_ptr -> pokeByteOff hsc_ptr 0))     buf (bhfiFileAttributes bhi)
{-# LINE 231 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 4))       buf (bhfiCreationTime bhi)
{-# LINE 232 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 12))     buf (bhfiLastAccessTime bhi)
{-# LINE 233 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 20))      buf (bhfiLastWriteTime bhi)
{-# LINE 234 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 28)) buf (bhfiVolumeSerialNumber bhi)
{-# LINE 235 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 32))        buf sizeHi
{-# LINE 236 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 36))         buf sizeLow
{-# LINE 237 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 40))       buf (bhfiNumberOfLinks bhi)
{-# LINE 238 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 44))       buf idxHi
{-# LINE 239 "libraries\Win32\System\Win32\File.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 48))        buf idxLow
{-# LINE 240 "libraries\Win32\System\Win32\File.hsc" #-}
        where
            (sizeHi,sizeLow) = ddwordToDwords $ bhfiSize bhi
            (idxHi,idxLow) = ddwordToDwords $ bhfiFileIndex bhi

    peek buf = do
        attr <- ((\hsc_ptr -> peekByteOff hsc_ptr 0))     buf
{-# LINE 246 "libraries\Win32\System\Win32\File.hsc" #-}
        ctim <- ((\hsc_ptr -> peekByteOff hsc_ptr 4))       buf
{-# LINE 247 "libraries\Win32\System\Win32\File.hsc" #-}
        lati <- ((\hsc_ptr -> peekByteOff hsc_ptr 12))     buf
{-# LINE 248 "libraries\Win32\System\Win32\File.hsc" #-}
        lwti <- ((\hsc_ptr -> peekByteOff hsc_ptr 20))      buf
{-# LINE 249 "libraries\Win32\System\Win32\File.hsc" #-}
        vser <- ((\hsc_ptr -> peekByteOff hsc_ptr 28)) buf
{-# LINE 250 "libraries\Win32\System\Win32\File.hsc" #-}
        fshi <- ((\hsc_ptr -> peekByteOff hsc_ptr 32))        buf
{-# LINE 251 "libraries\Win32\System\Win32\File.hsc" #-}
        fslo <- ((\hsc_ptr -> peekByteOff hsc_ptr 36))         buf
{-# LINE 252 "libraries\Win32\System\Win32\File.hsc" #-}
        link <- ((\hsc_ptr -> peekByteOff hsc_ptr 40))       buf
{-# LINE 253 "libraries\Win32\System\Win32\File.hsc" #-}
        idhi <- ((\hsc_ptr -> peekByteOff hsc_ptr 44))       buf
{-# LINE 254 "libraries\Win32\System\Win32\File.hsc" #-}
        idlo <- ((\hsc_ptr -> peekByteOff hsc_ptr 48))        buf
{-# LINE 255 "libraries\Win32\System\Win32\File.hsc" #-}
        return $ BY_HANDLE_FILE_INFORMATION attr ctim lati lwti vser
            (dwordsToDdword (fshi,fslo)) link (dwordsToDdword (idhi,idlo))

----------------------------------------------------------------
-- File operations
----------------------------------------------------------------

-- | like failIfFalse_, but retried on sharing violations.
-- This is necessary for many file operations; see
--   http://support.microsoft.com/kb/316609
--
failIfWithRetry :: (a -> Bool) -> String -> IO a -> IO a
failIfWithRetry cond msg action = retryOrFail retries
  where
    delay   = 100*1000 -- in ms, we use threadDelay
    retries = 20 :: Int
      -- KB article recommends 250/5

    -- retryOrFail :: Int -> IO a
    retryOrFail times
      | times <= 0 = errorWin msg
      | otherwise  = do
         ret <- action
         if not (cond ret)
            then return ret
            else do
              err_code <- getLastError
              if err_code == (32)
{-# LINE 283 "libraries\Win32\System\Win32\File.hsc" #-}
                then do threadDelay delay; retryOrFail (times - 1)
                else errorWin msg

failIfWithRetry_ :: (a -> Bool) -> String -> IO a -> IO ()
failIfWithRetry_ cond msg action = void $ failIfWithRetry cond msg action

failIfFalseWithRetry_ :: String -> IO Bool -> IO ()
failIfFalseWithRetry_ = failIfWithRetry_ not

deleteFile :: String -> IO ()
deleteFile name =
  withTString name $ \ c_name ->
    failIfFalseWithRetry_ (unwords ["DeleteFile",show name]) $
      c_DeleteFile c_name
foreign import WINDOWS_CCONV unsafe "windows.h DeleteFileW"
  c_DeleteFile :: LPCTSTR -> IO Bool

copyFile :: String -> String -> Bool -> IO ()
copyFile src dest over =
  withTString src $ \ c_src ->
  withTString dest $ \ c_dest ->
  failIfFalseWithRetry_ (unwords ["CopyFile",show src,show dest]) $
    c_CopyFile c_src c_dest over
foreign import WINDOWS_CCONV unsafe "windows.h CopyFileW"
  c_CopyFile :: LPCTSTR -> LPCTSTR -> Bool -> IO Bool

moveFile :: String -> String -> IO ()
moveFile src dest =
  withTString src $ \ c_src ->
  withTString dest $ \ c_dest ->
  failIfFalseWithRetry_ (unwords ["MoveFile",show src,show dest]) $
    c_MoveFile c_src c_dest
foreign import WINDOWS_CCONV unsafe "windows.h MoveFileW"
  c_MoveFile :: LPCTSTR -> LPCTSTR -> IO Bool

moveFileEx :: String -> String -> MoveFileFlag -> IO ()
moveFileEx src dest flags =
  withTString src $ \ c_src ->
  withTString dest $ \ c_dest ->
  failIfFalseWithRetry_ (unwords ["MoveFileEx",show src,show dest]) $
    c_MoveFileEx c_src c_dest flags
foreign import WINDOWS_CCONV unsafe "windows.h MoveFileExW"
  c_MoveFileEx :: LPCTSTR -> LPCTSTR -> MoveFileFlag -> IO Bool

setCurrentDirectory :: String -> IO ()
setCurrentDirectory name =
  withTString name $ \ c_name ->
  failIfFalse_ (unwords ["SetCurrentDirectory",show name]) $
    c_SetCurrentDirectory c_name
foreign import WINDOWS_CCONV unsafe "windows.h SetCurrentDirectoryW"
  c_SetCurrentDirectory :: LPCTSTR -> IO Bool

createDirectory :: String -> Maybe LPSECURITY_ATTRIBUTES -> IO ()
createDirectory name mb_attr =
  withTString name $ \ c_name ->
  failIfFalseWithRetry_ (unwords ["CreateDirectory",show name]) $
    c_CreateDirectory c_name (maybePtr mb_attr)
foreign import WINDOWS_CCONV unsafe "windows.h CreateDirectoryW"
  c_CreateDirectory :: LPCTSTR -> LPSECURITY_ATTRIBUTES -> IO Bool

createDirectoryEx :: String -> String -> Maybe LPSECURITY_ATTRIBUTES -> IO ()
createDirectoryEx template name mb_attr =
  withTString template $ \ c_template ->
  withTString name $ \ c_name ->
  failIfFalseWithRetry_ (unwords ["CreateDirectoryEx",show template,show name]) $
    c_CreateDirectoryEx c_template c_name (maybePtr mb_attr)
foreign import WINDOWS_CCONV unsafe "windows.h CreateDirectoryExW"
  c_CreateDirectoryEx :: LPCTSTR -> LPCTSTR -> LPSECURITY_ATTRIBUTES -> IO Bool

removeDirectory :: String -> IO ()
removeDirectory name =
  withTString name $ \ c_name ->
  failIfFalseWithRetry_ (unwords ["RemoveDirectory",show name]) $
    c_RemoveDirectory c_name
foreign import WINDOWS_CCONV unsafe "windows.h RemoveDirectoryW"
  c_RemoveDirectory :: LPCTSTR -> IO Bool

getBinaryType :: String -> IO BinaryType
getBinaryType name =
  withTString name $ \ c_name ->
  alloca $ \ p_btype -> do
  failIfFalse_ (unwords ["GetBinaryType",show name]) $
    c_GetBinaryType c_name p_btype
  peek p_btype
foreign import WINDOWS_CCONV unsafe "windows.h GetBinaryTypeW"
  c_GetBinaryType :: LPCTSTR -> Ptr DWORD -> IO Bool

----------------------------------------------------------------
-- HANDLE operations
----------------------------------------------------------------

createFile :: String -> AccessMode -> ShareMode -> Maybe LPSECURITY_ATTRIBUTES -> CreateMode -> FileAttributeOrFlag -> Maybe HANDLE -> IO HANDLE
createFile name access share mb_attr mode flag mb_h =
  withTString name $ \ c_name ->
  failIfWithRetry (==iNVALID_HANDLE_VALUE) (unwords ["CreateFile",show name]) $
    c_CreateFile c_name access share (maybePtr mb_attr) mode flag (maybePtr mb_h)
foreign import WINDOWS_CCONV unsafe "windows.h CreateFileW"
  c_CreateFile :: LPCTSTR -> AccessMode -> ShareMode -> LPSECURITY_ATTRIBUTES -> CreateMode -> FileAttributeOrFlag -> HANDLE -> IO HANDLE

closeHandle :: HANDLE -> IO ()
closeHandle h =
  failIfFalse_ "CloseHandle" $ c_CloseHandle h
foreign import WINDOWS_CCONV unsafe "windows.h CloseHandle"
  c_CloseHandle :: HANDLE -> IO Bool

{-# CFILES cbits/HsWin32.c #-}
foreign import ccall "HsWin32.h &CloseHandleFinaliser"
    c_CloseHandleFinaliser :: FunPtr (Ptr a -> IO ())

foreign import WINDOWS_CCONV unsafe "windows.h GetFileType"
  getFileType :: HANDLE -> IO FileType
--Apparently no error code

flushFileBuffers :: HANDLE -> IO ()
flushFileBuffers h =
  failIfFalse_ "FlushFileBuffers" $ c_FlushFileBuffers h
foreign import WINDOWS_CCONV unsafe "windows.h FlushFileBuffers"
  c_FlushFileBuffers :: HANDLE -> IO Bool

setEndOfFile :: HANDLE -> IO ()
setEndOfFile h =
  failIfFalse_ "SetEndOfFile" $ c_SetEndOfFile h
foreign import WINDOWS_CCONV unsafe "windows.h SetEndOfFile"
  c_SetEndOfFile :: HANDLE -> IO Bool

setFileAttributes :: String -> FileAttributeOrFlag -> IO ()
setFileAttributes name attr =
  withTString name $ \ c_name ->
  failIfFalseWithRetry_ (unwords ["SetFileAttributes",show name])
    $ c_SetFileAttributes c_name attr
foreign import WINDOWS_CCONV unsafe "windows.h SetFileAttributesW"
  c_SetFileAttributes :: LPCTSTR -> FileAttributeOrFlag -> IO Bool

getFileAttributes :: String -> IO FileAttributeOrFlag
getFileAttributes name =
  withTString name $ \ c_name ->
  failIfWithRetry (== 0xFFFFFFFF) (unwords ["GetFileAttributes",show name]) $
    c_GetFileAttributes c_name
foreign import WINDOWS_CCONV unsafe "windows.h GetFileAttributesW"
  c_GetFileAttributes :: LPCTSTR -> IO FileAttributeOrFlag

getFileInformationByHandle :: HANDLE -> IO BY_HANDLE_FILE_INFORMATION
getFileInformationByHandle h = alloca $ \res -> do
    failIfFalseWithRetry_ "GetFileInformationByHandle" $ c_GetFileInformationByHandle h res
    peek res
foreign import WINDOWS_CCONV unsafe "windows.h GetFileInformationByHandle"
    c_GetFileInformationByHandle :: HANDLE -> Ptr BY_HANDLE_FILE_INFORMATION -> IO BOOL

----------------------------------------------------------------
-- Read/write files
----------------------------------------------------------------

-- No support for this yet
--type OVERLAPPED =
-- (DWORD,  -- Offset
--  DWORD,  -- OffsetHigh
--  HANDLE) -- hEvent

type LPOVERLAPPED = Ptr ()

type MbLPOVERLAPPED = Maybe LPOVERLAPPED

--Sigh - I give up & prefix win32_ to the next two to avoid
-- senseless Prelude name clashes. --sof.

win32_ReadFile :: HANDLE -> Ptr a -> DWORD -> Maybe LPOVERLAPPED -> IO DWORD
win32_ReadFile h buf n mb_over =
  alloca $ \ p_n -> do
  failIfFalse_ "ReadFile" $ c_ReadFile h buf n p_n (maybePtr mb_over)
  peek p_n
foreign import WINDOWS_CCONV unsafe "windows.h ReadFile"
  c_ReadFile :: HANDLE -> Ptr a -> DWORD -> Ptr DWORD -> LPOVERLAPPED -> IO Bool

win32_WriteFile :: HANDLE -> Ptr a -> DWORD -> Maybe LPOVERLAPPED -> IO DWORD
win32_WriteFile h buf n mb_over =
  alloca $ \ p_n -> do
  failIfFalse_ "WriteFile" $ c_WriteFile h buf n p_n (maybePtr mb_over)
  peek p_n
foreign import WINDOWS_CCONV unsafe "windows.h WriteFile"
  c_WriteFile :: HANDLE -> Ptr a -> DWORD -> Ptr DWORD -> LPOVERLAPPED -> IO Bool

-- missing Seek functioinality; GSL ???
-- Dont have Word64; ADR
-- %fun SetFilePointer :: HANDLE -> Word64 -> FilePtrDirection -> IO Word64

----------------------------------------------------------------
-- File Notifications
--
-- Use these to initialise, "increment" and close a HANDLE you can wait
-- on.
----------------------------------------------------------------

findFirstChangeNotification :: String -> Bool -> FileNotificationFlag -> IO HANDLE
findFirstChangeNotification path watch flag =
  withTString path $ \ c_path ->
  failIfNull (unwords ["FindFirstChangeNotification",show path]) $
    c_FindFirstChangeNotification c_path watch flag
foreign import WINDOWS_CCONV unsafe "windows.h FindFirstChangeNotificationW"
  c_FindFirstChangeNotification :: LPCTSTR -> Bool -> FileNotificationFlag -> IO HANDLE

findNextChangeNotification :: HANDLE -> IO ()
findNextChangeNotification h =
  failIfFalse_ "FindNextChangeNotification" $ c_FindNextChangeNotification h
foreign import WINDOWS_CCONV unsafe "windows.h FindNextChangeNotification"
  c_FindNextChangeNotification :: HANDLE -> IO Bool

findCloseChangeNotification :: HANDLE -> IO ()
findCloseChangeNotification h =
  failIfFalse_ "FindCloseChangeNotification" $ c_FindCloseChangeNotification h
foreign import WINDOWS_CCONV unsafe "windows.h FindCloseChangeNotification"
  c_FindCloseChangeNotification :: HANDLE -> IO Bool

----------------------------------------------------------------
-- Directories
----------------------------------------------------------------

type WIN32_FIND_DATA = ()

newtype FindData = FindData (ForeignPtr WIN32_FIND_DATA)

getFindDataFileName :: FindData -> IO FilePath
getFindDataFileName (FindData fp) = 
  withForeignPtr fp $ \p -> 
    peekTString (((\hsc_ptr -> hsc_ptr `plusPtr` 44)) p)
{-# LINE 507 "libraries\Win32\System\Win32\File.hsc" #-}

findFirstFile :: String -> IO (HANDLE, FindData)
findFirstFile str = do
  fp_finddata <- mallocForeignPtrBytes (592)
{-# LINE 511 "libraries\Win32\System\Win32\File.hsc" #-}
  withForeignPtr fp_finddata $ \p_finddata -> do
    handle <- withTString str $ \tstr -> do
                failIf (== iNVALID_HANDLE_VALUE) "findFirstFile" $ 
                  c_FindFirstFile tstr p_finddata
    return (handle, FindData fp_finddata)
foreign import WINDOWS_CCONV unsafe "windows.h FindFirstFileW"
  c_FindFirstFile :: LPCTSTR -> Ptr WIN32_FIND_DATA -> IO HANDLE

findNextFile :: HANDLE -> FindData -> IO Bool -- False -> no more files
findNextFile h (FindData finddata) = do
  withForeignPtr finddata $ \p_finddata -> do
    b <- c_FindNextFile h p_finddata
    if b
       then return True
       else do
             err_code <- getLastError
             if err_code == (18)
{-# LINE 528 "libraries\Win32\System\Win32\File.hsc" #-}
                then return False
                else failWith "findNextFile" err_code
foreign import WINDOWS_CCONV unsafe "windows.h FindNextFileW"
  c_FindNextFile :: HANDLE -> Ptr WIN32_FIND_DATA -> IO BOOL

findClose :: HANDLE -> IO ()
findClose h = failIfFalse_ "findClose" $ c_FindClose h
foreign import WINDOWS_CCONV unsafe "windows.h FindClose"
  c_FindClose :: HANDLE -> IO BOOL

----------------------------------------------------------------
-- DOS Device flags
----------------------------------------------------------------

defineDosDevice :: DefineDosDeviceFlags -> String -> String -> IO ()
defineDosDevice flags name path =
  withTString path $ \ c_path ->
  withTString name $ \ c_name ->
  failIfFalse_ "DefineDosDevice" $ c_DefineDosDevice flags c_name c_path
foreign import WINDOWS_CCONV unsafe "windows.h DefineDosDeviceW"
  c_DefineDosDevice :: DefineDosDeviceFlags -> LPCTSTR -> LPCTSTR -> IO Bool

----------------------------------------------------------------

-- These functions are very unusual in the Win32 API:
-- They dont return error codes

foreign import WINDOWS_CCONV unsafe "windows.h AreFileApisANSI"
  areFileApisANSI :: IO Bool

foreign import WINDOWS_CCONV unsafe "windows.h SetFileApisToOEM"
  setFileApisToOEM :: IO ()

foreign import WINDOWS_CCONV unsafe "windows.h SetFileApisToANSI"
  setFileApisToANSI :: IO ()

foreign import WINDOWS_CCONV unsafe "windows.h SetHandleCount"
  setHandleCount :: UINT -> IO UINT

----------------------------------------------------------------

getLogicalDrives :: IO DWORD
getLogicalDrives =
  failIfZero "GetLogicalDrives" $ c_GetLogicalDrives
foreign import WINDOWS_CCONV unsafe "windows.h GetLogicalDrives"
  c_GetLogicalDrives :: IO DWORD

-- %fun GetDriveType :: Maybe String -> IO DriveType

getDiskFreeSpace :: Maybe String -> IO (DWORD,DWORD,DWORD,DWORD)
getDiskFreeSpace path =
  maybeWith withTString path $ \ c_path ->
  alloca $ \ p_sectors ->
  alloca $ \ p_bytes ->
  alloca $ \ p_nfree ->
  alloca $ \ p_nclusters -> do
  failIfFalse_ "GetDiskFreeSpace" $
    c_GetDiskFreeSpace c_path p_sectors p_bytes p_nfree p_nclusters
  sectors <- peek p_sectors
  bytes <- peek p_bytes
  nfree <- peek p_nfree
  nclusters <- peek p_nclusters
  return (sectors, bytes, nfree, nclusters)
foreign import WINDOWS_CCONV unsafe "windows.h GetDiskFreeSpaceW"
  c_GetDiskFreeSpace :: LPCTSTR -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> Ptr DWORD -> IO Bool

setVolumeLabel :: String -> String -> IO ()
setVolumeLabel path name =
  withTString path $ \ c_path ->
  withTString name $ \ c_name ->
  failIfFalse_ "SetVolumeLabel" $ c_SetVolumeLabel c_path c_name
foreign import WINDOWS_CCONV unsafe "windows.h SetVolumeLabelW"
  c_SetVolumeLabel :: LPCTSTR -> LPCTSTR -> IO Bool

----------------------------------------------------------------
-- End
----------------------------------------------------------------