{-# LANGUAGE CPP #-}
{-# LANGUAGE PackageImports #-}
module System.FS.IO.Unix
( FHandle
, close
, getSize
, open
, pread
, preadBuf
, pwriteBuf
, read
, readBuf
, seek
, truncate
, write
, writeBuf
) where
import Control.Monad (void)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Internal as Internal
import Data.Int (Int64)
import Data.Word (Word32, Word64, Word8)
import Foreign (Ptr)
import System.FS.API.Types
( AllowExisting (..)
, OpenMode (..)
, SeekMode (..)
)
import System.FS.IO.Handle
import System.Posix (ByteCount, Fd (..), FileOffset)
import qualified System.Posix as Posix
import qualified System.Posix.IO.ByteString.Ext as Posix
( fdPreadBuf
, fdPwriteBuf
)
import Prelude hiding (read, truncate)
type FHandle = HandleOS Fd
defaultFileFlags :: Posix.OpenFileFlags
defaultFileFlags :: OpenFileFlags
defaultFileFlags = Posix.OpenFileFlags {
append :: Bool
Posix.append = Bool
False
, exclusive :: Bool
Posix.exclusive = Bool
False
, noctty :: Bool
Posix.noctty = Bool
False
, nonBlock :: Bool
Posix.nonBlock = Bool
False
, trunc :: Bool
Posix.trunc = Bool
False
#if MIN_VERSION_unix(2,8,0)
, nofollow :: Bool
Posix.nofollow = Bool
False
, creat :: Maybe FileMode
Posix.creat = Maybe FileMode
forall a. Maybe a
Nothing
, cloexec :: Bool
Posix.cloexec = Bool
False
, directory :: Bool
Posix.directory = Bool
False
, sync :: Bool
Posix.sync = Bool
False
#endif
}
open :: FilePath -> OpenMode -> IO Fd
#if MIN_VERSION_unix(2,8,0)
open :: FilePath -> OpenMode -> IO Fd
open FilePath
fp OpenMode
openMode = FilePath -> OpenMode -> OpenFileFlags -> IO Fd
Posix.openFd FilePath
fp OpenMode
posixOpenMode OpenFileFlags
fileFlags
where
(OpenMode
posixOpenMode, OpenFileFlags
fileFlags) = case OpenMode
openMode of
OpenMode
ReadMode -> ( OpenMode
Posix.ReadOnly
, OpenFileFlags
defaultFileFlags
)
AppendMode AllowExisting
ex -> ( OpenMode
Posix.WriteOnly
, OpenFileFlags
defaultFileFlags { Posix.append = True
, Posix.exclusive = isExcl ex
, Posix.creat = creat ex }
)
ReadWriteMode AllowExisting
ex -> ( OpenMode
Posix.ReadWrite
, OpenFileFlags
defaultFileFlags { Posix.exclusive = isExcl ex
, Posix.creat = creat ex }
)
WriteMode AllowExisting
ex -> ( OpenMode
Posix.ReadWrite
, OpenFileFlags
defaultFileFlags { Posix.exclusive = isExcl ex
, Posix.creat = creat ex }
)
#else
open fp openMode = Posix.openFd fp posixOpenMode fileMode fileFlags
where
(posixOpenMode, fileMode, fileFlags) = case openMode of
ReadMode -> ( Posix.ReadOnly
, Nothing
, defaultFileFlags
)
AppendMode ex -> ( Posix.WriteOnly
, creat ex
, defaultFileFlags { Posix.append = True
, Posix.exclusive = isExcl ex }
)
ReadWriteMode ex -> ( Posix.ReadWrite
, creat ex
, defaultFileFlags { Posix.exclusive = isExcl ex }
)
WriteMode ex -> ( Posix.ReadWrite
, creat ex
, defaultFileFlags { Posix.exclusive = isExcl ex }
)
#endif
isExcl :: AllowExisting -> Bool
isExcl AllowExisting
AllowExisting = Bool
False
isExcl AllowExisting
MustBeNew = Bool
True
isExcl AllowExisting
MustExist = Bool
False
creat :: AllowExisting -> Maybe FileMode
creat AllowExisting
AllowExisting = FileMode -> Maybe FileMode
forall a. a -> Maybe a
Just FileMode
Posix.stdFileMode
creat AllowExisting
MustBeNew = FileMode -> Maybe FileMode
forall a. a -> Maybe a
Just FileMode
Posix.stdFileMode
creat AllowExisting
MustExist = Maybe FileMode
forall a. Maybe a
Nothing
write :: FHandle -> Ptr Word8 -> Int64 -> IO Word32
write :: FHandle -> Ptr Word8 -> Int64 -> IO Word32
write FHandle
h Ptr Word8
data' Int64
bytes = FilePath -> FHandle -> (Fd -> IO Word32) -> IO Word32
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"write" FHandle
h ((Fd -> IO Word32) -> IO Word32) -> (Fd -> IO Word32) -> IO Word32
forall a b. (a -> b) -> a -> b
$ \Fd
fd ->
ByteCount -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteCount -> Word32) -> IO ByteCount -> IO Word32
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
Posix.fdWriteBuf Fd
fd Ptr Word8
data' (Int64 -> ByteCount
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
bytes)
seek :: FHandle -> SeekMode -> Int64 -> IO ()
seek :: FHandle -> SeekMode -> Int64 -> IO ()
seek FHandle
h SeekMode
seekMode Int64
offset = FilePath -> FHandle -> (Fd -> IO ()) -> IO ()
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"seek" FHandle
h ((Fd -> IO ()) -> IO ()) -> (Fd -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Fd
fd ->
IO FileOffset -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO FileOffset -> IO ()) -> IO FileOffset -> IO ()
forall a b. (a -> b) -> a -> b
$ Fd -> SeekMode -> FileOffset -> IO FileOffset
Posix.fdSeek Fd
fd SeekMode
seekMode (Int64 -> FileOffset
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
offset)
read :: FHandle -> Word64 -> IO ByteString
read :: FHandle -> Word64 -> IO ByteString
read FHandle
h Word64
bytes = FilePath -> FHandle -> (Fd -> IO ByteString) -> IO ByteString
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"read" FHandle
h ((Fd -> IO ByteString) -> IO ByteString)
-> (Fd -> IO ByteString) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Fd
fd ->
Int -> (Ptr Word8 -> IO Int) -> IO ByteString
Internal.createUptoN (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
bytes) ((Ptr Word8 -> IO Int) -> IO ByteString)
-> (Ptr Word8 -> IO Int) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr ->
ByteCount -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteCount -> Int) -> IO ByteCount -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
Posix.fdReadBuf Fd
fd Ptr Word8
ptr (Word64 -> ByteCount
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
bytes)
readBuf :: FHandle -> Ptr Word8 -> ByteCount -> IO ByteCount
readBuf :: FHandle -> Ptr Word8 -> ByteCount -> IO ByteCount
readBuf FHandle
f Ptr Word8
buf ByteCount
c = FilePath -> FHandle -> (Fd -> IO ByteCount) -> IO ByteCount
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"readBuf" FHandle
f ((Fd -> IO ByteCount) -> IO ByteCount)
-> (Fd -> IO ByteCount) -> IO ByteCount
forall a b. (a -> b) -> a -> b
$ \Fd
fd -> Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
Posix.fdReadBuf Fd
fd Ptr Word8
buf ByteCount
c
writeBuf :: FHandle -> Ptr Word8 -> ByteCount -> IO ByteCount
writeBuf :: FHandle -> Ptr Word8 -> ByteCount -> IO ByteCount
writeBuf FHandle
f Ptr Word8
buf ByteCount
c = FilePath -> FHandle -> (Fd -> IO ByteCount) -> IO ByteCount
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"writeBuf" FHandle
f ((Fd -> IO ByteCount) -> IO ByteCount)
-> (Fd -> IO ByteCount) -> IO ByteCount
forall a b. (a -> b) -> a -> b
$ \Fd
fd -> Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
Posix.fdWriteBuf Fd
fd Ptr Word8
buf ByteCount
c
pread :: FHandle -> Word64 -> Word64 -> IO ByteString
pread :: FHandle -> Word64 -> Word64 -> IO ByteString
pread FHandle
h Word64
bytes Word64
offset = FilePath -> FHandle -> (Fd -> IO ByteString) -> IO ByteString
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"pread" FHandle
h ((Fd -> IO ByteString) -> IO ByteString)
-> (Fd -> IO ByteString) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Fd
fd ->
Int -> (Ptr Word8 -> IO Int) -> IO ByteString
Internal.createUptoN (Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
bytes) ((Ptr Word8 -> IO Int) -> IO ByteString)
-> (Ptr Word8 -> IO Int) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr ->
ByteCount -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteCount -> Int) -> IO ByteCount -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Fd -> Ptr Word8 -> ByteCount -> FileOffset -> IO ByteCount
Posix.fdPreadBuf Fd
fd Ptr Word8
ptr (Word64 -> ByteCount
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
bytes) (Word64 -> FileOffset
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
offset)
preadBuf :: FHandle -> Ptr Word8 -> ByteCount -> FileOffset -> IO ByteCount
preadBuf :: FHandle -> Ptr Word8 -> ByteCount -> FileOffset -> IO ByteCount
preadBuf FHandle
h Ptr Word8
buf ByteCount
c FileOffset
off = FilePath -> FHandle -> (Fd -> IO ByteCount) -> IO ByteCount
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"preadBuf" FHandle
h ((Fd -> IO ByteCount) -> IO ByteCount)
-> (Fd -> IO ByteCount) -> IO ByteCount
forall a b. (a -> b) -> a -> b
$ \Fd
fd -> Fd -> Ptr Word8 -> ByteCount -> FileOffset -> IO ByteCount
Posix.fdPreadBuf Fd
fd Ptr Word8
buf ByteCount
c FileOffset
off
pwriteBuf :: FHandle -> Ptr Word8 -> ByteCount -> FileOffset -> IO ByteCount
pwriteBuf :: FHandle -> Ptr Word8 -> ByteCount -> FileOffset -> IO ByteCount
pwriteBuf FHandle
h Ptr Word8
buf ByteCount
c FileOffset
off = FilePath -> FHandle -> (Fd -> IO ByteCount) -> IO ByteCount
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"pwriteBuf" FHandle
h ((Fd -> IO ByteCount) -> IO ByteCount)
-> (Fd -> IO ByteCount) -> IO ByteCount
forall a b. (a -> b) -> a -> b
$ \Fd
fd -> Fd -> Ptr Word8 -> ByteCount -> FileOffset -> IO ByteCount
Posix.fdPwriteBuf Fd
fd Ptr Word8
buf ByteCount
c FileOffset
off
truncate :: FHandle -> Word64 -> IO ()
truncate :: FHandle -> Word64 -> IO ()
truncate FHandle
h Word64
sz = FilePath -> FHandle -> (Fd -> IO ()) -> IO ()
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"truncate" FHandle
h ((Fd -> IO ()) -> IO ()) -> (Fd -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Fd
fd ->
Fd -> FileOffset -> IO ()
Posix.setFdSize Fd
fd (Word64 -> FileOffset
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
sz)
close :: FHandle -> IO ()
close :: FHandle -> IO ()
close FHandle
h = FHandle -> (Fd -> IO ()) -> IO ()
forall osHandle. HandleOS osHandle -> (osHandle -> IO ()) -> IO ()
closeHandleOS FHandle
h Fd -> IO ()
Posix.closeFd
getSize :: FHandle -> IO Word64
getSize :: FHandle -> IO Word64
getSize FHandle
h = FilePath -> FHandle -> (Fd -> IO Word64) -> IO Word64
forall osHandle a.
FilePath -> HandleOS osHandle -> (osHandle -> IO a) -> IO a
withOpenHandle FilePath
"getSize" FHandle
h ((Fd -> IO Word64) -> IO Word64) -> (Fd -> IO Word64) -> IO Word64
forall a b. (a -> b) -> a -> b
$ \Fd
fd ->
FileOffset -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (FileOffset -> Word64)
-> (FileStatus -> FileOffset) -> FileStatus -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileStatus -> FileOffset
Posix.fileSize (FileStatus -> Word64) -> IO FileStatus -> IO Word64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Fd -> IO FileStatus
Posix.getFdStatus Fd
fd