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 ()
45 , doesFileExist -- :: FilePath -> IO Bool
46 , doesDirectoryExist -- :: FilePath -> IO Bool
54 readable, -- :: Permissions -> Bool
55 writable, -- :: Permissions -> Bool
56 executable, -- :: Permissions -> Bool
57 searchable -- :: Permissions -> Bool
60 , getPermissions -- :: FilePath -> IO Permissions
61 , setPermissions -- :: FilePath -> Permissions -> IO ()
65 , getModificationTime -- :: FilePath -> IO ClockTime
68 import System.Directory.Internals
69 import System.Environment ( getEnv )
70 import System.IO.Error
71 import Control.Monad ( when, unless )
82 #ifdef __GLASGOW_HASKELL__
85 import Control.Exception ( bracket )
86 import System.Posix.Types
87 import System.Posix.Internals
88 import System.Time ( ClockTime(..) )
93 import GHC.IOBase ( IOException(..), IOErrorType(..), ioException )
96 A directory contains a series of entries, each of which is a named
97 reference to a file system object (file, directory etc.). Some
98 entries may be hidden, inaccessible, or have some administrative
99 function (e.g. `.' or `..' under POSIX
100 <http://www.opengroup.org/onlinepubs/007904975/toc.htm>), but in
101 this standard all such entries are considered to form part of the
102 directory contents. Entries in sub-directories are not, however,
103 considered to form part of the directory contents.
105 Each file system object is referenced by a /path/. There is
106 normally at least one absolute path to each file system object. In
107 some operating systems, it may also be possible to have paths which
108 are relative to the current directory.
111 -----------------------------------------------------------------------------
116 The 'Permissions' type is used to record whether certain operations are
117 permissible on a file\/directory. 'getPermissions' and 'setPermissions'
118 get and set these permissions, respectively. Permissions apply both to
119 files and directories. For directories, the executable field will be
120 'False', and for files the searchable field will be 'False'. Note that
121 directories may be searchable without being readable, if permission has
122 been given to use them as part of a path, but not to examine the
125 Note that to change some, but not all permissions, a construct on the following lines must be used.
127 > makeReadable f = do
128 > p <- getPermissions f
129 > setPermissions f (p {readable = True})
136 executable, searchable :: Bool
137 } deriving (Eq, Ord, Read, Show)
139 {- |The 'getPermissions' operation returns the
140 permissions for the file or directory.
142 The operation may fail with:
144 * 'isPermissionError' if the user is not permitted to access
147 * 'isDoesNotExistError' if the file or directory does not exist.
151 getPermissions :: FilePath -> IO Permissions
152 getPermissions name = do
153 withCString name $ \s -> do
154 read <- c_access s r_OK
155 write <- c_access s w_OK
156 exec <- c_access s x_OK
157 withFileStatus "getPermissions" name $ \st -> do
158 is_dir <- isDirectory st
161 readable = read == 0,
162 writable = write == 0,
163 executable = not is_dir && exec == 0,
164 searchable = is_dir && exec == 0
168 {- |The 'setPermissions' operation sets the
169 permissions for the file or directory.
171 The operation may fail with:
173 * 'isPermissionError' if the user is not permitted to set
176 * 'isDoesNotExistError' if the file or directory does not exist.
180 setPermissions :: FilePath -> Permissions -> IO ()
181 setPermissions name (Permissions r w e s) = do
182 allocaBytes sizeof_stat $ \ p_stat -> do
183 withCString name $ \p_name -> do
184 throwErrnoIfMinus1_ "setPermissions" $ do
186 mode <- st_mode p_stat
187 let mode1 = modifyBit r mode s_IRUSR
188 let mode2 = modifyBit w mode1 s_IWUSR
189 let mode3 = modifyBit (e || s) mode2 s_IXUSR
193 modifyBit :: Bool -> CMode -> CMode -> CMode
194 modifyBit False m b = m .&. (complement b)
195 modifyBit True m b = m .|. b
198 copyPermissions :: FilePath -> FilePath -> IO ()
199 copyPermissions source dest = do
200 allocaBytes sizeof_stat $ \ p_stat -> do
201 withCString source $ \p_source -> do
202 withCString dest $ \p_dest -> do
203 throwErrnoIfMinus1_ "copyPermissions" $ c_stat p_source p_stat
204 mode <- st_mode p_stat
205 throwErrnoIfMinus1_ "copyPermissions" $ c_chmod p_dest mode
207 -----------------------------------------------------------------------------
210 {- |@'createDirectory' dir@ creates a new directory @dir@ which is
211 initially empty, or as near to empty as the operating system
214 The operation may fail with:
216 * 'isPermissionError' \/ 'PermissionDenied'
217 The process has insufficient privileges to perform the operation.
220 * 'isAlreadyExistsError' \/ 'AlreadyExists'
221 The operand refers to a directory that already exists.
225 A physical I\/O error has occurred.
229 The operand is not a valid directory name.
230 @[ENAMETOOLONG, ELOOP]@
233 There is no path to the directory.
236 * 'ResourceExhausted'
237 Insufficient resources (virtual memory, process file descriptors,
238 physical disk space, etc.) are available to perform the operation.
239 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
241 * 'InappropriateType'
242 The path refers to an existing non-directory object.
247 createDirectory :: FilePath -> IO ()
248 createDirectory path = do
249 modifyIOError (`ioeSetFileName` path) $
250 withCString path $ \s -> do
251 throwErrnoIfMinus1Retry_ "createDirectory" $
254 #else /* !__GLASGOW_HASKELL__ */
256 copyPermissions :: FilePath -> FilePath -> IO ()
257 copyPermissions fromFPath toFPath
258 = getPermissions fromFPath >>= setPermissions toFPath
262 -- | @'createDirectoryIfMissing' parents dir@ creates a new directory
263 -- @dir@ if it doesn\'t exist. If the first argument is 'True'
264 -- the function will also create all parent directories if they are missing.
265 createDirectoryIfMissing :: Bool -- ^ Create its parents too?
266 -> FilePath -- ^ The path to the directory you want to make
268 createDirectoryIfMissing parents file = do
269 b <- doesDirectoryExist file
270 case (b,parents, file) of
271 (_, _, "") -> return ()
272 (True, _, _) -> return ()
273 (_, True, _) -> mapM_ (createDirectoryIfMissing False) (tail (pathParents file))
274 (_, False, _) -> createDirectory file
276 #if __GLASGOW_HASKELL__
277 {- | @'removeDirectory' dir@ removes an existing directory /dir/. The
278 implementation may specify additional constraints which must be
279 satisfied before a directory can be removed (e.g. the directory has to
280 be empty, or may not be in use by other processes). It is not legal
281 for an implementation to partially remove a directory unless the
282 entire directory is removed. A conformant implementation need not
283 support directory removal in all situations (e.g. removal of the root
286 The operation may fail with:
289 A physical I\/O error has occurred.
293 The operand is not a valid directory name.
294 [ENAMETOOLONG, ELOOP]
296 * 'isDoesNotExistError' \/ 'NoSuchThing'
297 The directory does not exist.
300 * 'isPermissionError' \/ 'PermissionDenied'
301 The process has insufficient privileges to perform the operation.
302 @[EROFS, EACCES, EPERM]@
304 * 'UnsatisfiedConstraints'
305 Implementation-dependent constraints are not satisfied.
306 @[EBUSY, ENOTEMPTY, EEXIST]@
308 * 'UnsupportedOperation'
309 The implementation does not support removal in this situation.
312 * 'InappropriateType'
313 The operand refers to an existing non-directory object.
318 removeDirectory :: FilePath -> IO ()
319 removeDirectory path = do
320 modifyIOError (`ioeSetFileName` path) $
321 withCString path $ \s ->
322 throwErrnoIfMinus1Retry_ "removeDirectory" (c_rmdir s)
325 -- | @'removeDirectoryRecursive' dir@ removes an existing directory /dir/
326 -- together with its content and all subdirectories. Be careful,
327 -- if the directory contains symlinks, the function will follow them.
328 removeDirectoryRecursive :: FilePath -> IO ()
329 removeDirectoryRecursive startLoc = do
330 cont <- getDirectoryContents startLoc
331 sequence_ [rm (startLoc `joinFileName` x) | x <- cont, x /= "." && x /= ".."]
332 removeDirectory startLoc
334 rm :: FilePath -> IO ()
335 rm f = do temp <- try (removeFile f)
337 Left e -> do isDir <- doesDirectoryExist f
338 -- If f is not a directory, re-throw the error
339 unless isDir $ ioError e
340 removeDirectoryRecursive f
343 #if __GLASGOW_HASKELL__
344 {- |'removeFile' /file/ removes the directory entry for an existing file
345 /file/, where /file/ is not itself a directory. The
346 implementation may specify additional constraints which must be
347 satisfied before a file can be removed (e.g. the file may not be in
348 use by other processes).
350 The operation may fail with:
353 A physical I\/O error has occurred.
357 The operand is not a valid file name.
358 @[ENAMETOOLONG, ELOOP]@
360 * 'isDoesNotExistError' \/ 'NoSuchThing'
361 The file does not exist.
364 * 'isPermissionError' \/ 'PermissionDenied'
365 The process has insufficient privileges to perform the operation.
366 @[EROFS, EACCES, EPERM]@
368 * 'UnsatisfiedConstraints'
369 Implementation-dependent constraints are not satisfied.
372 * 'InappropriateType'
373 The operand refers to an existing directory.
378 removeFile :: FilePath -> IO ()
380 modifyIOError (`ioeSetFileName` path) $
381 withCString path $ \s ->
382 throwErrnoIfMinus1Retry_ "removeFile" (c_unlink s)
384 {- |@'renameDirectory' old new@ changes the name of an existing
385 directory from /old/ to /new/. If the /new/ directory
386 already exists, it is atomically replaced by the /old/ directory.
387 If the /new/ directory is neither the /old/ directory nor an
388 alias of the /old/ directory, it is removed as if by
389 'removeDirectory'. A conformant implementation need not support
390 renaming directories in all situations (e.g. renaming to an existing
391 directory, or across different physical devices), but the constraints
394 On Win32 platforms, @renameDirectory@ fails if the /new/ directory already
397 The operation may fail with:
400 A physical I\/O error has occurred.
404 Either operand is not a valid directory name.
405 @[ENAMETOOLONG, ELOOP]@
407 * 'isDoesNotExistError' \/ 'NoSuchThing'
408 The original directory does not exist, or there is no path to the target.
411 * 'isPermissionError' \/ 'PermissionDenied'
412 The process has insufficient privileges to perform the operation.
413 @[EROFS, EACCES, EPERM]@
415 * 'ResourceExhausted'
416 Insufficient resources are available to perform the operation.
417 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
419 * 'UnsatisfiedConstraints'
420 Implementation-dependent constraints are not satisfied.
421 @[EBUSY, ENOTEMPTY, EEXIST]@
423 * 'UnsupportedOperation'
424 The implementation does not support renaming in this situation.
427 * 'InappropriateType'
428 Either path refers to an existing non-directory object.
433 renameDirectory :: FilePath -> FilePath -> IO ()
434 renameDirectory opath npath =
435 withFileStatus "renameDirectory" opath $ \st -> do
436 is_dir <- isDirectory st
438 then ioException (IOError Nothing InappropriateType "renameDirectory"
439 ("not a directory") (Just opath))
442 withCString opath $ \s1 ->
443 withCString npath $ \s2 ->
444 throwErrnoIfMinus1Retry_ "renameDirectory" (c_rename s1 s2)
446 {- |@'renameFile' old new@ changes the name of an existing file system
447 object from /old/ to /new/. If the /new/ object already
448 exists, it is atomically replaced by the /old/ object. Neither
449 path may refer to an existing directory. A conformant implementation
450 need not support renaming files in all situations (e.g. renaming
451 across different physical devices), but the constraints must be
454 The operation may fail with:
457 A physical I\/O error has occurred.
461 Either operand is not a valid file name.
462 @[ENAMETOOLONG, ELOOP]@
464 * 'isDoesNotExistError' \/ 'NoSuchThing'
465 The original file does not exist, or there is no path to the target.
468 * 'isPermissionError' \/ 'PermissionDenied'
469 The process has insufficient privileges to perform the operation.
470 @[EROFS, EACCES, EPERM]@
472 * 'ResourceExhausted'
473 Insufficient resources are available to perform the operation.
474 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
476 * 'UnsatisfiedConstraints'
477 Implementation-dependent constraints are not satisfied.
480 * 'UnsupportedOperation'
481 The implementation does not support renaming in this situation.
484 * 'InappropriateType'
485 Either path refers to an existing directory.
486 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
490 renameFile :: FilePath -> FilePath -> IO ()
491 renameFile opath npath =
492 withFileOrSymlinkStatus "renameFile" opath $ \st -> do
493 is_dir <- isDirectory st
495 then ioException (IOError Nothing InappropriateType "renameFile"
496 "is a directory" (Just opath))
499 withCString opath $ \s1 ->
500 withCString npath $ \s2 ->
501 throwErrnoIfMinus1Retry_ "renameFile" (c_rename s1 s2)
503 #endif /* __GLASGOW_HASKELL__ */
505 {- |@'copyFile' old new@ copies the existing file from /old/ to /new/.
506 If the /new/ file already exists, it is atomically replaced by the /old/ file.
507 Neither path may refer to an existing directory.
509 copyFile :: FilePath -> FilePath -> IO ()
510 copyFile fromFPath toFPath =
511 #if (!(defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ > 600))
512 do readFile fromFPath >>= writeFile toFPath
513 try (copyPermissions fromFPath toFPath)
516 (bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom ->
517 bracket (openBinaryFile toFPath WriteMode) hClose $ \hTo ->
518 allocaBytes bufferSize $ \buffer -> do
519 copyContents hFrom hTo buffer
520 try (copyPermissions fromFPath toFPath)
521 return ()) `catch` (ioError . changeFunName)
525 changeFunName (IOError h iot fun str mb_fp) = IOError h iot "copyFile" str mb_fp
527 copyContents hFrom hTo buffer = do
528 count <- hGetBuf hFrom buffer bufferSize
529 when (count > 0) $ do
530 hPutBuf hTo buffer count
531 copyContents hFrom hTo buffer
534 #ifdef __GLASGOW_HASKELL__
535 -- | Given path referring to a file or directory, returns a
536 -- canonicalized path, with the intent that two paths referring
537 -- to the same file\/directory will map to the same canonicalized
538 -- path. Note that it is impossible to guarantee that the
539 -- implication (same file\/dir \<=\> same canonicalizedPath) holds
540 -- in either direction: this function can make only a best-effort
542 canonicalizePath :: FilePath -> IO FilePath
543 canonicalizePath fpath =
544 withCString fpath $ \pInPath ->
545 allocaBytes long_path_size $ \pOutPath ->
546 #if defined(mingw32_HOST_OS)
547 alloca $ \ppFilePart ->
548 do c_GetFullPathName pInPath (fromIntegral long_path_size) pOutPath ppFilePart
550 do c_realpath pInPath pOutPath
554 #if defined(mingw32_HOST_OS)
555 foreign import stdcall unsafe "GetFullPathNameA"
556 c_GetFullPathName :: CString
562 foreign import ccall unsafe "realpath"
563 c_realpath :: CString
567 #else /* !__GLASGOW_HASKELL__ */
568 -- dummy implementation
569 canonicalizePath :: FilePath -> IO FilePath
570 canonicalizePath fpath = return fpath
571 #endif /* !__GLASGOW_HASKELL__ */
573 -- | Given an executable file name, searches for such file
574 -- in the directories listed in system PATH. The returned value
575 -- is the path to the found executable or Nothing if there isn't
576 -- such executable. For example (findExecutable \"ghc\")
577 -- gives you the path to GHC.
578 findExecutable :: String -> IO (Maybe FilePath)
579 findExecutable binary = do
580 path <- getEnv "PATH"
581 search (parseSearchPath path)
583 fileName = binary `joinFileExt` exeExtension
585 search :: [FilePath] -> IO (Maybe FilePath)
586 search [] = return Nothing
588 let path = d `joinFileName` fileName
589 b <- doesFileExist path
590 if b then return (Just path)
593 #ifdef __GLASGOW_HASKELL__
594 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
597 The operation may fail with:
600 A physical I\/O error has occurred.
604 The operand is not a valid directory name.
605 @[ENAMETOOLONG, ELOOP]@
607 * 'isDoesNotExistError' \/ 'NoSuchThing'
608 The directory does not exist.
611 * 'isPermissionError' \/ 'PermissionDenied'
612 The process has insufficient privileges to perform the operation.
615 * 'ResourceExhausted'
616 Insufficient resources are available to perform the operation.
619 * 'InappropriateType'
620 The path refers to an existing non-directory object.
625 getDirectoryContents :: FilePath -> IO [FilePath]
626 getDirectoryContents path = do
627 modifyIOError (`ioeSetFileName` path) $
628 alloca $ \ ptr_dEnt ->
630 (withCString path $ \s ->
631 throwErrnoIfNullRetry desc (c_opendir s))
632 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
633 (\p -> loop ptr_dEnt p)
635 desc = "getDirectoryContents"
637 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
638 loop ptr_dEnt dir = do
640 r <- readdir dir ptr_dEnt
643 dEnt <- peek ptr_dEnt
647 entry <- (d_name dEnt >>= peekCString)
649 entries <- loop ptr_dEnt dir
650 return (entry:entries)
651 else do errno <- getErrno
652 if (errno == eINTR) then loop ptr_dEnt dir else do
653 let (Errno eo) = errno
654 if (eo == end_of_dir)
660 {- |If the operating system has a notion of current directories,
661 'getCurrentDirectory' returns an absolute path to the
662 current directory of the calling process.
664 The operation may fail with:
667 A physical I\/O error has occurred.
670 * 'isDoesNotExistError' \/ 'NoSuchThing'
671 There is no path referring to the current directory.
672 @[EPERM, ENOENT, ESTALE...]@
674 * 'isPermissionError' \/ 'PermissionDenied'
675 The process has insufficient privileges to perform the operation.
678 * 'ResourceExhausted'
679 Insufficient resources are available to perform the operation.
681 * 'UnsupportedOperation'
682 The operating system has no notion of current directory.
686 getCurrentDirectory :: IO FilePath
687 getCurrentDirectory = do
688 p <- mallocBytes long_path_size
690 where go p bytes = do
691 p' <- c_getcwd p (fromIntegral bytes)
693 then do s <- peekCString p'
696 else do errno <- getErrno
698 then do let bytes' = bytes * 2
699 p' <- reallocBytes p bytes'
701 else throwErrno "getCurrentDirectory"
703 {- |If the operating system has a notion of current directories,
704 @'setCurrentDirectory' dir@ changes the current
705 directory of the calling process to /dir/.
707 The operation may fail with:
710 A physical I\/O error has occurred.
714 The operand is not a valid directory name.
715 @[ENAMETOOLONG, ELOOP]@
717 * 'isDoesNotExistError' \/ 'NoSuchThing'
718 The directory does not exist.
721 * 'isPermissionError' \/ 'PermissionDenied'
722 The process has insufficient privileges to perform the operation.
725 * 'UnsupportedOperation'
726 The operating system has no notion of current directory, or the
727 current directory cannot be dynamically changed.
729 * 'InappropriateType'
730 The path refers to an existing non-directory object.
735 setCurrentDirectory :: FilePath -> IO ()
736 setCurrentDirectory path = do
737 modifyIOError (`ioeSetFileName` path) $
738 withCString path $ \s ->
739 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
740 -- ToDo: add path to error
742 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
743 exists and is a directory, and 'False' otherwise.
746 doesDirectoryExist :: FilePath -> IO Bool
747 doesDirectoryExist name =
749 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
750 (\ _ -> return False)
752 {- |The operation 'doesFileExist' returns 'True'
753 if the argument file exists and is not a directory, and 'False' otherwise.
756 doesFileExist :: FilePath -> IO Bool
757 doesFileExist name = do
759 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
760 (\ _ -> return False)
762 {- |The 'getModificationTime' operation returns the
763 clock time at which the file or directory was last modified.
765 The operation may fail with:
767 * 'isPermissionError' if the user is not permitted to access
768 the modification time; or
770 * 'isDoesNotExistError' if the file or directory does not exist.
774 getModificationTime :: FilePath -> IO ClockTime
775 getModificationTime name =
776 withFileStatus "getModificationTime" name $ \ st ->
779 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
780 withFileStatus loc name f = do
781 modifyIOError (`ioeSetFileName` name) $
782 allocaBytes sizeof_stat $ \p ->
783 withCString (fileNameEndClean name) $ \s -> do
784 throwErrnoIfMinus1Retry_ loc (c_stat s p)
787 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
788 withFileOrSymlinkStatus loc name f = do
789 modifyIOError (`ioeSetFileName` name) $
790 allocaBytes sizeof_stat $ \p ->
791 withCString name $ \s -> do
792 throwErrnoIfMinus1Retry_ loc (lstat s p)
795 modificationTime :: Ptr CStat -> IO ClockTime
796 modificationTime stat = do
797 mtime <- st_mtime stat
798 let realToInteger = round . realToFrac :: Real a => a -> Integer
799 return (TOD (realToInteger (mtime :: CTime)) 0)
801 isDirectory :: Ptr CStat -> IO Bool
802 isDirectory stat = do
804 return (s_isdir mode)
806 fileNameEndClean :: String -> String
807 fileNameEndClean name =
808 if i > 0 && (ec == '\\' || ec == '/') then
809 fileNameEndClean (take i name)
813 i = (length name) - 1
816 foreign import ccall unsafe "__hscore_long_path_size"
817 long_path_size :: Int
819 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CMode
820 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CMode
821 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CMode
823 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
824 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
825 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
827 #endif /* __GLASGOW_HASKELL__ */
829 {- | Returns the current user's home directory.
831 The directory returned is expected to be writable by the current user,
832 but note that it isn't generally considered good practice to store
833 application-specific data here; use 'getAppUserDataDirectory'
836 On Unix, 'getHomeDirectory' returns the value of the @HOME@
837 environment variable. On Windows, the system is queried for a
838 suitable path; a typical path might be
839 @C:/Documents And Settings/user@.
841 The operation may fail with:
843 * 'UnsupportedOperation'
844 The operating system has no notion of home directory.
846 * 'isDoesNotExistError'
847 The home directory for the current user does not exist, or
850 getHomeDirectory :: IO FilePath
852 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
853 allocaBytes long_path_size $ \pPath -> do
854 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
857 r <- c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
858 when (r < 0) (raiseUnsupported "System.Directory.getHomeDirectory")
865 {- | Returns the pathname of a directory in which application-specific
866 data for the current user can be stored. The result of
867 'getAppUserDataDirectory' for a given application is specific to
870 The argument should be the name of the application, which will be used
871 to construct the pathname (so avoid using unusual characters that
872 might result in an invalid pathname).
874 Note: the directory may not actually exist, and may need to be created
875 first. It is expected that the parent directory exists and is
878 On Unix, this function returns @$HOME\/.appName@. On Windows, a
879 typical path might be
881 > C:/Documents And Settings/user/Application Data/appName
883 The operation may fail with:
885 * 'UnsupportedOperation'
886 The operating system has no notion of application-specific data directory.
888 * 'isDoesNotExistError'
889 The home directory for the current user does not exist, or
892 getAppUserDataDirectory :: String -> IO FilePath
893 getAppUserDataDirectory appName = do
894 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
895 allocaBytes long_path_size $ \pPath -> do
896 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
897 when (r<0) (raiseUnsupported "System.Directory.getAppUserDataDirectory")
898 s <- peekCString pPath
899 return (s++'\\':appName)
901 path <- getEnv "HOME"
902 return (path++'/':'.':appName)
905 {- | Returns the current user's document directory.
907 The directory returned is expected to be writable by the current user,
908 but note that it isn't generally considered good practice to store
909 application-specific data here; use 'getAppUserDataDirectory'
912 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
913 environment variable. On Windows, the system is queried for a
914 suitable path; a typical path might be
915 @C:\/Documents and Settings\/user\/My Documents@.
917 The operation may fail with:
919 * 'UnsupportedOperation'
920 The operating system has no notion of document directory.
922 * 'isDoesNotExistError'
923 The document directory for the current user does not exist, or
926 getUserDocumentsDirectory :: IO FilePath
927 getUserDocumentsDirectory = do
928 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
929 allocaBytes long_path_size $ \pPath -> do
930 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
931 when (r<0) (raiseUnsupported "System.Directory.getUserDocumentsDirectory")
937 {- | Returns the current directory for temporary files.
939 On Unix, 'getTemporaryDirectory' returns the value of the @TMPDIR@
940 environment variable or \"\/tmp\" if the variable isn\'t defined.
941 On Windows, the function checks for the existence of environment variables in
942 the following order and uses the first path found:
945 TMP environment variable.
948 TEMP environment variable.
951 USERPROFILE environment variable.
954 The Windows directory
956 The operation may fail with:
958 * 'UnsupportedOperation'
959 The operating system has no notion of temporary directory.
961 The function doesn\'t verify whether the path exists.
963 getTemporaryDirectory :: IO FilePath
964 getTemporaryDirectory = do
965 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
966 allocaBytes long_path_size $ \pPath -> do
967 r <- c_GetTempPath (fromIntegral long_path_size) pPath
970 catch (getEnv "TMPDIR") (\ex -> return "/tmp")
973 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
974 foreign import ccall unsafe "__hscore_getFolderPath"
975 c_SHGetFolderPath :: Ptr ()
981 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
982 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
983 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
984 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt
986 foreign import stdcall unsafe "GetTempPathA" c_GetTempPath :: CInt -> CString -> IO CInt
988 raiseUnsupported loc =
989 ioException (IOError Nothing UnsupportedOperation loc "unsupported operation" Nothing)