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 fileName = binary `joinFileExt` drop 1 exeExt
528 search :: [FilePath] -> IO (Maybe FilePath)
529 search [] = return Nothing
531 let path = d `joinFileName` fileName
532 b <- doesFileExist path
533 if b then return (Just path)
536 -- ToDo: This should be determined via autoconf (AC_EXEEXT)
538 #ifdef mingw32_TARGET_OS
544 #ifdef __GLASGOW_HASKELL__
545 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
548 The operation may fail with:
551 A physical I\/O error has occurred.
555 The operand is not a valid directory name.
556 @[ENAMETOOLONG, ELOOP]@
558 * 'isDoesNotExistError' \/ 'NoSuchThing'
559 The directory does not exist.
562 * 'isPermissionError' \/ 'PermissionDenied'
563 The process has insufficient privileges to perform the operation.
566 * 'ResourceExhausted'
567 Insufficient resources are available to perform the operation.
570 * 'InappropriateType'
571 The path refers to an existing non-directory object.
576 getDirectoryContents :: FilePath -> IO [FilePath]
577 getDirectoryContents path = do
578 modifyIOError (`ioeSetFileName` path) $
579 alloca $ \ ptr_dEnt ->
581 (withCString path $ \s ->
582 throwErrnoIfNullRetry desc (c_opendir s))
583 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
584 (\p -> loop ptr_dEnt p)
586 desc = "getDirectoryContents"
588 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
589 loop ptr_dEnt dir = do
591 r <- readdir dir ptr_dEnt
594 dEnt <- peek ptr_dEnt
598 entry <- (d_name dEnt >>= peekCString)
600 entries <- loop ptr_dEnt dir
601 return (entry:entries)
602 else do errno <- getErrno
603 if (errno == eINTR) then loop ptr_dEnt dir else do
604 let (Errno eo) = errno
605 if (eo == end_of_dir)
611 {- |If the operating system has a notion of current directories,
612 'getCurrentDirectory' returns an absolute path to the
613 current directory of the calling process.
615 The operation may fail with:
618 A physical I\/O error has occurred.
621 * 'isDoesNotExistError' \/ 'NoSuchThing'
622 There is no path referring to the current directory.
623 @[EPERM, ENOENT, ESTALE...]@
625 * 'isPermissionError' \/ 'PermissionDenied'
626 The process has insufficient privileges to perform the operation.
629 * 'ResourceExhausted'
630 Insufficient resources are available to perform the operation.
632 * 'UnsupportedOperation'
633 The operating system has no notion of current directory.
637 getCurrentDirectory :: IO FilePath
638 getCurrentDirectory = do
639 p <- mallocBytes long_path_size
641 where go p bytes = do
642 p' <- c_getcwd p (fromIntegral bytes)
644 then do s <- peekCString p'
647 else do errno <- getErrno
649 then do let bytes' = bytes * 2
650 p' <- reallocBytes p bytes'
652 else throwErrno "getCurrentDirectory"
654 {- |If the operating system has a notion of current directories,
655 @'setCurrentDirectory' dir@ changes the current
656 directory of the calling process to /dir/.
658 The operation may fail with:
661 A physical I\/O error has occurred.
665 The operand is not a valid directory name.
666 @[ENAMETOOLONG, ELOOP]@
668 * 'isDoesNotExistError' \/ 'NoSuchThing'
669 The directory does not exist.
672 * 'isPermissionError' \/ 'PermissionDenied'
673 The process has insufficient privileges to perform the operation.
676 * 'UnsupportedOperation'
677 The operating system has no notion of current directory, or the
678 current directory cannot be dynamically changed.
680 * 'InappropriateType'
681 The path refers to an existing non-directory object.
686 setCurrentDirectory :: FilePath -> IO ()
687 setCurrentDirectory path = do
688 modifyIOError (`ioeSetFileName` path) $
689 withCString path $ \s ->
690 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
691 -- ToDo: add path to error
693 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
694 exists and is a directory, and 'False' otherwise.
697 doesDirectoryExist :: FilePath -> IO Bool
698 doesDirectoryExist name =
700 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
701 (\ _ -> return False)
703 {- |The operation 'doesFileExist' returns 'True'
704 if the argument file exists and is not a directory, and 'False' otherwise.
707 doesFileExist :: FilePath -> IO Bool
708 doesFileExist name = do
710 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
711 (\ _ -> return False)
713 {- |The 'getModificationTime' operation returns the
714 clock time at which the file or directory was last modified.
716 The operation may fail with:
718 * 'isPermissionError' if the user is not permitted to access
719 the modification time; or
721 * 'isDoesNotExistError' if the file or directory does not exist.
725 getModificationTime :: FilePath -> IO ClockTime
726 getModificationTime name =
727 withFileStatus "getModificationTime" name $ \ st ->
730 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
731 withFileStatus loc name f = do
732 modifyIOError (`ioeSetFileName` name) $
733 allocaBytes sizeof_stat $ \p ->
734 withCString (fileNameEndClean name) $ \s -> do
735 throwErrnoIfMinus1Retry_ loc (c_stat s p)
738 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
739 withFileOrSymlinkStatus loc name f = do
740 modifyIOError (`ioeSetFileName` name) $
741 allocaBytes sizeof_stat $ \p ->
742 withCString name $ \s -> do
743 throwErrnoIfMinus1Retry_ loc (lstat s p)
746 modificationTime :: Ptr CStat -> IO ClockTime
747 modificationTime stat = do
748 mtime <- st_mtime stat
749 let realToInteger = round . realToFrac :: Real a => a -> Integer
750 return (TOD (realToInteger (mtime :: CTime)) 0)
752 isDirectory :: Ptr CStat -> IO Bool
753 isDirectory stat = do
755 return (s_isdir mode)
757 fileNameEndClean :: String -> String
758 fileNameEndClean name =
759 if i > 0 && (ec == '\\' || ec == '/') then
760 fileNameEndClean (take i name)
764 i = (length name) - 1
767 foreign import ccall unsafe "__hscore_long_path_size"
768 long_path_size :: Int
770 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CMode
771 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CMode
772 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CMode
774 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
775 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
776 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
778 #endif /* __GLASGOW_HASKELL__ */
780 {- | Returns the current user's home directory.
782 The directory returned is expected to be writable by the current user,
783 but note that it isn't generally considered good practice to store
784 application-specific data here; use 'getAppUserDataDirectory'
787 On Unix, 'getHomeDirectory' returns the value of the @HOME@
788 environment variable. On Windows, the system is queried for a
789 suitable path; a typical path might be
790 @C:/Documents And Settings/user@.
792 The operation may fail with:
794 * 'UnsupportedOperation'
795 The operating system has no notion of home directory.
797 * 'isDoesNotExistError'
798 The home directory for the current user does not exist, or
801 getHomeDirectory :: IO FilePath
803 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
804 allocaBytes long_path_size $ \pPath -> do
805 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
807 then c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
814 {- | Returns the pathname of a directory in which application-specific
815 data for the current user can be stored. The result of
816 'getAppUserDataDirectory' for a given application is specific to
819 The argument should be the name of the application, which will be used
820 to construct the pathname (so avoid using unusual characters that
821 might result in an invalid pathname).
823 Note: the directory may not actually exist, and may need to be created
824 first. It is expected that the parent directory exists and is
827 On Unix, this function returns @$HOME\/.appName@. On Windows, a
828 typical path might be
830 > C:/Documents And Settings/user/Application Data/appName
832 The operation may fail with:
834 * 'UnsupportedOperation'
835 The operating system has no notion of application-specific data directory.
837 * 'isDoesNotExistError'
838 The home directory for the current user does not exist, or
841 getAppUserDataDirectory :: String -> IO FilePath
842 getAppUserDataDirectory appName = do
843 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
844 allocaBytes long_path_size $ \pPath -> do
845 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
846 s <- peekCString pPath
847 return (s++'\\':appName)
849 path <- getEnv "HOME"
850 return (path++'/':'.':appName)
853 {- | Returns the current user's document directory.
855 The directory returned is expected to be writable by the current user,
856 but note that it isn't generally considered good practice to store
857 application-specific data here; use 'getAppUserDataDirectory'
860 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
861 environment variable. On Windows, the system is queried for a
862 suitable path; a typical path might be
863 @C:\/Documents and Settings\/user\/My Documents@.
865 The operation may fail with:
867 * 'UnsupportedOperation'
868 The operating system has no notion of document directory.
870 * 'isDoesNotExistError'
871 The document directory for the current user does not exist, or
874 getUserDocumentsDirectory :: IO FilePath
875 getUserDocumentsDirectory = do
876 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
877 allocaBytes long_path_size $ \pPath -> do
878 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
884 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
885 foreign import stdcall unsafe "SHGetFolderPath"
886 c_SHGetFolderPath :: Ptr ()
892 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
893 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
894 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
895 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt