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 , removeDirectory -- :: FilePath -> IO ()
22 , renameDirectory -- :: FilePath -> FilePath -> IO ()
24 , getDirectoryContents -- :: FilePath -> IO [FilePath]
25 , getCurrentDirectory -- :: IO FilePath
26 , setCurrentDirectory -- :: FilePath -> IO ()
28 -- * Pre-defined directories
30 , getAppUserDataDirectory
31 , getUserDocumentsDirectory
34 , removeFile -- :: FilePath -> IO ()
35 , renameFile -- :: FilePath -> FilePath -> IO ()
36 #ifdef __GLASGOW_HASKELL__
37 , copyFile -- :: FilePath -> FilePath -> IO ()
41 , doesFileExist -- :: FilePath -> IO Bool
42 , doesDirectoryExist -- :: FilePath -> IO Bool
50 readable, -- :: Permissions -> Bool
51 writable, -- :: Permissions -> Bool
52 executable, -- :: Permissions -> Bool
53 searchable -- :: Permissions -> Bool
56 , getPermissions -- :: FilePath -> IO Permissions
57 , setPermissions -- :: FilePath -> Permissions -> IO ()
61 , getModificationTime -- :: FilePath -> IO ClockTime
66 import System (getEnv)
71 import System.Environment (getEnv)
74 #ifdef __GLASGOW_HASKELL__
77 import Control.Exception ( bracket )
78 import Control.Monad ( when )
79 import System.Posix.Types
80 import System.Posix.Internals
81 import System.Time ( ClockTime(..) )
83 import System.IO.Error
87 import GHC.IOBase ( IOException(..), IOErrorType(..), ioException )
89 #ifndef mingw32_TARGET_OS
90 import System.Environment
94 A directory contains a series of entries, each of which is a named
95 reference to a file system object (file, directory etc.). Some
96 entries may be hidden, inaccessible, or have some administrative
97 function (e.g. `.' or `..' under POSIX
98 <http://www.opengroup.org/onlinepubs/007904975/toc.htm>), but in
99 this standard all such entries are considered to form part of the
100 directory contents. Entries in sub-directories are not, however,
101 considered to form part of the directory contents.
103 Each file system object is referenced by a /path/. There is
104 normally at least one absolute path to each file system object. In
105 some operating systems, it may also be possible to have paths which
106 are relative to the current directory.
109 -----------------------------------------------------------------------------
114 The 'Permissions' type is used to record whether certain operations are
115 permissible on a file\/directory. 'getPermissions' and 'setPermissions'
116 get and set these permissions, respectively. Permissions apply both to
117 files and directories. For directories, the executable field will be
118 'False', and for files the searchable field will be 'False'. Note that
119 directories may be searchable without being readable, if permission has
120 been given to use them as part of a path, but not to examine the
123 Note that to change some, but not all permissions, a construct on the following lines must be used.
125 > makeReadable f = do
126 > p <- getPermissions f
127 > setPermissions f (p {readable = True})
134 executable, searchable :: Bool
135 } deriving (Eq, Ord, Read, Show)
137 {- |The 'getPermissions' operation returns the
138 permissions for the file or directory.
140 The operation may fail with:
142 * 'isPermissionError' if the user is not permitted to access
145 * 'isDoesNotExistError' if the file or directory does not exist.
149 getPermissions :: FilePath -> IO Permissions
150 getPermissions name = do
151 withCString name $ \s -> do
152 read <- c_access s r_OK
153 write <- c_access s w_OK
154 exec <- c_access s x_OK
155 withFileStatus "getPermissions" name $ \st -> do
156 is_dir <- isDirectory st
159 readable = read == 0,
160 writable = write == 0,
161 executable = not is_dir && exec == 0,
162 searchable = is_dir && exec == 0
166 {- |The 'setPermissions' operation sets the
167 permissions for the file or directory.
169 The operation may fail with:
171 * 'isPermissionError' if the user is not permitted to set
174 * 'isDoesNotExistError' if the file or directory does not exist.
178 setPermissions :: FilePath -> Permissions -> IO ()
179 setPermissions name (Permissions r w e s) = do
180 allocaBytes sizeof_stat $ \ p_stat -> do
181 withCString name $ \p_name -> do
182 throwErrnoIfMinus1_ "setPermissions" $ do
184 mode <- st_mode p_stat
185 let mode1 = modifyBit r mode s_IRUSR
186 let mode2 = modifyBit w mode1 s_IWUSR
187 let mode3 = modifyBit (e || s) mode2 s_IXUSR
191 modifyBit :: Bool -> CMode -> CMode -> CMode
192 modifyBit False m b = m .&. (complement b)
193 modifyBit True m b = m .|. b
195 -----------------------------------------------------------------------------
198 {- |@'createDirectory' dir@ creates a new directory @dir@ which is
199 initially empty, or as near to empty as the operating system
202 The operation may fail with:
204 * 'isPermissionError' \/ 'PermissionDenied'
205 The process has insufficient privileges to perform the operation.
208 * 'isAlreadyExistsError' \/ 'AlreadyExists'
209 The operand refers to a directory that already exists.
213 A physical I\/O error has occurred.
217 The operand is not a valid directory name.
218 @[ENAMETOOLONG, ELOOP]@
221 There is no path to the directory.
224 * 'ResourceExhausted'
225 Insufficient resources (virtual memory, process file descriptors,
226 physical disk space, etc.) are available to perform the operation.
227 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
229 * 'InappropriateType'
230 The path refers to an existing non-directory object.
235 createDirectory :: FilePath -> IO ()
236 createDirectory path = do
237 withCString path $ \s -> do
238 throwErrnoIfMinus1Retry_ "createDirectory" $
241 {- | @'removeDirectory' dir@ removes an existing directory /dir/. The
242 implementation may specify additional constraints which must be
243 satisfied before a directory can be removed (e.g. the directory has to
244 be empty, or may not be in use by other processes). It is not legal
245 for an implementation to partially remove a directory unless the
246 entire directory is removed. A conformant implementation need not
247 support directory removal in all situations (e.g. removal of the root
250 The operation may fail with:
253 A physical I\/O error has occurred.
257 The operand is not a valid directory name.
258 [ENAMETOOLONG, ELOOP]
260 * 'isDoesNotExistError' \/ 'NoSuchThing'
261 The directory does not exist.
264 * 'isPermissionError' \/ 'PermissionDenied'
265 The process has insufficient privileges to perform the operation.
266 @[EROFS, EACCES, EPERM]@
268 * 'UnsatisfiedConstraints'
269 Implementation-dependent constraints are not satisfied.
270 @[EBUSY, ENOTEMPTY, EEXIST]@
272 * 'UnsupportedOperation'
273 The implementation does not support removal in this situation.
276 * 'InappropriateType'
277 The operand refers to an existing non-directory object.
282 removeDirectory :: FilePath -> IO ()
283 removeDirectory path = do
284 modifyIOError (`ioeSetFileName` path) $
285 withCString path $ \s ->
286 throwErrnoIfMinus1Retry_ "removeDirectory" (c_rmdir s)
288 {- |'removeFile' /file/ removes the directory entry for an existing file
289 /file/, where /file/ is not itself a directory. The
290 implementation may specify additional constraints which must be
291 satisfied before a file can be removed (e.g. the file may not be in
292 use by other processes).
294 The operation may fail with:
297 A physical I\/O error has occurred.
301 The operand is not a valid file name.
302 @[ENAMETOOLONG, ELOOP]@
304 * 'isDoesNotExistError' \/ 'NoSuchThing'
305 The file does not exist.
308 * 'isPermissionError' \/ 'PermissionDenied'
309 The process has insufficient privileges to perform the operation.
310 @[EROFS, EACCES, EPERM]@
312 * 'UnsatisfiedConstraints'
313 Implementation-dependent constraints are not satisfied.
316 * 'InappropriateType'
317 The operand refers to an existing directory.
322 removeFile :: FilePath -> IO ()
324 modifyIOError (`ioeSetFileName` path) $
325 withCString path $ \s ->
326 throwErrnoIfMinus1Retry_ "removeFile" (c_unlink s)
328 {- |@'renameDirectory' old new@ changes the name of an existing
329 directory from /old/ to /new/. If the /new/ directory
330 already exists, it is atomically replaced by the /old/ directory.
331 If the /new/ directory is neither the /old/ directory nor an
332 alias of the /old/ directory, it is removed as if by
333 'removeDirectory'. A conformant implementation need not support
334 renaming directories in all situations (e.g. renaming to an existing
335 directory, or across different physical devices), but the constraints
338 On Win32 platforms, @renameDirectory@ fails if the /new/ directory already
341 The operation may fail with:
344 A physical I\/O error has occurred.
348 Either operand is not a valid directory name.
349 @[ENAMETOOLONG, ELOOP]@
351 * 'isDoesNotExistError' \/ 'NoSuchThing'
352 The original directory does not exist, or there is no path to the target.
355 * 'isPermissionError' \/ 'PermissionDenied'
356 The process has insufficient privileges to perform the operation.
357 @[EROFS, EACCES, EPERM]@
359 * 'ResourceExhausted'
360 Insufficient resources are available to perform the operation.
361 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
363 * 'UnsatisfiedConstraints'
364 Implementation-dependent constraints are not satisfied.
365 @[EBUSY, ENOTEMPTY, EEXIST]@
367 * 'UnsupportedOperation'
368 The implementation does not support renaming in this situation.
371 * 'InappropriateType'
372 Either path refers to an existing non-directory object.
377 renameDirectory :: FilePath -> FilePath -> IO ()
378 renameDirectory opath npath =
379 withFileStatus "renameDirectory" opath $ \st -> do
380 is_dir <- isDirectory st
382 then ioException (IOError Nothing InappropriateType "renameDirectory"
383 ("not a directory") (Just opath))
386 withCString opath $ \s1 ->
387 withCString npath $ \s2 ->
388 throwErrnoIfMinus1Retry_ "renameDirectory" (c_rename s1 s2)
390 {- |@'renameFile' old new@ changes the name of an existing file system
391 object from /old/ to /new/. If the /new/ object already
392 exists, it is atomically replaced by the /old/ object. Neither
393 path may refer to an existing directory. A conformant implementation
394 need not support renaming files in all situations (e.g. renaming
395 across different physical devices), but the constraints must be
398 The operation may fail with:
401 A physical I\/O error has occurred.
405 Either operand is not a valid file name.
406 @[ENAMETOOLONG, ELOOP]@
408 * 'isDoesNotExistError' \/ 'NoSuchThing'
409 The original file does not exist, or there is no path to the target.
412 * 'isPermissionError' \/ 'PermissionDenied'
413 The process has insufficient privileges to perform the operation.
414 @[EROFS, EACCES, EPERM]@
416 * 'ResourceExhausted'
417 Insufficient resources are available to perform the operation.
418 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
420 * 'UnsatisfiedConstraints'
421 Implementation-dependent constraints are not satisfied.
424 * 'UnsupportedOperation'
425 The implementation does not support renaming in this situation.
428 * 'InappropriateType'
429 Either path refers to an existing directory.
430 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
434 renameFile :: FilePath -> FilePath -> IO ()
435 renameFile opath npath =
436 withFileOrSymlinkStatus "renameFile" opath $ \st -> do
437 is_dir <- isDirectory st
439 then ioException (IOError Nothing InappropriateType "renameFile"
440 "is a directory" (Just opath))
443 withCString opath $ \s1 ->
444 withCString npath $ \s2 ->
445 throwErrnoIfMinus1Retry_ "renameFile" (c_rename s1 s2)
447 {- |@'copyFile' old new@ copies the existing file from /old/ to /new/.
448 If the /new/ file already exists, it is atomically replaced by the /old/ file.
449 Neither path may refer to an existing directory.
451 copyFile :: FilePath -> FilePath -> IO ()
452 copyFile fromFPath toFPath =
453 (bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom ->
454 bracket (openBinaryFile toFPath WriteMode) hClose $ \hTo ->
455 allocaBytes bufferSize $ \buffer ->
456 copyContents hFrom hTo buffer) `catch` (ioError . changeFunName)
460 changeFunName (IOError h iot fun str mb_fp) = IOError h iot "copyFile" str mb_fp
462 copyContents hFrom hTo buffer = do
463 count <- hGetBuf hFrom buffer bufferSize
464 when (count > 0) $ do
465 hPutBuf hTo buffer count
466 copyContents hFrom hTo buffer
469 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
472 The operation may fail with:
475 A physical I\/O error has occurred.
479 The operand is not a valid directory name.
480 @[ENAMETOOLONG, ELOOP]@
482 * 'isDoesNotExistError' \/ 'NoSuchThing'
483 The directory does not exist.
486 * 'isPermissionError' \/ 'PermissionDenied'
487 The process has insufficient privileges to perform the operation.
490 * 'ResourceExhausted'
491 Insufficient resources are available to perform the operation.
494 * 'InappropriateType'
495 The path refers to an existing non-directory object.
500 getDirectoryContents :: FilePath -> IO [FilePath]
501 getDirectoryContents path = do
502 modifyIOError (`ioeSetFileName` path) $
503 alloca $ \ ptr_dEnt ->
505 (withCString path $ \s ->
506 throwErrnoIfNullRetry desc (c_opendir s))
507 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
508 (\p -> loop ptr_dEnt p)
510 desc = "getDirectoryContents"
512 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
513 loop ptr_dEnt dir = do
515 r <- readdir dir ptr_dEnt
518 dEnt <- peek ptr_dEnt
522 entry <- (d_name dEnt >>= peekCString)
524 entries <- loop ptr_dEnt dir
525 return (entry:entries)
526 else do errno <- getErrno
527 if (errno == eINTR) then loop ptr_dEnt dir else do
528 let (Errno eo) = errno
529 if (eo == end_of_dir)
535 {- |If the operating system has a notion of current directories,
536 'getCurrentDirectory' returns an absolute path to the
537 current directory of the calling process.
539 The operation may fail with:
542 A physical I\/O error has occurred.
545 * 'isDoesNotExistError' \/ 'NoSuchThing'
546 There is no path referring to the current directory.
547 @[EPERM, ENOENT, ESTALE...]@
549 * 'isPermissionError' \/ 'PermissionDenied'
550 The process has insufficient privileges to perform the operation.
553 * 'ResourceExhausted'
554 Insufficient resources are available to perform the operation.
556 * 'UnsupportedOperation'
557 The operating system has no notion of current directory.
561 getCurrentDirectory :: IO FilePath
562 getCurrentDirectory = do
563 p <- mallocBytes long_path_size
565 where go p bytes = do
566 p' <- c_getcwd p (fromIntegral bytes)
568 then do s <- peekCString p'
571 else do errno <- getErrno
573 then do let bytes' = bytes * 2
574 p' <- reallocBytes p bytes'
576 else throwErrno "getCurrentDirectory"
578 {- |If the operating system has a notion of current directories,
579 @'setCurrentDirectory' dir@ changes the current
580 directory of the calling process to /dir/.
582 The operation may fail with:
585 A physical I\/O error has occurred.
589 The operand is not a valid directory name.
590 @[ENAMETOOLONG, ELOOP]@
592 * 'isDoesNotExistError' \/ 'NoSuchThing'
593 The directory does not exist.
596 * 'isPermissionError' \/ 'PermissionDenied'
597 The process has insufficient privileges to perform the operation.
600 * 'UnsupportedOperation'
601 The operating system has no notion of current directory, or the
602 current directory cannot be dynamically changed.
604 * 'InappropriateType'
605 The path refers to an existing non-directory object.
610 setCurrentDirectory :: FilePath -> IO ()
611 setCurrentDirectory path = do
612 modifyIOError (`ioeSetFileName` path) $
613 withCString path $ \s ->
614 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
615 -- ToDo: add path to error
617 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
618 exists and is a directory, and 'False' otherwise.
621 doesDirectoryExist :: FilePath -> IO Bool
622 doesDirectoryExist name =
624 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
625 (\ _ -> return False)
627 {- |The operation 'doesFileExist' returns 'True'
628 if the argument file exists and is not a directory, and 'False' otherwise.
631 doesFileExist :: FilePath -> IO Bool
632 doesFileExist name = do
634 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
635 (\ _ -> return False)
637 {- |The 'getModificationTime' operation returns the
638 clock time at which the file or directory was last modified.
640 The operation may fail with:
642 * 'isPermissionError' if the user is not permitted to access
643 the modification time; or
645 * 'isDoesNotExistError' if the file or directory does not exist.
649 getModificationTime :: FilePath -> IO ClockTime
650 getModificationTime name =
651 withFileStatus "getModificationTime" name $ \ st ->
654 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
655 withFileStatus loc name f = do
656 modifyIOError (`ioeSetFileName` name) $
657 allocaBytes sizeof_stat $ \p ->
658 withCString (fileNameEndClean name) $ \s -> do
659 throwErrnoIfMinus1Retry_ loc (c_stat s p)
662 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
663 withFileOrSymlinkStatus loc name f = do
664 modifyIOError (`ioeSetFileName` name) $
665 allocaBytes sizeof_stat $ \p ->
666 withCString name $ \s -> do
667 throwErrnoIfMinus1Retry_ loc (lstat s p)
670 modificationTime :: Ptr CStat -> IO ClockTime
671 modificationTime stat = do
672 mtime <- st_mtime stat
673 let realToInteger = round . realToFrac :: Real a => a -> Integer
674 return (TOD (realToInteger (mtime :: CTime)) 0)
676 isDirectory :: Ptr CStat -> IO Bool
677 isDirectory stat = do
679 return (s_isdir mode)
681 fileNameEndClean :: String -> String
682 fileNameEndClean name =
683 if i > 0 && (ec == '\\' || ec == '/') then
684 fileNameEndClean (take i name)
688 i = (length name) - 1
691 foreign import ccall unsafe "__hscore_long_path_size"
692 long_path_size :: Int
694 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CMode
695 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CMode
696 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CMode
698 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
699 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
700 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
702 #endif /* __GLASGOW_HASKELL__ */
704 {- | Returns the current user's home directory.
706 The directory returned is expected to be writable by the current user,
707 but note that it isn't generally considered good practice to store
708 application-specific data here; use 'getAppUserDataDirectory'
711 On Unix, 'getHomeDirectory' returns the value of the @HOME@
712 environment variable. On Windows, the system is queried for a
713 suitable path; a typical path might be
714 @C:/Documents And Settings/user@.
716 The operation may fail with:
718 * 'UnsupportedOperation'
719 The operating system has no notion of home directory.
721 * 'isDoesNotExistError'
722 The home directory for the current user does not exist, or
725 getHomeDirectory :: IO FilePath
727 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
728 allocaBytes long_path_size $ \pPath -> do
729 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
731 then c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
738 {- | Returns the pathname of a directory in which application-specific
739 data for the current user can be stored. The result of
740 'getAppUserDataDirectory' for a given application is specific to
743 The argument should be the name of the application, which will be used
744 to construct the pathname (so avoid using unusual characters that
745 might result in an invalid pathname).
747 Note: the directory may not actually exist, and may need to be created
748 first. It is expected that the parent directory exists and is
751 On Unix, this function returns @$HOME\/.appName@. On Windows, a
752 typical path might be
754 > C:/Documents And Settings/user/Application Data/appName
756 The operation may fail with:
758 * 'UnsupportedOperation'
759 The operating system has no notion of application-specific data directory.
761 * 'isDoesNotExistError'
762 The home directory for the current user does not exist, or
765 getAppUserDataDirectory :: String -> IO FilePath
766 getAppUserDataDirectory appName = do
767 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
768 allocaBytes long_path_size $ \pPath -> do
769 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
770 s <- peekCString pPath
771 return (s++'\\':appName)
773 path <- getEnv "HOME"
774 return (path++'/':'.':appName)
777 {- | Returns the current user's document directory.
779 The directory returned is expected to be writable by the current user,
780 but note that it isn't generally considered good practice to store
781 application-specific data here; use 'getAppUserDataDirectory'
784 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
785 environment variable. On Windows, the system is queried for a
786 suitable path; a typical path might be
787 @C:\/Documents and Settings\/user\/My Documents@.
789 The operation may fail with:
791 * 'UnsupportedOperation'
792 The operating system has no notion of document directory.
794 * 'isDoesNotExistError'
795 The document directory for the current user does not exist, or
798 getUserDocumentsDirectory :: IO FilePath
799 getUserDocumentsDirectory = do
800 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
801 allocaBytes long_path_size $ \pPath -> do
802 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
808 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
809 foreign import stdcall unsafe "SHGetFolderPath"
810 c_SHGetFolderPath :: Ptr ()
816 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
817 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
818 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
819 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt