-- * Actions on directories
createDirectory -- :: FilePath -> IO ()
+ , createDirectoryIfMissing -- :: Bool -> FilePath -> IO ()
, removeDirectory -- :: FilePath -> IO ()
+ , removeDirectoryRecursive -- :: FilePath -> IO ()
, renameDirectory -- :: FilePath -> FilePath -> IO ()
, getDirectoryContents -- :: FilePath -> IO [FilePath]
, getModificationTime -- :: FilePath -> IO ClockTime
) where
+import System.Directory.Internals
import System.Environment ( getEnv )
-import System.FilePath
import System.IO.Error
+import Control.Monad ( when, unless )
#ifdef __NHC__
import Directory
#ifdef __HUGS__
import Hugs.Directory
+import Control.Exception ( bracket )
+import System.IO
#endif /* __HUGS__ */
#ifdef __GLASGOW_HASKELL__
import Prelude
import Control.Exception ( bracket )
-import Control.Monad ( when )
import System.Posix.Types
import System.Posix.Internals
import System.Time ( ClockTime(..) )
createDirectory :: FilePath -> IO ()
createDirectory path = do
+ modifyIOError (`ioeSetFileName` path) $
withCString path $ \s -> do
throwErrnoIfMinus1Retry_ "createDirectory" $
mkdir s 0o777
+#endif
+-- | @'createDirectoryIfMissing' parents dir@ creates a new directory
+-- @dir@ if it doesn\'t exist. If the first argument is 'True'
+-- the function will also create all parent directories if they are missing.
+createDirectoryIfMissing :: Bool -- ^ Create its parents too?
+ -> FilePath -- ^ The path to the directory you want to make
+ -> IO ()
+createDirectoryIfMissing parents file = do
+ b <- doesDirectoryExist file
+ case (b,parents, file) of
+ (_, _, "") -> return ()
+ (True, _, _) -> return ()
+ (_, True, _) -> mapM_ (createDirectoryIfMissing False) (tail (pathParents file))
+ (_, False, _) -> createDirectory file
+
+#if __GLASGOW_HASKELL__
{- | @'removeDirectory' dir@ removes an existing directory /dir/. The
implementation may specify additional constraints which must be
satisfied before a directory can be removed (e.g. the directory has to
modifyIOError (`ioeSetFileName` path) $
withCString path $ \s ->
throwErrnoIfMinus1Retry_ "removeDirectory" (c_rmdir s)
+#endif
+-- | @'removeDirectoryRecursive' dir@ removes an existing directory /dir/
+-- together with its content and all subdirectories. Be careful,
+-- if the directory contains symlinks, the function will follow them.
+removeDirectoryRecursive :: FilePath -> IO ()
+removeDirectoryRecursive startLoc = do
+ cont <- getDirectoryContents startLoc
+ sequence_ [rm (startLoc `joinFileName` x) | x <- cont, x /= "." && x /= ".."]
+ removeDirectory startLoc
+ where
+ rm :: FilePath -> IO ()
+ rm f = do temp <- try (removeFile f)
+ case temp of
+ Left e -> do isDir <- doesDirectoryExist f
+ -- If f is not a directory, re-throw the error
+ unless isDir $ ioError e
+ removeDirectoryRecursive f
+ Right _ -> return ()
+
+#if __GLASGOW_HASKELL__
{- |'removeFile' /file/ removes the directory entry for an existing file
/file/, where /file/ is not itself a directory. The
implementation may specify additional constraints which must be
-}
copyFile :: FilePath -> FilePath -> IO ()
copyFile fromFPath toFPath =
-#if (!(defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ > 600))
+#if defined(__HUGS__)
+ (bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom ->
+ bracket (openBinaryFile toFPath WriteMode) hClose $ \hTo -> do
+ hGetContents hFrom >>= hPutStr hTo
+ try (getPermissions fromFPath >>= setPermissions toFPath)
+ return ()) `catch` \err ->
+ ioError (annotateIOError err "copyFile" Nothing Nothing)
+#elif (!defined(__GLASGOW_HASKELL__) || __GLASGOW_HASKELL__ <= 600)
do readFile fromFPath >>= writeFile toFPath
try (getPermissions fromFPath >>= setPermissions toFPath)
return ()
-- canonicalized path, with the intent that two paths referring
-- to the same file\/directory will map to the same canonicalized
-- path. Note that it is impossible to guarantee that the
--- implication (same file\/dir <=> same canonicalizedPath) holds
+-- implication (same file\/dir \<=\> same canonicalizedPath) holds
-- in either direction: this function can make only a best-effort
-- attempt.
canonicalizePath :: FilePath -> IO FilePath
canonicalizePath fpath =
withCString fpath $ \pInPath ->
allocaBytes long_path_size $ \pOutPath ->
-#if defined(mingw32_TARGET_OS)
+#if defined(mingw32_HOST_OS)
alloca $ \ppFilePart ->
do c_GetFullPathName pInPath (fromIntegral long_path_size) pOutPath ppFilePart
#else
#endif
peekCString pOutPath
-#if defined(mingw32_TARGET_OS)
+#if defined(mingw32_HOST_OS)
foreign import stdcall unsafe "GetFullPathName"
c_GetFullPathName :: CString
-> CInt
-}
getHomeDirectory :: IO FilePath
getHomeDirectory =
-#if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
+#if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
allocaBytes long_path_size $ \pPath -> do
r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
if (r < 0)
-}
getAppUserDataDirectory :: String -> IO FilePath
getAppUserDataDirectory appName = do
-#if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
+#if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
allocaBytes long_path_size $ \pPath -> do
r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
s <- peekCString pPath
-}
getUserDocumentsDirectory :: IO FilePath
getUserDocumentsDirectory = do
-#if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
+#if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
allocaBytes long_path_size $ \pPath -> do
r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
peekCString pPath
-}
getTemporaryDirectory :: IO FilePath
getTemporaryDirectory = do
-#if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
+#if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
allocaBytes long_path_size $ \pPath -> do
r <- c_GetTempPath (fromIntegral long_path_size) pPath
peekCString pPath
catch (getEnv "TMPDIR") (\ex -> return "/tmp")
#endif
-#if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
+#if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
foreign import stdcall unsafe "SHGetFolderPath"
c_SHGetFolderPath :: Ptr ()
-> CInt