{-# LINE 1 "System/Directory/Internal/Posix.hsc" #-}
{-# LANGUAGE CApiFFI #-}
module System.Directory.Internal.Posix where


{-# LINE 5 "System/Directory/Internal/Posix.hsc" #-}


{-# LINE 7 "System/Directory/Internal/Posix.hsc" #-}


{-# LINE 9 "System/Directory/Internal/Posix.hsc" #-}

{-# LINE 10 "System/Directory/Internal/Posix.hsc" #-}


{-# LINE 12 "System/Directory/Internal/Posix.hsc" #-}
import Prelude ()
import System.Directory.Internal.Prelude

{-# LINE 15 "System/Directory/Internal/Posix.hsc" #-}
import System.Directory.Internal.C_utimensat

{-# LINE 17 "System/Directory/Internal/Posix.hsc" #-}
import System.Directory.Internal.Common
import System.Directory.Internal.Config (exeExtension)
import Data.Time (UTCTime)
import Data.Time.Clock.POSIX (POSIXTime)
import System.OsPath ((</>), isRelative, splitSearchPath)
import System.OsString.Internal.Types (OsString(OsString, getOsString))
import qualified Data.Time.Clock.POSIX as POSIXTime
import qualified System.OsPath.Internal as OsPath
import qualified System.Posix.Directory.Fd as Posix
import qualified System.Posix.Directory.PosixPath as Posix
import qualified System.Posix.Env.PosixString as Posix
import qualified System.Posix.Files as Posix (FileStatus(..))
import qualified System.Posix.Files.PosixString as Posix
import qualified System.Posix.Internals as Posix (CStat)
import qualified System.Posix.IO.PosixString as Posix
import qualified System.Posix.PosixPath.FilePath as Posix
import qualified System.Posix.Types as Posix
import qualified System.Posix.User.ByteString as Posix

c_AT_FDCWD :: Posix.Fd
c_AT_FDCWD :: Fd
c_AT_FDCWD = CInt -> Fd
Posix.Fd (-CInt
100)
{-# LINE 38 "System/Directory/Internal/Posix.hsc" #-}

c_AT_SYMLINK_NOFOLLOW :: CInt
c_AT_SYMLINK_NOFOLLOW :: CInt
c_AT_SYMLINK_NOFOLLOW = (CInt
256)
{-# LINE 41 "System/Directory/Internal/Posix.hsc" #-}

atWhetherFollow :: WhetherFollow -> CInt
atWhetherFollow :: WhetherFollow -> CInt
atWhetherFollow WhetherFollow
NoFollow    = CInt
c_AT_SYMLINK_NOFOLLOW
atWhetherFollow WhetherFollow
FollowLinks = CInt
0

defaultOpenFlags :: Posix.OpenFileFlags
defaultOpenFlags :: OpenFileFlags
defaultOpenFlags =
  OpenFileFlags
Posix.defaultFileFlags
  { Posix.noctty = True
  , Posix.nonBlock = True
  , Posix.cloexec = True
  }

type RawHandle = Posix.Fd

openRaw :: WhetherFollow -> Maybe RawHandle -> OsPath -> IO RawHandle
openRaw :: WhetherFollow -> Maybe Fd -> OsString -> IO Fd
openRaw WhetherFollow
whetherFollow Maybe Fd
dir (OsString PlatformString
path) =
  Maybe Fd -> PlatformString -> OpenMode -> OpenFileFlags -> IO Fd
Posix.openFdAt Maybe Fd
dir PlatformString
path OpenMode
Posix.ReadOnly OpenFileFlags
flags
  where
    flags :: OpenFileFlags
flags = OpenFileFlags
defaultOpenFlags { Posix.nofollow = isNoFollow whetherFollow }

closeRaw :: RawHandle -> IO ()
closeRaw :: Fd -> IO ()
closeRaw = Fd -> IO ()
Posix.closeFd

createDirectoryInternal :: OsPath -> IO ()
createDirectoryInternal :: OsString -> IO ()
createDirectoryInternal (OsString PlatformString
path) = PlatformString -> Mode -> IO ()
Posix.createDirectory PlatformString
path Mode
0o777

foreign import ccall "unistd.h unlinkat" c_unlinkat
  :: Posix.Fd -> CString -> CInt -> IO CInt

removePathAt :: FileType -> Maybe RawHandle -> OsPath -> IO ()
removePathAt :: FileType -> Maybe Fd -> OsString -> IO ()
removePathAt FileType
ty Maybe Fd
dir (OsString PlatformString
path) =
  PlatformString -> (CString -> IO ()) -> IO ()
forall a. PlatformString -> (CString -> IO a) -> IO a
Posix.withFilePath PlatformString
path ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ CString
pPath -> do
    String -> PlatformString -> IO CInt -> IO ()
forall a.
(Eq a, Num a) =>
String -> PlatformString -> IO a -> IO ()
Posix.throwErrnoPathIfMinus1_ String
"unlinkat" PlatformString
path
      (Fd -> CString -> CInt -> IO CInt
c_unlinkat (Fd -> Maybe Fd -> Fd
forall a. a -> Maybe a -> a
fromMaybe Fd
c_AT_FDCWD Maybe Fd
dir) CString
pPath CInt
flag)
    () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  where
    flag :: CInt
flag | FileType -> Bool
fileTypeIsDirectory FileType
ty = (CInt
512)
{-# LINE 79 "System/Directory/Internal/Posix.hsc" #-}
         | Bool
otherwise              = CInt
0

removePathInternal :: Bool -> OsPath -> IO ()
removePathInternal :: Bool -> OsString -> IO ()
removePathInternal Bool
True  = PlatformString -> IO ()
Posix.removeDirectory (PlatformString -> IO ())
-> (OsString -> PlatformString) -> OsString -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsString -> PlatformString
getOsString
removePathInternal Bool
False = PlatformString -> IO ()
Posix.removeLink (PlatformString -> IO ())
-> (OsString -> PlatformString) -> OsString -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsString -> PlatformString
getOsString

renamePathInternal :: OsPath -> OsPath -> IO ()
renamePathInternal :: OsString -> OsString -> IO ()
renamePathInternal (OsString PlatformString
p1) (OsString PlatformString
p2) = PlatformString -> PlatformString -> IO ()
Posix.rename PlatformString
p1 PlatformString
p2

-- On POSIX, the removability of a file is only affected by the attributes of
-- the containing directory.
filesAlwaysRemovable :: Bool
filesAlwaysRemovable :: Bool
filesAlwaysRemovable = Bool
True

-- | On POSIX, equivalent to 'simplifyPosix'.
simplify :: OsPath -> OsPath
simplify :: OsString -> OsString
simplify = OsString -> OsString
simplifyPosix

-- we use the 'free' from the standard library here since it's not entirely
-- clear whether Haskell's 'free' corresponds to the same one
foreign import ccall unsafe "free" c_free :: Ptr a -> IO ()

c_PATH_MAX :: Maybe Int

{-# LINE 103 "System/Directory/Internal/Posix.hsc" #-}
c_PATH_MAX | c_PATH_MAX' > toInteger maxValue = Nothing
           | otherwise                        = Just (fromInteger c_PATH_MAX')
  where c_PATH_MAX' = (4096)
{-# LINE 106 "System/Directory/Internal/Posix.hsc" #-}
        maxValue = maxBound `asTypeInMaybe` c_PATH_MAX
        asTypeInMaybe :: a -> Maybe a -> a
        asTypeInMaybe = const

{-# LINE 112 "System/Directory/Internal/Posix.hsc" #-}


{-# LINE 119 "System/Directory/Internal/Posix.hsc" #-}

foreign import ccall "realpath" c_realpath :: CString -> CString -> IO CString


{-# LINE 123 "System/Directory/Internal/Posix.hsc" #-}

withRealpath :: CString -> (CString -> IO a) -> IO a
withRealpath :: forall a. CString -> (CString -> IO a) -> IO a
withRealpath CString
path CString -> IO a
action = case Maybe Int
c_PATH_MAX of
  Maybe Int
Nothing ->
    -- newer versions of POSIX support cases where the 2nd arg is NULL;
    -- hopefully that is the case here, as there is no safer way
    IO CString -> (CString -> IO ()) -> (CString -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (CString -> IO CString
realpath CString
forall a. Ptr a
nullPtr) CString -> IO ()
forall a. Ptr a -> IO ()
c_free CString -> IO a
action
  Just Int
pathMax ->
    -- allocate one extra just to be safe
    Int -> (CString -> IO a) -> IO a
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes (Int
pathMax Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (CString -> IO CString
realpath (CString -> IO CString) -> (CString -> IO a) -> CString -> IO a
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> CString -> IO a
action)
  where realpath :: CString -> IO CString
realpath = String -> IO CString -> IO CString
forall a. String -> IO (Ptr a) -> IO (Ptr a)
throwErrnoIfNull String
"" (IO CString -> IO CString)
-> (CString -> IO CString) -> CString -> IO CString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CString -> CString -> IO CString
c_realpath CString
path

realPath :: OsPath -> IO OsPath
realPath :: OsString -> IO OsString
realPath (OsString PlatformString
path') =
  PlatformString -> (CString -> IO OsString) -> IO OsString
forall a. PlatformString -> (CString -> IO a) -> IO a
Posix.withFilePath PlatformString
path'
    (CString -> (CString -> IO OsString) -> IO OsString
forall a. CString -> (CString -> IO a) -> IO a
`withRealpath` ((PlatformString -> OsString
OsString (PlatformString -> OsString) -> IO PlatformString -> IO OsString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (IO PlatformString -> IO OsString)
-> (CString -> IO PlatformString) -> CString -> IO OsString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CString -> IO PlatformString
Posix.peekFilePath))

canonicalizePathSimplify :: OsPath -> IO OsPath
canonicalizePathSimplify :: OsString -> IO OsString
canonicalizePathSimplify = OsString -> IO OsString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

findExecutablesLazyInternal :: ([OsPath] -> OsString -> ListT IO OsPath)
                            -> OsString
                            -> ListT IO OsPath
findExecutablesLazyInternal :: ([OsString] -> OsString -> ListT IO OsString)
-> OsString -> ListT IO OsString
findExecutablesLazyInternal [OsString] -> OsString -> ListT IO OsString
findExecutablesInDirectoriesLazy OsString
binary =
  IO (ListT IO OsString) -> ListT IO OsString
forall (m :: * -> *) a. Monad m => m (ListT m a) -> ListT m a
liftJoinListT (IO (ListT IO OsString) -> ListT IO OsString)
-> IO (ListT IO OsString) -> ListT IO OsString
forall a b. (a -> b) -> a -> b
$ do
    [OsString]
path <- IO [OsString]
getPath
    ListT IO OsString -> IO (ListT IO OsString)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([OsString] -> OsString -> ListT IO OsString
findExecutablesInDirectoriesLazy [OsString]
path OsString
binary)

exeExtensionInternal :: OsString
exeExtensionInternal :: OsString
exeExtensionInternal = OsString
exeExtension

openDirFromFd :: Posix.Fd -> IO Posix.DirStream
openDirFromFd :: Fd -> IO DirStream
openDirFromFd Fd
fd = Fd -> IO DirStream
Posix.unsafeOpenDirStreamFd (Fd -> IO DirStream) -> IO Fd -> IO DirStream
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Fd -> IO Fd
Posix.dup Fd
fd

readDirStreamToEnd :: Posix.DirStream -> IO [OsPath]
readDirStreamToEnd :: DirStream -> IO [OsString]
readDirStreamToEnd DirStream
stream = ([OsString] -> [OsString]) -> IO [OsString]
forall {c}. ([OsString] -> c) -> IO c
loop [OsString] -> [OsString]
forall a. a -> a
id
  where
    loop :: ([OsString] -> c) -> IO c
loop [OsString] -> c
acc = do
      PlatformString
e <- DirStream -> IO PlatformString
Posix.readDirStream DirStream
stream
      if PlatformString
e PlatformString -> PlatformString -> Bool
forall a. Eq a => a -> a -> Bool
== PlatformString
forall a. Monoid a => a
mempty
        then c -> IO c
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([OsString] -> c
acc [])
        else ([OsString] -> c) -> IO c
loop ([OsString] -> c
acc ([OsString] -> c) -> ([OsString] -> [OsString]) -> [OsString] -> c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (PlatformString -> OsString
OsString PlatformString
e OsString -> [OsString] -> [OsString]
forall a. a -> [a] -> [a]
:))

readDirToEnd :: RawHandle -> IO [OsPath]
readDirToEnd :: Fd -> IO [OsString]
readDirToEnd Fd
fd =
  IO DirStream
-> (DirStream -> IO ())
-> (DirStream -> IO [OsString])
-> IO [OsString]
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (Fd -> IO DirStream
openDirFromFd Fd
fd) DirStream -> IO ()
Posix.closeDirStream DirStream -> IO [OsString]
readDirStreamToEnd

getDirectoryContentsInternal :: OsPath -> IO [OsPath]
getDirectoryContentsInternal :: OsString -> IO [OsString]
getDirectoryContentsInternal (OsString PlatformString
path) =
  IO DirStream
-> (DirStream -> IO ())
-> (DirStream -> IO [OsString])
-> IO [OsString]
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (PlatformString -> IO DirStream
Posix.openDirStream PlatformString
path) DirStream -> IO ()
Posix.closeDirStream DirStream -> IO [OsString]
readDirStreamToEnd

getCurrentDirectoryInternal :: IO OsPath
getCurrentDirectoryInternal :: IO OsString
getCurrentDirectoryInternal = PlatformString -> OsString
OsString (PlatformString -> OsString) -> IO PlatformString -> IO OsString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO PlatformString
Posix.getWorkingDirectory

-- | Convert a path into an absolute path.  If the given path is relative, the
-- current directory is prepended and the path may or may not be simplified.
-- If the path is already absolute, the path is returned unchanged.  The
-- function preserves the presence or absence of the trailing path separator.
--
-- If the path is already absolute, the operation never fails.  Otherwise, the
-- operation may throw exceptions.
--
-- Empty paths are treated as the current directory.
prependCurrentDirectory :: OsPath -> IO OsPath
prependCurrentDirectory :: OsString -> IO OsString
prependCurrentDirectory OsString
path
  | OsString -> Bool
isRelative OsString
path =
    ((IOError -> String -> IOError
`ioeAddLocation` String
"prependCurrentDirectory") (IOError -> IOError) -> (IOError -> IOError) -> IOError -> IOError
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
     (IOError -> OsString -> IOError
`ioeSetOsPath` OsString
path)) (IOError -> IOError) -> IO OsString -> IO OsString
forall a. (IOError -> IOError) -> IO a -> IO a
`modifyIOError` do
      (OsString -> OsString -> OsString
</> OsString
path) (OsString -> OsString) -> IO OsString -> IO OsString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO OsString
getCurrentDirectoryInternal
  | Bool
otherwise = OsString -> IO OsString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure OsString
path

setCurrentDirectoryInternal :: OsPath -> IO ()
setCurrentDirectoryInternal :: OsString -> IO ()
setCurrentDirectoryInternal = PlatformString -> IO ()
Posix.changeWorkingDirectory (PlatformString -> IO ())
-> (OsString -> PlatformString) -> OsString -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsString -> PlatformString
getOsString

linkToDirectoryIsDirectory :: Bool
linkToDirectoryIsDirectory :: Bool
linkToDirectoryIsDirectory = Bool
False

createHardLink :: OsPath -> OsPath -> IO ()
createHardLink :: OsString -> OsString -> IO ()
createHardLink (OsString PlatformString
p1) (OsString PlatformString
p2) = PlatformString -> PlatformString -> IO ()
Posix.createLink PlatformString
p1 PlatformString
p2

createSymbolicLink :: Bool -> OsPath -> OsPath -> IO ()
createSymbolicLink :: Bool -> OsString -> OsString -> IO ()
createSymbolicLink Bool
_ (OsString PlatformString
p1) (OsString PlatformString
p2) =
  PlatformString -> PlatformString -> IO ()
Posix.createSymbolicLink PlatformString
p1 PlatformString
p2

readSymbolicLink :: OsPath -> IO OsPath
readSymbolicLink :: OsString -> IO OsString
readSymbolicLink = (PlatformString -> OsString
OsString (PlatformString -> OsString) -> IO PlatformString -> IO OsString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (IO PlatformString -> IO OsString)
-> (OsString -> IO PlatformString) -> OsString -> IO OsString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PlatformString -> IO PlatformString
Posix.readSymbolicLink (PlatformString -> IO PlatformString)
-> (OsString -> PlatformString) -> OsString -> IO PlatformString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsString -> PlatformString
getOsString

type Metadata = Posix.FileStatus

foreign import capi "sys/stat.h fstatat" c_fstatat
  :: Posix.Fd -> CString -> Ptr Posix.CStat -> CInt -> IO CInt

getMetadataAt :: WhetherFollow -> Maybe RawHandle -> OsPath -> IO Metadata
getMetadataAt :: WhetherFollow -> Maybe Fd -> OsString -> IO Metadata
getMetadataAt WhetherFollow
whetherFollow Maybe Fd
dir (OsString PlatformString
path) =
  PlatformString -> (CString -> IO Metadata) -> IO Metadata
forall a. PlatformString -> (CString -> IO a) -> IO a
Posix.withFilePath PlatformString
path ((CString -> IO Metadata) -> IO Metadata)
-> (CString -> IO Metadata) -> IO Metadata
forall a b. (a -> b) -> a -> b
$ \ CString
pPath -> do
    ForeignPtr CStat
stat <- Int -> IO (ForeignPtr CStat)
forall a. Int -> IO (ForeignPtr a)
mallocForeignPtrBytes (Int
144)
{-# LINE 219 "System/Directory/Internal/Posix.hsc" #-}
    withForeignPtr stat $ \ pStat -> do
      Posix.throwErrnoPathIfMinus1_ "fstatat" path $ do
        c_fstatat (fromMaybe c_AT_FDCWD dir) pPath pStat flags
    Metadata -> IO Metadata
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ForeignPtr CStat -> Metadata
Posix.FileStatus ForeignPtr CStat
stat)
  where
    flags :: CInt
flags = WhetherFollow -> CInt
atWhetherFollow WhetherFollow
whetherFollow

getSymbolicLinkMetadata :: OsPath -> IO Metadata
getSymbolicLinkMetadata :: OsString -> IO Metadata
getSymbolicLinkMetadata = PlatformString -> IO Metadata
Posix.getSymbolicLinkStatus (PlatformString -> IO Metadata)
-> (OsString -> PlatformString) -> OsString -> IO Metadata
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsString -> PlatformString
getOsString

getFileMetadata :: OsPath -> IO Metadata
getFileMetadata :: OsString -> IO Metadata
getFileMetadata = PlatformString -> IO Metadata
Posix.getFileStatus (PlatformString -> IO Metadata)
-> (OsString -> PlatformString) -> OsString -> IO Metadata
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsString -> PlatformString
getOsString

fileTypeFromMetadata :: Metadata -> FileType
fileTypeFromMetadata :: Metadata -> FileType
fileTypeFromMetadata Metadata
stat
  | Bool
isLink    = FileType
SymbolicLink
  | Bool
isDir     = FileType
Directory
  | Bool
otherwise = FileType
File
  where
    isLink :: Bool
isLink = Metadata -> Bool
Posix.isSymbolicLink Metadata
stat
    isDir :: Bool
isDir  = Metadata -> Bool
Posix.isDirectory Metadata
stat

fileSizeFromMetadata :: Metadata -> Integer
fileSizeFromMetadata :: Metadata -> Integer
fileSizeFromMetadata = FileOffset -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (FileOffset -> Integer)
-> (Metadata -> FileOffset) -> Metadata -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Metadata -> FileOffset
Posix.fileSize

accessTimeFromMetadata :: Metadata -> UTCTime
accessTimeFromMetadata :: Metadata -> UTCTime
accessTimeFromMetadata =
  POSIXTime -> UTCTime
POSIXTime.posixSecondsToUTCTime (POSIXTime -> UTCTime)
-> (Metadata -> POSIXTime) -> Metadata -> UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Metadata -> POSIXTime
Posix.accessTimeHiRes

modificationTimeFromMetadata :: Metadata -> UTCTime
modificationTimeFromMetadata :: Metadata -> UTCTime
modificationTimeFromMetadata =
  POSIXTime -> UTCTime
POSIXTime.posixSecondsToUTCTime (POSIXTime -> UTCTime)
-> (Metadata -> POSIXTime) -> Metadata -> UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Metadata -> POSIXTime
Posix.modificationTimeHiRes

type Mode = Posix.FileMode

modeFromMetadata :: Metadata -> Mode
modeFromMetadata :: Metadata -> Mode
modeFromMetadata = Metadata -> Mode
Posix.fileMode

allWriteMode :: Posix.FileMode
allWriteMode :: Mode
allWriteMode =
  Mode
Posix.ownerWriteMode Mode -> Mode -> Mode
forall a. Bits a => a -> a -> a
.|.
  Mode
Posix.groupWriteMode Mode -> Mode -> Mode
forall a. Bits a => a -> a -> a
.|.
  Mode
Posix.otherWriteMode

hasWriteMode :: Mode -> Bool
hasWriteMode :: Mode -> Bool
hasWriteMode Mode
m = Mode
m Mode -> Mode -> Mode
forall a. Bits a => a -> a -> a
.&. Mode
allWriteMode Mode -> Mode -> Bool
forall a. Eq a => a -> a -> Bool
/= Mode
0

setWriteMode :: Bool -> Mode -> Mode
setWriteMode :: Bool -> Mode -> Mode
setWriteMode Bool
False Mode
m = Mode
m Mode -> Mode -> Mode
forall a. Bits a => a -> a -> a
.&. Mode -> Mode
forall a. Bits a => a -> a
complement Mode
allWriteMode
setWriteMode Bool
True  Mode
m = Mode
m Mode -> Mode -> Mode
forall a. Bits a => a -> a -> a
.|. Mode
allWriteMode

setForceRemoveMode :: Mode -> Mode
setForceRemoveMode :: Mode -> Mode
setForceRemoveMode Mode
m = Mode
m Mode -> Mode -> Mode
forall a. Bits a => a -> a -> a
.|. Mode
Posix.ownerModes

foreign import capi "sys/stat.h fchmodat" c_fchmodat
  :: Posix.Fd -> CString -> Posix.FileMode -> CInt -> IO CInt

setModeAt :: WhetherFollow -> Maybe RawHandle -> OsPath -> Mode -> IO ()
setModeAt :: WhetherFollow -> Maybe Fd -> OsString -> Mode -> IO ()
setModeAt WhetherFollow
whetherFollow Maybe Fd
dir (OsString PlatformString
path) Mode
mode = do
  PlatformString -> (CString -> IO ()) -> IO ()
forall a. PlatformString -> (CString -> IO a) -> IO a
Posix.withFilePath PlatformString
path ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ CString
pPath ->
    String -> PlatformString -> IO CInt -> IO ()
forall a.
(Eq a, Num a) =>
String -> PlatformString -> IO a -> IO ()
Posix.throwErrnoPathIfMinus1_ String
"fchmodat" PlatformString
path (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ do
      Fd -> CString -> Mode -> CInt -> IO CInt
c_fchmodat (Fd -> Maybe Fd -> Fd
forall a. a -> Maybe a -> a
fromMaybe Fd
c_AT_FDCWD Maybe Fd
dir) CString
pPath Mode
mode CInt
flags
  where
    flags :: CInt
flags = WhetherFollow -> CInt
atWhetherFollow WhetherFollow
whetherFollow

setFileMode :: OsPath -> Mode -> IO ()
setFileMode :: OsString -> Mode -> IO ()
setFileMode = PlatformString -> Mode -> IO ()
Posix.setFileMode (PlatformString -> Mode -> IO ())
-> (OsString -> PlatformString) -> OsString -> Mode -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OsString -> PlatformString
getOsString

setFilePermissions :: OsPath -> Mode -> IO ()
setFilePermissions :: OsString -> Mode -> IO ()
setFilePermissions = OsString -> Mode -> IO ()
setFileMode

getAccessPermissions :: OsPath -> IO Permissions
getAccessPermissions :: OsString -> IO Permissions
getAccessPermissions OsString
path = do
  Metadata
m <- OsString -> IO Metadata
getFileMetadata OsString
path
  let isDir :: Bool
isDir = FileType -> Bool
fileTypeIsDirectory (Metadata -> FileType
fileTypeFromMetadata Metadata
m)
  let OsString PlatformString
path' = OsString
path
  Bool
r <- PlatformString -> Bool -> Bool -> Bool -> IO Bool
Posix.fileAccess PlatformString
path' Bool
True  Bool
False Bool
False
  Bool
w <- PlatformString -> Bool -> Bool -> Bool -> IO Bool
Posix.fileAccess PlatformString
path' Bool
False Bool
True  Bool
False
  Bool
x <- PlatformString -> Bool -> Bool -> Bool -> IO Bool
Posix.fileAccess PlatformString
path' Bool
False Bool
False Bool
True
  Permissions -> IO Permissions
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Permissions
       { readable :: Bool
readable   = Bool
r
       , writable :: Bool
writable   = Bool
w
       , executable :: Bool
executable = Bool
x Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
isDir
       , searchable :: Bool
searchable = Bool
x Bool -> Bool -> Bool
&& Bool
isDir
       }

setAccessPermissions :: OsPath -> Permissions -> IO ()
setAccessPermissions :: OsString -> Permissions -> IO ()
setAccessPermissions OsString
path (Permissions Bool
r Bool
w Bool
e Bool
s) = do
  Metadata
m <- OsString -> IO Metadata
getFileMetadata OsString
path
  OsString -> Mode -> IO ()
setFileMode OsString
path (Bool -> Mode -> Mode -> Mode
modifyBit (Bool
e Bool -> Bool -> Bool
|| Bool
s) Mode
Posix.ownerExecuteMode (Mode -> Mode) -> (Metadata -> Mode) -> Metadata -> Mode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                    Bool -> Mode -> Mode -> Mode
modifyBit Bool
w Mode
Posix.ownerWriteMode (Mode -> Mode) -> (Metadata -> Mode) -> Metadata -> Mode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                    Bool -> Mode -> Mode -> Mode
modifyBit Bool
r Mode
Posix.ownerReadMode (Mode -> Mode) -> (Metadata -> Mode) -> Metadata -> Mode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                    Metadata -> Mode
modeFromMetadata (Metadata -> Mode) -> Metadata -> Mode
forall a b. (a -> b) -> a -> b
$ Metadata
m)
  where
    modifyBit :: Bool -> Posix.FileMode -> Posix.FileMode -> Posix.FileMode
    modifyBit :: Bool -> Mode -> Mode -> Mode
modifyBit Bool
False Mode
b Mode
m = Mode
m Mode -> Mode -> Mode
forall a. Bits a => a -> a -> a
.&. Mode -> Mode
forall a. Bits a => a -> a
complement Mode
b
    modifyBit Bool
True  Mode
b Mode
m = Mode
m Mode -> Mode -> Mode
forall a. Bits a => a -> a -> a
.|. Mode
b

copyOwnerFromStatus :: Posix.FileStatus -> OsPath -> IO ()
copyOwnerFromStatus :: Metadata -> OsString -> IO ()
copyOwnerFromStatus Metadata
st (OsString PlatformString
dst) = do
  PlatformString -> UserID -> GroupID -> IO ()
Posix.setOwnerAndGroup PlatformString
dst (Metadata -> UserID
Posix.fileOwner Metadata
st) (-GroupID
1)

copyGroupFromStatus :: Posix.FileStatus -> OsPath -> IO ()
copyGroupFromStatus :: Metadata -> OsString -> IO ()
copyGroupFromStatus Metadata
st (OsString PlatformString
dst) = do
  PlatformString -> UserID -> GroupID -> IO ()
Posix.setOwnerAndGroup PlatformString
dst (-UserID
1) (Metadata -> GroupID
Posix.fileGroup Metadata
st)

tryCopyOwnerAndGroupFromStatus :: Posix.FileStatus -> OsPath -> IO ()
tryCopyOwnerAndGroupFromStatus :: Metadata -> OsString -> IO ()
tryCopyOwnerAndGroupFromStatus Metadata
st OsString
dst = do
  IO () -> IO ()
ignoreIOExceptions (Metadata -> OsString -> IO ()
copyOwnerFromStatus Metadata
st OsString
dst)
  IO () -> IO ()
ignoreIOExceptions (Metadata -> OsString -> IO ()
copyGroupFromStatus Metadata
st OsString
dst)

-- | Truncate the destination file and then copy the contents of the source
-- file to the destination file.  If the destination file already exists, its
-- attributes shall remain unchanged.  Otherwise, its attributes are reset to
-- the defaults.
copyFileContents :: OsPath              -- ^ Source filename
                 -> OsPath              -- ^ Destination filename
                 -> IO ()
copyFileContents :: OsString -> OsString -> IO ()
copyFileContents OsString
fromFPath OsString
toFPath =
  (IOError -> String -> IOError
`ioeAddLocation` String
"copyFileContents") (IOError -> IOError) -> IO () -> IO ()
forall a. (IOError -> IOError) -> IO a -> IO a
`modifyIOError` do
    OsString -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. OsString -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile OsString
toFPath IOMode
WriteMode ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Handle
hTo -> do
      OsString -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. OsString -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile OsString
fromFPath IOMode
ReadMode ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ Handle
hFrom -> do
        Handle -> Handle -> IO ()
copyHandleData Handle
hFrom Handle
hTo

copyFileWithMetadataInternal :: (Metadata -> OsPath -> IO ())
                             -> (Metadata -> OsPath -> IO ())
                             -> OsPath
                             -> OsPath
                             -> IO ()
copyFileWithMetadataInternal :: (Metadata -> OsString -> IO ())
-> (Metadata -> OsString -> IO ()) -> OsString -> OsString -> IO ()
copyFileWithMetadataInternal Metadata -> OsString -> IO ()
copyPermissionsFromMetadata
                             Metadata -> OsString -> IO ()
copyTimesFromMetadata
                             OsString
src
                             OsString
dst = do
  Metadata
st <- PlatformString -> IO Metadata
Posix.getFileStatus (OsString -> PlatformString
getOsString OsString
src)
  OsString -> OsString -> IO ()
copyFileContents OsString
src OsString
dst
  Metadata -> OsString -> IO ()
tryCopyOwnerAndGroupFromStatus Metadata
st OsString
dst
  Metadata -> OsString -> IO ()
copyPermissionsFromMetadata Metadata
st OsString
dst
  Metadata -> OsString -> IO ()
copyTimesFromMetadata Metadata
st OsString
dst

setTimes :: OsPath -> (Maybe POSIXTime, Maybe POSIXTime) -> IO ()

setTimes :: OsString -> (Maybe POSIXTime, Maybe POSIXTime) -> IO ()
{-# LINE 360 "System/Directory/Internal/Posix.hsc" #-}
setTimes (OsString path') (atime', mtime') =
  Posix.withFilePath path' $ \ path'' ->
  withArray [ maybe utimeOmit toCTimeSpec atime'
            , maybe utimeOmit toCTimeSpec mtime' ] $ \ times ->
  Posix.throwErrnoPathIfMinus1_ "" path' $
    c_utimensat c_AT_FDCWD path'' times 0

{-# LINE 377 "System/Directory/Internal/Posix.hsc" #-}

lookupEnvOs :: OsString -> IO (Maybe OsString)
lookupEnvOs :: OsString -> IO (Maybe OsString)
lookupEnvOs (OsString PlatformString
name) = (PlatformString -> OsString
OsString (PlatformString -> OsString)
-> Maybe PlatformString -> Maybe OsString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Maybe PlatformString -> Maybe OsString)
-> IO (Maybe PlatformString) -> IO (Maybe OsString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> PlatformString -> IO (Maybe PlatformString)
Posix.getEnv PlatformString
name

getEnvOs :: OsString -> IO OsString
getEnvOs :: OsString -> IO OsString
getEnvOs OsString
name = do
  Maybe OsString
env <- OsString -> IO (Maybe OsString)
lookupEnvOs OsString
name
  case Maybe OsString
env of
    Maybe OsString
Nothing ->
      IOError -> IO OsString
forall e a. Exception e => e -> IO a
throwIO (IOError -> IO OsString) -> IOError -> IO OsString
forall a b. (a -> b) -> a -> b
$
        IOErrorType -> String -> Maybe Handle -> Maybe String -> IOError
mkIOError
          IOErrorType
doesNotExistErrorType
          (String
"env var " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> OsString -> String
forall a. Show a => a -> String
show OsString
name String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" not found")
          Maybe Handle
forall a. Maybe a
Nothing
          Maybe String
forall a. Maybe a
Nothing
    Just OsString
value -> OsString -> IO OsString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure OsString
value

-- | Get the contents of the @PATH@ environment variable.
getPath :: IO [OsPath]
getPath :: IO [OsString]
getPath = OsString -> [OsString]
splitSearchPath (OsString -> [OsString]) -> IO OsString -> IO [OsString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> OsString -> IO OsString
getEnvOs (String -> OsString
os String
"PATH")

-- | $HOME is preferred, because the user has control over it. However, POSIX
-- doesn't define it as a mandatory variable, so fall back to `getpwuid_r`.
getHomeDirectoryInternal :: IO OsPath
getHomeDirectoryInternal :: IO OsString
getHomeDirectoryInternal = do
  Maybe OsString
e <- OsString -> IO (Maybe OsString)
lookupEnvOs (String -> OsString
os String
"HOME")
  case Maybe OsString
e of
    Just OsString
fp -> OsString -> IO OsString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure OsString
fp
    Maybe OsString
Nothing ->
      ByteString -> IO OsString
forall (m :: * -> *). MonadThrow m => ByteString -> m OsString
OsPath.fromBytes (ByteString -> IO OsString)
-> (UserEntry -> ByteString) -> UserEntry -> IO OsString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UserEntry -> ByteString
Posix.homeDirectory (UserEntry -> IO OsString) -> IO UserEntry -> IO OsString
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<
        UserID -> IO UserEntry
Posix.getUserEntryForID (UserID -> IO UserEntry) -> IO UserID -> IO UserEntry
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<
        IO UserID
Posix.getEffectiveUserID

getXdgDirectoryFallback :: IO OsPath -> XdgDirectory -> IO OsPath
getXdgDirectoryFallback :: IO OsString -> XdgDirectory -> IO OsString
getXdgDirectoryFallback IO OsString
getHomeDirectory XdgDirectory
xdgDir = do
  ((OsString -> OsString) -> IO OsString -> IO OsString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO OsString
getHomeDirectory) ((OsString -> OsString) -> IO OsString)
-> (OsString -> OsString) -> IO OsString
forall a b. (a -> b) -> a -> b
$ (OsString -> OsString -> OsString)
-> OsString -> OsString -> OsString
forall a b c. (a -> b -> c) -> b -> a -> c
flip OsString -> OsString -> OsString
(</>) (OsString -> OsString -> OsString)
-> OsString -> OsString -> OsString
forall a b. (a -> b) -> a -> b
$ case XdgDirectory
xdgDir of
    XdgDirectory
XdgData   -> String -> OsString
os String
".local/share"
    XdgDirectory
XdgConfig -> String -> OsString
os String
".config"
    XdgDirectory
XdgCache  -> String -> OsString
os String
".cache"
    XdgDirectory
XdgState  -> String -> OsString
os String
".local/state"

getXdgDirectoryListFallback :: XdgDirectoryList -> IO [OsPath]
getXdgDirectoryListFallback :: XdgDirectoryList -> IO [OsString]
getXdgDirectoryListFallback XdgDirectoryList
xdgDirs =
  [OsString] -> IO [OsString]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([OsString] -> IO [OsString]) -> [OsString] -> IO [OsString]
forall a b. (a -> b) -> a -> b
$ case XdgDirectoryList
xdgDirs of
    XdgDirectoryList
XdgDataDirs   -> [String -> OsString
os String
"/usr/local/share/", String -> OsString
os String
"/usr/share/"]
    XdgDirectoryList
XdgConfigDirs -> [String -> OsString
os String
"/etc/xdg"]

getAppUserDataDirectoryInternal :: OsPath -> IO OsPath
getAppUserDataDirectoryInternal :: OsString -> IO OsString
getAppUserDataDirectoryInternal OsString
appName =
  (\ OsString
home -> OsString
home OsString -> OsString -> OsString
forall a. Semigroup a => a -> a -> a
<> (String -> OsString
os String
"/" OsString -> OsString -> OsString
forall a. Semigroup a => a -> a -> a
<> String -> OsString
os String
"." OsString -> OsString -> OsString
forall a. Semigroup a => a -> a -> a
<> OsString
appName)) (OsString -> OsString) -> IO OsString -> IO OsString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO OsString
getHomeDirectoryInternal

getUserDocumentsDirectoryInternal :: IO OsPath
getUserDocumentsDirectoryInternal :: IO OsString
getUserDocumentsDirectoryInternal = IO OsString
getHomeDirectoryInternal

getTemporaryDirectoryInternal :: IO OsPath
getTemporaryDirectoryInternal :: IO OsString
getTemporaryDirectoryInternal = OsString -> Maybe OsString -> OsString
forall a. a -> Maybe a -> a
fromMaybe (String -> OsString
os String
"/tmp") (Maybe OsString -> OsString) -> IO (Maybe OsString) -> IO OsString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> OsString -> IO (Maybe OsString)
lookupEnvOs (String -> OsString
os String
"TMPDIR")


{-# LINE 435 "System/Directory/Internal/Posix.hsc" #-}