2 % (c) The AQUA Project, Glasgow University, 1994-1997
5 \section[Directory]{Module @Directory@}
7 A directory contains a series of entries, each of which is a named
8 reference to a file system object (file, directory etc.). Some
9 entries may be hidden, inaccessible, or have some administrative
10 function (e.g. "." or ".." under POSIX), but in this standard all such
11 entries are considered to form part of the directory contents.
12 Entries in sub-directories are not, however, considered to form part
13 of the directory contents.
15 Each file system object is referenced by a {\em path}. There is
16 normally at least one absolute path to each file system object. In
17 some operating systems, it may also be possible to have paths which
18 are relative to the current directory.
22 -- Permissions(Permissions),
23 createDirectory, removeDirectory, removeFile,
24 renameDirectory, renameFile, getDirectoryContents,
25 getCurrentDirectory, setCurrentDirectory
27 ,doesFileExist, doesDirectoryExist,
28 getPermissions, setPermissions,
36 import STBase ( PrimIO )
37 import PackedString ( packCBytesST, unpackPS )
40 %*********************************************************
42 \subsection{Signatures}
44 %*********************************************************
47 createDirectory :: FilePath -> IO ()
48 removeDirectory :: FilePath -> IO ()
49 removeFile :: FilePath -> IO ()
50 renameDirectory :: FilePath -> FilePath -> IO ()
51 renameFile :: FilePath -> FilePath -> IO ()
52 getDirectoryContents :: FilePath -> IO [FilePath]
53 getCurrentDirectory :: IO FilePath
54 setCurrentDirectory :: FilePath -> IO ()
58 %*********************************************************
60 \subsection{Permissions}
62 %*********************************************************
64 The @Permissions@ type is used to record whether certain operations are permissible on a
71 executable, searchable :: Bool
72 } deriving (Eq, Ord, Read, Show)
76 %*********************************************************
78 \subsection{Implementation}
80 %*********************************************************
82 @createDirectory dir@ creates a new directory {\em dir} which is
83 initially empty, or as near to empty as the operating system
86 The operation may fail with:
89 \item @isPermissionError@ / @PermissionDenied@
90 The process has insufficient privileges to perform the operation.
92 \item @isAlreadyExistsError@ / @AlreadyExists@
93 The operand refers to a directory that already exists.
96 A physical I/O error has occurred.
98 \item @InvalidArgument@
99 The operand is not a valid directory name.
100 @[ENAMETOOLONG, ELOOP]@
102 There is no path to the directory.
104 \item @ResourceExhausted@
105 Insufficient resources (virtual memory, process file descriptors,
106 physical disk space, etc.) are available to perform the operation.
107 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
108 \item @InappropriateType@
109 The path refers to an existing non-directory object.
114 createDirectory path =
115 _ccall_ createDirectory path `thenIO_Prim` \ rc ->
119 constructErrorAndFail "createDirectory"
122 @removeDirectory dir@ removes an existing directory {\em dir}. The
123 implementation may specify additional constraints which must be
124 satisfied before a directory can be removed (e.g. the directory has to
125 be empty, or may not be in use by other processes). It is not legal
126 for an implementation to partially remove a directory unless the
127 entire directory is removed. A conformant implementation need not
128 support directory removal in all situations (e.g. removal of the root
131 The operation may fail with:
133 \item @HardwareFault@
134 A physical I/O error has occurred.
136 \item @InvalidArgument@
137 The operand is not a valid directory name.
138 @[ENAMETOOLONG, ELOOP]@
139 \item @isDoesNotExist@ / @NoSuchThing@
140 The directory does not exist.
142 \item @isPermissionError@ / @PermissionDenied@
143 The process has insufficient privileges to perform the operation.
144 @[EROFS, EACCES, EPERM]@
145 \item @UnsatisfiedConstraints@
146 Implementation-dependent constraints are not satisfied.
147 @[EBUSY, ENOTEMPTY, EEXIST]@
148 \item @UnsupportedOperation@
149 The implementation does not support removal in this situation.
151 \item @InappropriateType@
152 The operand refers to an existing non-directory object.
157 removeDirectory path =
158 _ccall_ removeDirectory path `thenIO_Prim` \ rc ->
162 constructErrorAndFail "removeDirectory"
165 @removeFile file@ removes the directory entry for an existing file
166 {\em file}, where {\em file} is not itself a directory. The
167 implementation may specify additional constraints which must be
168 satisfied before a file can be removed (e.g. the file may not be in
169 use by other processes).
171 The operation may fail with:
173 \item @HardwareFault@
174 A physical I/O error has occurred.
176 \item @InvalidArgument@
177 The operand is not a valid file name.
178 @[ENAMETOOLONG, ELOOP]@
179 \item @isDoesNotExist@ / @NoSuchThing@
180 The file does not exist.
182 \item @isPermissionError@ / @PermissionDenied@
183 The process has insufficient privileges to perform the operation.
184 @[EROFS, EACCES, EPERM]@
185 \item @UnsatisfiedConstraints@
186 Implementation-dependent constraints are not satisfied.
188 \item @InappropriateType@
189 The operand refers to an existing directory.
195 _ccall_ removeFile path `thenIO_Prim` \ rc ->
199 constructErrorAndFail "removeFile"
202 @renameDirectory old@ {\em new} changes the name of an existing
203 directory from {\em old} to {\em new}. If the {\em new} directory
204 already exists, it is atomically replaced by the {\em old} directory.
205 If the {\em new} directory is neither the {\em old} directory nor an
206 alias of the {\em old} directory, it is removed as if by
207 $removeDirectory$. A conformant implementation need not support
208 renaming directories in all situations (e.g. renaming to an existing
209 directory, or across different physical devices), but the constraints
212 The operation may fail with:
214 \item @HardwareFault@
215 A physical I/O error has occurred.
217 \item @InvalidArgument@
218 Either operand is not a valid directory name.
219 @[ENAMETOOLONG, ELOOP]@
220 \item @isDoesNotExistError@ / @NoSuchThing@
221 The original directory does not exist, or there is no path to the target.
223 \item @isPermissionError@ / @PermissionDenied@
224 The process has insufficient privileges to perform the operation.
225 @[EROFS, EACCES, EPERM]@
226 \item @ResourceExhausted@
227 Insufficient resources are available to perform the operation.
228 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
229 \item @UnsatisfiedConstraints@
230 Implementation-dependent constraints are not satisfied.
231 @[EBUSY, ENOTEMPTY, EEXIST]@
232 \item @UnsupportedOperation@
233 The implementation does not support renaming in this situation.
235 \item @InappropriateType@
236 Either path refers to an existing non-directory object.
241 renameDirectory opath npath =
242 _ccall_ renameDirectory opath npath `thenIO_Prim` \ rc ->
246 constructErrorAndFail "renameDirectory"
249 @renameFile old@ {\em new} changes the name of an existing file system
250 object from {\em old} to {\em new}. If the {\em new} object already
251 exists, it is atomically replaced by the {\em old} object. Neither
252 path may refer to an existing directory. A conformant implementation
253 need not support renaming files in all situations (e.g. renaming
254 across different physical devices), but the constraints must be
257 The operation may fail with:
259 \item @HardwareFault@
260 A physical I/O error has occurred.
262 \item @InvalidArgument@
263 Either operand is not a valid file name.
264 @[ENAMETOOLONG, ELOOP]@
265 \item @isDoesNotExistError@ / @NoSuchThing@
266 The original file does not exist, or there is no path to the target.
268 \item @isPermissionError@ / @PermissionDenied@
269 The process has insufficient privileges to perform the operation.
270 @[EROFS, EACCES, EPERM]@
271 \item @ResourceExhausted@
272 Insufficient resources are available to perform the operation.
273 @[EDQUOT, ENOSPC, ENOMEM, EMLINK]@
274 \item @UnsatisfiedConstraints@
275 Implementation-dependent constraints are not satisfied.
277 \item @UnsupportedOperation@
278 The implementation does not support renaming in this situation.
280 \item @InappropriateType@
281 Either path refers to an existing directory.
282 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
286 renameFile opath npath =
287 _ccall_ renameFile opath npath `thenIO_Prim` \ rc ->
291 constructErrorAndFail "renameFile"
294 @getDirectoryContents dir@ returns a list of {\em all} entries
297 The operation may fail with:
299 \item @HardwareFault@
300 A physical I/O error has occurred.
302 \item @InvalidArgument@
303 The operand is not a valid directory name.
304 @[ENAMETOOLONG, ELOOP]@
305 \item @isDoesNotExistError@ / @NoSuchThing@
306 The directory does not exist.
308 \item @isPermissionError@ / @PermissionDenied@
309 The process has insufficient privileges to perform the operation.
311 \item @ResourceExhausted@
312 Insufficient resources are available to perform the operation.
314 \item @InappropriateType@
315 The path refers to an existing non-directory object.
320 getDirectoryContents path =
321 _ccall_ getDirectoryContents path `thenIO_Prim` \ ptr ->
322 if ptr == ``NULL'' then
323 constructErrorAndFail "getDirectoryContents"
325 stToIO (getEntries ptr 0) >>= \ entries ->
326 _ccall_ free ptr `thenIO_Prim` \ () ->
329 getEntries :: Addr -> Int -> PrimIO [FilePath]
331 _casm_ ``%r = ((char **)%0)[%1];'' ptr n >>= \ str ->
332 if str == ``NULL'' then
335 _ccall_ strlen str >>= \ len ->
336 packCBytesST len str >>= \ entry ->
337 _ccall_ free str >>= \ () ->
338 getEntries ptr (n+1) >>= \ entries ->
339 return (unpackPS entry : entries)
342 If the operating system has a notion of current directories,
343 @getCurrentDirectory@ returns an absolute path to the
344 current directory of the calling process.
346 The operation may fail with:
348 \item @HardwareFault@
349 A physical I/O error has occurred.
351 \item @isDoesNotExistError@ / @NoSuchThing@
352 There is no path referring to the current directory.
353 @[EPERM, ENOENT, ESTALE...]@
354 \item @isPermissionError@ / @PermissionDenied@
355 The process has insufficient privileges to perform the operation.
357 \item @ResourceExhausted@
358 Insufficient resources are available to perform the operation.
359 \item @UnsupportedOperation@
360 The operating system has no notion of current directory.
364 getCurrentDirectory =
365 _ccall_ getCurrentDirectory `thenIO_Prim` \ str ->
366 if str /= ``NULL'' then
367 _ccall_ strlen str `thenIO_Prim` \ len ->
368 stToIO (packCBytesST len str) >>= \ pwd ->
369 _ccall_ free str `thenIO_Prim` \ () ->
370 return (unpackPS pwd)
372 constructErrorAndFail "getCurrentDirectory"
375 If the operating system has a notion of current directories,
376 @setCurrentDirectory dir@ changes the current
377 directory of the calling process to {\em dir}.
379 The operation may fail with:
381 \item @HardwareFault@
382 A physical I/O error has occurred.
384 \item @InvalidArgument@
385 The operand is not a valid directory name.
386 @[ENAMETOOLONG, ELOOP]@
387 \item @isDoesNotExistError@ / @NoSuchThing@
388 The directory does not exist.
390 \item @isPermissionError@ / @PermissionDenied@
391 The process has insufficient privileges to perform the operation.
393 \item @UnsupportedOperation@
394 The operating system has no notion of current directory, or the
395 current directory cannot be dynamically changed.
396 \item @InappropriateType@
397 The path refers to an existing non-directory object.
402 setCurrentDirectory path =
403 _ccall_ setCurrentDirectory path `thenIO_Prim` \ rc ->
407 constructErrorAndFail "setCurrentDirectory"
414 doesFileExist :: FilePath -> IO Bool
416 psToByteArrayST name `thenIO_Prim` \ path ->
417 _ccall_ access path (``F_OK''::Int) `thenIO_Prim` \ rc ->
420 doesDirectoryExist :: FilePath -> IO Bool
421 doesDirectoryExist name =
422 (getFileStatus >>= isDirectory) `catch` (\ _ -> return False)
424 getModificationTime :: FilePath -> IO Bool
425 getModificationTime name =
426 getFileStatus >>= \ st ->
427 return (modificationTime st)
429 getPermissions :: FilePath -> IO Permissions
430 getPermissions name =
431 getFileStatus >>= \ st ->
434 isect v = intersectFileMode v fm == v
438 readable = isect ownerReadMode,
439 writeable = isect ownerWriteMode,
440 executable = not (isDirectory st) && isect ownerExecuteMode,
441 searchable = not (isRegularFile st) && isect ownerExecuteMode