{-# LINE 1 "System/Posix/IO.hsc" #-}
{-# LANGUAGE Safe #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  System.Posix.IO
-- Copyright   :  (c) The University of Glasgow 2002
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  provisional
-- Portability :  non-portable (requires POSIX)
--
-- POSIX IO support.  These types and functions correspond to the unix
-- functions open(2), close(2), etc.  For more portable functions
-- which are more like fopen(3) and friends from stdio.h, see
-- "System.IO".
--
-----------------------------------------------------------------------------



module System.Posix.IO (
    -- * Input \/ Output

    -- ** Standard file descriptors
    stdInput, stdOutput, stdError,

    -- ** Opening and closing files
    OpenMode(..),
    OpenFileFlags(..), defaultFileFlags,
    openFd, openFdAt, createFile, createFileAt,
    closeFd,

    -- ** Reading\/writing data
    -- |Programmers using the 'fdRead' and 'fdWrite' API should be aware that
    -- EAGAIN exceptions may occur for non-blocking IO!

    fdRead, fdWrite,
    fdReadBuf, fdWriteBuf,

    -- ** Seeking
    fdSeek,

    -- ** File options
    FdOption(..),
    queryFdOption,
    setFdOption,

    -- ** Locking
    FileLock,
    LockRequest(..),
    getLock,  setLock,
    waitToSetLock,

    -- ** Pipes
    createPipe,

    -- ** Duplicating file descriptors
    dup, dupTo,

    -- ** Converting file descriptors to\/from Handles
    handleToFd,
    fdToHandle,

  ) where

import Foreign ( allocaBytes, castPtr )
import Foreign.C ( peekCStringLen, withCStringLen )

import GHC.IO.Exception ( IOErrorType(EOF) )

import System.IO.Error ( ioeSetErrorString, mkIOError )

import System.Posix.Types
import System.Posix.Error
import System.Posix.IO.Common
import System.Posix.Internals ( withFilePath )

-- |Open and optionally create this file.  See 'System.Posix.Files'
-- for information on how to use the 'FileMode' type.
openFd :: FilePath
       -> OpenMode
       -> OpenFileFlags
       -> IO Fd
openFd :: FilePath -> OpenMode -> OpenFileFlags -> IO Fd
openFd = Maybe Fd -> FilePath -> OpenMode -> OpenFileFlags -> IO Fd
openFdAt Maybe Fd
forall a. Maybe a
Nothing

-- | Open a file relative to an optional directory file descriptor.
--
-- Directory file descriptors can be used to avoid some race conditions when
-- navigating changing directory trees, or to retain access to a portion of the
-- directory tree that would otherwise become inaccessible after dropping
-- privileges.
openFdAt :: Maybe Fd -- ^ Optional directory file descriptor
         -> FilePath -- ^ Pathname to open
         -> OpenMode -- ^ Read-only, read-write or write-only
         -> OpenFileFlags -- ^ Append, exclusive, truncate, etc.
         -> IO Fd
openFdAt :: Maybe Fd -> FilePath -> OpenMode -> OpenFileFlags -> IO Fd
openFdAt Maybe Fd
fdMay FilePath
name OpenMode
how OpenFileFlags
flags =
  FilePath -> (CString -> IO Fd) -> IO Fd
forall a. FilePath -> (CString -> IO a) -> IO a
withFilePath FilePath
name ((CString -> IO Fd) -> IO Fd) -> (CString -> IO Fd) -> IO Fd
forall a b. (a -> b) -> a -> b
$ \CString
str ->
    FilePath -> FilePath -> IO Fd -> IO Fd
forall a. (Eq a, Num a) => FilePath -> FilePath -> IO a -> IO a
throwErrnoPathIfMinus1Retry FilePath
"openFdAt" FilePath
name (IO Fd -> IO Fd) -> IO Fd -> IO Fd
forall a b. (a -> b) -> a -> b
$
      Maybe Fd -> CString -> OpenMode -> OpenFileFlags -> IO Fd
openat_ Maybe Fd
fdMay CString
str OpenMode
how OpenFileFlags
flags

-- |Create and open this file in WriteOnly mode.  A special case of
-- 'openFd'.  See 'System.Posix.Files' for information on how to use
-- the 'FileMode' type.
createFile :: FilePath -> FileMode -> IO Fd
createFile :: FilePath -> FileMode -> IO Fd
createFile = Maybe Fd -> FilePath -> FileMode -> IO Fd
createFileAt Maybe Fd
forall a. Maybe a
Nothing

-- | Create and open a file for write-only, with default flags,
-- relative an optional directory file-descriptor.
--
-- Directory file descriptors can be used to avoid some race conditions when
-- navigating changing directory trees, or to retain access to a portion of the
-- directory tree that would otherwise become inaccessible after dropping
-- privileges.
createFileAt :: Maybe Fd -- ^ Optional directory file descriptor
             -> FilePath -- ^ Pathname to create
             -> FileMode -- ^ File permission bits (before umask)
             -> IO Fd
createFileAt :: Maybe Fd -> FilePath -> FileMode -> IO Fd
createFileAt Maybe Fd
fdMay FilePath
name FileMode
mode
  = Maybe Fd -> FilePath -> OpenMode -> OpenFileFlags -> IO Fd
openFdAt Maybe Fd
fdMay FilePath
name OpenMode
WriteOnly OpenFileFlags
defaultFileFlags{ trunc :: Bool
trunc=Bool
True, creat :: Maybe FileMode
creat=(FileMode -> Maybe FileMode
forall a. a -> Maybe a
Just FileMode
mode) }

{-# DEPRECATED fdRead "This function is scheduled to be dropped in favor of 'System.Posix.IO.ByteString.fdRead', because decoding e.g. UTF-8 streams partially is unsafe." #-} -- deprecated in 2.8.0.0
-- | 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 -> ByteCount -> IO (FilePath, ByteCount)
fdRead Fd
_fd ByteCount
0 = (FilePath, ByteCount) -> IO (FilePath, ByteCount)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath
"", ByteCount
0)
fdRead Fd
fd ByteCount
nbytes =
  Int
-> (Ptr Word8 -> IO (FilePath, ByteCount))
-> IO (FilePath, ByteCount)
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes (ByteCount -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ByteCount
nbytes) ((Ptr Word8 -> IO (FilePath, ByteCount))
 -> IO (FilePath, ByteCount))
-> (Ptr Word8 -> IO (FilePath, ByteCount))
-> IO (FilePath, ByteCount)
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
buf -> do
  ByteCount
rc <- Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
fdReadBuf Fd
fd Ptr Word8
buf ByteCount
nbytes
  case ByteCount
rc of
    ByteCount
0 -> IOError -> IO (FilePath, ByteCount)
forall a. IOError -> IO a
ioError (IOError -> FilePath -> IOError
ioeSetErrorString (IOErrorType
-> FilePath -> Maybe Handle -> Maybe FilePath -> IOError
mkIOError IOErrorType
EOF FilePath
"fdRead" Maybe Handle
forall a. Maybe a
Nothing Maybe FilePath
forall a. Maybe a
Nothing) FilePath
"EOF")
    ByteCount
n -> do
      FilePath
s <- CStringLen -> IO FilePath
peekCStringLen (Ptr Word8 -> CString
forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
buf, ByteCount -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral ByteCount
n)
      (FilePath, ByteCount) -> IO (FilePath, ByteCount)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath
s, ByteCount
n)

-- | Write a 'String' to an 'Fd' using the locale encoding.
fdWrite :: Fd -> String -> IO ByteCount
fdWrite :: Fd -> FilePath -> IO ByteCount
fdWrite Fd
fd FilePath
str =
  FilePath -> (CStringLen -> IO ByteCount) -> IO ByteCount
forall a. FilePath -> (CStringLen -> IO a) -> IO a
withCStringLen FilePath
str ((CStringLen -> IO ByteCount) -> IO ByteCount)
-> (CStringLen -> IO ByteCount) -> IO ByteCount
forall a b. (a -> b) -> a -> b
$ \ (CString
buf,Int
len) ->
    Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
fdWriteBuf Fd
fd (CString -> Ptr Word8
forall a b. Ptr a -> Ptr b
castPtr CString
buf) (Int -> ByteCount
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)