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 )
84 {-# CFILES cbits/directory.c #-}
86 #ifdef __GLASGOW_HASKELL__
89 import Control.Exception ( bracket )
90 import System.Posix.Types
91 import System.Posix.Internals
92 import System.Time ( ClockTime(..) )
95 import GHC.IOBase ( IOException(..), IOErrorType(..), ioException )
98 A directory contains a series of entries, each of which is a named
99 reference to a file system object (file, directory etc.). Some
100 entries may be hidden, inaccessible, or have some administrative
101 function (e.g. `.' or `..' under POSIX
102 <http://www.opengroup.org/onlinepubs/007904975/toc.htm>), but in
103 this standard all such entries are considered to form part of the
104 directory contents. Entries in sub-directories are not, however,
105 considered to form part of the directory contents.
107 Each file system object is referenced by a /path/. There is
108 normally at least one absolute path to each file system object. In
109 some operating systems, it may also be possible to have paths which
110 are relative to the current directory.
113 -----------------------------------------------------------------------------
118 The 'Permissions' type is used to record whether certain operations are
119 permissible on a file\/directory. 'getPermissions' and 'setPermissions'
120 get and set these permissions, respectively. Permissions apply both to
121 files and directories. For directories, the executable field will be
122 'False', and for files the searchable field will be 'False'. Note that
123 directories may be searchable without being readable, if permission has
124 been given to use them as part of a path, but not to examine the
127 Note that to change some, but not all permissions, a construct on the following lines must be used.
129 > makeReadable f = do
130 > p <- getPermissions f
131 > setPermissions f (p {readable = True})
138 executable, searchable :: Bool
139 } deriving (Eq, Ord, Read, Show)
141 {- |The 'getPermissions' operation returns the
142 permissions for the file or directory.
144 The operation may fail with:
146 * 'isPermissionError' if the user is not permitted to access
149 * 'isDoesNotExistError' if the file or directory does not exist.
153 getPermissions :: FilePath -> IO Permissions
154 getPermissions name = do
155 withCString name $ \s -> do
156 read <- c_access s r_OK
157 write <- c_access s w_OK
158 exec <- c_access s x_OK
159 withFileStatus "getPermissions" name $ \st -> do
160 is_dir <- isDirectory st
163 readable = read == 0,
164 writable = write == 0,
165 executable = not is_dir && exec == 0,
166 searchable = is_dir && exec == 0
170 {- |The 'setPermissions' operation sets the
171 permissions for the file or directory.
173 The operation may fail with:
175 * 'isPermissionError' if the user is not permitted to set
178 * 'isDoesNotExistError' if the file or directory does not exist.
182 setPermissions :: FilePath -> Permissions -> IO ()
183 setPermissions name (Permissions r w e s) = do
184 allocaBytes sizeof_stat $ \ p_stat -> do
185 withCString name $ \p_name -> do
186 throwErrnoIfMinus1_ "setPermissions" $ do
188 mode <- st_mode p_stat
189 let mode1 = modifyBit r mode s_IRUSR
190 let mode2 = modifyBit w mode1 s_IWUSR
191 let mode3 = modifyBit (e || s) mode2 s_IXUSR
195 modifyBit :: Bool -> CMode -> CMode -> CMode
196 modifyBit False m b = m .&. (complement b)
197 modifyBit True m b = m .|. b
200 copyPermissions :: FilePath -> FilePath -> IO ()
201 copyPermissions source dest = do
202 allocaBytes sizeof_stat $ \ p_stat -> do
203 withCString source $ \p_source -> do
204 withCString dest $ \p_dest -> do
205 throwErrnoIfMinus1_ "copyPermissions" $ c_stat p_source p_stat
206 mode <- st_mode p_stat
207 throwErrnoIfMinus1_ "copyPermissions" $ c_chmod p_dest mode
209 -----------------------------------------------------------------------------
212 {- |@'createDirectory' dir@ creates a new directory @dir@ which is
213 initially empty, or as near to empty as the operating system
216 The operation may fail with:
218 * 'isPermissionError' \/ 'PermissionDenied'
219 The process has insufficient privileges to perform the operation.
222 * 'isAlreadyExistsError' \/ 'AlreadyExists'
223 The operand refers to a directory that already exists.
227 A physical I\/O error has occurred.
231 The operand is not a valid directory name.
232 @[ENAMETOOLONG, ELOOP]@
235 There is no path to the directory.
238 * 'ResourceExhausted'
239 Insufficient resources (virtual memory, process file descriptors,
240 physical disk space, etc.) are available to perform the operation.
241 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
243 * 'InappropriateType'
244 The path refers to an existing non-directory object.
249 createDirectory :: FilePath -> IO ()
250 createDirectory path = do
251 modifyIOError (`ioeSetFileName` path) $
252 withCString path $ \s -> do
253 throwErrnoIfMinus1Retry_ "createDirectory" $
256 #else /* !__GLASGOW_HASKELL__ */
258 copyPermissions :: FilePath -> FilePath -> IO ()
259 copyPermissions fromFPath toFPath
260 = getPermissions fromFPath >>= setPermissions toFPath
264 -- | @'createDirectoryIfMissing' parents dir@ creates a new directory
265 -- @dir@ if it doesn\'t exist. If the first argument is 'True'
266 -- the function will also create all parent directories if they are missing.
267 createDirectoryIfMissing :: Bool -- ^ Create its parents too?
268 -> FilePath -- ^ The path to the directory you want to make
270 createDirectoryIfMissing parents file = do
271 b <- doesDirectoryExist file
272 case (b,parents, file) of
273 (_, _, "") -> return ()
274 (True, _, _) -> return ()
275 (_, True, _) -> mapM_ (createDirectoryIfMissing False) (tail (pathParents file))
276 (_, False, _) -> createDirectory file
278 #if __GLASGOW_HASKELL__
279 {- | @'removeDirectory' dir@ removes an existing directory /dir/. The
280 implementation may specify additional constraints which must be
281 satisfied before a directory can be removed (e.g. the directory has to
282 be empty, or may not be in use by other processes). It is not legal
283 for an implementation to partially remove a directory unless the
284 entire directory is removed. A conformant implementation need not
285 support directory removal in all situations (e.g. removal of the root
288 The operation may fail with:
291 A physical I\/O error has occurred.
295 The operand is not a valid directory name.
296 [ENAMETOOLONG, ELOOP]
298 * 'isDoesNotExistError' \/ 'NoSuchThing'
299 The directory does not exist.
302 * 'isPermissionError' \/ 'PermissionDenied'
303 The process has insufficient privileges to perform the operation.
304 @[EROFS, EACCES, EPERM]@
306 * 'UnsatisfiedConstraints'
307 Implementation-dependent constraints are not satisfied.
308 @[EBUSY, ENOTEMPTY, EEXIST]@
310 * 'UnsupportedOperation'
311 The implementation does not support removal in this situation.
314 * 'InappropriateType'
315 The operand refers to an existing non-directory object.
320 removeDirectory :: FilePath -> IO ()
321 removeDirectory path = do
322 modifyIOError (`ioeSetFileName` path) $
323 withCString path $ \s ->
324 throwErrnoIfMinus1Retry_ "removeDirectory" (c_rmdir s)
327 -- | @'removeDirectoryRecursive' dir@ removes an existing directory /dir/
328 -- together with its content and all subdirectories. Be careful,
329 -- if the directory contains symlinks, the function will follow them.
330 removeDirectoryRecursive :: FilePath -> IO ()
331 removeDirectoryRecursive startLoc = do
332 cont <- getDirectoryContents startLoc
333 sequence_ [rm (startLoc `joinFileName` x) | x <- cont, x /= "." && x /= ".."]
334 removeDirectory startLoc
336 rm :: FilePath -> IO ()
337 rm f = do temp <- try (removeFile f)
339 Left e -> do isDir <- doesDirectoryExist f
340 -- If f is not a directory, re-throw the error
341 unless isDir $ ioError e
342 removeDirectoryRecursive f
345 #if __GLASGOW_HASKELL__
346 {- |'removeFile' /file/ removes the directory entry for an existing file
347 /file/, where /file/ is not itself a directory. The
348 implementation may specify additional constraints which must be
349 satisfied before a file can be removed (e.g. the file may not be in
350 use by other processes).
352 The operation may fail with:
355 A physical I\/O error has occurred.
359 The operand is not a valid file name.
360 @[ENAMETOOLONG, ELOOP]@
362 * 'isDoesNotExistError' \/ 'NoSuchThing'
363 The file does not exist.
366 * 'isPermissionError' \/ 'PermissionDenied'
367 The process has insufficient privileges to perform the operation.
368 @[EROFS, EACCES, EPERM]@
370 * 'UnsatisfiedConstraints'
371 Implementation-dependent constraints are not satisfied.
374 * 'InappropriateType'
375 The operand refers to an existing directory.
380 removeFile :: FilePath -> IO ()
382 modifyIOError (`ioeSetFileName` path) $
383 withCString path $ \s ->
384 throwErrnoIfMinus1Retry_ "removeFile" (c_unlink s)
386 {- |@'renameDirectory' old new@ changes the name of an existing
387 directory from /old/ to /new/. If the /new/ directory
388 already exists, it is atomically replaced by the /old/ directory.
389 If the /new/ directory is neither the /old/ directory nor an
390 alias of the /old/ directory, it is removed as if by
391 'removeDirectory'. A conformant implementation need not support
392 renaming directories in all situations (e.g. renaming to an existing
393 directory, or across different physical devices), but the constraints
396 On Win32 platforms, @renameDirectory@ fails if the /new/ directory already
399 The operation may fail with:
402 A physical I\/O error has occurred.
406 Either operand is not a valid directory name.
407 @[ENAMETOOLONG, ELOOP]@
409 * 'isDoesNotExistError' \/ 'NoSuchThing'
410 The original directory does not exist, or there is no path to the target.
413 * 'isPermissionError' \/ 'PermissionDenied'
414 The process has insufficient privileges to perform the operation.
415 @[EROFS, EACCES, EPERM]@
417 * 'ResourceExhausted'
418 Insufficient resources are available to perform the operation.
419 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
421 * 'UnsatisfiedConstraints'
422 Implementation-dependent constraints are not satisfied.
423 @[EBUSY, ENOTEMPTY, EEXIST]@
425 * 'UnsupportedOperation'
426 The implementation does not support renaming in this situation.
429 * 'InappropriateType'
430 Either path refers to an existing non-directory object.
435 renameDirectory :: FilePath -> FilePath -> IO ()
436 renameDirectory opath npath =
437 withFileStatus "renameDirectory" opath $ \st -> do
438 is_dir <- isDirectory st
440 then ioException (IOError Nothing InappropriateType "renameDirectory"
441 ("not a directory") (Just opath))
444 withCString opath $ \s1 ->
445 withCString npath $ \s2 ->
446 throwErrnoIfMinus1Retry_ "renameDirectory" (c_rename s1 s2)
448 {- |@'renameFile' old new@ changes the name of an existing file system
449 object from /old/ to /new/. If the /new/ object already
450 exists, it is atomically replaced by the /old/ object. Neither
451 path may refer to an existing directory. A conformant implementation
452 need not support renaming files in all situations (e.g. renaming
453 across different physical devices), but the constraints must be
456 The operation may fail with:
459 A physical I\/O error has occurred.
463 Either operand is not a valid file name.
464 @[ENAMETOOLONG, ELOOP]@
466 * 'isDoesNotExistError' \/ 'NoSuchThing'
467 The original file does not exist, or there is no path to the target.
470 * 'isPermissionError' \/ 'PermissionDenied'
471 The process has insufficient privileges to perform the operation.
472 @[EROFS, EACCES, EPERM]@
474 * 'ResourceExhausted'
475 Insufficient resources are available to perform the operation.
476 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
478 * 'UnsatisfiedConstraints'
479 Implementation-dependent constraints are not satisfied.
482 * 'UnsupportedOperation'
483 The implementation does not support renaming in this situation.
486 * 'InappropriateType'
487 Either path refers to an existing directory.
488 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
492 renameFile :: FilePath -> FilePath -> IO ()
493 renameFile opath npath =
494 withFileOrSymlinkStatus "renameFile" opath $ \st -> do
495 is_dir <- isDirectory st
497 then ioException (IOError Nothing InappropriateType "renameFile"
498 "is a directory" (Just opath))
501 withCString opath $ \s1 ->
502 withCString npath $ \s2 ->
503 throwErrnoIfMinus1Retry_ "renameFile" (c_rename s1 s2)
505 #endif /* __GLASGOW_HASKELL__ */
507 {- |@'copyFile' old new@ copies the existing file from /old/ to /new/.
508 If the /new/ file already exists, it is atomically replaced by the /old/ file.
509 Neither path may refer to an existing directory. The permissions of /old/ are
510 copied to /new/, if possible.
515 It's tempting to try to remove the target file before opening it for
516 writing. This could be useful: for example if the target file is an
517 executable that is in use, writing will fail, but unlinking first
520 However, it certainly isn't always what you want.
522 * if the target file is hardlinked, removing it would break
523 the hard link, but just opening would preserve it.
525 * opening and truncating will preserve permissions and
528 * If the destination file is read-only in a writable directory,
529 we might want copyFile to fail. Removing the target first
530 would succeed, however.
532 * If the destination file is special (eg. /dev/null), removing
533 it is probably not the right thing. Copying to /dev/null
534 should leave /dev/null intact, not replace it with a plain
537 * There's a small race condition between removing the target and
538 opening it for writing during which time someone might
541 copyFile :: FilePath -> FilePath -> IO ()
542 copyFile fromFPath toFPath =
543 #if (!(defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ > 600))
544 do readFile fromFPath >>= writeFile toFPath
545 try (copyPermissions fromFPath toFPath)
548 (bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom ->
549 bracket (openBinaryFile toFPath WriteMode) hClose $ \hTo ->
550 allocaBytes bufferSize $ \buffer -> do
551 copyContents hFrom hTo buffer
552 try (copyPermissions fromFPath toFPath)
553 return ()) `catch` (ioError . changeFunName)
557 changeFunName (IOError h iot fun str mb_fp) = IOError h iot "copyFile" str mb_fp
559 copyContents hFrom hTo buffer = do
560 count <- hGetBuf hFrom buffer bufferSize
561 when (count > 0) $ do
562 hPutBuf hTo buffer count
563 copyContents hFrom hTo buffer
566 -- | Given path referring to a file or directory, returns a
567 -- canonicalized path, with the intent that two paths referring
568 -- to the same file\/directory will map to the same canonicalized
569 -- path. Note that it is impossible to guarantee that the
570 -- implication (same file\/dir \<=\> same canonicalizedPath) holds
571 -- in either direction: this function can make only a best-effort
573 canonicalizePath :: FilePath -> IO FilePath
574 canonicalizePath fpath =
575 withCString fpath $ \pInPath ->
576 allocaBytes long_path_size $ \pOutPath ->
577 #if defined(mingw32_HOST_OS)
578 alloca $ \ppFilePart ->
579 do c_GetFullPathName pInPath (fromIntegral long_path_size) pOutPath ppFilePart
581 do c_realpath pInPath pOutPath
585 #if defined(mingw32_HOST_OS)
586 foreign import stdcall unsafe "GetFullPathNameA"
587 c_GetFullPathName :: CString
593 foreign import ccall unsafe "realpath"
594 c_realpath :: CString
599 -- | Given an executable file name, searches for such file
600 -- in the directories listed in system PATH. The returned value
601 -- is the path to the found executable or Nothing if there isn't
602 -- such executable. For example (findExecutable \"ghc\")
603 -- gives you the path to GHC.
604 findExecutable :: String -> IO (Maybe FilePath)
605 findExecutable binary =
606 #if defined(mingw32_HOST_OS)
607 withCString binary $ \c_binary ->
608 withCString ('.':exeExtension) $ \c_ext ->
609 allocaBytes long_path_size $ \pOutPath ->
610 alloca $ \ppFilePart -> do
611 res <- c_SearchPath nullPtr c_binary c_ext (fromIntegral long_path_size) pOutPath ppFilePart
612 if res > 0 && res < fromIntegral long_path_size
613 then do fpath <- peekCString pOutPath
617 foreign import stdcall unsafe "SearchPathA"
618 c_SearchPath :: CString
627 path <- getEnv "PATH"
628 search (parseSearchPath path)
630 fileName = binary `joinFileExt` exeExtension
632 search :: [FilePath] -> IO (Maybe FilePath)
633 search [] = return Nothing
635 let path = d `joinFileName` fileName
636 b <- doesFileExist path
637 if b then return (Just path)
642 #ifdef __GLASGOW_HASKELL__
643 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
646 The operation may fail with:
649 A physical I\/O error has occurred.
653 The operand is not a valid directory name.
654 @[ENAMETOOLONG, ELOOP]@
656 * 'isDoesNotExistError' \/ 'NoSuchThing'
657 The directory does not exist.
660 * 'isPermissionError' \/ 'PermissionDenied'
661 The process has insufficient privileges to perform the operation.
664 * 'ResourceExhausted'
665 Insufficient resources are available to perform the operation.
668 * 'InappropriateType'
669 The path refers to an existing non-directory object.
674 getDirectoryContents :: FilePath -> IO [FilePath]
675 getDirectoryContents path = do
676 modifyIOError (`ioeSetFileName` path) $
677 alloca $ \ ptr_dEnt ->
679 (withCString path $ \s ->
680 throwErrnoIfNullRetry desc (c_opendir s))
681 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
682 (\p -> loop ptr_dEnt p)
684 desc = "getDirectoryContents"
686 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
687 loop ptr_dEnt dir = do
689 r <- readdir dir ptr_dEnt
692 dEnt <- peek ptr_dEnt
696 entry <- (d_name dEnt >>= peekCString)
698 entries <- loop ptr_dEnt dir
699 return (entry:entries)
700 else do errno <- getErrno
701 if (errno == eINTR) then loop ptr_dEnt dir else do
702 let (Errno eo) = errno
703 if (eo == end_of_dir)
709 {- |If the operating system has a notion of current directories,
710 'getCurrentDirectory' returns an absolute path to the
711 current directory of the calling process.
713 The operation may fail with:
716 A physical I\/O error has occurred.
719 * 'isDoesNotExistError' \/ 'NoSuchThing'
720 There is no path referring to the current directory.
721 @[EPERM, ENOENT, ESTALE...]@
723 * 'isPermissionError' \/ 'PermissionDenied'
724 The process has insufficient privileges to perform the operation.
727 * 'ResourceExhausted'
728 Insufficient resources are available to perform the operation.
730 * 'UnsupportedOperation'
731 The operating system has no notion of current directory.
735 getCurrentDirectory :: IO FilePath
736 getCurrentDirectory = do
737 p <- mallocBytes long_path_size
739 where go p bytes = do
740 p' <- c_getcwd p (fromIntegral bytes)
742 then do s <- peekCString p'
745 else do errno <- getErrno
747 then do let bytes' = bytes * 2
748 p' <- reallocBytes p bytes'
750 else throwErrno "getCurrentDirectory"
752 {- |If the operating system has a notion of current directories,
753 @'setCurrentDirectory' dir@ changes the current
754 directory of the calling process to /dir/.
756 The operation may fail with:
759 A physical I\/O error has occurred.
763 The operand is not a valid directory name.
764 @[ENAMETOOLONG, ELOOP]@
766 * 'isDoesNotExistError' \/ 'NoSuchThing'
767 The directory does not exist.
770 * 'isPermissionError' \/ 'PermissionDenied'
771 The process has insufficient privileges to perform the operation.
774 * 'UnsupportedOperation'
775 The operating system has no notion of current directory, or the
776 current directory cannot be dynamically changed.
778 * 'InappropriateType'
779 The path refers to an existing non-directory object.
784 setCurrentDirectory :: FilePath -> IO ()
785 setCurrentDirectory path = do
786 modifyIOError (`ioeSetFileName` path) $
787 withCString path $ \s ->
788 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
789 -- ToDo: add path to error
791 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
792 exists and is a directory, and 'False' otherwise.
795 doesDirectoryExist :: FilePath -> IO Bool
796 doesDirectoryExist name =
798 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
799 (\ _ -> return False)
801 {- |The operation 'doesFileExist' returns 'True'
802 if the argument file exists and is not a directory, and 'False' otherwise.
805 doesFileExist :: FilePath -> IO Bool
806 doesFileExist name = do
808 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
809 (\ _ -> return False)
811 {- |The 'getModificationTime' operation returns the
812 clock time at which the file or directory was last modified.
814 The operation may fail with:
816 * 'isPermissionError' if the user is not permitted to access
817 the modification time; or
819 * 'isDoesNotExistError' if the file or directory does not exist.
823 getModificationTime :: FilePath -> IO ClockTime
824 getModificationTime name =
825 withFileStatus "getModificationTime" name $ \ st ->
828 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
829 withFileStatus loc name f = do
830 modifyIOError (`ioeSetFileName` name) $
831 allocaBytes sizeof_stat $ \p ->
832 withCString (fileNameEndClean name) $ \s -> do
833 throwErrnoIfMinus1Retry_ loc (c_stat s p)
836 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
837 withFileOrSymlinkStatus loc name f = do
838 modifyIOError (`ioeSetFileName` name) $
839 allocaBytes sizeof_stat $ \p ->
840 withCString name $ \s -> do
841 throwErrnoIfMinus1Retry_ loc (lstat s p)
844 modificationTime :: Ptr CStat -> IO ClockTime
845 modificationTime stat = do
846 mtime <- st_mtime stat
847 let realToInteger = round . realToFrac :: Real a => a -> Integer
848 return (TOD (realToInteger (mtime :: CTime)) 0)
850 isDirectory :: Ptr CStat -> IO Bool
851 isDirectory stat = do
853 return (s_isdir mode)
855 fileNameEndClean :: String -> String
856 fileNameEndClean name =
857 if i > 0 && (ec == '\\' || ec == '/') then
858 fileNameEndClean (take i name)
862 i = (length name) - 1
865 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CInt
866 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CInt
867 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CInt
869 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
870 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
871 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
873 foreign import ccall unsafe "__hscore_long_path_size"
874 long_path_size :: Int
877 long_path_size :: Int
878 long_path_size = 2048 /* guess? */
880 #endif /* __GLASGOW_HASKELL__ */
882 {- | Returns the current user's home directory.
884 The directory returned is expected to be writable by the current user,
885 but note that it isn't generally considered good practice to store
886 application-specific data here; use 'getAppUserDataDirectory'
889 On Unix, 'getHomeDirectory' returns the value of the @HOME@
890 environment variable. On Windows, the system is queried for a
891 suitable path; a typical path might be
892 @C:/Documents And Settings/user@.
894 The operation may fail with:
896 * 'UnsupportedOperation'
897 The operating system has no notion of home directory.
899 * 'isDoesNotExistError'
900 The home directory for the current user does not exist, or
903 getHomeDirectory :: IO FilePath
905 #if defined(mingw32_HOST_OS)
906 allocaBytes long_path_size $ \pPath -> do
907 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
910 r <- c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
911 when (r < 0) (raiseUnsupported "System.Directory.getHomeDirectory")
918 {- | Returns the pathname of a directory in which application-specific
919 data for the current user can be stored. The result of
920 'getAppUserDataDirectory' for a given application is specific to
923 The argument should be the name of the application, which will be used
924 to construct the pathname (so avoid using unusual characters that
925 might result in an invalid pathname).
927 Note: the directory may not actually exist, and may need to be created
928 first. It is expected that the parent directory exists and is
931 On Unix, this function returns @$HOME\/.appName@. On Windows, a
932 typical path might be
934 > C:/Documents And Settings/user/Application Data/appName
936 The operation may fail with:
938 * 'UnsupportedOperation'
939 The operating system has no notion of application-specific data directory.
941 * 'isDoesNotExistError'
942 The home directory for the current user does not exist, or
945 getAppUserDataDirectory :: String -> IO FilePath
946 getAppUserDataDirectory appName = do
947 #if defined(mingw32_HOST_OS)
948 allocaBytes long_path_size $ \pPath -> do
949 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
950 when (r<0) (raiseUnsupported "System.Directory.getAppUserDataDirectory")
951 s <- peekCString pPath
952 return (s++'\\':appName)
954 path <- getEnv "HOME"
955 return (path++'/':'.':appName)
958 {- | Returns the current user's document directory.
960 The directory returned is expected to be writable by the current user,
961 but note that it isn't generally considered good practice to store
962 application-specific data here; use 'getAppUserDataDirectory'
965 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
966 environment variable. On Windows, the system is queried for a
967 suitable path; a typical path might be
968 @C:\/Documents and Settings\/user\/My Documents@.
970 The operation may fail with:
972 * 'UnsupportedOperation'
973 The operating system has no notion of document directory.
975 * 'isDoesNotExistError'
976 The document directory for the current user does not exist, or
979 getUserDocumentsDirectory :: IO FilePath
980 getUserDocumentsDirectory = do
981 #if defined(mingw32_HOST_OS)
982 allocaBytes long_path_size $ \pPath -> do
983 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
984 when (r<0) (raiseUnsupported "System.Directory.getUserDocumentsDirectory")
990 {- | Returns the current directory for temporary files.
992 On Unix, 'getTemporaryDirectory' returns the value of the @TMPDIR@
993 environment variable or \"\/tmp\" if the variable isn\'t defined.
994 On Windows, the function checks for the existence of environment variables in
995 the following order and uses the first path found:
998 TMP environment variable.
1001 TEMP environment variable.
1004 USERPROFILE environment variable.
1007 The Windows directory
1009 The operation may fail with:
1011 * 'UnsupportedOperation'
1012 The operating system has no notion of temporary directory.
1014 The function doesn\'t verify whether the path exists.
1016 getTemporaryDirectory :: IO FilePath
1017 getTemporaryDirectory = do
1018 #if defined(mingw32_HOST_OS)
1019 allocaBytes long_path_size $ \pPath -> do
1020 r <- c_GetTempPath (fromIntegral long_path_size) pPath
1023 catch (getEnv "TMPDIR") (\ex -> return "/tmp")
1026 #if defined(mingw32_HOST_OS)
1027 foreign import ccall unsafe "__hscore_getFolderPath"
1028 c_SHGetFolderPath :: Ptr ()
1034 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
1035 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
1036 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
1037 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt
1039 foreign import stdcall unsafe "GetTempPathA" c_GetTempPath :: CInt -> CString -> IO CInt
1041 raiseUnsupported loc =
1042 ioException (IOError Nothing UnsupportedOperation loc "unsupported operation" Nothing)