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
73 #ifdef __GLASGOW_HASKELL__
76 import Control.Exception ( bracket )
77 import Control.Monad ( when )
78 import System.Posix.Types
79 import System.Posix.Internals
80 import System.Time ( ClockTime(..) )
82 import System.IO.Error
83 import System.FilePath
84 import System.Environment (getEnv)
88 import GHC.IOBase ( IOException(..), IOErrorType(..), ioException )
91 A directory contains a series of entries, each of which is a named
92 reference to a file system object (file, directory etc.). Some
93 entries may be hidden, inaccessible, or have some administrative
94 function (e.g. `.' or `..' under POSIX
95 <http://www.opengroup.org/onlinepubs/007904975/toc.htm>), but in
96 this standard all such entries are considered to form part of the
97 directory contents. Entries in sub-directories are not, however,
98 considered to form part of the directory contents.
100 Each file system object is referenced by a /path/. There is
101 normally at least one absolute path to each file system object. In
102 some operating systems, it may also be possible to have paths which
103 are relative to the current directory.
106 -----------------------------------------------------------------------------
111 The 'Permissions' type is used to record whether certain operations are
112 permissible on a file\/directory. 'getPermissions' and 'setPermissions'
113 get and set these permissions, respectively. Permissions apply both to
114 files and directories. For directories, the executable field will be
115 'False', and for files the searchable field will be 'False'. Note that
116 directories may be searchable without being readable, if permission has
117 been given to use them as part of a path, but not to examine the
120 Note that to change some, but not all permissions, a construct on the following lines must be used.
122 > makeReadable f = do
123 > p <- getPermissions f
124 > setPermissions f (p {readable = True})
131 executable, searchable :: Bool
132 } deriving (Eq, Ord, Read, Show)
134 {- |The 'getPermissions' operation returns the
135 permissions for the file or directory.
137 The operation may fail with:
139 * 'isPermissionError' if the user is not permitted to access
142 * 'isDoesNotExistError' if the file or directory does not exist.
146 getPermissions :: FilePath -> IO Permissions
147 getPermissions name = do
148 withCString name $ \s -> do
149 read <- c_access s r_OK
150 write <- c_access s w_OK
151 exec <- c_access s x_OK
152 withFileStatus "getPermissions" name $ \st -> do
153 is_dir <- isDirectory st
156 readable = read == 0,
157 writable = write == 0,
158 executable = not is_dir && exec == 0,
159 searchable = is_dir && exec == 0
163 {- |The 'setPermissions' operation sets the
164 permissions for the file or directory.
166 The operation may fail with:
168 * 'isPermissionError' if the user is not permitted to set
171 * 'isDoesNotExistError' if the file or directory does not exist.
175 setPermissions :: FilePath -> Permissions -> IO ()
176 setPermissions name (Permissions r w e s) = do
177 allocaBytes sizeof_stat $ \ p_stat -> do
178 withCString name $ \p_name -> do
179 throwErrnoIfMinus1_ "setPermissions" $ do
181 mode <- st_mode p_stat
182 let mode1 = modifyBit r mode s_IRUSR
183 let mode2 = modifyBit w mode1 s_IWUSR
184 let mode3 = modifyBit (e || s) mode2 s_IXUSR
188 modifyBit :: Bool -> CMode -> CMode -> CMode
189 modifyBit False m b = m .&. (complement b)
190 modifyBit True m b = m .|. b
192 -----------------------------------------------------------------------------
195 {- |@'createDirectory' dir@ creates a new directory @dir@ which is
196 initially empty, or as near to empty as the operating system
199 The operation may fail with:
201 * 'isPermissionError' \/ 'PermissionDenied'
202 The process has insufficient privileges to perform the operation.
205 * 'isAlreadyExistsError' \/ 'AlreadyExists'
206 The operand refers to a directory that already exists.
210 A physical I\/O error has occurred.
214 The operand is not a valid directory name.
215 @[ENAMETOOLONG, ELOOP]@
218 There is no path to the directory.
221 * 'ResourceExhausted'
222 Insufficient resources (virtual memory, process file descriptors,
223 physical disk space, etc.) are available to perform the operation.
224 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
226 * 'InappropriateType'
227 The path refers to an existing non-directory object.
232 createDirectory :: FilePath -> IO ()
233 createDirectory path = do
234 withCString path $ \s -> do
235 throwErrnoIfMinus1Retry_ "createDirectory" $
238 {- | @'removeDirectory' dir@ removes an existing directory /dir/. The
239 implementation may specify additional constraints which must be
240 satisfied before a directory can be removed (e.g. the directory has to
241 be empty, or may not be in use by other processes). It is not legal
242 for an implementation to partially remove a directory unless the
243 entire directory is removed. A conformant implementation need not
244 support directory removal in all situations (e.g. removal of the root
247 The operation may fail with:
250 A physical I\/O error has occurred.
254 The operand is not a valid directory name.
255 [ENAMETOOLONG, ELOOP]
257 * 'isDoesNotExistError' \/ 'NoSuchThing'
258 The directory does not exist.
261 * 'isPermissionError' \/ 'PermissionDenied'
262 The process has insufficient privileges to perform the operation.
263 @[EROFS, EACCES, EPERM]@
265 * 'UnsatisfiedConstraints'
266 Implementation-dependent constraints are not satisfied.
267 @[EBUSY, ENOTEMPTY, EEXIST]@
269 * 'UnsupportedOperation'
270 The implementation does not support removal in this situation.
273 * 'InappropriateType'
274 The operand refers to an existing non-directory object.
279 removeDirectory :: FilePath -> IO ()
280 removeDirectory path = do
281 modifyIOError (`ioeSetFileName` path) $
282 withCString path $ \s ->
283 throwErrnoIfMinus1Retry_ "removeDirectory" (c_rmdir s)
285 {- |'removeFile' /file/ removes the directory entry for an existing file
286 /file/, where /file/ is not itself a directory. The
287 implementation may specify additional constraints which must be
288 satisfied before a file can be removed (e.g. the file may not be in
289 use by other processes).
291 The operation may fail with:
294 A physical I\/O error has occurred.
298 The operand is not a valid file name.
299 @[ENAMETOOLONG, ELOOP]@
301 * 'isDoesNotExistError' \/ 'NoSuchThing'
302 The file does not exist.
305 * 'isPermissionError' \/ 'PermissionDenied'
306 The process has insufficient privileges to perform the operation.
307 @[EROFS, EACCES, EPERM]@
309 * 'UnsatisfiedConstraints'
310 Implementation-dependent constraints are not satisfied.
313 * 'InappropriateType'
314 The operand refers to an existing directory.
319 removeFile :: FilePath -> IO ()
321 modifyIOError (`ioeSetFileName` path) $
322 withCString path $ \s ->
323 throwErrnoIfMinus1Retry_ "removeFile" (c_unlink s)
325 {- |@'renameDirectory' old new@ changes the name of an existing
326 directory from /old/ to /new/. If the /new/ directory
327 already exists, it is atomically replaced by the /old/ directory.
328 If the /new/ directory is neither the /old/ directory nor an
329 alias of the /old/ directory, it is removed as if by
330 'removeDirectory'. A conformant implementation need not support
331 renaming directories in all situations (e.g. renaming to an existing
332 directory, or across different physical devices), but the constraints
335 On Win32 platforms, @renameDirectory@ fails if the /new/ directory already
338 The operation may fail with:
341 A physical I\/O error has occurred.
345 Either operand is not a valid directory name.
346 @[ENAMETOOLONG, ELOOP]@
348 * 'isDoesNotExistError' \/ 'NoSuchThing'
349 The original directory does not exist, or there is no path to the target.
352 * 'isPermissionError' \/ 'PermissionDenied'
353 The process has insufficient privileges to perform the operation.
354 @[EROFS, EACCES, EPERM]@
356 * 'ResourceExhausted'
357 Insufficient resources are available to perform the operation.
358 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
360 * 'UnsatisfiedConstraints'
361 Implementation-dependent constraints are not satisfied.
362 @[EBUSY, ENOTEMPTY, EEXIST]@
364 * 'UnsupportedOperation'
365 The implementation does not support renaming in this situation.
368 * 'InappropriateType'
369 Either path refers to an existing non-directory object.
374 renameDirectory :: FilePath -> FilePath -> IO ()
375 renameDirectory opath npath =
376 withFileStatus "renameDirectory" opath $ \st -> do
377 is_dir <- isDirectory st
379 then ioException (IOError Nothing InappropriateType "renameDirectory"
380 ("not a directory") (Just opath))
383 withCString opath $ \s1 ->
384 withCString npath $ \s2 ->
385 throwErrnoIfMinus1Retry_ "renameDirectory" (c_rename s1 s2)
387 {- |@'renameFile' old new@ changes the name of an existing file system
388 object from /old/ to /new/. If the /new/ object already
389 exists, it is atomically replaced by the /old/ object. Neither
390 path may refer to an existing directory. A conformant implementation
391 need not support renaming files in all situations (e.g. renaming
392 across different physical devices), but the constraints must be
395 The operation may fail with:
398 A physical I\/O error has occurred.
402 Either operand is not a valid file name.
403 @[ENAMETOOLONG, ELOOP]@
405 * 'isDoesNotExistError' \/ 'NoSuchThing'
406 The original file does not exist, or there is no path to the target.
409 * 'isPermissionError' \/ 'PermissionDenied'
410 The process has insufficient privileges to perform the operation.
411 @[EROFS, EACCES, EPERM]@
413 * 'ResourceExhausted'
414 Insufficient resources are available to perform the operation.
415 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
417 * 'UnsatisfiedConstraints'
418 Implementation-dependent constraints are not satisfied.
421 * 'UnsupportedOperation'
422 The implementation does not support renaming in this situation.
425 * 'InappropriateType'
426 Either path refers to an existing directory.
427 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
431 renameFile :: FilePath -> FilePath -> IO ()
432 renameFile opath npath =
433 withFileOrSymlinkStatus "renameFile" opath $ \st -> do
434 is_dir <- isDirectory st
436 then ioException (IOError Nothing InappropriateType "renameFile"
437 "is a directory" (Just opath))
440 withCString opath $ \s1 ->
441 withCString npath $ \s2 ->
442 throwErrnoIfMinus1Retry_ "renameFile" (c_rename s1 s2)
444 {- |@'copyFile' old new@ copies the existing file from /old/ to /new/.
445 If the /new/ file already exists, it is atomically replaced by the /old/ file.
446 Neither path may refer to an existing directory.
448 copyFile :: FilePath -> FilePath -> IO ()
449 copyFile fromFPath toFPath =
450 #if (!(defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ > 600))
451 do readFile fromFPath >>= writeFile toFPath
452 try (getPermissions fromFPath >>= setPermissions toFPath)
455 (bracket (openBinaryFile fromFPath ReadMode) hClose $ \hFrom ->
456 bracket (openBinaryFile toFPath WriteMode) hClose $ \hTo ->
457 allocaBytes bufferSize $ \buffer -> do
458 copyContents hFrom hTo buffer
459 try (getPermissions fromFPath >>= setPermissions toFPath)
460 return ()) `catch` (ioError . changeFunName)
464 changeFunName (IOError h iot fun str mb_fp) = IOError h iot "copyFile" str mb_fp
466 copyContents hFrom hTo buffer = do
467 count <- hGetBuf hFrom buffer bufferSize
468 when (count > 0) $ do
469 hPutBuf hTo buffer count
470 copyContents hFrom hTo buffer
473 -- | Given path referring to a file or directory, returns a
474 -- canonicalized path, with the intent that two paths referring
475 -- to the same file\/directory will map to the same canonicalized
476 -- path. Note that it is impossible to guarantee that the
477 -- implication (same file\/dir <=> same canonicalizedPath) holds
478 -- in either direction: this function can make only a best-effort
480 canonicalizePath :: FilePath -> IO FilePath
481 canonicalizePath fpath =
482 withCString fpath $ \pInPath ->
483 allocaBytes long_path_size $ \pOutPath ->
484 #if defined(mingw32_TARGET_OS)
485 alloca $ \ppFilePart ->
486 do c_GetFullPathName pInPath (fromIntegral long_path_size) pOutPath ppFilePart
488 do c_realpath pInPath pOutPath
492 #if defined(mingw32_TARGET_OS)
493 foreign import stdcall unsafe "GetFullPathName"
494 c_GetFullPathName :: CString
500 foreign import ccall unsafe "realpath"
501 c_realpath :: CString
506 -- | Given an executable file name, searches for such file
507 -- in the directories listed in system PATH. The returned value
508 -- is the path to the found executable or Nothing if there isn't
509 -- such executable. For example (findExecutable \"ghc\")
510 -- gives you the path to GHC.
511 findExecutable :: String -> IO (Maybe FilePath)
512 findExecutable binary = do
513 path <- getEnv "PATH"
514 search (parseSearchPath path)
516 #ifdef mingw32_TARGET_OS
517 fileName = binary `joinFileExt` "exe"
522 search :: [FilePath] -> IO (Maybe FilePath)
523 search [] = return Nothing
525 let path = d `joinFileName` fileName
526 b <- doesFileExist path
527 if b then return (Just path)
531 {- |@'getDirectoryContents' dir@ returns a list of /all/ entries
534 The operation may fail with:
537 A physical I\/O error has occurred.
541 The operand is not a valid directory name.
542 @[ENAMETOOLONG, ELOOP]@
544 * 'isDoesNotExistError' \/ 'NoSuchThing'
545 The directory does not exist.
548 * 'isPermissionError' \/ 'PermissionDenied'
549 The process has insufficient privileges to perform the operation.
552 * 'ResourceExhausted'
553 Insufficient resources are available to perform the operation.
556 * 'InappropriateType'
557 The path refers to an existing non-directory object.
562 getDirectoryContents :: FilePath -> IO [FilePath]
563 getDirectoryContents path = do
564 modifyIOError (`ioeSetFileName` path) $
565 alloca $ \ ptr_dEnt ->
567 (withCString path $ \s ->
568 throwErrnoIfNullRetry desc (c_opendir s))
569 (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
570 (\p -> loop ptr_dEnt p)
572 desc = "getDirectoryContents"
574 loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [String]
575 loop ptr_dEnt dir = do
577 r <- readdir dir ptr_dEnt
580 dEnt <- peek ptr_dEnt
584 entry <- (d_name dEnt >>= peekCString)
586 entries <- loop ptr_dEnt dir
587 return (entry:entries)
588 else do errno <- getErrno
589 if (errno == eINTR) then loop ptr_dEnt dir else do
590 let (Errno eo) = errno
591 if (eo == end_of_dir)
597 {- |If the operating system has a notion of current directories,
598 'getCurrentDirectory' returns an absolute path to the
599 current directory of the calling process.
601 The operation may fail with:
604 A physical I\/O error has occurred.
607 * 'isDoesNotExistError' \/ 'NoSuchThing'
608 There is no path referring to the current directory.
609 @[EPERM, ENOENT, ESTALE...]@
611 * 'isPermissionError' \/ 'PermissionDenied'
612 The process has insufficient privileges to perform the operation.
615 * 'ResourceExhausted'
616 Insufficient resources are available to perform the operation.
618 * 'UnsupportedOperation'
619 The operating system has no notion of current directory.
623 getCurrentDirectory :: IO FilePath
624 getCurrentDirectory = do
625 p <- mallocBytes long_path_size
627 where go p bytes = do
628 p' <- c_getcwd p (fromIntegral bytes)
630 then do s <- peekCString p'
633 else do errno <- getErrno
635 then do let bytes' = bytes * 2
636 p' <- reallocBytes p bytes'
638 else throwErrno "getCurrentDirectory"
640 {- |If the operating system has a notion of current directories,
641 @'setCurrentDirectory' dir@ changes the current
642 directory of the calling process to /dir/.
644 The operation may fail with:
647 A physical I\/O error has occurred.
651 The operand is not a valid directory name.
652 @[ENAMETOOLONG, ELOOP]@
654 * 'isDoesNotExistError' \/ 'NoSuchThing'
655 The directory does not exist.
658 * 'isPermissionError' \/ 'PermissionDenied'
659 The process has insufficient privileges to perform the operation.
662 * 'UnsupportedOperation'
663 The operating system has no notion of current directory, or the
664 current directory cannot be dynamically changed.
666 * 'InappropriateType'
667 The path refers to an existing non-directory object.
672 setCurrentDirectory :: FilePath -> IO ()
673 setCurrentDirectory path = do
674 modifyIOError (`ioeSetFileName` path) $
675 withCString path $ \s ->
676 throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
677 -- ToDo: add path to error
679 {- |The operation 'doesDirectoryExist' returns 'True' if the argument file
680 exists and is a directory, and 'False' otherwise.
683 doesDirectoryExist :: FilePath -> IO Bool
684 doesDirectoryExist name =
686 (withFileStatus "doesDirectoryExist" name $ \st -> isDirectory st)
687 (\ _ -> return False)
689 {- |The operation 'doesFileExist' returns 'True'
690 if the argument file exists and is not a directory, and 'False' otherwise.
693 doesFileExist :: FilePath -> IO Bool
694 doesFileExist name = do
696 (withFileStatus "doesFileExist" name $ \st -> do b <- isDirectory st; return (not b))
697 (\ _ -> return False)
699 {- |The 'getModificationTime' operation returns the
700 clock time at which the file or directory was last modified.
702 The operation may fail with:
704 * 'isPermissionError' if the user is not permitted to access
705 the modification time; or
707 * 'isDoesNotExistError' if the file or directory does not exist.
711 getModificationTime :: FilePath -> IO ClockTime
712 getModificationTime name =
713 withFileStatus "getModificationTime" name $ \ st ->
716 withFileStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
717 withFileStatus loc name f = do
718 modifyIOError (`ioeSetFileName` name) $
719 allocaBytes sizeof_stat $ \p ->
720 withCString (fileNameEndClean name) $ \s -> do
721 throwErrnoIfMinus1Retry_ loc (c_stat s p)
724 withFileOrSymlinkStatus :: String -> FilePath -> (Ptr CStat -> IO a) -> IO a
725 withFileOrSymlinkStatus loc name f = do
726 modifyIOError (`ioeSetFileName` name) $
727 allocaBytes sizeof_stat $ \p ->
728 withCString name $ \s -> do
729 throwErrnoIfMinus1Retry_ loc (lstat s p)
732 modificationTime :: Ptr CStat -> IO ClockTime
733 modificationTime stat = do
734 mtime <- st_mtime stat
735 let realToInteger = round . realToFrac :: Real a => a -> Integer
736 return (TOD (realToInteger (mtime :: CTime)) 0)
738 isDirectory :: Ptr CStat -> IO Bool
739 isDirectory stat = do
741 return (s_isdir mode)
743 fileNameEndClean :: String -> String
744 fileNameEndClean name =
745 if i > 0 && (ec == '\\' || ec == '/') then
746 fileNameEndClean (take i name)
750 i = (length name) - 1
753 foreign import ccall unsafe "__hscore_long_path_size"
754 long_path_size :: Int
756 foreign import ccall unsafe "__hscore_R_OK" r_OK :: CMode
757 foreign import ccall unsafe "__hscore_W_OK" w_OK :: CMode
758 foreign import ccall unsafe "__hscore_X_OK" x_OK :: CMode
760 foreign import ccall unsafe "__hscore_S_IRUSR" s_IRUSR :: CMode
761 foreign import ccall unsafe "__hscore_S_IWUSR" s_IWUSR :: CMode
762 foreign import ccall unsafe "__hscore_S_IXUSR" s_IXUSR :: CMode
764 #endif /* __GLASGOW_HASKELL__ */
766 {- | Returns the current user's home directory.
768 The directory returned is expected to be writable by the current user,
769 but note that it isn't generally considered good practice to store
770 application-specific data here; use 'getAppUserDataDirectory'
773 On Unix, 'getHomeDirectory' returns the value of the @HOME@
774 environment variable. On Windows, the system is queried for a
775 suitable path; a typical path might be
776 @C:/Documents And Settings/user@.
778 The operation may fail with:
780 * 'UnsupportedOperation'
781 The operating system has no notion of home directory.
783 * 'isDoesNotExistError'
784 The home directory for the current user does not exist, or
787 getHomeDirectory :: IO FilePath
789 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
790 allocaBytes long_path_size $ \pPath -> do
791 r <- c_SHGetFolderPath nullPtr csidl_PROFILE nullPtr 0 pPath
793 then c_SHGetFolderPath nullPtr csidl_WINDOWS nullPtr 0 pPath
800 {- | Returns the pathname of a directory in which application-specific
801 data for the current user can be stored. The result of
802 'getAppUserDataDirectory' for a given application is specific to
805 The argument should be the name of the application, which will be used
806 to construct the pathname (so avoid using unusual characters that
807 might result in an invalid pathname).
809 Note: the directory may not actually exist, and may need to be created
810 first. It is expected that the parent directory exists and is
813 On Unix, this function returns @$HOME\/.appName@. On Windows, a
814 typical path might be
816 > C:/Documents And Settings/user/Application Data/appName
818 The operation may fail with:
820 * 'UnsupportedOperation'
821 The operating system has no notion of application-specific data directory.
823 * 'isDoesNotExistError'
824 The home directory for the current user does not exist, or
827 getAppUserDataDirectory :: String -> IO FilePath
828 getAppUserDataDirectory appName = do
829 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
830 allocaBytes long_path_size $ \pPath -> do
831 r <- c_SHGetFolderPath nullPtr csidl_APPDATA nullPtr 0 pPath
832 s <- peekCString pPath
833 return (s++'\\':appName)
835 path <- getEnv "HOME"
836 return (path++'/':'.':appName)
839 {- | Returns the current user's document directory.
841 The directory returned is expected to be writable by the current user,
842 but note that it isn't generally considered good practice to store
843 application-specific data here; use 'getAppUserDataDirectory'
846 On Unix, 'getUserDocumentsDirectory' returns the value of the @HOME@
847 environment variable. On Windows, the system is queried for a
848 suitable path; a typical path might be
849 @C:\/Documents and Settings\/user\/My Documents@.
851 The operation may fail with:
853 * 'UnsupportedOperation'
854 The operating system has no notion of document directory.
856 * 'isDoesNotExistError'
857 The document directory for the current user does not exist, or
860 getUserDocumentsDirectory :: IO FilePath
861 getUserDocumentsDirectory = do
862 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
863 allocaBytes long_path_size $ \pPath -> do
864 r <- c_SHGetFolderPath nullPtr csidl_PERSONAL nullPtr 0 pPath
870 #if __GLASGOW_HASKELL__ && defined(mingw32_TARGET_OS)
871 foreign import stdcall unsafe "SHGetFolderPath"
872 c_SHGetFolderPath :: Ptr ()
878 foreign import ccall unsafe "__hscore_CSIDL_PROFILE" csidl_PROFILE :: CInt
879 foreign import ccall unsafe "__hscore_CSIDL_APPDATA" csidl_APPDATA :: CInt
880 foreign import ccall unsafe "__hscore_CSIDL_WINDOWS" csidl_WINDOWS :: CInt
881 foreign import ccall unsafe "__hscore_CSIDL_PERSONAL" csidl_PERSONAL :: CInt