X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=System%2FDirectory.hs;h=5da67b691ff3e71521d8c83edc548ba3e3a04b4d;hb=4265c3f9425684443ce11c78dfd7dfd05de0c88a;hp=c3698a2822357e4e886696b93984fbdbf1902b94;hpb=fe5420ba0484d7a0937ec3a1153bd9b41967a803;p=haskell-directory.git diff --git a/System/Directory.hs b/System/Directory.hs index c3698a2..5da67b6 100644 --- a/System/Directory.hs +++ b/System/Directory.hs @@ -1,3 +1,6 @@ +{-# OPTIONS_GHC -w #-} +-- XXX We get some warnings on Windows + ----------------------------------------------------------------------------- -- | -- Module : System.Directory @@ -67,12 +70,14 @@ module System.Directory ) where import Prelude hiding ( catch ) +import qualified Prelude import System.Environment ( getEnv ) import System.FilePath +import System.IO import System.IO.Error hiding ( catch, try ) import Control.Monad ( when, unless ) -import Control.Exception +import Control.Exception.Base #ifdef __NHC__ import Directory @@ -92,16 +97,21 @@ import Foreign.C import System.Posix.Types import System.Posix.Internals import System.Time ( ClockTime(..) ) -import System.IO import GHC.IOBase ( IOException(..), IOErrorType(..), ioException ) +#ifdef mingw32_HOST_OS +import qualified System.Win32 +#else +import qualified System.Posix +#endif + {- $intro A directory contains a series of entries, each of which is a named reference to a file system object (file, directory etc.). Some entries may be hidden, inaccessible, or have some administrative function (e.g. `.' or `..' under POSIX -), but in +), but in this standard all such entries are considered to form part of the directory contents. Entries in sub-directories are not, however, considered to form part of the directory contents. @@ -165,30 +175,30 @@ getPermissions name = do allocaBytes sizeof_stat $ \ p_stat -> do throwErrnoIfMinus1_ "getPermissions" $ c_stat s p_stat mode <- st_mode p_stat - let read = mode .&. s_IRUSR - let write = mode .&. s_IWUSR - let exec = mode .&. s_IXUSR + let usr_read = mode .&. s_IRUSR + let usr_write = mode .&. s_IWUSR + let usr_exec = mode .&. s_IXUSR let is_dir = mode .&. s_IFDIR return ( Permissions { - readable = read /= 0, - writable = write /= 0, - executable = is_dir == 0 && exec /= 0, - searchable = is_dir /= 0 && exec /= 0 + readable = usr_read /= 0, + writable = usr_write /= 0, + executable = is_dir == 0 && usr_exec /= 0, + searchable = is_dir /= 0 && usr_exec /= 0 } ) #else - read <- c_access s r_OK - write <- c_access s w_OK - exec <- c_access s x_OK + read_ok <- c_access s r_OK + write_ok <- c_access s w_OK + exec_ok <- c_access s x_OK withFileStatus "getPermissions" name $ \st -> do is_dir <- isDirectory st return ( Permissions { - readable = read == 0, - writable = write == 0, - executable = not is_dir && exec == 0, - searchable = is_dir && exec == 0 + readable = read_ok == 0, + writable = write_ok == 0, + executable = not is_dir && exec_ok == 0, + searchable = is_dir && exec_ok == 0 } ) #endif @@ -365,7 +375,7 @@ removeDirectoryRecursive startLoc = do case temp of Left e -> do isDir <- doesDirectoryExist f -- If f is not a directory, re-throw the error - unless isDir $ throw e + unless isDir $ throw (e :: SomeException) removeDirectoryRecursive f Right _ -> return () @@ -461,16 +471,18 @@ Either path refers to an existing non-directory object. renameDirectory :: FilePath -> FilePath -> IO () renameDirectory opath npath = + -- XXX this test isn't performed atomically with the following rename withFileStatus "renameDirectory" opath $ \st -> do is_dir <- isDirectory st if (not is_dir) then ioException (IOError Nothing InappropriateType "renameDirectory" ("not a directory") (Just opath)) else do - - withCString opath $ \s1 -> - withCString npath $ \s2 -> - throwErrnoIfMinus1Retry_ "renameDirectory" (c_rename s1 s2) +#ifdef mingw32_HOST_OS + System.Win32.moveFileEx opath npath System.Win32.mOVEFILE_REPLACE_EXISTING +#else + System.Posix.rename s1 s2 +#endif {- |@'renameFile' old new@ changes the name of an existing file system object from /old/ to /new/. If the /new/ object already @@ -518,16 +530,18 @@ Either path refers to an existing directory. renameFile :: FilePath -> FilePath -> IO () renameFile opath npath = + -- XXX this test isn't performed atomically with the following rename withFileOrSymlinkStatus "renameFile" opath $ \st -> do is_dir <- isDirectory st if is_dir then ioException (IOError Nothing InappropriateType "renameFile" "is a directory" (Just opath)) else do - - withCString opath $ \s1 -> - withCString npath $ \s2 -> - throwErrnoIfMinus1Retry_ "renameFile" (c_rename s1 s2) +#ifdef mingw32_HOST_OS + System.Win32.moveFileEx opath npath System.Win32.mOVEFILE_REPLACE_EXISTING +#else + System.Posix.rename s1 s2 +#endif #endif /* __GLASGOW_HASKELL__ */ @@ -541,23 +555,21 @@ copyFile :: FilePath -> FilePath -> IO () #ifdef __NHC__ copyFile fromFPath toFPath = do readFile fromFPath >>= writeFile toFPath - try (copyPermissions fromFPath toFPath) - return () + Prelude.catch (copyPermissions fromFPath toFPath) + (\_ -> return ()) #else copyFile fromFPath toFPath = - copy `catch` (\e -> case e of - IOException e -> - throw $ IOException $ ioeSetLocation e "copyFile" - _ -> throw e) + copy `Prelude.catch` (\exc -> throw $ ioeSetLocation exc "copyFile") where copy = bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom -> bracketOnError openTmp cleanTmp $ \(tmpFPath, hTmp) -> do allocaBytes bufferSize $ copyContents hFrom hTmp hClose hTmp - try (copyPermissions fromFPath tmpFPath) + ignoreIOExceptions $ copyPermissions fromFPath tmpFPath renameFile tmpFPath toFPath openTmp = openBinaryTempFile (takeDirectory toFPath) ".copyFile.tmp" - cleanTmp (tmpFPath, hTmp) = do try $ hClose hTmp - try $ removeFile tmpFPath + cleanTmp (tmpFPath, hTmp) + = do ignoreIOExceptions $ hClose hTmp + ignoreIOExceptions $ removeFile tmpFPath bufferSize = 1024 copyContents hFrom hTo buffer = do @@ -565,6 +577,10 @@ copyFile fromFPath toFPath = when (count > 0) $ do hPutBuf hTo buffer count copyContents hFrom hTo buffer + + ignoreIOExceptions io = io `catch` ioExceptionIgnorer + ioExceptionIgnorer :: IOException -> IO () + ioExceptionIgnorer _ = return () #endif -- | Given path referring to a file or directory, returns a @@ -584,7 +600,9 @@ canonicalizePath fpath = #else do c_realpath pInPath pOutPath #endif - peekCString pOutPath + path <- peekCString pOutPath + return (normalise path) + -- normalise does more stuff, like upper-casing the drive letter #if defined(mingw32_HOST_OS) foreign import stdcall unsafe "GetFullPathNameA" @@ -755,8 +773,8 @@ getCurrentDirectory = do else do errno <- getErrno if errno == eRANGE then do let bytes' = bytes * 2 - p' <- reallocBytes p bytes' - go p' bytes' + p'' <- reallocBytes p bytes' + go p'' bytes' else throwErrno "getCurrentDirectory" {- |If the operating system has a notion of current directories, @@ -803,20 +821,18 @@ exists and is a directory, and 'False' otherwise. -} doesDirectoryExist :: FilePath -> IO Bool -doesDirectoryExist name = - catch +doesDirectoryExist name = (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st) - (\ _ -> return False) + `catch` ((\ _ -> return False) :: IOException -> IO Bool) {- |The operation 'doesFileExist' returns 'True' if the argument file exists and is not a directory, and 'False' otherwise. -} doesFileExist :: FilePath -> IO Bool -doesFileExist name = do - catch +doesFileExist name = (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b)) - (\ _ -> return False) + `catch` ((\ _ -> return False) :: IOException -> IO Bool) {- |The 'getModificationTime' operation returns the clock time at which the file or directory was last modified. @@ -873,7 +889,9 @@ foreign import ccall unsafe "__hscore_X_OK" x_OK :: CInt foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode +#ifdef mingw32_HOST_OS foreign import ccall unsafe "__hscore_S_IFDIR" s_IFDIR :: CMode +#endif foreign import ccall unsafe "__hscore_long_path_size" long_path_size :: Int @@ -909,11 +927,11 @@ getHomeDirectory :: IO FilePath getHomeDirectory = #if defined(mingw32_HOST_OS) allocaBytes long_path_size $ \pPath -> do - r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath - if (r < 0) + r0 <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath + if (r0 < 0) then do - r <- c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath - when (r < 0) (raiseUnsupported "System.Directory.getHomeDirectory") + r1 <- c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath + when (r1 < 0) (raiseUnsupported "System.Directory.getHomeDirectory") else return () peekCString pPath #else @@ -1022,10 +1040,16 @@ getTemporaryDirectory :: IO FilePath getTemporaryDirectory = do #if defined(mingw32_HOST_OS) allocaBytes long_path_size $ \pPath -> do - r <- c_GetTempPath (fromIntegral long_path_size) pPath + _r <- c_GetTempPath (fromIntegral long_path_size) pPath peekCString pPath #else - catch (getEnv "TMPDIR") (\ex -> return "/tmp") + getEnv "TMPDIR" +#if !__NHC__ + `Prelude.catch` \e -> if isDoesNotExistError e then return "/tmp" + else throw e +#else + `Prelude.catch` (\ex -> return "/tmp") +#endif #endif #if defined(mingw32_HOST_OS) @@ -1043,6 +1067,7 @@ foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt foreign import stdcall unsafe "GetTempPathA" c_GetTempPath :: CInt -> CString -> IO CInt +raiseUnsupported :: String -> IO () raiseUnsupported loc = ioException (IOError Nothing UnsupportedOperation loc "unsupported operation" Nothing)