aboutsummaryrefslogtreecommitdiffhomepage
path: root/System/Posix/IO.hsc
diff options
context:
space:
mode:
Diffstat (limited to 'System/Posix/IO.hsc')
-rw-r--r--System/Posix/IO.hsc400
1 files changed, 7 insertions, 393 deletions
diff --git a/System/Posix/IO.hsc b/System/Posix/IO.hsc
index c1a2d0c..c5b8e55 100644
--- a/System/Posix/IO.hsc
+++ b/System/Posix/IO.hsc
@@ -21,6 +21,8 @@
--
-----------------------------------------------------------------------------
+#include "HsUnix.h"
+
module System.Posix.IO (
-- * Input \/ Output
@@ -66,36 +68,9 @@ module System.Posix.IO (
) where
-import System.IO
-import System.IO.Error
import System.Posix.Types
import System.Posix.Error
-import qualified System.Posix.Internals as Base
-
-import Foreign
-import Foreign.C
-import Data.Bits
-
-#ifdef __GLASGOW_HASKELL__
-#if __GLASGOW_HASKELL__ >= 611
-import GHC.IO.Handle
-import GHC.IO.Handle.Internals
-import GHC.IO.Handle.Types
-import qualified GHC.IO.FD as FD
-import qualified GHC.IO.Handle.FD as FD
-import GHC.IO.Exception
-import Data.Typeable (cast)
-#else
-import GHC.IOBase
-import GHC.Handle hiding (fdToHandle)
-import qualified GHC.Handle
-#endif
-#endif
-
-#ifdef __HUGS__
-import Hugs.Prelude (IOException(..), IOErrorType(..))
-import qualified Hugs.IO (handleToFd, openFd)
-#endif
+import System.Posix.IO.Common
#if __GLASGOW_HASKELL__ > 611
import System.Posix.Internals ( withFilePath )
@@ -104,81 +79,6 @@ withFilePath :: FilePath -> (CString -> IO a) -> IO a
withFilePath = withCString
#endif
-#include "HsUnix.h"
-
--- -----------------------------------------------------------------------------
--- Pipes
--- |The 'createPipe' function creates a pair of connected file
--- descriptors. The first component is the fd to read from, the second
--- is the write end. Although pipes may be bidirectional, this
--- behaviour is not portable and programmers should use two separate
--- pipes for this purpose. May throw an exception if this is an
--- invalid descriptor.
-
-createPipe :: IO (Fd, Fd)
-createPipe =
- allocaArray 2 $ \p_fd -> do
- throwErrnoIfMinus1_ "createPipe" (c_pipe p_fd)
- rfd <- peekElemOff p_fd 0
- wfd <- peekElemOff p_fd 1
- return (Fd rfd, Fd wfd)
-
-foreign import ccall unsafe "pipe"
- c_pipe :: Ptr CInt -> IO CInt
-
--- -----------------------------------------------------------------------------
--- Duplicating file descriptors
-
--- | May throw an exception if this is an invalid descriptor.
-dup :: Fd -> IO Fd
-dup (Fd fd) = do r <- throwErrnoIfMinus1 "dup" (c_dup fd); return (Fd r)
-
--- | May throw an exception if this is an invalid descriptor.
-dupTo :: Fd -> Fd -> IO Fd
-dupTo (Fd fd1) (Fd fd2) = do
- r <- throwErrnoIfMinus1 "dupTo" (c_dup2 fd1 fd2)
- return (Fd r)
-
-foreign import ccall unsafe "dup"
- c_dup :: CInt -> IO CInt
-
-foreign import ccall unsafe "dup2"
- c_dup2 :: CInt -> CInt -> IO CInt
-
--- -----------------------------------------------------------------------------
--- Opening and closing files
-
-stdInput, stdOutput, stdError :: Fd
-stdInput = Fd (#const STDIN_FILENO)
-stdOutput = Fd (#const STDOUT_FILENO)
-stdError = Fd (#const STDERR_FILENO)
-
-data OpenMode = ReadOnly | WriteOnly | ReadWrite
-
--- |Correspond to some of the int flags from C's fcntl.h.
-data OpenFileFlags =
- OpenFileFlags {
- append :: Bool, -- ^ O_APPEND
- exclusive :: Bool, -- ^ O_EXCL
- noctty :: Bool, -- ^ O_NOCTTY
- nonBlock :: Bool, -- ^ O_NONBLOCK
- trunc :: Bool -- ^ O_TRUNC
- }
-
-
--- |Default values for the 'OpenFileFlags' type. False for each of
--- append, exclusive, noctty, nonBlock, and trunc.
-defaultFileFlags :: OpenFileFlags
-defaultFileFlags =
- OpenFileFlags {
- append = False,
- exclusive = False,
- noctty = False,
- nonBlock = False,
- trunc = False
- }
-
-
-- |Open and optionally create this file. See 'System.Posix.Files'
-- for information on how to use the 'FileMode' type.
openFd :: FilePath
@@ -186,32 +86,10 @@ openFd :: FilePath
-> Maybe FileMode -- ^Just x => creates the file with the given modes, Nothing => the file must exist.
-> OpenFileFlags
-> IO Fd
-openFd name how maybe_mode (OpenFileFlags appendFlag exclusiveFlag nocttyFlag
- nonBlockFlag truncateFlag) = do
- withFilePath name $ \s -> do
- fd <- throwErrnoPathIfMinus1Retry "openFd" name (c_open s all_flags mode_w)
- return (Fd fd)
- where
- all_flags = creat .|. flags .|. open_mode
-
- flags =
- (if appendFlag then (#const O_APPEND) else 0) .|.
- (if exclusiveFlag then (#const O_EXCL) else 0) .|.
- (if nocttyFlag then (#const O_NOCTTY) else 0) .|.
- (if nonBlockFlag then (#const O_NONBLOCK) else 0) .|.
- (if truncateFlag then (#const O_TRUNC) else 0)
-
- (creat, mode_w) = case maybe_mode of
- Nothing -> (0,0)
- Just x -> ((#const O_CREAT), x)
-
- open_mode = case how of
- ReadOnly -> (#const O_RDONLY)
- WriteOnly -> (#const O_WRONLY)
- ReadWrite -> (#const O_RDWR)
-
-foreign import ccall unsafe "__hscore_open"
- c_open :: CString -> CInt -> CMode -> IO CInt
+openFd name how maybe_mode flags = do
+ withFilePath name $ \str -> do
+ throwErrnoPathIfMinus1Retry "openFd" name $
+ open_ str how maybe_mode flags
-- |Create and open this file in WriteOnly mode. A special case of
-- 'openFd'. See 'System.Posix.Files' for information on how to use
@@ -220,267 +98,3 @@ foreign import ccall unsafe "__hscore_open"
createFile :: FilePath -> FileMode -> IO Fd
createFile name mode
= openFd name WriteOnly (Just mode) defaultFileFlags{ trunc=True }
-
--- |Close this file descriptor. May throw an exception if this is an
--- invalid descriptor.
-
-closeFd :: Fd -> IO ()
-closeFd (Fd fd) = throwErrnoIfMinus1_ "closeFd" (c_close fd)
-
-foreign import ccall unsafe "HsBase.h close"
- c_close :: CInt -> IO CInt
-
--- -----------------------------------------------------------------------------
--- Converting file descriptors to/from Handles
-
--- | Extracts the 'Fd' from a 'Handle'. This function has the side effect
--- of closing the 'Handle' and flushing its write buffer, if necessary.
-handleToFd :: Handle -> IO Fd
-
--- | Converts an 'Fd' into a 'Handle' that can be used with the
--- standard Haskell IO library (see "System.IO").
---
--- GHC only: this function has the side effect of putting the 'Fd'
--- into non-blocking mode (@O_NONBLOCK@) due to the way the standard
--- IO library implements multithreaded I\/O.
---
-fdToHandle :: Fd -> IO Handle
-
-#ifdef __GLASGOW_HASKELL__
-#if __GLASGOW_HASKELL__ >= 611
-handleToFd h@(FileHandle _ m) = do
- withHandle' "handleToFd" h m $ handleToFd' h
-handleToFd h@(DuplexHandle _ r w) = do
- _ <- withHandle' "handleToFd" h r $ handleToFd' h
- withHandle' "handleToFd" h w $ handleToFd' h
- -- for a DuplexHandle, make sure we mark both sides as closed,
- -- otherwise a finalizer will come along later and close the other
- -- side. (#3914)
-
-handleToFd' :: Handle -> Handle__ -> IO (Handle__, Fd)
-handleToFd' h h_@Handle__{haType=_,..} = do
- case cast haDevice of
- Nothing -> ioError (ioeSetErrorString (mkIOError IllegalOperation
- "handleToFd" (Just h) Nothing)
- "handle is not a file descriptor")
- Just fd -> do
- -- converting a Handle into an Fd effectively means
- -- letting go of the Handle; it is put into a closed
- -- state as a result.
- flushWriteBuffer h_
- FD.release fd
- return (Handle__{haType=ClosedHandle,..}, Fd (FD.fdFD fd))
-
-fdToHandle fd = FD.fdToHandle (fromIntegral fd)
-
-#else
-
-handleToFd h = withHandle "handleToFd" h $ \ h_ -> do
- -- converting a Handle into an Fd effectively means
- -- letting go of the Handle; it is put into a closed
- -- state as a result.
- let fd = haFD h_
- flushWriteBufferOnly h_
- unlockFile (fromIntegral fd)
- -- setting the Handle's fd to (-1) as well as its 'type'
- -- to closed, is enough to disable the finalizer that
- -- eventually is run on the Handle.
- return (h_{haFD= (-1),haType=ClosedHandle}, Fd (fromIntegral fd))
-
-fdToHandle fd = GHC.Handle.fdToHandle (fromIntegral fd)
-#endif
-#endif
-
-#ifdef __HUGS__
-handleToFd h = do
- fd <- Hugs.IO.handleToFd h
- return (fromIntegral fd)
-
-fdToHandle fd = do
- mode <- fdGetMode (fromIntegral fd)
- Hugs.IO.openFd (fromIntegral fd) False mode True
-#endif
-
--- -----------------------------------------------------------------------------
--- Fd options
-
-data FdOption = AppendOnWrite -- ^O_APPEND
- | CloseOnExec -- ^FD_CLOEXEC
- | NonBlockingRead -- ^O_NONBLOCK
- | SynchronousWrites -- ^O_SYNC
-
-fdOption2Int :: FdOption -> CInt
-fdOption2Int CloseOnExec = (#const FD_CLOEXEC)
-fdOption2Int AppendOnWrite = (#const O_APPEND)
-fdOption2Int NonBlockingRead = (#const O_NONBLOCK)
-fdOption2Int SynchronousWrites = (#const O_SYNC)
-
--- | May throw an exception if this is an invalid descriptor.
-queryFdOption :: Fd -> FdOption -> IO Bool
-queryFdOption (Fd fd) opt = do
- r <- throwErrnoIfMinus1 "queryFdOption" (c_fcntl_read fd flag)
- return ((r .&. fdOption2Int opt) /= 0)
- where
- flag = case opt of
- CloseOnExec -> (#const F_GETFD)
- _ -> (#const F_GETFL)
-
--- | May throw an exception if this is an invalid descriptor.
-setFdOption :: Fd -> FdOption -> Bool -> IO ()
-setFdOption (Fd fd) opt val = do
- r <- throwErrnoIfMinus1 "setFdOption" (c_fcntl_read fd getflag)
- let r' | val = r .|. opt_val
- | otherwise = r .&. (complement opt_val)
- throwErrnoIfMinus1_ "setFdOption"
- (c_fcntl_write fd setflag (fromIntegral r'))
- where
- (getflag,setflag)= case opt of
- CloseOnExec -> ((#const F_GETFD),(#const F_SETFD))
- _ -> ((#const F_GETFL),(#const F_SETFL))
- opt_val = fdOption2Int opt
-
-foreign import ccall unsafe "HsBase.h fcntl_read"
- c_fcntl_read :: CInt -> CInt -> IO CInt
-
-foreign import ccall unsafe "HsBase.h fcntl_write"
- c_fcntl_write :: CInt -> CInt -> CLong -> IO CInt
-
--- -----------------------------------------------------------------------------
--- Seeking
-
-mode2Int :: SeekMode -> CInt
-mode2Int AbsoluteSeek = (#const SEEK_SET)
-mode2Int RelativeSeek = (#const SEEK_CUR)
-mode2Int SeekFromEnd = (#const SEEK_END)
-
--- | May throw an exception if this is an invalid descriptor.
-fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset
-fdSeek (Fd fd) mode off =
- throwErrnoIfMinus1 "fdSeek" (Base.c_lseek fd off (mode2Int mode))
-
--- -----------------------------------------------------------------------------
--- Locking
-
-data LockRequest = ReadLock
- | WriteLock
- | Unlock
-
-type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset)
-
--- | May throw an exception if this is an invalid descriptor.
-getLock :: Fd -> FileLock -> IO (Maybe (ProcessID, FileLock))
-getLock (Fd fd) lock =
- allocaLock lock $ \p_flock -> do
- throwErrnoIfMinus1_ "getLock" (c_fcntl_lock fd (#const F_GETLK) p_flock)
- result <- bytes2ProcessIDAndLock p_flock
- return (maybeResult result)
- where
- maybeResult (_, (Unlock, _, _, _)) = Nothing
- maybeResult x = Just x
-
-type CFLock = ()
-
-foreign import ccall unsafe "HsBase.h fcntl_lock"
- c_fcntl_lock :: CInt -> CInt -> Ptr CFLock -> IO CInt
-
-allocaLock :: FileLock -> (Ptr CFLock -> IO a) -> IO a
-allocaLock (lockreq, mode, start, len) io =
- allocaBytes (#const sizeof(struct flock)) $ \p -> do
- (#poke struct flock, l_type) p (lockReq2Int lockreq :: CShort)
- (#poke struct flock, l_whence) p (fromIntegral (mode2Int mode) :: CShort)
- (#poke struct flock, l_start) p start
- (#poke struct flock, l_len) p len
- io p
-
-lockReq2Int :: LockRequest -> CShort
-lockReq2Int ReadLock = (#const F_RDLCK)
-lockReq2Int WriteLock = (#const F_WRLCK)
-lockReq2Int Unlock = (#const F_UNLCK)
-
-bytes2ProcessIDAndLock :: Ptr CFLock -> IO (ProcessID, FileLock)
-bytes2ProcessIDAndLock p = do
- req <- (#peek struct flock, l_type) p
- mode <- (#peek struct flock, l_whence) p
- start <- (#peek struct flock, l_start) p
- len <- (#peek struct flock, l_len) p
- pid <- (#peek struct flock, l_pid) p
- return (pid, (int2req req, int2mode mode, start, len))
- where
- int2req :: CShort -> LockRequest
- int2req (#const F_RDLCK) = ReadLock
- int2req (#const F_WRLCK) = WriteLock
- int2req (#const F_UNLCK) = Unlock
- int2req _ = error $ "int2req: bad argument"
-
- int2mode :: CShort -> SeekMode
- int2mode (#const SEEK_SET) = AbsoluteSeek
- int2mode (#const SEEK_CUR) = RelativeSeek
- int2mode (#const SEEK_END) = SeekFromEnd
- int2mode _ = error $ "int2mode: bad argument"
-
--- | May throw an exception if this is an invalid descriptor.
-setLock :: Fd -> FileLock -> IO ()
-setLock (Fd fd) lock = do
- allocaLock lock $ \p_flock ->
- throwErrnoIfMinus1_ "setLock" (c_fcntl_lock fd (#const F_SETLK) p_flock)
-
--- | May throw an exception if this is an invalid descriptor.
-waitToSetLock :: Fd -> FileLock -> IO ()
-waitToSetLock (Fd fd) lock = do
- allocaLock lock $ \p_flock ->
- throwErrnoIfMinus1_ "waitToSetLock"
- (c_fcntl_lock fd (#const F_SETLKW) p_flock)
-
--- -----------------------------------------------------------------------------
--- fd{Read,Write}
-
--- | Read data from an 'Fd' and convert it to a 'String' using the locale encoding.
--- Throws an exception if this is an invalid descriptor, or EOF has been
--- reached.
-fdRead :: Fd
- -> ByteCount -- ^How many bytes to read
- -> IO (String, ByteCount) -- ^The bytes read, how many bytes were read.
-fdRead _fd 0 = return ("", 0)
-fdRead fd nbytes = do
- allocaBytes (fromIntegral nbytes) $ \ buf -> do
- rc <- fdReadBuf fd buf nbytes
- case rc of
- 0 -> ioError (ioeSetErrorString (mkIOError EOF "fdRead" Nothing Nothing) "EOF")
- n -> do
- s <- peekCStringLen (castPtr buf, fromIntegral n)
- return (s, n)
-
--- | Read data from an 'Fd' into memory. This is exactly equivalent
--- to the POSIX @read@ function.
-fdReadBuf :: Fd
- -> Ptr Word8 -- ^ Memory in which to put the data
- -> ByteCount -- ^ Maximum number of bytes to read
- -> IO ByteCount -- ^ Number of bytes read (zero for EOF)
-fdReadBuf _fd _buf 0 = return 0
-fdReadBuf fd buf nbytes =
- fmap fromIntegral $
- throwErrnoIfMinus1Retry "fdReadBuf" $
- c_safe_read (fromIntegral fd) (castPtr buf) nbytes
-
-foreign import ccall safe "read"
- c_safe_read :: CInt -> Ptr CChar -> CSize -> IO CSsize
-
--- | Write a 'String' to an 'Fd' using the locale encoding.
-fdWrite :: Fd -> String -> IO ByteCount
-fdWrite fd str =
- withCStringLen str $ \ (buf,len) ->
- fdWriteBuf fd (castPtr buf) (fromIntegral len)
-
--- | Write data from memory to an 'Fd'. This is exactly equivalent
--- to the POSIX @write@ function.
-fdWriteBuf :: Fd
- -> Ptr Word8 -- ^ Memory containing the data to write
- -> ByteCount -- ^ Maximum number of bytes to write
- -> IO ByteCount -- ^ Number of bytes written
-fdWriteBuf fd buf len =
- fmap fromIntegral $
- throwErrnoIfMinus1Retry "fdWriteBuf" $
- c_safe_write (fromIntegral fd) (castPtr buf) len
-
-foreign import ccall safe "write"
- c_safe_write :: CInt -> Ptr CChar -> CSize -> IO CSsize