2 % (c) The GRASP/AQUA Project, Glasgow University, 1995
4 \section[LibPosixFiles]{Haskell 1.3 POSIX File and Directory Operations}
18 changeWorkingDirectory, -- Too much like LibDirectory thing?
20 createDirectory, -- Too much like LibDirectory thing?
34 getWorkingDirectory, -- Too much like LibDirectory thing?
61 removeDirectory, -- Too much like LibDirectory thing
86 import LibDirectory ( removeDirectory, -- re-use its code
91 type DirStream = _Addr
93 openDirStream :: FilePath -> IO DirStream
95 _packBytesForCST name `thenStrictlyST` \ dir ->
96 _ccall_ opendir dir `thenPrimIO` \ dirp ->
97 if dirp /= ``NULL'' then
100 syserr "openDirStream"
102 readDirStream :: DirStream -> IO String
104 setErrorCode noError >>
105 _ccall_ readdir dirp `thenPrimIO` \ dirent ->
106 if dirent /= (``NULL''::_Addr) then
107 _casm_ ``%r = ((struct dirent *)%0)->d_name;'' dirent
108 `thenPrimIO` \ str ->
109 strcpy str `thenPrimIO` \ name ->
112 getErrorCode >>= \ errno ->
113 if errno == noError then
116 syserr "readDirStream"
118 rewindDirStream :: DirStream -> IO ()
119 rewindDirStream dirp =
120 _ccall_ rewinddir dirp `thenPrimIO` \ () ->
123 closeDirStream :: DirStream -> IO ()
124 closeDirStream dirp =
125 _ccall_ closedir dirp `thenPrimIO` \ rc ->
129 syserr "closeDirStream"
131 getWorkingDirectory :: IO FilePath
132 getWorkingDirectory = getCurrentDirectory{-LibDirectory-}
134 _ccall_ getCurrentDirectory `thenPrimIO` \ str ->
135 if str /= ``NULL'' then
136 strcpy str `thenPrimIO` \ pwd ->
137 _ccall_ free str `thenPrimIO` \ () ->
140 syserr "getWorkingDirectory"
143 changeWorkingDirectory :: FilePath -> IO ()
144 changeWorkingDirectory name = setCurrentDirectory{-LibDirectory-} name
146 _packBytesForCST name `thenStrictlyST` \ dir ->
147 _ccall_ chdir dir `thenPrimIO` \ rc ->
151 syserr "changeWorkingDirectory"
154 type FileMode = _Word
156 nullFileMode :: FileMode
159 ownerReadMode :: FileMode
160 ownerReadMode = ``S_IRUSR''
162 ownerWriteMode :: FileMode
163 ownerWriteMode = ``S_IWUSR''
165 ownerExecuteMode :: FileMode
166 ownerExecuteMode = ``S_IXUSR''
168 groupReadMode :: FileMode
169 groupReadMode = ``S_IRGRP''
171 groupWriteMode :: FileMode
172 groupWriteMode = ``S_IWGRP''
174 groupExecuteMode :: FileMode
175 groupExecuteMode = ``S_IXGRP''
177 otherReadMode :: FileMode
178 otherReadMode = ``S_IROTH''
180 otherWriteMode :: FileMode
181 otherWriteMode = ``S_IWOTH''
183 otherExecuteMode :: FileMode
184 otherExecuteMode = ``S_IXOTH''
186 setUserIDMode :: FileMode
187 setUserIDMode = ``S_ISUID''
189 setGroupIDMode :: FileMode
190 setGroupIDMode = ``S_ISGID''
192 stdFileMode :: FileMode
193 stdFileMode = ``(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)''
195 ownerModes :: FileMode
196 ownerModes = ``S_IRWXU''
198 groupModes :: FileMode
199 groupModes = ``S_IRWXG''
201 otherModes :: FileMode
202 otherModes = ``S_IRWXO''
204 accessModes :: FileMode
205 accessModes = ``(S_IRWXU|S_IRWXG|S_IRWXO)''
207 unionFileModes :: FileMode -> FileMode -> FileMode
208 unionFileModes (W# m1#) (W# m2#) = W# (m1# `or#` m2#)
210 intersectFileModes :: FileMode -> FileMode -> FileMode
211 intersectFileModes (W# m1#) (W# m2#) = W# (m1# `and#` m2#)
222 data OpenMode = ReadOnly
226 openChannel :: FilePath
228 -> Maybe FileMode -- Just x => O_CREAT, Nothing => must exist
232 -> Bool -- O_NONBLOCK
235 openChannel name how maybe_mode append excl noctty nonblock trunc =
236 _packBytesForCST name `thenStrictlyST` \ file ->
237 _ccall_ open file flags mode `thenPrimIO` \ fd ->
243 mode, creat :: FileMode
244 mode = case maybe_mode of { Nothing -> ``0'' ; Just x -> x }
246 creat = case maybe_mode of { Nothing -> ``0'' ; Just _ -> ``O_CREAT'' }
247 creat# = case creat of { W# x -> x }
249 flags = W# (creat# `or#` append# `or#` excl# `or#`
250 noctty# `or#` nonblock# `or#` trunc# `or#` how#)
251 how# = case (case how of { ReadOnly -> ``O_RDONLY'';WriteOnly -> ``O_WRONLY'';ReadWrite -> ``O_RDWR''}) of { W# x -> x }
252 append# = case (if append then ``O_APPEND'' else ``0'') of { W# x -> x }
253 excl# = case (if excl then ``O_EXCL'' else ``0'') of { W# x -> x }
254 noctty# = case (if noctty then ``O_NOCTTY'' else ``0'') of { W# x -> x }
255 nonblock# = case (if nonblock then ``O_NONBLOCK'' else ``0'') of { W# x -> x }
256 trunc# = case (if trunc then ``O_TRUNC'' else ``0'') of { W# x -> x }
258 createFile :: FilePath -> FileMode -> IO Channel
259 createFile name mode =
260 _packBytesForCST name `thenStrictlyST` \ file ->
261 _ccall_ creat file mode `thenPrimIO` \ fd ->
267 setFileCreationMask :: FileMode -> IO FileMode
268 setFileCreationMask mask =
269 _ccall_ umask mask `thenPrimIO` \ omask ->
272 createLink :: FilePath -> FilePath -> IO ()
273 createLink name1 name2 =
274 _packBytesForCST name1 `thenStrictlyST` \ path1 ->
275 _packBytesForCST name2 `thenStrictlyST` \ path2 ->
276 _ccall_ link path1 path2 `thenPrimIO` \ rc ->
282 createDirectory :: FilePath -> FileMode -> IO ()
283 createDirectory name mode = -- NB: diff signature from LibDirectory one!
284 _packBytesForCST name `thenStrictlyST` \ dir ->
285 _ccall_ mkdir dir mode `thenPrimIO` \ rc ->
289 syserr "createDirectory"
291 createNamedPipe :: FilePath -> FileMode -> IO ()
292 createNamedPipe name mode =
293 _packBytesForCST name `thenStrictlyST` \ pipe ->
294 _ccall_ mkfifo pipe mode `thenPrimIO` \ rc ->
298 syserr "createNamedPipe"
300 removeLink :: FilePath -> IO ()
302 _packBytesForCST name `thenStrictlyST` \ path ->
303 _ccall_ unlink path `thenPrimIO` \ rc ->
309 {- USE LibDirectory ONE:
310 removeDirectory :: FilePath -> IO ()
311 removeDirectory name =
312 _packBytesForCST name `thenStrictlyST` \ dir ->
313 _ccall_ rmdir dir `thenPrimIO` \ rc ->
317 syserr "removeDirectory"
320 rename :: FilePath -> FilePath -> IO ()
322 _packBytesForCST name1 `thenStrictlyST` \ path1 ->
323 _packBytesForCST name2 `thenStrictlyST` \ path2 ->
324 _ccall_ rename path1 path2 `thenPrimIO` \ rc ->
330 type FileStatus = _ByteArray ()
334 fileMode :: FileStatus -> FileMode
335 fileMode stat = unsafePerformPrimIO (
336 _casm_ ``%r = ((struct stat *)%0)->st_mode;'' stat
337 `thenStrictlyST` \ mode ->
340 fileID :: FileStatus -> FileID
341 fileID stat = unsafePerformPrimIO (
342 _casm_ ``%r = ((struct stat *)%0)->st_ino;'' stat
343 `thenStrictlyST` \ ino ->
346 deviceID :: FileStatus -> DeviceID
347 deviceID stat = unsafePerformPrimIO (
348 _casm_ ``%r = ((struct stat *)%0)->st_dev;'' stat
349 `thenStrictlyST` \ dev ->
352 linkCount :: FileStatus -> LinkCount
353 linkCount stat = unsafePerformPrimIO (
354 _casm_ ``%r = ((struct stat *)%0)->st_nlink;'' stat
355 `thenStrictlyST` \ nlink ->
358 fileOwner :: FileStatus -> UserID
359 fileOwner stat = unsafePerformPrimIO (
360 _casm_ ``%r = ((struct stat *)%0)->st_uid;'' stat
361 `thenStrictlyST` \ uid ->
364 fileGroup :: FileStatus -> GroupID
365 fileGroup stat = unsafePerformPrimIO (
366 _casm_ ``%r = ((struct stat *)%0)->st_gid;'' stat
367 `thenStrictlyST` \ gid ->
370 fileSize :: FileStatus -> FileOffset
371 fileSize stat = unsafePerformPrimIO (
372 _casm_ ``%r = ((struct stat *)%0)->st_size;'' stat
373 `thenStrictlyST` \ size ->
376 accessTime :: FileStatus -> EpochTime
377 accessTime stat = unsafePerformPrimIO (
378 _casm_ ``%r = ((struct stat *)%0)->st_atime;'' stat
379 `thenStrictlyST` \ atime ->
382 modificationTime :: FileStatus -> EpochTime
383 modificationTime stat = unsafePerformPrimIO (
384 _casm_ ``%r = ((struct stat *)%0)->st_mtime;'' stat
385 `thenStrictlyST` \ mtime ->
388 statusChangeTime :: FileStatus -> EpochTime
389 statusChangeTime stat = unsafePerformPrimIO (
390 _casm_ ``%r = ((struct stat *)%0)->st_ctime;'' stat
391 `thenStrictlyST` \ ctime ->
394 isDirectory :: FileStatus -> Bool
395 isDirectory stat = unsafePerformPrimIO (
396 _casm_ ``%r = S_ISDIR(((struct stat *)%0)->st_mode);'' stat
397 `thenStrictlyST` \ rc ->
398 returnPrimIO (rc /= 0))
400 isCharacterDevice :: FileStatus -> Bool
401 isCharacterDevice stat = unsafePerformPrimIO (
402 _casm_ ``%r = S_ISCHR(((struct stat *)%0)->st_mode);'' stat
403 `thenStrictlyST` \ rc ->
404 returnPrimIO (rc /= 0))
406 isBlockDevice :: FileStatus -> Bool
407 isBlockDevice stat = unsafePerformPrimIO (
408 _casm_ ``%r = S_ISBLK(((struct stat *)%0)->st_mode);'' stat
409 `thenStrictlyST` \ rc ->
410 returnPrimIO (rc /= 0))
412 isRegularFile :: FileStatus -> Bool
413 isRegularFile stat = unsafePerformPrimIO (
414 _casm_ ``%r = S_ISREG(((struct stat *)%0)->st_mode);'' stat
415 `thenStrictlyST` \ rc ->
416 returnPrimIO (rc /= 0))
418 isNamedPipe :: FileStatus -> Bool
419 isNamedPipe stat = unsafePerformPrimIO (
420 _casm_ ``%r = S_ISFIFO(((struct stat *)%0)->st_mode);'' stat
421 `thenStrictlyST` \ rc ->
422 returnPrimIO (rc /= 0))
424 getFileStatus :: FilePath -> IO FileStatus
426 _packBytesForCST name `thenStrictlyST` \ path ->
427 allocChars ``sizeof(struct stat)'' `thenStrictlyST` \ bytes ->
428 _casm_ ``%r = stat(%0,(struct stat *)%1);'' path bytes
431 freeze bytes `thenStrictlyST` \ stat ->
434 syserr "getFileStatus"
436 getChannelStatus :: Channel -> IO FileStatus
437 getChannelStatus fd =
438 allocChars ``sizeof(struct stat)'' `thenStrictlyST` \ bytes ->
439 _casm_ ``%r = fstat(%0,(struct stat *)%1);'' fd bytes
442 freeze bytes `thenStrictlyST` \ stat ->
445 syserr "getChannelStatus"
447 queryAccess :: FilePath -> Bool -> Bool -> Bool -> IO Bool
448 queryAccess name read write exec =
449 _packBytesForCST name `thenStrictlyST` \ path ->
450 _ccall_ access path flags `thenPrimIO` \ rc ->
453 flags = I# (word2Int# (read# `or#` write# `or#` exec#))
454 read# = case (if read then ``R_OK'' else ``0'') of { W# x -> x }
455 write# = case (if write then ``W_OK'' else ``0'') of { W# x -> x }
456 exec# = case (if exec then ``X_OK'' else ``0'') of { W# x -> x }
458 queryFile :: FilePath -> IO Bool
460 _packBytesForCST name `thenStrictlyST` \ path ->
461 _ccall_ access path (``F_OK''::Int) `thenPrimIO` \ rc ->
464 setFileMode :: FilePath -> FileMode -> IO ()
465 setFileMode name mode =
466 _packBytesForCST name `thenStrictlyST` \ path ->
467 _ccall_ chmod path mode `thenPrimIO` \ rc ->
473 setOwnerAndGroup :: FilePath -> UserID -> GroupID -> IO ()
474 setOwnerAndGroup name uid gid =
475 _packBytesForCST name `thenStrictlyST` \ path ->
476 _ccall_ chown path uid gid `thenPrimIO` \ rc ->
480 syserr "setOwnerAndGroup"
482 setFileTimes :: FilePath -> EpochTime -> EpochTime -> IO ()
483 setFileTimes name atime mtime =
484 _packBytesForCST name `thenStrictlyST` \ path ->
485 _casm_ ``do {struct utimbuf ub; ub.actime = (time_t) %0; ub.modtime = (time_t) %1;
486 %r = utime(%2, &ub);} while(0);'' atime mtime path
491 syserr "setFileTimes"
493 touchFile :: FilePath -> IO ()
495 _packBytesForCST name `thenStrictlyST` \ path ->
496 _ccall_ utime path (``NULL''::_Addr) `thenPrimIO` \ rc ->
502 data PathVar = LinkLimit
508 | SetOwnerAndGroupIsRestricted
509 | FileNamesAreNotTruncated
511 getPathVar :: PathVar -> FilePath -> IO Limit
514 LinkLimit -> pathconf ``_PC_LINK_MAX''
515 InputLineLimit -> pathconf ``_PC_MAX_CANON''
516 InputQueueLimit -> pathconf ``_PC_MAX_INPUT''
517 FileNameLimit -> pathconf ``_PC_NAME_MAX''
518 PathNameLimit -> pathconf ``_PC_PATH_MAX''
519 PipeBufferLimit -> pathconf ``_PC_PIPE_BUF''
520 SetOwnerAndGroupIsRestricted -> pathconf ``_PC_CHOWN_RESTRICTED''
521 FileNamesAreNotTruncated -> pathconf ``_PC_NO_TRUNC''
523 pathconf :: Int -> IO Limit
525 _packBytesForCST name `thenStrictlyST` \ path ->
526 _ccall_ pathconf path n `thenPrimIO` \ rc ->
530 getErrorCode >>= \ errno ->
531 if errno == invalidArgument then
532 failWith (NoSuchThing "no such path limit or option")
536 getChannelVar :: PathVar -> Channel -> IO Limit
539 LinkLimit -> fpathconf ``_PC_LINK_MAX''
540 InputLineLimit -> fpathconf ``_PC_MAX_CANON''
541 InputQueueLimit -> fpathconf ``_PC_MAX_INPUT''
542 FileNameLimit -> fpathconf ``_PC_NAME_MAX''
543 PathNameLimit -> fpathconf ``_PC_PATH_MAX''
544 PipeBufferLimit -> fpathconf ``_PC_PIPE_BUF''
545 SetOwnerAndGroupIsRestricted -> fpathconf ``_PC_CHOWN_RESTRICTED''
546 FileNamesAreNotTruncated -> fpathconf ``_PC_NO_TRUNC''
548 fpathconf :: Int -> IO Limit
550 _ccall_ fpathconf fd n `thenPrimIO` \ rc ->
554 getErrorCode >>= \ errno ->
555 if errno == invalidArgument then
556 failWith (NoSuchThing "no such path limit or option")