    {-# LANGUAGE CPP #-}
    {-# LANGUAGE ScopedTypeVariables #-}

    module System.EasyFile.Directory (
        module System.EasyFile.Directory
      , module System.Directory
      ) where

    import System.Directory (
        createDirectory
      , createDirectoryIfMissing
      , removeDirectory
      , removeDirectoryRecursive
      , renameDirectory
      , getDirectoryContents
      , setCurrentDirectory
      , removeFile
      , renameFile
      , copyFile
      , canonicalizePath
      , doesFileExist
      , doesDirectoryExist
      , Permissions(..)
      , getPermissions
      , setPermissions
      )

    import qualified System.Directory as D (
        getCurrentDirectory
      , getHomeDirectory
      , getAppUserDataDirectory
      , getUserDocumentsDirectory
      , getTemporaryDirectory
      , copyPermissions
      )

    #if !MIN_VERSION_base(4,8,0)
    import Control.Applicative
    #endif
    import qualified Control.Exception as E
    import System.Environment

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

    {- |If the operating system has a notion of current directories,
    'getCurrentDirectory' returns an absolute path to the
    current directory of the calling process.

    The operation may fail with:

    * 'HardwareFault'
    A physical I\/O error has occurred.
    @[EIO]@

    * 'isDoesNotExistError' \/ 'NoSuchThing'
    There is no path referring to the current directory.
    @[EPERM, ENOENT, ESTALE...]@

    * 'isPermissionError' \/ 'PermissionDenied'
    The process has insufficient privileges to perform the operation.
    @[EACCES]@

    * 'ResourceExhausted'
    Insufficient resources are available to perform the operation.

    * 'UnsupportedOperation'
    The operating system has no notion of current directory.

    -}
    getCurrentDirectory :: IO FilePath
    getCurrentDirectory :: IO FilePath
    getCurrentDirectory = FilePath -> FilePath
    fixPath (FilePath -> FilePath) -> IO FilePath -> IO FilePath
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO FilePath
    D.getCurrentDirectory

    {- | Returns the current user's home directory.

    The directory returned is expected to be writable by the current user,
    but note that it isn't generally considered good practice to store
    application-specific data here; use 'getAppUserDataDirectory'
    instead.

    On Unix, 'getHomeDirectory' returns the value of the @HOME@
    environment variable.  On Windows, the system is queried for a
    suitable path; a typical path might be
    @C:/Documents And Settings/user@.

    The operation may fail with:

    * 'UnsupportedOperation'
    The operating system has no notion of home directory.

    * 'isDoesNotExistError'
    The home directory for the current user does not exist, or
    cannot be found.
    -}
    getHomeDirectory :: IO FilePath
    getHomeDirectory :: IO FilePath
    getHomeDirectory = FilePath -> FilePath
    fixPath (FilePath -> FilePath) -> IO FilePath -> IO FilePath
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO FilePath
    D.getHomeDirectory

    {- | Returns the current user's home directory from
    the @HOME@ environment variable.
    -}

    getHomeDirectory2 :: IO (Maybe FilePath)
    getHomeDirectory2 :: IO (Maybe FilePath)
    getHomeDirectory2 = (FilePath -> Maybe FilePath
    forall a. a -> Maybe a
    Just (FilePath -> Maybe FilePath)
    -> (FilePath -> FilePath) -> FilePath -> Maybe FilePath
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . FilePath -> FilePath
    fixPath (FilePath -> Maybe FilePath) -> IO FilePath -> IO (Maybe FilePath)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> FilePath -> IO FilePath
    getEnv FilePath
    "HOME") IO (Maybe FilePath)
    -> (IOException -> IO (Maybe FilePath)) -> IO (Maybe FilePath)
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    `E.catch`
                        \(IOException
    _ :: E.IOException) -> Maybe FilePath -> IO (Maybe FilePath)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe FilePath
    forall a. Maybe a
    Nothing

    {- | Returns the pathname of a directory in which application-specific
    data for the current user can be stored.  The result of
    'getAppUserDataDirectory' for a given application is specific to
    the current user.

    The argument should be the name of the application, which will be used
    to construct the pathname (so avoid using unusual characters that
    might result in an invalid pathname).

    Note: the directory may not actually exist, and may need to be created
    first.  It is expected that the parent directory exists and is
    writable.

    On Unix, this function returns @$HOME\/.appName@.  On Windows, a
    typical path might be

    > C:/Documents And Settings/user/Application Data/appName

    The operation may fail with:

    * 'UnsupportedOperation'
    The operating system has no notion of application-specific data directory.

    * 'isDoesNotExistError'
    The home directory for the current user does not exist, or
    cannot be found.
    -}

    getAppUserDataDirectory :: String -> IO FilePath
    getAppUserDataDirectory :: FilePath -> IO FilePath
    getAppUserDataDirectory FilePath
    x = FilePath -> FilePath
    fixPath (FilePath -> FilePath) -> IO FilePath -> IO FilePath
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> FilePath -> IO FilePath
    D.getAppUserDataDirectory FilePath
    x

    {- | Returns the current user's document directory.

    The directory returned is expected to be writable by the current user,
    but note that it isn't generally considered good practice to store
    application-specific data here; use 'getAppUserDataDirectory'
    instead.

    On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
    environment variable.  On Windows, the system is queried for a
    suitable path; a typical path might be
    @C:\/Documents and Settings\/user\/My Documents@.

    The operation may fail with:

    * 'UnsupportedOperation'
    The operating system has no notion of document directory.

    * 'isDoesNotExistError'
    The document directory for the current user does not exist, or
    cannot be found.
    -}
    getUserDocumentsDirectory :: IO FilePath
    getUserDocumentsDirectory :: IO FilePath
    getUserDocumentsDirectory = FilePath -> FilePath
    fixPath (FilePath -> FilePath) -> IO FilePath -> IO FilePath
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO FilePath
    D.getUserDocumentsDirectory

    {- | Returns the current directory for temporary files.

    On Unix, 'getTemporaryDirectory' returns the value of the @TMPDIR@
    environment variable or \"\/tmp\" if the variable isn\'t defined.
    On Windows, the function checks for the existence of environment variables in
    the following order and uses the first path found:

    * TMP environment variable.

    * TEMP environment variable.

    * USERPROFILE environment variable.

    * The Windows directory

    The operation may fail with:

    * 'UnsupportedOperation'
    The operating system has no notion of temporary directory.

    The function doesn\'t verify whether the path exists.
    -}

    getTemporaryDirectory :: IO FilePath
    getTemporaryDirectory :: IO FilePath
    getTemporaryDirectory = FilePath -> FilePath
    fixPath (FilePath -> FilePath) -> IO FilePath -> IO FilePath
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO FilePath
    D.getTemporaryDirectory

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

    fixPath :: FilePath -> FilePath
    #if defined(mingw32_HOST_OS) || defined(__MINGW32__)
    fixPath [] = []
    fixPath (c:cs)
     | c == '\\' = '/' : fixPath cs
     | otherwise = c   : fixPath cs
    #else
    fixPath :: FilePath -> FilePath
    fixPath = FilePath -> FilePath
    forall a. a -> a
    id
    #endif

    ----------------------------------------------------------------
    -- Just adding documentation.

    {-|
      This function copy the permission of the first file to the second.
    -}
    copyPermissions :: FilePath -> FilePath -> IO ()
    copyPermissions :: FilePath -> FilePath -> IO ()
    copyPermissions = FilePath -> FilePath -> IO ()
    D.copyPermissions