1 -----------------------------------------------------------------------------
3 -- Module : System.Directory
4 -- Copyright : (c) The University of Glasgow 2001
5 -- License : BSD-style (see the file libraries/base/LICENSE)
7 -- Maintainer : libraries@haskell.org
9 -- Portability : portable
11 -- System-independent interface to directory manipulation.
13 -----------------------------------------------------------------------------
15 module System.Directory
19 -- * Actions on directories
20 createDirectory -- :: FilePath -> IO ()
21 , createDirectoryIfMissing -- :: Bool -> FilePath -> IO ()
22 , removeDirectory -- :: FilePath -> IO ()
23 , removeDirectoryRecursive -- :: FilePath -> IO ()
24 , renameDirectory -- :: FilePath -> FilePath -> IO ()
26 , getDirectoryContents -- :: FilePath -> IO [FilePath]
27 , getCurrentDirectory -- :: IO FilePath
28 , setCurrentDirectory -- :: FilePath -> IO ()
30 -- * Pre-defined directories
32 , getAppUserDataDirectory
33 , getUserDocumentsDirectory
34 , getTemporaryDirectory
37 , removeFile -- :: FilePath -> IO ()
38 , renameFile -- :: FilePath -> FilePath -> IO ()
39 , copyFile -- :: FilePath -> FilePath -> IO ()
42 , makeRelativeToCurrentDirectory
46 , doesFileExist -- :: FilePath -> IO Bool
47 , doesDirectoryExist -- :: FilePath -> IO Bool
55 readable, -- :: Permissions -> Bool
56 writable, -- :: Permissions -> Bool
57 executable, -- :: Permissions -> Bool
58 searchable -- :: Permissions -> Bool
61 , getPermissions -- :: FilePath -> IO Permissions
62 , setPermissions -- :: FilePath -> Permissions -> IO ()
66 , getModificationTime -- :: FilePath -> IO ClockTime
69 import Prelude hiding ( catch )
71 import System.Environment ( getEnv )
72 import System.FilePath
73 import System.IO.Error hiding ( catch, try )
74 import Control.Monad ( when, unless )
75 import Control.Exception
79 import System (system)
89 {-# CFILES cbits/directory.c #-}
91 #ifdef __GLASGOW_HASKELL__
92 import System.Posix.Types
93 import System.Posix.Internals
94 import System.Time ( ClockTime(..) )
97 import GHC.IOBase ( IOException(..), IOErrorType(..), ioException )
100 A directory contains a series of entries, each of which is a named
101 reference to a file system object (file, directory etc.). Some
102 entries may be hidden, inaccessible, or have some administrative
103 function (e.g. `.' or `..' under POSIX
104 <http://www.opengroup.org/onlinepubs/007904975/toc.htm>), but in
105 this standard all such entries are considered to form part of the
106 directory contents. Entries in sub-directories are not, however,
107 considered to form part of the directory contents.
109 Each file system object is referenced by a /path/. There is
110 normally at least one absolute path to each file system object. In
111 some operating systems, it may also be possible to have paths which
112 are relative to the current directory.
115 -----------------------------------------------------------------------------
120 The 'Permissions' type is used to record whether certain operations are
121 permissible on a file\/directory. 'getPermissions' and 'setPermissions'
122 get and set these permissions, respectively. Permissions apply both to
123 files and directories. For directories, the executable field will be
124 'False', and for files the searchable field will be 'False'. Note that
125 directories may be searchable without being readable, if permission has
126 been given to use them as part of a path, but not to examine the
129 Note that to change some, but not all permissions, a construct on the following lines must be used.
131 > makeReadable f = do
132 > p <- getPermissions f
133 > setPermissions f (p {readable = True})
140 executable, searchable :: Bool
141 } deriving (Eq, Ord, Read, Show)
143 {- |The 'getPermissions' operation returns the
144 permissions for the file or directory.
146 The operation may fail with:
148 * 'isPermissionError' if the user is not permitted to access
151 * 'isDoesNotExistError' if the file or directory does not exist.
155 getPermissions :: FilePath -> IO Permissions
156 getPermissions name = do
157 withCString name $ \s -> do
158 read <- c_access s r_OK
159 write <- c_access s w_OK
160 exec <- c_access s x_OK
161 withFileStatus "getPermissions" name $ \st -> do
162 is_dir <- isDirectory st
165 readable = read == 0,
166 writable = write == 0,
167 executable = not is_dir && exec == 0,
168 searchable = is_dir && exec == 0
172 {- |The 'setPermissions' operation sets the
173 permissions for the file or directory.
175 The operation may fail with:
177 * 'isPermissionError' if the user is not permitted to set
180 * 'isDoesNotExistError' if the file or directory does not exist.
184 setPermissions :: FilePath -> Permissions -> IO ()
185 setPermissions name (Permissions r w e s) = do
186 allocaBytes sizeof_stat $ \ p_stat -> do
187 withCString name $ \p_name -> do
188 throwErrnoIfMinus1_ "setPermissions" $ do
190 mode <- st_mode p_stat
191 let mode1 = modifyBit r mode s_IRUSR
192 let mode2 = modifyBit w mode1 s_IWUSR
193 let mode3 = modifyBit (e || s) mode2 s_IXUSR
197 modifyBit :: Bool -> CMode -> CMode -> CMode
198 modifyBit False m b = m .&. (complement b)
199 modifyBit True m b = m .|. b
202 copyPermissions :: FilePath -> FilePath -> IO ()
203 copyPermissions source dest = do
204 allocaBytes sizeof_stat $ \ p_stat -> do
205 withCString source $ \p_source -> do
206 withCString dest $ \p_dest -> do
207 throwErrnoIfMinus1_ "copyPermissions" $ c_stat p_source p_stat
208 mode <- st_mode p_stat
209 throwErrnoIfMinus1_ "copyPermissions" $ c_chmod p_dest mode
211 -----------------------------------------------------------------------------
214 {- |@'createDirectory' dir@ creates a new directory @dir@ which is
215 initially empty, or as near to empty as the operating system
218 The operation may fail with:
220 * 'isPermissionError' \/ 'PermissionDenied'
221 The process has insufficient privileges to perform the operation.
224 * 'isAlreadyExistsError' \/ 'AlreadyExists'
225 The operand refers to a directory that already exists.
229 A physical I\/O error has occurred.
233 The operand is not a valid directory name.
234 @[ENAMETOOLONG, ELOOP]@
237 There is no path to the directory.
240 * 'ResourceExhausted'
241 Insufficient resources (virtual memory, process file descriptors,
242 physical disk space, etc.) are available to perform the operation.
243 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
245 * 'InappropriateType'
246 The path refers to an existing non-directory object.
251 createDirectory :: FilePath -> IO ()
252 createDirectory path = do
253 modifyIOError (`ioeSetFileName` path) $
254 withCString path $ \s -> do
255 throwErrnoIfMinus1Retry_ "createDirectory" $
258 #else /* !__GLASGOW_HASKELL__ */
260 copyPermissions :: FilePath -> FilePath -> IO ()
261 copyPermissions fromFPath toFPath
262 = getPermissions fromFPath >>= setPermissions toFPath
266 -- | @'createDirectoryIfMissing' parents dir@ creates a new directory
267 -- @dir@ if it doesn\'t exist. If the first argument is 'True'
268 -- the function will also create all parent directories if they are missing.
269 createDirectoryIfMissing :: Bool -- ^ Create its parents too?
270 -> FilePath -- ^ The path to the directory you want to make
272 createDirectoryIfMissing parents file = do
273 b <- doesDirectoryExist file
274 case (b,parents, file) of
275 (_, _, "") -> return ()
276 (True, _, _) -> return ()
277 (_, True, _) -> mapM_ (createDirectoryIfMissing False) $ mkParents file
278 (_, False, _) -> createDirectory file
279 where mkParents = scanl1 (</>) . splitDirectories . normalise
281 #if __GLASGOW_HASKELL__
282 {- | @'removeDirectory' dir@ removes an existing directory /dir/. The
283 implementation may specify additional constraints which must be
284 satisfied before a directory can be removed (e.g. the directory has to
285 be empty, or may not be in use by other processes). It is not legal
286 for an implementation to partially remove a directory unless the
287 entire directory is removed. A conformant implementation need not
288 support directory removal in all situations (e.g. removal of the root
291 The operation may fail with:
294 A physical I\/O error has occurred.
298 The operand is not a valid directory name.
299 [ENAMETOOLONG, ELOOP]
301 * 'isDoesNotExistError' \/ 'NoSuchThing'
302 The directory does not exist.
305 * 'isPermissionError' \/ 'PermissionDenied'
306 The process has insufficient privileges to perform the operation.
307 @[EROFS, EACCES, EPERM]@
309 * 'UnsatisfiedConstraints'
310 Implementation-dependent constraints are not satisfied.
311 @[EBUSY, ENOTEMPTY, EEXIST]@
313 * 'UnsupportedOperation'
314 The implementation does not support removal in this situation.
317 * 'InappropriateType'
318 The operand refers to an existing non-directory object.
323 removeDirectory :: FilePath -> IO ()
324 removeDirectory path = do
325 modifyIOError (`ioeSetFileName` path) $
326 withCString path $ \s ->
327 throwErrnoIfMinus1Retry_ "removeDirectory" (c_rmdir s)
330 -- | @'removeDirectoryRecursive' dir@ removes an existing directory /dir/
331 -- together with its content and all subdirectories. Be careful,
332 -- if the directory contains symlinks, the function will follow them.
333 removeDirectoryRecursive :: FilePath -> IO ()
334 removeDirectoryRecursive startLoc = do
335 cont <- getDirectoryContents startLoc
336 sequence_ [rm (startLoc </> x) | x <- cont, x /= "." && x /= ".."]
337 removeDirectory startLoc
339 rm :: FilePath -> IO ()
340 rm f = do temp <- try (removeFile f)
342 Left e -> do isDir <- doesDirectoryExist f
343 -- If f is not a directory, re-throw the error
344 unless isDir $ throw e
345 removeDirectoryRecursive f
348 #if __GLASGOW_HASKELL__
349 {- |'removeFile' /file/ removes the directory entry for an existing file
350 /file/, where /file/ is not itself a directory. The
351 implementation may specify additional constraints which must be
352 satisfied before a file can be removed (e.g. the file may not be in
353 use by other processes).
355 The operation may fail with:
358 A physical I\/O error has occurred.
362 The operand is not a valid file name.
363 @[ENAMETOOLONG, ELOOP]@
365 * 'isDoesNotExistError' \/ 'NoSuchThing'
366 The file does not exist.
369 * 'isPermissionError' \/ 'PermissionDenied'
370 The process has insufficient privileges to perform the operation.
371 @[EROFS, EACCES, EPERM]@
373 * 'UnsatisfiedConstraints'
374 Implementation-dependent constraints are not satisfied.
377 * 'InappropriateType'
378 The operand refers to an existing directory.
383 removeFile :: FilePath -> IO ()
385 modifyIOError (`ioeSetFileName` path) $
386 withCString path $ \s ->
387 throwErrnoIfMinus1Retry_ "removeFile" (c_unlink s)
389 {- |@'renameDirectory' old new@ changes the name of an existing
390 directory from /old/ to /new/. If the /new/ directory
391 already exists, it is atomically replaced by the /old/ directory.
392 If the /new/ directory is neither the /old/ directory nor an
393 alias of the /old/ directory, it is removed as if by
394 'removeDirectory'. A conformant implementation need not support
395 renaming directories in all situations (e.g. renaming to an existing
396 directory, or across different physical devices), but the constraints
399 On Win32 platforms, @renameDirectory@ fails if the /new/ directory already
402 The operation may fail with:
405 A physical I\/O error has occurred.
409 Either operand is not a valid directory name.
410 @[ENAMETOOLONG, ELOOP]@
412 * 'isDoesNotExistError' \/ 'NoSuchThing'
413 The original directory does not exist, or there is no path to the target.
416 * 'isPermissionError' \/ 'PermissionDenied'
417 The process has insufficient privileges to perform the operation.
418 @[EROFS, EACCES, EPERM]@
420 * 'ResourceExhausted'
421 Insufficient resources are available to perform the operation.
422 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
424 * 'UnsatisfiedConstraints'
425 Implementation-dependent constraints are not satisfied.
426 @[EBUSY, ENOTEMPTY, EEXIST]@
428 * 'UnsupportedOperation'
429 The implementation does not support renaming in this situation.
432 * 'InappropriateType'
433 Either path refers to an existing non-directory object.
438 renameDirectory :: FilePath -> FilePath -> IO ()
439 renameDirectory opath npath =
440 withFileStatus "renameDirectory" opath $ \st -> do
441 is_dir <- isDirectory st
443 then ioException (IOError Nothing InappropriateType "renameDirectory"
444 ("not a directory") (Just opath))
447 withCString opath $ \s1 ->
448 withCString npath $ \s2 ->
449 throwErrnoIfMinus1Retry_ "renameDirectory" (c_rename s1 s2)
451 {- |@'renameFile' old new@ changes the name of an existing file system
452 object from /old/ to /new/. If the /new/ object already
453 exists, it is atomically replaced by the /old/ object. Neither
454 path may refer to an existing directory. A conformant implementation
455 need not support renaming files in all situations (e.g. renaming
456 across different physical devices), but the constraints must be
459 The operation may fail with:
462 A physical I\/O error has occurred.
466 Either operand is not a valid file name.
467 @[ENAMETOOLONG, ELOOP]@
469 * 'isDoesNotExistError' \/ 'NoSuchThing'
470 The original file does not exist, or there is no path to the target.
473 * 'isPermissionError' \/ 'PermissionDenied'
474 The process has insufficient privileges to perform the operation.
475 @[EROFS, EACCES, EPERM]@
477 * 'ResourceExhausted'
478 Insufficient resources are available to perform the operation.
479 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
481 * 'UnsatisfiedConstraints'
482 Implementation-dependent constraints are not satisfied.
485 * 'UnsupportedOperation'
486 The implementation does not support renaming in this situation.
489 * 'InappropriateType'
490 Either path refers to an existing directory.
491 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
495 renameFile :: FilePath -> FilePath -> IO ()
496 renameFile opath npath =
497 withFileOrSymlinkStatus "renameFile" opath $ \st -> do
498 is_dir <- isDirectory st
500 then ioException (IOError Nothing InappropriateType "renameFile"
501 "is a directory" (Just opath))
504 withCString opath $ \s1 ->
505 withCString npath $ \s2 ->
506 throwErrnoIfMinus1Retry_ "renameFile" (c_rename s1 s2)
508 #endif /* __GLASGOW_HASKELL__ */
510 {- |@'copyFile' old new@ copies the existing file from /old/ to /new/.
511 If the /new/ file already exists, it is atomically replaced by the /old/ file.
512 Neither path may refer to an existing directory. The permissions of /old/ are
513 copied to /new/, if possible.
516 copyFile :: FilePath -> FilePath -> IO ()
518 copyFile fromFPath toFPath =
519 do readFile fromFPath >>= writeFile toFPath
520 try (copyPermissions fromFPath toFPath)
523 copyFile fromFPath toFPath =
524 copy `catch` (\e -> case e of
526 throw $ IOException $ ioeSetLocation e "copyFile"
528 where copy = bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom ->
529 bracketOnError openTmp cleanTmp $ \(tmpFPath, hTmp) ->
530 do allocaBytes bufferSize $ copyContents hFrom hTmp
532 try (copyPermissions fromFPath toFPath)
533 renameFile tmpFPath toFPath
534 openTmp = openBinaryTempFile (takeDirectory toFPath) ".copyFile.tmp"
535 cleanTmp (tmpFPath, hTmp) = do try $ hClose hTmp
536 try $ removeFile tmpFPath
539 copyContents hFrom hTo buffer = do
540 count <- hGetBuf hFrom buffer bufferSize
541 when (count > 0) $ do
542 hPutBuf hTo buffer count
543 copyContents hFrom hTo buffer
546 -- | Given path referring to a file or directory, returns a
547 -- canonicalized path, with the intent that two paths referring
548 -- to the same file\/directory will map to the same canonicalized
549 -- path. Note that it is impossible to guarantee that the
550 -- implication (same file\/dir \<=\> same canonicalizedPath) holds
551 -- in either direction: this function can make only a best-effort
553 canonicalizePath :: FilePath -> IO FilePath
554 canonicalizePath fpath =
555 withCString fpath $ \pInPath ->
556 allocaBytes long_path_size $ \pOutPath ->
557 #if defined(mingw32_HOST_OS)
558 alloca $ \ppFilePart ->
559 do c_GetFullPathName pInPath (fromIntegral long_path_size) pOutPath ppFilePart
561 do c_realpath pInPath pOutPath
565 #if defined(mingw32_HOST_OS)
566 foreign import stdcall unsafe "GetFullPathNameA"
567 c_GetFullPathName :: CString
573 foreign import ccall unsafe "realpath"
574 c_realpath :: CString
579 -- | 'makeRelative' the current directory.
580 makeRelativeToCurrentDirectory :: FilePath -> IO FilePath
581 makeRelativeToCurrentDirectory x = do
582 cur <- getCurrentDirectory
583 return $ makeRelative cur x
585 -- | Given an executable file name, searches for such file
586 -- in the directories listed in system PATH. The returned value
587 -- is the path to the found executable or Nothing if there isn't
588 -- such executable. For example (findExecutable \"ghc\")
589 -- gives you the path to GHC.
590 findExecutable :: String -> IO (Maybe FilePath)
591 findExecutable binary =
592 #if defined(mingw32_HOST_OS)
593 withCString binary $ \c_binary ->
594 withCString ('.':exeExtension) $ \c_ext ->
595 allocaBytes long_path_size $ \pOutPath ->
596 alloca $ \ppFilePart -> do
597 res <- c_SearchPath nullPtr c_binary c_ext (fromIntegral long_path_size) pOutPath ppFilePart
598 if res > 0 && res < fromIntegral long_path_size
599 then do fpath <- peekCString pOutPath
603 foreign import stdcall unsafe "SearchPathA"
604 c_SearchPath :: CString
613 path <- getEnv "PATH"
614 search (splitSearchPath path)
616 fileName = binary <.> exeExtension
618 search :: [FilePath] -> IO (Maybe FilePath)
619 search [] = return Nothing
621 let path = d </> fileName
622 b <- doesFileExist path
623 if b then return (Just path)
628 #ifdef __GLASGOW_HASKELL__
629 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
632 The operation may fail with:
635 A physical I\/O error has occurred.
639 The operand is not a valid directory name.
640 @[ENAMETOOLONG, ELOOP]@
642 * 'isDoesNotExistError' \/ 'NoSuchThing'
643 The directory does not exist.
646 * 'isPermissionError' \/ 'PermissionDenied'
647 The process has insufficient privileges to perform the operation.
650 * 'ResourceExhausted'
651 Insufficient resources are available to perform the operation.
654 * 'InappropriateType'
655 The path refers to an existing non-directory object.
660 getDirectoryContents :: FilePath -> IO [FilePath]
661 getDirectoryContents path = do
662 modifyIOError (`ioeSetFileName` path) $
663 alloca $ \ ptr_dEnt ->
665 (withCString path $ \s ->
666 throwErrnoIfNullRetry desc (c_opendir s))
667 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
668 (\p -> loop ptr_dEnt p)
670 desc = "getDirectoryContents"
672 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
673 loop ptr_dEnt dir = do
675 r <- readdir dir ptr_dEnt
678 dEnt <- peek ptr_dEnt
682 entry <- (d_name dEnt >>= peekCString)
684 entries <- loop ptr_dEnt dir
685 return (entry:entries)
686 else do errno <- getErrno
687 if (errno == eINTR) then loop ptr_dEnt dir else do
688 let (Errno eo) = errno
689 if (eo == end_of_dir)
695 {- |If the operating system has a notion of current directories,
696 'getCurrentDirectory' returns an absolute path to the
697 current directory of the calling process.
699 The operation may fail with:
702 A physical I\/O error has occurred.
705 * 'isDoesNotExistError' \/ 'NoSuchThing'
706 There is no path referring to the current directory.
707 @[EPERM, ENOENT, ESTALE...]@
709 * 'isPermissionError' \/ 'PermissionDenied'
710 The process has insufficient privileges to perform the operation.
713 * 'ResourceExhausted'
714 Insufficient resources are available to perform the operation.
716 * 'UnsupportedOperation'
717 The operating system has no notion of current directory.
721 getCurrentDirectory :: IO FilePath
722 getCurrentDirectory = do
723 p <- mallocBytes long_path_size
725 where go p bytes = do
726 p' <- c_getcwd p (fromIntegral bytes)
728 then do s <- peekCString p'
731 else do errno <- getErrno
733 then do let bytes' = bytes * 2
734 p' <- reallocBytes p bytes'
736 else throwErrno "getCurrentDirectory"
738 {- |If the operating system has a notion of current directories,
739 @'setCurrentDirectory' dir@ changes the current
740 directory of the calling process to /dir/.
742 The operation may fail with:
745 A physical I\/O error has occurred.
749 The operand is not a valid directory name.
750 @[ENAMETOOLONG, ELOOP]@
752 * 'isDoesNotExistError' \/ 'NoSuchThing'
753 The directory does not exist.
756 * 'isPermissionError' \/ 'PermissionDenied'
757 The process has insufficient privileges to perform the operation.
760 * 'UnsupportedOperation'
761 The operating system has no notion of current directory, or the
762 current directory cannot be dynamically changed.
764 * 'InappropriateType'
765 The path refers to an existing non-directory object.
770 setCurrentDirectory :: FilePath -> IO ()
771 setCurrentDirectory path = do
772 modifyIOError (`ioeSetFileName` path) $
773 withCString path $ \s ->
774 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
775 -- ToDo: add path to error
777 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
778 exists and is a directory, and 'False' otherwise.
781 doesDirectoryExist :: FilePath -> IO Bool
782 doesDirectoryExist name =
784 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
785 (\ _ -> return False)
787 {- |The operation 'doesFileExist' returns 'True'
788 if the argument file exists and is not a directory, and 'False' otherwise.
791 doesFileExist :: FilePath -> IO Bool
792 doesFileExist name = do
794 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
795 (\ _ -> return False)
797 {- |The 'getModificationTime' operation returns the
798 clock time at which the file or directory was last modified.
800 The operation may fail with:
802 * 'isPermissionError' if the user is not permitted to access
803 the modification time; or
805 * 'isDoesNotExistError' if the file or directory does not exist.
809 getModificationTime :: FilePath -> IO ClockTime
810 getModificationTime name =
811 withFileStatus "getModificationTime" name $ \ st ->
814 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
815 withFileStatus loc name f = do
816 modifyIOError (`ioeSetFileName` name) $
817 allocaBytes sizeof_stat $ \p ->
818 withCString (fileNameEndClean name) $ \s -> do
819 throwErrnoIfMinus1Retry_ loc (c_stat s p)
822 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
823 withFileOrSymlinkStatus loc name f = do
824 modifyIOError (`ioeSetFileName` name) $
825 allocaBytes sizeof_stat $ \p ->
826 withCString name $ \s -> do
827 throwErrnoIfMinus1Retry_ loc (lstat s p)
830 modificationTime :: Ptr CStat -> IO ClockTime
831 modificationTime stat = do
832 mtime <- st_mtime stat
833 let realToInteger = round . realToFrac :: Real a => a -> Integer
834 return (TOD (realToInteger (mtime :: CTime)) 0)
836 isDirectory :: Ptr CStat -> IO Bool
837 isDirectory stat = do
839 return (s_isdir mode)
841 fileNameEndClean :: String -> String
842 fileNameEndClean name = if isDrive name then addTrailingPathSeparator name
843 else dropTrailingPathSeparator name
845 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CInt
846 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CInt
847 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CInt
849 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
850 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
851 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
853 foreign import ccall unsafe "__hscore_long_path_size"
854 long_path_size :: Int
857 long_path_size :: Int
858 long_path_size = 2048 -- // guess?
860 #endif /* __GLASGOW_HASKELL__ */
862 {- | Returns the current user's home directory.
864 The directory returned is expected to be writable by the current user,
865 but note that it isn't generally considered good practice to store
866 application-specific data here; use 'getAppUserDataDirectory'
869 On Unix, 'getHomeDirectory' returns the value of the @HOME@
870 environment variable. On Windows, the system is queried for a
871 suitable path; a typical path might be
872 @C:/Documents And Settings/user@.
874 The operation may fail with:
876 * 'UnsupportedOperation'
877 The operating system has no notion of home directory.
879 * 'isDoesNotExistError'
880 The home directory for the current user does not exist, or
883 getHomeDirectory :: IO FilePath
885 #if defined(mingw32_HOST_OS)
886 allocaBytes long_path_size $ \pPath -> do
887 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
890 r <- c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
891 when (r < 0) (raiseUnsupported "System.Directory.getHomeDirectory")
898 {- | Returns the pathname of a directory in which application-specific
899 data for the current user can be stored. The result of
900 'getAppUserDataDirectory' for a given application is specific to
903 The argument should be the name of the application, which will be used
904 to construct the pathname (so avoid using unusual characters that
905 might result in an invalid pathname).
907 Note: the directory may not actually exist, and may need to be created
908 first. It is expected that the parent directory exists and is
911 On Unix, this function returns @$HOME\/.appName@. On Windows, a
912 typical path might be
914 > C:/Documents And Settings/user/Application Data/appName
916 The operation may fail with:
918 * 'UnsupportedOperation'
919 The operating system has no notion of application-specific data directory.
921 * 'isDoesNotExistError'
922 The home directory for the current user does not exist, or
925 getAppUserDataDirectory :: String -> IO FilePath
926 getAppUserDataDirectory appName = do
927 #if defined(mingw32_HOST_OS)
928 allocaBytes long_path_size $ \pPath -> do
929 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
930 when (r<0) (raiseUnsupported "System.Directory.getAppUserDataDirectory")
931 s <- peekCString pPath
932 return (s++'\\':appName)
934 path <- getEnv "HOME"
935 return (path++'/':'.':appName)
938 {- | Returns the current user's document directory.
940 The directory returned is expected to be writable by the current user,
941 but note that it isn't generally considered good practice to store
942 application-specific data here; use 'getAppUserDataDirectory'
945 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
946 environment variable. On Windows, the system is queried for a
947 suitable path; a typical path might be
948 @C:\/Documents and Settings\/user\/My Documents@.
950 The operation may fail with:
952 * 'UnsupportedOperation'
953 The operating system has no notion of document directory.
955 * 'isDoesNotExistError'
956 The document directory for the current user does not exist, or
959 getUserDocumentsDirectory :: IO FilePath
960 getUserDocumentsDirectory = do
961 #if defined(mingw32_HOST_OS)
962 allocaBytes long_path_size $ \pPath -> do
963 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
964 when (r<0) (raiseUnsupported "System.Directory.getUserDocumentsDirectory")
970 {- | Returns the current directory for temporary files.
972 On Unix, 'getTemporaryDirectory' returns the value of the @TMPDIR@
973 environment variable or \"\/tmp\" if the variable isn\'t defined.
974 On Windows, the function checks for the existence of environment variables in
975 the following order and uses the first path found:
978 TMP environment variable.
981 TEMP environment variable.
984 USERPROFILE environment variable.
987 The Windows directory
989 The operation may fail with:
991 * 'UnsupportedOperation'
992 The operating system has no notion of temporary directory.
994 The function doesn\'t verify whether the path exists.
996 getTemporaryDirectory :: IO FilePath
997 getTemporaryDirectory = do
998 #if defined(mingw32_HOST_OS)
999 allocaBytes long_path_size $ \pPath -> do
1000 r <- c_GetTempPath (fromIntegral long_path_size) pPath
1003 catch (getEnv "TMPDIR") (\ex -> return "/tmp")
1006 #if defined(mingw32_HOST_OS)
1007 foreign import ccall unsafe "__hscore_getFolderPath"
1008 c_SHGetFolderPath :: Ptr ()
1014 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
1015 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
1016 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
1017 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt
1019 foreign import stdcall unsafe "GetTempPathA" c_GetTempPath :: CInt -> CString -> IO CInt
1021 raiseUnsupported loc =
1022 ioException (IOError Nothing UnsupportedOperation loc "unsupported operation" Nothing)
1026 -- ToDo: This should be determined via autoconf (AC_EXEEXT)
1027 -- | Extension for executable files
1028 -- (typically @\"\"@ on Unix and @\"exe\"@ on Windows or OS\/2)
1029 exeExtension :: String
1030 #ifdef mingw32_HOST_OS
1031 exeExtension = "exe"