e9f70e96d9e9ae3c1c3e3776c4b6ecb281519150
[ghc-hetmet.git] / ghc / lib / required / Directory.lhs
1 %
2 % (c) The AQUA Project, Glasgow University, 1994-1997
3 %
4
5 \section[Directory]{Module @Directory@}
6
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.
14
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.
19
20 \begin{code}
21 module Directory ( 
22 --    Permissions(Permissions),
23     createDirectory, removeDirectory, removeFile, 
24     renameDirectory, renameFile, getDirectoryContents,
25     getCurrentDirectory, setCurrentDirectory
26 {-
27     ,doesFileExist, doesDirectoryExist,
28     getPermissions, setPermissions,
29     getModificationTime
30 -}
31   ) where
32
33 import Prelude
34 import Foreign
35 import IOBase
36 import STBase           ( PrimIO )
37 import PackedString     ( packCBytesST, unpackPS )
38 \end{code}
39
40 %*********************************************************
41 %*                                                      *
42 \subsection{Signatures}
43 %*                                                      *
44 %*********************************************************
45
46 \begin{code}
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 ()
55 \end{code}
56
57
58 %*********************************************************
59 %*                                                      *
60 \subsection{Permissions}
61 %*                                                      *
62 %*********************************************************
63
64 The @Permissions@ type is used to record whether certain operations are permissible on a
65 file/directory:
66
67 \begin{code}
68 data Permissions
69  = Permissions {
70     readable,   writeable, 
71     executable, searchable :: Bool 
72    } deriving (Eq, Ord, Read, Show)
73
74 \end{code}
75
76 %*********************************************************
77 %*                                                      *
78 \subsection{Implementation}
79 %*                                                      *
80 %*********************************************************
81
82 @createDirectory dir@ creates a new directory {\em dir} which is
83 initially empty, or as near to empty as the operating system
84 allows.
85
86 The operation may fail with:
87
88 \begin{itemize}
89 \item @isPermissionError@ / @PermissionDenied@
90 The process has insufficient privileges to perform the operation.
91 @[EROFS, EACCES]@
92 \item @isAlreadyExistsError@ / @AlreadyExists@
93 The operand refers to a directory that already exists.  
94 @ [EEXIST]@
95 \item @HardwareFault@
96 A physical I/O error has occurred.
97 @ [EIO]@
98 \item @InvalidArgument@
99 The operand is not a valid directory name.
100 @[ENAMETOOLONG, ELOOP]@
101 \item @NoSuchThing@
102 There is no path to the directory. 
103 @[ENOENT, ENOTDIR]@
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.
110 @[EEXIST]@
111 \end{itemize}
112
113 \begin{code}
114 createDirectory path =
115     _ccall_ createDirectory path    `thenIO_Prim` \ rc ->
116     if rc == 0 then
117         return ()
118     else
119         constructErrorAndFail "createDirectory"
120 \end{code}
121
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
129 directory).
130
131 The operation may fail with:
132 \begin{itemize}
133 \item @HardwareFault@
134 A physical I/O error has occurred.
135 [@EIO@]
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. 
141 @[ENOENT, ENOTDIR]@
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.
150 @[EINVAL]@
151 \item @InappropriateType@
152 The operand refers to an existing non-directory object.
153 @[ENOTDIR]@
154 \end{itemize}
155
156 \begin{code}
157 removeDirectory path =
158     _ccall_ removeDirectory path    `thenIO_Prim` \ rc ->
159     if rc == 0 then
160         return ()
161     else
162         constructErrorAndFail "removeDirectory"
163 \end{code}
164
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).
170
171 The operation may fail with:
172 \begin{itemize}
173 \item @HardwareFault@
174 A physical I/O error has occurred.
175 @[EIO]@
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. 
181 @[ENOENT, ENOTDIR]@
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.  
187 @[EBUSY]@
188 \item @InappropriateType@
189 The operand refers to an existing directory.
190 @[EPERM, EINVAL]@
191 \end{itemize}
192
193 \begin{code}
194 removeFile path =
195     _ccall_ removeFile path `thenIO_Prim` \ rc ->
196     if rc == 0 then
197         return ()
198     else
199         constructErrorAndFail "removeFile"
200 \end{code}
201
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
210 must be documented.
211
212 The operation may fail with:
213 \begin{itemize}
214 \item @HardwareFault@
215 A physical I/O error has occurred.
216 @[EIO]@
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.
222 @[ENOENT, ENOTDIR]@
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.
234 @[EINVAL, EXDEV]@
235 \item @InappropriateType@
236 Either path refers to an existing non-directory object.
237 @[ENOTDIR, EISDIR]@
238 \end{itemize}
239
240 \begin{code}
241 renameDirectory opath npath =
242     _ccall_ renameDirectory opath npath `thenIO_Prim` \ rc ->
243     if rc == 0 then
244         return ()
245     else
246         constructErrorAndFail "renameDirectory"
247 \end{code}
248
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
255 documented.
256
257 The operation may fail with:
258 \begin{itemize}
259 \item @HardwareFault@
260 A physical I/O error has occurred.
261 @[EIO]@
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.
267 @[ENOENT, ENOTDIR]@
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.
276 @[EBUSY]@
277 \item @UnsupportedOperation@
278 The implementation does not support renaming in this situation.
279 @[EXDEV]@
280 \item @InappropriateType@
281 Either path refers to an existing directory.
282 @[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]@
283 \end{itemize}
284
285 \begin{code}
286 renameFile opath npath =
287     _ccall_ renameFile opath npath  `thenIO_Prim` \ rc ->
288     if rc == 0 then
289         return ()
290     else
291         constructErrorAndFail   "renameFile"
292 \end{code}
293
294 @getDirectoryContents dir@ returns a list of {\em all} entries
295 in {\em dir}. 
296
297 The operation may fail with:
298 \begin{itemize}
299 \item @HardwareFault@
300 A physical I/O error has occurred.
301 @[EIO]@
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.
307 @[ENOENT, ENOTDIR]@
308 \item @isPermissionError@ / @PermissionDenied@
309 The process has insufficient privileges to perform the operation.
310 @[EACCES]@
311 \item @ResourceExhausted@
312 Insufficient resources are available to perform the operation.
313 @[EMFILE, ENFILE]@
314 \item @InappropriateType@
315 The path refers to an existing non-directory object.
316 @[ENOTDIR]@
317 \end{itemize}
318
319 \begin{code}
320 getDirectoryContents path =
321     _ccall_ getDirectoryContents path   `thenIO_Prim` \ ptr ->
322     if ptr == ``NULL'' then
323         constructErrorAndFail "getDirectoryContents"
324     else
325         stToIO (getEntries ptr 0)       >>= \ entries ->
326         _ccall_ free ptr                `thenIO_Prim` \ () ->
327         return entries
328   where
329     getEntries :: Addr -> Int -> PrimIO [FilePath]
330     getEntries ptr n =
331         _casm_ ``%r = ((char **)%0)[%1];'' ptr n    >>= \ str ->
332         if str == ``NULL'' then 
333             return []
334         else
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)
340 \end{code}
341
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.
345
346 The operation may fail with:
347 \begin{itemize}
348 \item @HardwareFault@
349 A physical I/O error has occurred.
350 @[EIO]@
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.
356 @[EACCES]@
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.
361 \end{itemize}
362
363 \begin{code}
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)
371     else
372         constructErrorAndFail "getCurrentDirectory"
373 \end{code}
374
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}.
378
379 The operation may fail with:
380 \begin{itemize}
381 \item @HardwareFault@
382 A physical I/O error has occurred.
383 @[EIO]@
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.
389 @[ENOENT, ENOTDIR]@
390 \item @isPermissionError@ / @PermissionDenied@
391 The process has insufficient privileges to perform the operation.
392 @[EACCES]@
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.
398 @[ENOTDIR]@
399 \end{itemize}
400
401 \begin{code}
402 setCurrentDirectory path =
403     _ccall_ setCurrentDirectory path    `thenIO_Prim` \ rc ->
404     if rc == 0 then
405         return ()
406     else
407         constructErrorAndFail "setCurrentDirectory"
408 \end{code}
409
410
411
412 \begin{code}
413 {-
414 doesFileExist :: FilePath -> IO Bool
415 doesFileExist name =
416   psToByteArrayST name                      `thenIO_Prim` \ path ->
417   _ccall_ access path (``F_OK''::Int)       `thenIO_Prim` \ rc ->
418   return (rc == 0)
419
420 doesDirectoryExist :: FilePath -> IO Bool
421 doesDirectoryExist name =  
422  (getFileStatus >>= isDirectory) `catch` (\ _ -> return False)
423
424 getModificationTime :: FilePath -> IO Bool
425 getModificationTime name =
426  getFileStatus >>= \ st ->
427  return (modificationTime st)
428
429 getPermissions :: FilePath -> IO Permissions
430 getPermissions name =
431   getFileStatus >>= \ st ->
432   let
433    fm = fileMode st
434    isect v = intersectFileMode v fm == v
435   in
436   return (
437     Permissions {
438       readable   = isect ownerReadMode,
439       writeable  = isect ownerWriteMode,
440       executable = not (isDirectory st)   && isect ownerExecuteMode,
441       searchable = not (isRegularFile st) && isect ownerExecuteMode
442     }
443   )
444 -}
445 \end{code}