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 , copyFile -- :: FilePath -> FilePath -> IO ()
42 , doesFileExist -- :: FilePath -> IO Bool
43 , doesDirectoryExist -- :: FilePath -> IO Bool
51 readable, -- :: Permissions -> Bool
52 writable, -- :: Permissions -> Bool
53 executable, -- :: Permissions -> Bool
54 searchable -- :: Permissions -> Bool
57 , getPermissions -- :: FilePath -> IO Permissions
58 , setPermissions -- :: FilePath -> Permissions -> IO ()
62 , getModificationTime -- :: FilePath -> IO ClockTime
65 import System.Environment ( getEnv )
66 import System.FilePath
67 import System.IO.Error
78 #ifdef __GLASGOW_HASKELL__
81 import Control.Exception ( bracket )
82 import Control.Monad ( when )
83 import System.Posix.Types
84 import System.Posix.Internals
85 import System.Time ( ClockTime(..) )
90 import GHC.IOBase ( IOException(..), IOErrorType(..), ioException )
93 A directory contains a series of entries, each of which is a named
94 reference to a file system object (file, directory etc.). Some
95 entries may be hidden, inaccessible, or have some administrative
96 function (e.g. `.' or `..' under POSIX
97 <http://www.opengroup.org/onlinepubs/007904975/toc.htm>), but in
98 this standard all such entries are considered to form part of the
99 directory contents. Entries in sub-directories are not, however,
100 considered to form part of the directory contents.
102 Each file system object is referenced by a /path/. There is
103 normally at least one absolute path to each file system object. In
104 some operating systems, it may also be possible to have paths which
105 are relative to the current directory.
108 -----------------------------------------------------------------------------
113 The 'Permissions' type is used to record whether certain operations are
114 permissible on a file\/directory. 'getPermissions' and 'setPermissions'
115 get and set these permissions, respectively. Permissions apply both to
116 files and directories. For directories, the executable field will be
117 'False', and for files the searchable field will be 'False'. Note that
118 directories may be searchable without being readable, if permission has
119 been given to use them as part of a path, but not to examine the
122 Note that to change some, but not all permissions, a construct on the following lines must be used.
124 > makeReadable f = do
125 > p <- getPermissions f
126 > setPermissions f (p {readable = True})
133 executable, searchable :: Bool
134 } deriving (Eq, Ord, Read, Show)
136 {- |The 'getPermissions' operation returns the
137 permissions for the file or directory.
139 The operation may fail with:
141 * 'isPermissionError' if the user is not permitted to access
144 * 'isDoesNotExistError' if the file or directory does not exist.
148 getPermissions :: FilePath -> IO Permissions
149 getPermissions name = do
150 withCString name $ \s -> do
151 read <- c_access s r_OK
152 write <- c_access s w_OK
153 exec <- c_access s x_OK
154 withFileStatus "getPermissions" name $ \st -> do
155 is_dir <- isDirectory st
158 readable = read == 0,
159 writable = write == 0,
160 executable = not is_dir && exec == 0,
161 searchable = is_dir && exec == 0
165 {- |The 'setPermissions' operation sets the
166 permissions for the file or directory.
168 The operation may fail with:
170 * 'isPermissionError' if the user is not permitted to set
173 * 'isDoesNotExistError' if the file or directory does not exist.
177 setPermissions :: FilePath -> Permissions -> IO ()
178 setPermissions name (Permissions r w e s) = do
179 allocaBytes sizeof_stat $ \ p_stat -> do
180 withCString name $ \p_name -> do
181 throwErrnoIfMinus1_ "setPermissions" $ do
183 mode <- st_mode p_stat
184 let mode1 = modifyBit r mode s_IRUSR
185 let mode2 = modifyBit w mode1 s_IWUSR
186 let mode3 = modifyBit (e || s) mode2 s_IXUSR
190 modifyBit :: Bool -> CMode -> CMode -> CMode
191 modifyBit False m b = m .&. (complement b)
192 modifyBit True m b = m .|. b
194 -----------------------------------------------------------------------------
197 {- |@'createDirectory' dir@ creates a new directory @dir@ which is
198 initially empty, or as near to empty as the operating system
201 The operation may fail with:
203 * 'isPermissionError' \/ 'PermissionDenied'
204 The process has insufficient privileges to perform the operation.
207 * 'isAlreadyExistsError' \/ 'AlreadyExists'
208 The operand refers to a directory that already exists.
212 A physical I\/O error has occurred.
216 The operand is not a valid directory name.
217 @[ENAMETOOLONG, ELOOP]@
220 There is no path to the directory.
223 * 'ResourceExhausted'
224 Insufficient resources (virtual memory, process file descriptors,
225 physical disk space, etc.) are available to perform the operation.
226 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
228 * 'InappropriateType'
229 The path refers to an existing non-directory object.
234 createDirectory :: FilePath -> IO ()
235 createDirectory path = do
236 withCString path $ \s -> do
237 throwErrnoIfMinus1Retry_ "createDirectory" $
240 {- | @'removeDirectory' dir@ removes an existing directory /dir/. The
241 implementation may specify additional constraints which must be
242 satisfied before a directory can be removed (e.g. the directory has to
243 be empty, or may not be in use by other processes). It is not legal
244 for an implementation to partially remove a directory unless the
245 entire directory is removed. A conformant implementation need not
246 support directory removal in all situations (e.g. removal of the root
249 The operation may fail with:
252 A physical I\/O error has occurred.
256 The operand is not a valid directory name.
257 [ENAMETOOLONG, ELOOP]
259 * 'isDoesNotExistError' \/ 'NoSuchThing'
260 The directory does not exist.
263 * 'isPermissionError' \/ 'PermissionDenied'
264 The process has insufficient privileges to perform the operation.
265 @[EROFS, EACCES, EPERM]@
267 * 'UnsatisfiedConstraints'
268 Implementation-dependent constraints are not satisfied.
269 @[EBUSY, ENOTEMPTY, EEXIST]@
271 * 'UnsupportedOperation'
272 The implementation does not support removal in this situation.
275 * 'InappropriateType'
276 The operand refers to an existing non-directory object.
281 removeDirectory :: FilePath -> IO ()
282 removeDirectory path = do
283 modifyIOError (`ioeSetFileName` path) $
284 withCString path $ \s ->
285 throwErrnoIfMinus1Retry_ "removeDirectory" (c_rmdir s)
287 {- |'removeFile' /file/ removes the directory entry for an existing file
288 /file/, where /file/ is not itself a directory. The
289 implementation may specify additional constraints which must be
290 satisfied before a file can be removed (e.g. the file may not be in
291 use by other processes).
293 The operation may fail with:
296 A physical I\/O error has occurred.
300 The operand is not a valid file name.
301 @[ENAMETOOLONG, ELOOP]@
303 * 'isDoesNotExistError' \/ 'NoSuchThing'
304 The file does not exist.
307 * 'isPermissionError' \/ 'PermissionDenied'
308 The process has insufficient privileges to perform the operation.
309 @[EROFS, EACCES, EPERM]@
311 * 'UnsatisfiedConstraints'
312 Implementation-dependent constraints are not satisfied.
315 * 'InappropriateType'
316 The operand refers to an existing directory.
321 removeFile :: FilePath -> IO ()
323 modifyIOError (`ioeSetFileName` path) $
324 withCString path $ \s ->
325 throwErrnoIfMinus1Retry_ "removeFile" (c_unlink s)
327 {- |@'renameDirectory' old new@ changes the name of an existing
328 directory from /old/ to /new/. If the /new/ directory
329 already exists, it is atomically replaced by the /old/ directory.
330 If the /new/ directory is neither the /old/ directory nor an
331 alias of the /old/ directory, it is removed as if by
332 'removeDirectory'. A conformant implementation need not support
333 renaming directories in all situations (e.g. renaming to an existing
334 directory, or across different physical devices), but the constraints
337 On Win32 platforms, @renameDirectory@ fails if the /new/ directory already
340 The operation may fail with:
343 A physical I\/O error has occurred.
347 Either operand is not a valid directory name.
348 @[ENAMETOOLONG, ELOOP]@
350 * 'isDoesNotExistError' \/ 'NoSuchThing'
351 The original directory does not exist, or there is no path to the target.
354 * 'isPermissionError' \/ 'PermissionDenied'
355 The process has insufficient privileges to perform the operation.
356 @[EROFS, EACCES, EPERM]@
358 * 'ResourceExhausted'
359 Insufficient resources are available to perform the operation.
360 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
362 * 'UnsatisfiedConstraints'
363 Implementation-dependent constraints are not satisfied.
364 @[EBUSY, ENOTEMPTY, EEXIST]@
366 * 'UnsupportedOperation'
367 The implementation does not support renaming in this situation.
370 * 'InappropriateType'
371 Either path refers to an existing non-directory object.
376 renameDirectory :: FilePath -> FilePath -> IO ()
377 renameDirectory opath npath =
378 withFileStatus "renameDirectory" opath $ \st -> do
379 is_dir <- isDirectory st
381 then ioException (IOError Nothing InappropriateType "renameDirectory"
382 ("not a directory") (Just opath))
385 withCString opath $ \s1 ->
386 withCString npath $ \s2 ->
387 throwErrnoIfMinus1Retry_ "renameDirectory" (c_rename s1 s2)
389 {- |@'renameFile' old new@ changes the name of an existing file system
390 object from /old/ to /new/. If the /new/ object already
391 exists, it is atomically replaced by the /old/ object. Neither
392 path may refer to an existing directory. A conformant implementation
393 need not support renaming files in all situations (e.g. renaming
394 across different physical devices), but the constraints must be
397 The operation may fail with:
400 A physical I\/O error has occurred.
404 Either operand is not a valid file name.
405 @[ENAMETOOLONG, ELOOP]@
407 * 'isDoesNotExistError' \/ 'NoSuchThing'
408 The original file 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.
423 * 'UnsupportedOperation'
424 The implementation does not support renaming in this situation.
427 * 'InappropriateType'
428 Either path refers to an existing directory.
429 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
433 renameFile :: FilePath -> FilePath -> IO ()
434 renameFile opath npath =
435 withFileOrSymlinkStatus "renameFile" opath $ \st -> do
436 is_dir <- isDirectory st
438 then ioException (IOError Nothing InappropriateType "renameFile"
439 "is a directory" (Just opath))
442 withCString opath $ \s1 ->
443 withCString npath $ \s2 ->
444 throwErrnoIfMinus1Retry_ "renameFile" (c_rename s1 s2)
446 #endif /* __GLASGOW_HASKELL__ */
448 {- |@'copyFile' old new@ copies the existing file from /old/ to /new/.
449 If the /new/ file already exists, it is atomically replaced by the /old/ file.
450 Neither path may refer to an existing directory.
452 copyFile :: FilePath -> FilePath -> IO ()
453 copyFile fromFPath toFPath =
454 #if (!(defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ > 600))
455 do readFile fromFPath >>= writeFile toFPath
456 try (getPermissions fromFPath >>= setPermissions toFPath)
459 (bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom ->
460 bracket (openBinaryFile toFPath WriteMode) hClose $ \hTo ->
461 allocaBytes bufferSize $ \buffer -> do
462 copyContents hFrom hTo buffer
463 try (getPermissions fromFPath >>= setPermissions toFPath)
464 return ()) `catch` (ioError . changeFunName)
468 changeFunName (IOError h iot fun str mb_fp) = IOError h iot "copyFile" str mb_fp
470 copyContents hFrom hTo buffer = do
471 count <- hGetBuf hFrom buffer bufferSize
472 when (count > 0) $ do
473 hPutBuf hTo buffer count
474 copyContents hFrom hTo buffer
477 #ifdef __GLASGOW_HASKELL__
478 -- | Given path referring to a file or directory, returns a
479 -- canonicalized path, with the intent that two paths referring
480 -- to the same file\/directory will map to the same canonicalized
481 -- path. Note that it is impossible to guarantee that the
482 -- implication (same file\/dir <=> same canonicalizedPath) holds
483 -- in either direction: this function can make only a best-effort
485 canonicalizePath :: FilePath -> IO FilePath
486 canonicalizePath fpath =
487 withCString fpath $ \pInPath ->
488 allocaBytes long_path_size $ \pOutPath ->
489 #if defined(mingw32_TARGET_OS)
490 alloca $ \ppFilePart ->
491 do c_GetFullPathName pInPath (fromIntegral long_path_size) pOutPath ppFilePart
493 do c_realpath pInPath pOutPath
497 #if defined(mingw32_TARGET_OS)
498 foreign import stdcall unsafe "GetFullPathName"
499 c_GetFullPathName :: CString
505 foreign import ccall unsafe "realpath"
506 c_realpath :: CString
510 #else /* !__GLASGOW_HASKELL__ */
511 -- dummy implementation
512 canonicalizePath :: FilePath -> IO FilePath
513 canonicalizePath fpath = return fpath
514 #endif /* !__GLASGOW_HASKELL__ */
516 -- | Given an executable file name, searches for such file
517 -- in the directories listed in system PATH. The returned value
518 -- is the path to the found executable or Nothing if there isn't
519 -- such executable. For example (findExecutable \"ghc\")
520 -- gives you the path to GHC.
521 findExecutable :: String -> IO (Maybe FilePath)
522 findExecutable binary = do
523 path <- getEnv "PATH"
524 search (parseSearchPath path)
526 #ifdef mingw32_TARGET_OS
527 fileName = binary `joinFileExt` "exe"
532 search :: [FilePath] -> IO (Maybe FilePath)
533 search [] = return Nothing
535 let path = d `joinFileName` fileName
536 b <- doesFileExist path
537 if b then return (Just path)
540 #ifdef __GLASGOW_HASKELL__
541 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
544 The operation may fail with:
547 A physical I\/O error has occurred.
551 The operand is not a valid directory name.
552 @[ENAMETOOLONG, ELOOP]@
554 * 'isDoesNotExistError' \/ 'NoSuchThing'
555 The directory does not exist.
558 * 'isPermissionError' \/ 'PermissionDenied'
559 The process has insufficient privileges to perform the operation.
562 * 'ResourceExhausted'
563 Insufficient resources are available to perform the operation.
566 * 'InappropriateType'
567 The path refers to an existing non-directory object.
572 getDirectoryContents :: FilePath -> IO [FilePath]
573 getDirectoryContents path = do
574 modifyIOError (`ioeSetFileName` path) $
575 alloca $ \ ptr_dEnt ->
577 (withCString path $ \s ->
578 throwErrnoIfNullRetry desc (c_opendir s))
579 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
580 (\p -> loop ptr_dEnt p)
582 desc = "getDirectoryContents"
584 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
585 loop ptr_dEnt dir = do
587 r <- readdir dir ptr_dEnt
590 dEnt <- peek ptr_dEnt
594 entry <- (d_name dEnt >>= peekCString)
596 entries <- loop ptr_dEnt dir
597 return (entry:entries)
598 else do errno <- getErrno
599 if (errno == eINTR) then loop ptr_dEnt dir else do
600 let (Errno eo) = errno
601 if (eo == end_of_dir)
607 {- |If the operating system has a notion of current directories,
608 'getCurrentDirectory' returns an absolute path to the
609 current directory of the calling process.
611 The operation may fail with:
614 A physical I\/O error has occurred.
617 * 'isDoesNotExistError' \/ 'NoSuchThing'
618 There is no path referring to the current directory.
619 @[EPERM, ENOENT, ESTALE...]@
621 * 'isPermissionError' \/ 'PermissionDenied'
622 The process has insufficient privileges to perform the operation.
625 * 'ResourceExhausted'
626 Insufficient resources are available to perform the operation.
628 * 'UnsupportedOperation'
629 The operating system has no notion of current directory.
633 getCurrentDirectory :: IO FilePath
634 getCurrentDirectory = do
635 p <- mallocBytes long_path_size
637 where go p bytes = do
638 p' <- c_getcwd p (fromIntegral bytes)
640 then do s <- peekCString p'
643 else do errno <- getErrno
645 then do let bytes' = bytes * 2
646 p' <- reallocBytes p bytes'
648 else throwErrno "getCurrentDirectory"
650 {- |If the operating system has a notion of current directories,
651 @'setCurrentDirectory' dir@ changes the current
652 directory of the calling process to /dir/.
654 The operation may fail with:
657 A physical I\/O error has occurred.
661 The operand is not a valid directory name.
662 @[ENAMETOOLONG, ELOOP]@
664 * 'isDoesNotExistError' \/ 'NoSuchThing'
665 The directory does not exist.
668 * 'isPermissionError' \/ 'PermissionDenied'
669 The process has insufficient privileges to perform the operation.
672 * 'UnsupportedOperation'
673 The operating system has no notion of current directory, or the
674 current directory cannot be dynamically changed.
676 * 'InappropriateType'
677 The path refers to an existing non-directory object.
682 setCurrentDirectory :: FilePath -> IO ()
683 setCurrentDirectory path = do
684 modifyIOError (`ioeSetFileName` path) $
685 withCString path $ \s ->
686 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
687 -- ToDo: add path to error
689 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
690 exists and is a directory, and 'False' otherwise.
693 doesDirectoryExist :: FilePath -> IO Bool
694 doesDirectoryExist name =
696 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
697 (\ _ -> return False)
699 {- |The operation 'doesFileExist' returns 'True'
700 if the argument file exists and is not a directory, and 'False' otherwise.
703 doesFileExist :: FilePath -> IO Bool
704 doesFileExist name = do
706 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
707 (\ _ -> return False)
709 {- |The 'getModificationTime' operation returns the
710 clock time at which the file or directory was last modified.
712 The operation may fail with:
714 * 'isPermissionError' if the user is not permitted to access
715 the modification time; or
717 * 'isDoesNotExistError' if the file or directory does not exist.
721 getModificationTime :: FilePath -> IO ClockTime
722 getModificationTime name =
723 withFileStatus "getModificationTime" name $ \ st ->
726 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
727 withFileStatus loc name f = do
728 modifyIOError (`ioeSetFileName` name) $
729 allocaBytes sizeof_stat $ \p ->
730 withCString (fileNameEndClean name) $ \s -> do
731 throwErrnoIfMinus1Retry_ loc (c_stat s p)
734 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
735 withFileOrSymlinkStatus loc name f = do
736 modifyIOError (`ioeSetFileName` name) $
737 allocaBytes sizeof_stat $ \p ->
738 withCString name $ \s -> do
739 throwErrnoIfMinus1Retry_ loc (lstat s p)
742 modificationTime :: Ptr CStat -> IO ClockTime
743 modificationTime stat = do
744 mtime <- st_mtime stat
745 let realToInteger = round . realToFrac :: Real a => a -> Integer
746 return (TOD (realToInteger (mtime :: CTime)) 0)
748 isDirectory :: Ptr CStat -> IO Bool
749 isDirectory stat = do
751 return (s_isdir mode)
753 fileNameEndClean :: String -> String
754 fileNameEndClean name =
755 if i > 0 && (ec == '\\' || ec == '/') then
756 fileNameEndClean (take i name)
760 i = (length name) - 1
763 foreign import ccall unsafe "__hscore_long_path_size"
764 long_path_size :: Int
766 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CMode
767 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CMode
768 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CMode
770 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
771 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
772 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
774 #endif /* __GLASGOW_HASKELL__ */
776 {- | Returns the current user's home directory.
778 The directory returned is expected to be writable by the current user,
779 but note that it isn't generally considered good practice to store
780 application-specific data here; use 'getAppUserDataDirectory'
783 On Unix, 'getHomeDirectory' returns the value of the @HOME@
784 environment variable. On Windows, the system is queried for a
785 suitable path; a typical path might be
786 @C:/Documents And Settings/user@.
788 The operation may fail with:
790 * 'UnsupportedOperation'
791 The operating system has no notion of home directory.
793 * 'isDoesNotExistError'
794 The home directory for the current user does not exist, or
797 getHomeDirectory :: IO FilePath
799 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
800 allocaBytes long_path_size $ \pPath -> do
801 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
803 then c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
810 {- | Returns the pathname of a directory in which application-specific
811 data for the current user can be stored. The result of
812 'getAppUserDataDirectory' for a given application is specific to
815 The argument should be the name of the application, which will be used
816 to construct the pathname (so avoid using unusual characters that
817 might result in an invalid pathname).
819 Note: the directory may not actually exist, and may need to be created
820 first. It is expected that the parent directory exists and is
823 On Unix, this function returns @$HOME\/.appName@. On Windows, a
824 typical path might be
826 > C:/Documents And Settings/user/Application Data/appName
828 The operation may fail with:
830 * 'UnsupportedOperation'
831 The operating system has no notion of application-specific data directory.
833 * 'isDoesNotExistError'
834 The home directory for the current user does not exist, or
837 getAppUserDataDirectory :: String -> IO FilePath
838 getAppUserDataDirectory appName = do
839 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
840 allocaBytes long_path_size $ \pPath -> do
841 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
842 s <- peekCString pPath
843 return (s++'\\':appName)
845 path <- getEnv "HOME"
846 return (path++'/':'.':appName)
849 {- | Returns the current user's document directory.
851 The directory returned is expected to be writable by the current user,
852 but note that it isn't generally considered good practice to store
853 application-specific data here; use 'getAppUserDataDirectory'
856 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
857 environment variable. On Windows, the system is queried for a
858 suitable path; a typical path might be
859 @C:\/Documents and Settings\/user\/My Documents@.
861 The operation may fail with:
863 * 'UnsupportedOperation'
864 The operating system has no notion of document directory.
866 * 'isDoesNotExistError'
867 The document directory for the current user does not exist, or
870 getUserDocumentsDirectory :: IO FilePath
871 getUserDocumentsDirectory = do
872 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
873 allocaBytes long_path_size $ \pPath -> do
874 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
880 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
881 foreign import stdcall unsafe "SHGetFolderPath"
882 c_SHGetFolderPath :: Ptr ()
888 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
889 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
890 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
891 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt