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 exeExtension
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 #ifdef __GLASGOW_HASKELL__
537 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
540 The operation may fail with:
543 A physical I\/O error has occurred.
547 The operand is not a valid directory name.
548 @[ENAMETOOLONG, ELOOP]@
550 * 'isDoesNotExistError' \/ 'NoSuchThing'
551 The directory does not exist.
554 * 'isPermissionError' \/ 'PermissionDenied'
555 The process has insufficient privileges to perform the operation.
558 * 'ResourceExhausted'
559 Insufficient resources are available to perform the operation.
562 * 'InappropriateType'
563 The path refers to an existing non-directory object.
568 getDirectoryContents :: FilePath -> IO [FilePath]
569 getDirectoryContents path = do
570 modifyIOError (`ioeSetFileName` path) $
571 alloca $ \ ptr_dEnt ->
573 (withCString path $ \s ->
574 throwErrnoIfNullRetry desc (c_opendir s))
575 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
576 (\p -> loop ptr_dEnt p)
578 desc = "getDirectoryContents"
580 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
581 loop ptr_dEnt dir = do
583 r <- readdir dir ptr_dEnt
586 dEnt <- peek ptr_dEnt
590 entry <- (d_name dEnt >>= peekCString)
592 entries <- loop ptr_dEnt dir
593 return (entry:entries)
594 else do errno <- getErrno
595 if (errno == eINTR) then loop ptr_dEnt dir else do
596 let (Errno eo) = errno
597 if (eo == end_of_dir)
603 {- |If the operating system has a notion of current directories,
604 'getCurrentDirectory' returns an absolute path to the
605 current directory of the calling process.
607 The operation may fail with:
610 A physical I\/O error has occurred.
613 * 'isDoesNotExistError' \/ 'NoSuchThing'
614 There is no path referring to the current directory.
615 @[EPERM, ENOENT, ESTALE...]@
617 * 'isPermissionError' \/ 'PermissionDenied'
618 The process has insufficient privileges to perform the operation.
621 * 'ResourceExhausted'
622 Insufficient resources are available to perform the operation.
624 * 'UnsupportedOperation'
625 The operating system has no notion of current directory.
629 getCurrentDirectory :: IO FilePath
630 getCurrentDirectory = do
631 p <- mallocBytes long_path_size
633 where go p bytes = do
634 p' <- c_getcwd p (fromIntegral bytes)
636 then do s <- peekCString p'
639 else do errno <- getErrno
641 then do let bytes' = bytes * 2
642 p' <- reallocBytes p bytes'
644 else throwErrno "getCurrentDirectory"
646 {- |If the operating system has a notion of current directories,
647 @'setCurrentDirectory' dir@ changes the current
648 directory of the calling process to /dir/.
650 The operation may fail with:
653 A physical I\/O error has occurred.
657 The operand is not a valid directory name.
658 @[ENAMETOOLONG, ELOOP]@
660 * 'isDoesNotExistError' \/ 'NoSuchThing'
661 The directory does not exist.
664 * 'isPermissionError' \/ 'PermissionDenied'
665 The process has insufficient privileges to perform the operation.
668 * 'UnsupportedOperation'
669 The operating system has no notion of current directory, or the
670 current directory cannot be dynamically changed.
672 * 'InappropriateType'
673 The path refers to an existing non-directory object.
678 setCurrentDirectory :: FilePath -> IO ()
679 setCurrentDirectory path = do
680 modifyIOError (`ioeSetFileName` path) $
681 withCString path $ \s ->
682 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
683 -- ToDo: add path to error
685 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
686 exists and is a directory, and 'False' otherwise.
689 doesDirectoryExist :: FilePath -> IO Bool
690 doesDirectoryExist name =
692 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
693 (\ _ -> return False)
695 {- |The operation 'doesFileExist' returns 'True'
696 if the argument file exists and is not a directory, and 'False' otherwise.
699 doesFileExist :: FilePath -> IO Bool
700 doesFileExist name = do
702 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
703 (\ _ -> return False)
705 {- |The 'getModificationTime' operation returns the
706 clock time at which the file or directory was last modified.
708 The operation may fail with:
710 * 'isPermissionError' if the user is not permitted to access
711 the modification time; or
713 * 'isDoesNotExistError' if the file or directory does not exist.
717 getModificationTime :: FilePath -> IO ClockTime
718 getModificationTime name =
719 withFileStatus "getModificationTime" name $ \ st ->
722 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
723 withFileStatus loc name f = do
724 modifyIOError (`ioeSetFileName` name) $
725 allocaBytes sizeof_stat $ \p ->
726 withCString (fileNameEndClean name) $ \s -> do
727 throwErrnoIfMinus1Retry_ loc (c_stat s p)
730 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
731 withFileOrSymlinkStatus loc name f = do
732 modifyIOError (`ioeSetFileName` name) $
733 allocaBytes sizeof_stat $ \p ->
734 withCString name $ \s -> do
735 throwErrnoIfMinus1Retry_ loc (lstat s p)
738 modificationTime :: Ptr CStat -> IO ClockTime
739 modificationTime stat = do
740 mtime <- st_mtime stat
741 let realToInteger = round . realToFrac :: Real a => a -> Integer
742 return (TOD (realToInteger (mtime :: CTime)) 0)
744 isDirectory :: Ptr CStat -> IO Bool
745 isDirectory stat = do
747 return (s_isdir mode)
749 fileNameEndClean :: String -> String
750 fileNameEndClean name =
751 if i > 0 && (ec == '\\' || ec == '/') then
752 fileNameEndClean (take i name)
756 i = (length name) - 1
759 foreign import ccall unsafe "__hscore_long_path_size"
760 long_path_size :: Int
762 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CMode
763 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CMode
764 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CMode
766 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
767 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
768 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
770 #endif /* __GLASGOW_HASKELL__ */
772 {- | Returns the current user's home directory.
774 The directory returned is expected to be writable by the current user,
775 but note that it isn't generally considered good practice to store
776 application-specific data here; use 'getAppUserDataDirectory'
779 On Unix, 'getHomeDirectory' returns the value of the @HOME@
780 environment variable. On Windows, the system is queried for a
781 suitable path; a typical path might be
782 @C:/Documents And Settings/user@.
784 The operation may fail with:
786 * 'UnsupportedOperation'
787 The operating system has no notion of home directory.
789 * 'isDoesNotExistError'
790 The home directory for the current user does not exist, or
793 getHomeDirectory :: IO FilePath
795 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
796 allocaBytes long_path_size $ \pPath -> do
797 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
799 then c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
806 {- | Returns the pathname of a directory in which application-specific
807 data for the current user can be stored. The result of
808 'getAppUserDataDirectory' for a given application is specific to
811 The argument should be the name of the application, which will be used
812 to construct the pathname (so avoid using unusual characters that
813 might result in an invalid pathname).
815 Note: the directory may not actually exist, and may need to be created
816 first. It is expected that the parent directory exists and is
819 On Unix, this function returns @$HOME\/.appName@. On Windows, a
820 typical path might be
822 > C:/Documents And Settings/user/Application Data/appName
824 The operation may fail with:
826 * 'UnsupportedOperation'
827 The operating system has no notion of application-specific data directory.
829 * 'isDoesNotExistError'
830 The home directory for the current user does not exist, or
833 getAppUserDataDirectory :: String -> IO FilePath
834 getAppUserDataDirectory appName = do
835 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
836 allocaBytes long_path_size $ \pPath -> do
837 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
838 s <- peekCString pPath
839 return (s++'\\':appName)
841 path <- getEnv "HOME"
842 return (path++'/':'.':appName)
845 {- | Returns the current user's document directory.
847 The directory returned is expected to be writable by the current user,
848 but note that it isn't generally considered good practice to store
849 application-specific data here; use 'getAppUserDataDirectory'
852 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
853 environment variable. On Windows, the system is queried for a
854 suitable path; a typical path might be
855 @C:\/Documents and Settings\/user\/My Documents@.
857 The operation may fail with:
859 * 'UnsupportedOperation'
860 The operating system has no notion of document directory.
862 * 'isDoesNotExistError'
863 The document directory for the current user does not exist, or
866 getUserDocumentsDirectory :: IO FilePath
867 getUserDocumentsDirectory = do
868 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
869 allocaBytes long_path_size $ \pPath -> do
870 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
876 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
877 foreign import stdcall unsafe "SHGetFolderPath"
878 c_SHGetFolderPath :: Ptr ()
884 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
885 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
886 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
887 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt