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 =
580 #if defined(mingw32_HOST_OS)
581 withCString binary $ \c_binary ->
582 withCString ('.':exeExtension) $ \c_ext ->
583 allocaBytes long_path_size $ \pOutPath ->
584 alloca $ \ppFilePart -> do
585 res <- c_SearchPath nullPtr c_binary c_ext (fromIntegral long_path_size) pOutPath ppFilePart
586 if res > 0 && res < fromIntegral long_path_size
587 then do fpath <- peekCString pOutPath
591 foreign import stdcall unsafe "SearchPath"
592 c_SearchPath :: CString
600 path <- getEnv "PATH"
601 search (parseSearchPath path)
603 fileName = binary `joinFileExt` exeExtension
605 search :: [FilePath] -> IO (Maybe FilePath)
606 search [] = return Nothing
608 let path = d `joinFileName` fileName
609 b <- doesFileExist path
610 if b then return (Just path)
615 #ifdef __GLASGOW_HASKELL__
616 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
619 The operation may fail with:
622 A physical I\/O error has occurred.
626 The operand is not a valid directory name.
627 @[ENAMETOOLONG, ELOOP]@
629 * 'isDoesNotExistError' \/ 'NoSuchThing'
630 The directory does not exist.
633 * 'isPermissionError' \/ 'PermissionDenied'
634 The process has insufficient privileges to perform the operation.
637 * 'ResourceExhausted'
638 Insufficient resources are available to perform the operation.
641 * 'InappropriateType'
642 The path refers to an existing non-directory object.
647 getDirectoryContents :: FilePath -> IO [FilePath]
648 getDirectoryContents path = do
649 modifyIOError (`ioeSetFileName` path) $
650 alloca $ \ ptr_dEnt ->
652 (withCString path $ \s ->
653 throwErrnoIfNullRetry desc (c_opendir s))
654 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
655 (\p -> loop ptr_dEnt p)
657 desc = "getDirectoryContents"
659 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
660 loop ptr_dEnt dir = do
662 r <- readdir dir ptr_dEnt
665 dEnt <- peek ptr_dEnt
669 entry <- (d_name dEnt >>= peekCString)
671 entries <- loop ptr_dEnt dir
672 return (entry:entries)
673 else do errno <- getErrno
674 if (errno == eINTR) then loop ptr_dEnt dir else do
675 let (Errno eo) = errno
676 if (eo == end_of_dir)
682 {- |If the operating system has a notion of current directories,
683 'getCurrentDirectory' returns an absolute path to the
684 current directory of the calling process.
686 The operation may fail with:
689 A physical I\/O error has occurred.
692 * 'isDoesNotExistError' \/ 'NoSuchThing'
693 There is no path referring to the current directory.
694 @[EPERM, ENOENT, ESTALE...]@
696 * 'isPermissionError' \/ 'PermissionDenied'
697 The process has insufficient privileges to perform the operation.
700 * 'ResourceExhausted'
701 Insufficient resources are available to perform the operation.
703 * 'UnsupportedOperation'
704 The operating system has no notion of current directory.
708 getCurrentDirectory :: IO FilePath
709 getCurrentDirectory = do
710 p <- mallocBytes long_path_size
712 where go p bytes = do
713 p' <- c_getcwd p (fromIntegral bytes)
715 then do s <- peekCString p'
718 else do errno <- getErrno
720 then do let bytes' = bytes * 2
721 p' <- reallocBytes p bytes'
723 else throwErrno "getCurrentDirectory"
725 {- |If the operating system has a notion of current directories,
726 @'setCurrentDirectory' dir@ changes the current
727 directory of the calling process to /dir/.
729 The operation may fail with:
732 A physical I\/O error has occurred.
736 The operand is not a valid directory name.
737 @[ENAMETOOLONG, ELOOP]@
739 * 'isDoesNotExistError' \/ 'NoSuchThing'
740 The directory does not exist.
743 * 'isPermissionError' \/ 'PermissionDenied'
744 The process has insufficient privileges to perform the operation.
747 * 'UnsupportedOperation'
748 The operating system has no notion of current directory, or the
749 current directory cannot be dynamically changed.
751 * 'InappropriateType'
752 The path refers to an existing non-directory object.
757 setCurrentDirectory :: FilePath -> IO ()
758 setCurrentDirectory path = do
759 modifyIOError (`ioeSetFileName` path) $
760 withCString path $ \s ->
761 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
762 -- ToDo: add path to error
764 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
765 exists and is a directory, and 'False' otherwise.
768 doesDirectoryExist :: FilePath -> IO Bool
769 doesDirectoryExist name =
771 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
772 (\ _ -> return False)
774 {- |The operation 'doesFileExist' returns 'True'
775 if the argument file exists and is not a directory, and 'False' otherwise.
778 doesFileExist :: FilePath -> IO Bool
779 doesFileExist name = do
781 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
782 (\ _ -> return False)
784 {- |The 'getModificationTime' operation returns the
785 clock time at which the file or directory was last modified.
787 The operation may fail with:
789 * 'isPermissionError' if the user is not permitted to access
790 the modification time; or
792 * 'isDoesNotExistError' if the file or directory does not exist.
796 getModificationTime :: FilePath -> IO ClockTime
797 getModificationTime name =
798 withFileStatus "getModificationTime" name $ \ st ->
801 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
802 withFileStatus loc name f = do
803 modifyIOError (`ioeSetFileName` name) $
804 allocaBytes sizeof_stat $ \p ->
805 withCString (fileNameEndClean name) $ \s -> do
806 throwErrnoIfMinus1Retry_ loc (c_stat s p)
809 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
810 withFileOrSymlinkStatus loc name f = do
811 modifyIOError (`ioeSetFileName` name) $
812 allocaBytes sizeof_stat $ \p ->
813 withCString name $ \s -> do
814 throwErrnoIfMinus1Retry_ loc (lstat s p)
817 modificationTime :: Ptr CStat -> IO ClockTime
818 modificationTime stat = do
819 mtime <- st_mtime stat
820 let realToInteger = round . realToFrac :: Real a => a -> Integer
821 return (TOD (realToInteger (mtime :: CTime)) 0)
823 isDirectory :: Ptr CStat -> IO Bool
824 isDirectory stat = do
826 return (s_isdir mode)
828 fileNameEndClean :: String -> String
829 fileNameEndClean name =
830 if i > 0 && (ec == '\\' || ec == '/') then
831 fileNameEndClean (take i name)
835 i = (length name) - 1
838 foreign import ccall unsafe "__hscore_long_path_size"
839 long_path_size :: Int
841 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CMode
842 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CMode
843 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CMode
845 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
846 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
847 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
849 #endif /* __GLASGOW_HASKELL__ */
851 {- | Returns the current user's home directory.
853 The directory returned is expected to be writable by the current user,
854 but note that it isn't generally considered good practice to store
855 application-specific data here; use 'getAppUserDataDirectory'
858 On Unix, 'getHomeDirectory' returns the value of the @HOME@
859 environment variable. On Windows, the system is queried for a
860 suitable path; a typical path might be
861 @C:/Documents And Settings/user@.
863 The operation may fail with:
865 * 'UnsupportedOperation'
866 The operating system has no notion of home directory.
868 * 'isDoesNotExistError'
869 The home directory for the current user does not exist, or
872 getHomeDirectory :: IO FilePath
874 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
875 allocaBytes long_path_size $ \pPath -> do
876 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
879 r <- c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
880 when (r < 0) (raiseUnsupported "System.Directory.getHomeDirectory")
887 {- | Returns the pathname of a directory in which application-specific
888 data for the current user can be stored. The result of
889 'getAppUserDataDirectory' for a given application is specific to
892 The argument should be the name of the application, which will be used
893 to construct the pathname (so avoid using unusual characters that
894 might result in an invalid pathname).
896 Note: the directory may not actually exist, and may need to be created
897 first. It is expected that the parent directory exists and is
900 On Unix, this function returns @$HOME\/.appName@. On Windows, a
901 typical path might be
903 > C:/Documents And Settings/user/Application Data/appName
905 The operation may fail with:
907 * 'UnsupportedOperation'
908 The operating system has no notion of application-specific data directory.
910 * 'isDoesNotExistError'
911 The home directory for the current user does not exist, or
914 getAppUserDataDirectory :: String -> IO FilePath
915 getAppUserDataDirectory appName = do
916 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
917 allocaBytes long_path_size $ \pPath -> do
918 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
919 when (r<0) (raiseUnsupported "System.Directory.getAppUserDataDirectory")
920 s <- peekCString pPath
921 return (s++'\\':appName)
923 path <- getEnv "HOME"
924 return (path++'/':'.':appName)
927 {- | Returns the current user's document directory.
929 The directory returned is expected to be writable by the current user,
930 but note that it isn't generally considered good practice to store
931 application-specific data here; use 'getAppUserDataDirectory'
934 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
935 environment variable. On Windows, the system is queried for a
936 suitable path; a typical path might be
937 @C:\/Documents and Settings\/user\/My Documents@.
939 The operation may fail with:
941 * 'UnsupportedOperation'
942 The operating system has no notion of document directory.
944 * 'isDoesNotExistError'
945 The document directory for the current user does not exist, or
948 getUserDocumentsDirectory :: IO FilePath
949 getUserDocumentsDirectory = do
950 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
951 allocaBytes long_path_size $ \pPath -> do
952 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
953 when (r<0) (raiseUnsupported "System.Directory.getUserDocumentsDirectory")
959 {- | Returns the current directory for temporary files.
961 On Unix, 'getTemporaryDirectory' returns the value of the @TMPDIR@
962 environment variable or \"\/tmp\" if the variable isn\'t defined.
963 On Windows, the function checks for the existence of environment variables in
964 the following order and uses the first path found:
967 TMP environment variable.
970 TEMP environment variable.
973 USERPROFILE environment variable.
976 The Windows directory
978 The operation may fail with:
980 * 'UnsupportedOperation'
981 The operating system has no notion of temporary directory.
983 The function doesn\'t verify whether the path exists.
985 getTemporaryDirectory :: IO FilePath
986 getTemporaryDirectory = do
987 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
988 allocaBytes long_path_size $ \pPath -> do
989 r <- c_GetTempPath (fromIntegral long_path_size) pPath
992 catch (getEnv "TMPDIR") (\ex -> return "/tmp")
995 #if __GLASGOW_HASKELL__ && defined(mingw32_HOST_OS)
996 foreign import ccall unsafe "__hscore_getFolderPath"
997 c_SHGetFolderPath :: Ptr ()
1003 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
1004 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
1005 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
1006 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt
1008 foreign import stdcall unsafe "GetTempPathA" c_GetTempPath :: CInt -> CString -> IO CInt
1010 raiseUnsupported loc =
1011 ioException (IOError Nothing UnsupportedOperation loc "unsupported operation" Nothing)