Ticket #5013: ByteString.hsc

File ByteString.hsc, 13.0 KB (added by maeder, 15 months ago)

patched

Line 
1#if __GLASGOW_HASKELL__ >= 701
2{-# LANGUAGE Trustworthy #-}
3#endif
4-----------------------------------------------------------------------------
5-- |
6-- Module      :  System.Posix.Files.ByteString
7-- Copyright   :  (c) The University of Glasgow 2002
8-- License     :  BSD-style (see the file libraries/base/LICENSE)
9--
10-- Maintainer  :  [email protected]
11-- Stability   :  provisional
12-- Portability :  non-portable (requires POSIX)
13--
14-- Functions defined by the POSIX standards for manipulating and querying the
15-- file system. Names of underlying POSIX functions are indicated whenever
16-- possible. A more complete documentation of the POSIX functions together
17-- with a more detailed description of different error conditions are usually
18-- available in the system's manual pages or from
19-- <http://www.unix.org/version3/online.html> (free registration required).
20--
21-- When a function that calls an underlying POSIX function fails, the errno
22-- code is converted to an 'IOError' using 'Foreign.C.Error.errnoToIOError'.
23-- For a list of which errno codes may be generated, consult the POSIX
24-- documentation for the underlying function.
25--
26-----------------------------------------------------------------------------
27
28#include "HsUnix.h"
29
30module System.Posix.Files.ByteString (
31    -- * File modes
32    -- FileMode exported by System.Posix.Types
33    unionFileModes, intersectFileModes,
34    nullFileMode,
35    ownerReadMode, ownerWriteMode, ownerExecuteMode, ownerModes,
36    groupReadMode, groupWriteMode, groupExecuteMode, groupModes,
37    otherReadMode, otherWriteMode, otherExecuteMode, otherModes,
38    setUserIDMode, setGroupIDMode,
39    stdFileMode,   accessModes,
40    fileTypeModes,
41    blockSpecialMode, characterSpecialMode, namedPipeMode, regularFileMode,
42    directoryMode, symbolicLinkMode, socketMode,
43
44    -- ** Setting file modes
45    setFileMode, setFdMode, setFileCreationMask,
46
47    -- ** Checking file existence and permissions
48    fileAccess, fileExist,
49
50    -- * File status
51    FileStatus,
52    -- ** Obtaining file status
53    getFileStatus, getFdStatus, getSymbolicLinkStatus,
54    -- ** Querying file status
55    deviceID, fileID, fileMode, linkCount, fileOwner, fileGroup,
56    specialDeviceID, fileSize, accessTime, modificationTime,
57    statusChangeTime,
58    accessTimeHiRes, modificationTimeHiRes, statusChangeTimeHiRes,
59    isBlockDevice, isCharacterDevice, isNamedPipe, isRegularFile,
60    isDirectory, isSymbolicLink, isSocket,
61
62    -- * Creation
63    createNamedPipe,
64    createDevice,
65
66    -- * Hard links
67    createLink, removeLink,
68
69    -- * Symbolic links
70    createSymbolicLink, readSymbolicLink,
71
72    -- * Renaming files
73    rename,
74
75    -- * Changing file ownership
76    setOwnerAndGroup,  setFdOwnerAndGroup,
77#if HAVE_LCHOWN
78    setSymbolicLinkOwnerAndGroup,
79#endif
80
81    -- * Changing file timestamps
82    setFileTimes, touchFile,
83
84    -- * Setting file sizes
85    setFileSize, setFdSize,
86
87    -- * Find system-specific limits for a file
88    PathVar(..), getPathVar, getFdPathVar,
89  ) where
90
91import System.Posix.Types
92import System.Posix.Internals hiding (withFilePath, peekFilePathLen)
93import Foreign
94import Foreign.C hiding (
95     throwErrnoPath,
96     throwErrnoPathIf,
97     throwErrnoPathIf_,
98     throwErrnoPathIfNull,
99     throwErrnoPathIfMinus1,
100     throwErrnoPathIfMinus1_ )
101
102import System.Posix.Files.Common
103import System.Posix.ByteString.FilePath
104
105-- -----------------------------------------------------------------------------
106-- chmod()
107
108-- | @setFileMode path mode@ changes permission of the file given by @path@
109-- to @mode@. This operation may fail with 'throwErrnoPathIfMinus1_' if @path@
110-- doesn't exist or if the effective user ID of the current process is not that
111-- of the file's owner.
112--
113-- Note: calls @chmod@.
114setFileMode :: RawFilePath -> FileMode -> IO ()
115setFileMode name m =
116  withFilePath name $ \s -> do
117    throwErrnoPathIfMinus1_ "setFileMode" name (c_chmod s m)
118
119-- -----------------------------------------------------------------------------
120-- access()
121
122-- | @fileAccess name read write exec@ checks if the file (or other file system
123-- object) @name@ can be accessed for reading, writing and\/or executing. To
124-- check a permission set the corresponding argument to 'True'.
125--
126-- Note: calls @access@.
127fileAccess :: RawFilePath -> Bool -> Bool -> Bool -> IO Bool
128fileAccess name readOK writeOK execOK = access name flags
129  where
130   flags   = read_f .|. write_f .|. exec_f
131   read_f  = if readOK  then (#const R_OK) else 0
132   write_f = if writeOK then (#const W_OK) else 0
133   exec_f  = if execOK  then (#const X_OK) else 0
134
135-- | Checks for the existence of the file.
136--
137-- Note: calls @access@.
138fileExist :: RawFilePath -> IO Bool
139fileExist name =
140  withFilePath name $ \s -> do
141    r <- c_access s (#const F_OK)
142    if (r == 0)
143        then return True
144        else do err <- getErrno
145                if (err == eNOENT)
146                   then return False
147                   else throwErrnoPath "fileExist" name
148
149access :: RawFilePath -> CMode -> IO Bool
150access name flags =
151  withFilePath name $ \s -> do
152    r <- c_access s (fromIntegral flags)
153    if (r == 0)
154        then return True
155        else do err <- getErrno
156                if (err == eACCES)
157                   then return False
158                   else throwErrnoPath "fileAccess" name
159
160
161-- | @getFileStatus path@ calls gets the @FileStatus@ information (user ID,
162-- size, access times, etc.) for the file @path@.
163--
164-- Note: calls @stat@.
165getFileStatus :: RawFilePath -> IO FileStatus
166getFileStatus path = do
167  fp <- mallocForeignPtrBytes (#const sizeof(struct stat))
168  withForeignPtr fp $ \p ->
169    withFilePath path $ \s ->
170      throwErrnoPathIfMinus1Retry_ "getFileStatus" path (c_stat s p)
171  return (FileStatus fp)
172
173-- | Acts as 'getFileStatus' except when the 'RawFilePath' refers to a symbolic
174-- link. In that case the @FileStatus@ information of the symbolic link itself
175-- is returned instead of that of the file it points to.
176--
177-- Note: calls @lstat@.
178getSymbolicLinkStatus :: RawFilePath -> IO FileStatus
179getSymbolicLinkStatus path = do
180  fp <- mallocForeignPtrBytes (#const sizeof(struct stat))
181  withForeignPtr fp $ \p ->
182    withFilePath path $ \s ->
183      throwErrnoPathIfMinus1_ "getSymbolicLinkStatus" path (c_lstat s p)
184  return (FileStatus fp)
185
186foreign import ccall unsafe "__hsunix_lstat"
187  c_lstat :: CString -> Ptr CStat -> IO CInt
188
189-- | @createNamedPipe fifo mode@
190-- creates a new named pipe, @fifo@, with permissions based on
191-- @mode@. May fail with 'throwErrnoPathIfMinus1_' if a file named @name@
192-- already exists or if the effective user ID of the current process doesn't
193-- have permission to create the pipe.
194--
195-- Note: calls @mkfifo@.
196createNamedPipe :: RawFilePath -> FileMode -> IO ()
197createNamedPipe name mode = do
198  withFilePath name $ \s ->
199    throwErrnoPathIfMinus1_ "createNamedPipe" name (c_mkfifo s mode)
200
201-- | @createDevice path mode dev@ creates either a regular or a special file
202-- depending on the value of @mode@ (and @dev@).  @mode@ will normally be either
203-- 'blockSpecialMode' or 'characterSpecialMode'.  May fail with
204-- 'throwErrnoPathIfMinus1_' if a file named @name@ already exists or if the
205-- effective user ID of the current process doesn't have permission to create
206-- the file.
207--
208-- Note: calls @mknod@.
209createDevice :: RawFilePath -> FileMode -> DeviceID -> IO ()
210createDevice path mode dev =
211  withFilePath path $ \s ->
212    throwErrnoPathIfMinus1_ "createDevice" path (c_mknod s mode dev)
213
214foreign import ccall unsafe "__hsunix_mknod"
215  c_mknod :: CString -> CMode -> CDev -> IO CInt
216
217-- -----------------------------------------------------------------------------
218-- Hard links
219
220-- | @createLink old new@ creates a new path, @new@, linked to an existing file,
221-- @old@.
222--
223-- Note: calls @link@.
224createLink :: RawFilePath -> RawFilePath -> IO ()
225createLink name1 name2 =
226  withFilePath name1 $ \s1 ->
227  withFilePath name2 $ \s2 ->
228  throwErrnoPathIfMinus1_ "createLink" name1 (c_link s1 s2)
229
230-- | @removeLink path@ removes the link named @path@.
231--
232-- Note: calls @unlink@.
233removeLink :: RawFilePath -> IO ()
234removeLink name =
235  withFilePath name $ \s ->
236  throwErrnoPathIfMinus1_ "removeLink" name (c_unlink s)
237
238-- -----------------------------------------------------------------------------
239-- Symbolic Links
240
241-- | @createSymbolicLink file1 file2@ creates a symbolic link named @file2@
242-- which points to the file @file1@.
243--
244-- Symbolic links are interpreted at run-time as if the contents of the link
245-- had been substituted into the path being followed to find a file or directory.
246--
247-- Note: calls @symlink@.
248createSymbolicLink :: RawFilePath -> RawFilePath -> IO ()
249createSymbolicLink file1 file2 =
250  withFilePath file1 $ \s1 ->
251  withFilePath file2 $ \s2 ->
252  throwErrnoPathIfMinus1_ "createSymbolicLink" file1 (c_symlink s1 s2)
253
254foreign import ccall unsafe "symlink"
255  c_symlink :: CString -> CString -> IO CInt
256
257-- ToDo: should really use SYMLINK_MAX, but not everyone supports it yet,
258-- and it seems that the intention is that SYMLINK_MAX is no larger than
259-- PATH_MAX.
260#if !defined(PATH_MAX)
261-- PATH_MAX is not defined on systems with unlimited path length.
262-- Ugly.  Fix this.
263#define PATH_MAX 4096
264#endif
265
266-- | Reads the @RawFilePath@ pointed to by the symbolic link and returns it.
267--
268-- Note: calls @readlink@.
269readSymbolicLink :: RawFilePath -> IO RawFilePath
270readSymbolicLink file =
271  allocaArray0 (#const PATH_MAX) $ \buf -> do
272    withFilePath file $ \s -> do
273      len <- throwErrnoPathIfMinus1 "readSymbolicLink" file $
274        c_readlink s buf (#const PATH_MAX)
275      peekFilePathLen (buf,fromIntegral len)
276
277foreign import ccall unsafe "readlink"
278  c_readlink :: CString -> CString -> CSize -> IO CInt
279
280-- -----------------------------------------------------------------------------
281-- Renaming files
282
283-- | @rename old new@ renames a file or directory from @old@ to @new@.
284--
285-- Note: calls @rename@.
286rename :: RawFilePath -> RawFilePath -> IO ()
287rename name1 name2 =
288  withFilePath name1 $ \s1 ->
289  withFilePath name2 $ \s2 ->
290  throwErrnoPathIfMinus1_ "rename" name1 (c_rename s1 s2)
291
292foreign import ccall unsafe "rename"
293   c_rename :: CString -> CString -> IO CInt
294
295-- -----------------------------------------------------------------------------
296-- chown()
297
298-- | @setOwnerAndGroup path uid gid@ changes the owner and group of @path@ to
299-- @uid@ and @gid@, respectively.
300--
301-- If @uid@ or @gid@ is specified as -1, then that ID is not changed.
302--
303-- Note: calls @chown@.
304setOwnerAndGroup :: RawFilePath -> UserID -> GroupID -> IO ()
305setOwnerAndGroup name uid gid = do
306  withFilePath name $ \s ->
307    throwErrnoPathIfMinus1_ "setOwnerAndGroup" name (c_chown s uid gid)
308
309foreign import ccall unsafe "chown"
310  c_chown :: CString -> CUid -> CGid -> IO CInt
311
312#if HAVE_LCHOWN
313-- | Acts as 'setOwnerAndGroup' but does not follow symlinks (and thus
314-- changes permissions on the link itself).
315--
316-- Note: calls @lchown@.
317setSymbolicLinkOwnerAndGroup :: RawFilePath -> UserID -> GroupID -> IO ()
318setSymbolicLinkOwnerAndGroup name uid gid = do
319  withFilePath name $ \s ->
320    throwErrnoPathIfMinus1_ "setSymbolicLinkOwnerAndGroup" name
321        (c_lchown s uid gid)
322
323foreign import ccall unsafe "lchown"
324  c_lchown :: CString -> CUid -> CGid -> IO CInt
325#endif
326
327-- -----------------------------------------------------------------------------
328-- utime()
329
330-- | @setFileTimes path atime mtime@ sets the access and modification times
331-- associated with file @path@ to @atime@ and @mtime@, respectively.
332--
333-- Note: calls @utime@.
334setFileTimes :: RawFilePath -> EpochTime -> EpochTime -> IO ()
335setFileTimes name atime mtime = do
336  withFilePath name $ \s ->
337   allocaBytes (#const sizeof(struct utimbuf)) $ \p -> do
338     (#poke struct utimbuf, actime)  p atime
339     (#poke struct utimbuf, modtime) p mtime
340     throwErrnoPathIfMinus1_ "setFileTimes" name (c_utime s p)
341
342-- | @touchFile path@ sets the access and modification times associated with
343-- file @path@ to the current time.
344--
345-- Note: calls @utime@.
346touchFile :: RawFilePath -> IO ()
347touchFile name = do
348  withFilePath name $ \s ->
349   throwErrnoPathIfMinus1_ "touchFile" name (c_utime s nullPtr)
350
351-- -----------------------------------------------------------------------------
352-- Setting file sizes
353
354-- | Truncates the file down to the specified length. If the file was larger
355-- than the given length before this operation was performed the extra is lost.
356--
357-- Note: calls @truncate@.
358setFileSize :: RawFilePath -> FileOffset -> IO ()
359setFileSize file off =
360  withFilePath file $ \s ->
361    throwErrnoPathIfMinus1_ "setFileSize" file (c_truncate s off)
362
363foreign import ccall unsafe "truncate"
364  c_truncate :: CString -> COff -> IO CInt
365
366-- -----------------------------------------------------------------------------
367-- pathconf()/fpathconf() support
368
369-- | @getPathVar var path@ obtains the dynamic value of the requested
370-- configurable file limit or option associated with file or directory @path@.
371-- For defined file limits, @getPathVar@ returns the associated
372-- value.  For defined file options, the result of @getPathVar@
373-- is undefined, but not failure.
374--
375-- Note: calls @pathconf@.
376getPathVar :: RawFilePath -> PathVar -> IO Limit
377getPathVar name v = do
378  withFilePath name $ \ nameP ->
379    throwErrnoPathIfMinus1 "getPathVar" name $
380      c_pathconf nameP (pathVarConst v)
381
382foreign import ccall unsafe "pathconf"
383  c_pathconf :: CString -> CInt -> IO CLong