/
FileControl.chs
308 lines (253 loc) · 7.63 KB
/
FileControl.chs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
{-# LANGUAGE GADTs #-}
module System.Posix.FileControl
( fcntl
, Fcntl(..)
, FileDescriptorFlags(..)
, FileStatusFlags(..)
, newFlock
, Flock
, flockType
, FlockType(..)
, flockWhence
, FlockWhence(..)
, flockStart
, flockLen
, flockPid
) where
import Control.Applicative
import Foreign
import Foreign.C
import System.Posix.Types
import Foreign.Var hiding (get)
#include <unistd.h>
#include <fcntl.h>
{# pointer *flock as ^ foreign newtype #}
-- | Perform one of the operations in 'Fcntl'
fcntl :: Fd -> Fcntl a -> IO a
fcntl fd cmd = case cmd of
-- Duplicating a file descriptor
F_DUPFD minFd ->
fcntl_set_int fd {# const F_DUPFD #} minFd
F_DUPFD_CLOEXEC minFd ->
fcntl_set_int fd {# const F_DUPFD_CLOEXEC #} minFd
-- File descriptor flags
F_GETFD ->
toEnum <$> fcntl_get_int fd {# const F_GETFD #}
F_SETFD flags ->
fcntl_set_int_ fd {# const F_SETFD #} (fromEnum flags)
-- File status flags
F_GETFL ->
toEnum <$> fcntl_get_int fd {# const F_GETFL #}
F_SETFL flags ->
fcntl_set_int_ fd {# const F_SETFL #} (fromEnum flags)
-- Advisory or mandatory locking
F_GETLK ->
fcntl_get_flock fd {# const F_GETLK #}
F_SETLK flock ->
fcntl_set_flock fd {# const F_SETLK #} flock
F_SETLKW flock ->
fcntl_set_flock fd {# const F_SETLKW #} flock
#if defined(_GNU_SOURCE)
-- Open description locks
F_OFD_GETLK ->
fcntl_get_flock fd {# const F_OFD_GETLK #}
F_OFD_SETLK flock ->
fcntl_set_flock fd {# const F_OFD_SETLK #} flock
F_OFD_SETLKW flock ->
fcntl_set_flock fd {# const F_OFD_SETLKW #} flock
#endif
-- Managing signals
F_GETOWN ->
fcntl_get_int fd {# const F_GETOWN #}
F_SETOWN pid ->
fcntl_set_int_ fd {# const F_SETFL #} pid
#if defined(F_GET_SEALS)
-- File sealing
F_GET_SEALS ->
fcntl_get_int fd {# const F_GET_SEALS #}
F_ADD_SEALS ->
fcntl_set_int_ fd {# const F_ADD_SEALS #}
#endif -- defined(F_GET_SEALS)
data Fcntl a where
-- Duplicating a file descriptor
F_DUPFD :: Fd -> Fcntl Fd
F_DUPFD_CLOEXEC :: Fd -> Fcntl Fd
-- File descriptor flags
F_GETFD :: Fcntl FileDescriptorFlags
F_SETFD :: FileDescriptorFlags -> Fcntl ()
-- File status flags
F_GETFL :: Fcntl FileStatusFlags
F_SETFL :: FileStatusFlags -> Fcntl ()
-- Advisory or mandatory locking
F_GETLK :: Fcntl Flock
F_SETLK :: Flock -> Fcntl ()
F_SETLKW :: Flock -> Fcntl ()
#if defined(_GNU_SOURCE)
-- Open file description locks
F_OFD_GETLK :: Fcntl Flock
F_OFD_SETLK :: Flock -> Fcntl ()
F_OFD_SETLKW :: Flock -> Fcntl ()
#endif
-- Managing signals
F_GETOWN :: Fcntl ProcessID
F_SETOWN :: ProcessID -> Fcntl ()
-- F_GETOWN_EX ::
-- F_SETOWN_EX ::
-- F_GETSIG :: Fcntl Signal
-- F_SETSIG :: Signal -> Fcntl ()
-- Leases
-- F_GETLEASE :: Fcntl FlockType
-- F_SETLEASE :: FlockType -> Fcntl ()
-- File and directory change notification (dnotify)
-- F_NOTIFY ::
-- Changing the capacity of a pipe
-- F_SETPIPE_SZ :: Int -> Fcntl ()
-- F_GETPIPE_SZ :: Fcntl Int
#if defined(F_GET_SEALS)
-- File sealing (Linux 3.17)
F_GET_SEALS :: Fcntl Seal
F_ADD_SEALS :: Seal -> Fcntl ()
#endif -- defined(F_GET_SEALS)
fcntl_get_int :: Integral a => Fd -> CInt -> IO a
fcntl_get_int fd cmd =
fromIntegral <$> throwErrnoIfMinus1 "fcntl" (c_fcntl_get_int fd cmd)
{# fun fcntl as c_fcntl_get_int
{ fromIntegral `Fd'
, `CInt'
} -> `CInt'
#}
fcntl_set_int :: (Integral a, Integral b) => Fd -> CInt -> a -> IO b
fcntl_set_int fd cmd n =
fromIntegral <$> throwErrnoIfMinus1 "fcntl"
(c_fcntl_set_int fd cmd (fromIntegral n))
fcntl_set_int_ :: Integral a => Fd -> CInt -> a -> IO ()
fcntl_set_int_ fd cmd n =
throwErrnoIfMinus1_ "fcntl" (c_fcntl_set_int fd cmd (fromIntegral n))
{# fun variadic fcntl[int] as c_fcntl_set_int
{ fromIntegral `Fd'
, `CInt'
, `CInt'
} -> `CInt'
#}
fcntl_get_flock :: Fd -> CInt -> IO Flock
fcntl_get_flock fd cmd = do
flock <- newFlock
throwErrnoIfMinus1_ "fcntl" $ c_fcntl_get_flock fd cmd flock
return flock
{# fun variadic fcntl[struct flock *] as c_fcntl_get_flock
{ fromIntegral `Fd'
, `CInt'
, `Flock'
} -> `CInt'
#}
fcntl_set_flock :: Fd -> CInt -> Flock -> IO ()
fcntl_set_flock fd cmd =
throwErrnoIfMinus1_ "fcntl" . c_fcntl_set_flock fd cmd
{# fun variadic fcntl[struct flock *] as c_fcntl_set_flock
{ fromIntegral `Fd'
, `CInt'
, `Flock'
} -> `CInt'
#}
-----------------------------------------------------------
-- File descriptor flags
{# enum define FileDescriptorFlags
{ FD_CLOEXEC as FD_CLOEXEC
} deriving (Show, Eq)
#}
-----------------------------------------------------------
-- File status flags
{# enum define FileStatusFlags
-- File access modes
{ O_RDONLY as O_RDONLY
, O_WRONLY as O_WRONLY
, O_RDWR as O_RDWR
, O_ACCMODE as O_ACCMODE
-- Open-time flags
, O_CREAT as O_CREAT
, O_EXCL as O_EXCL
, O_NONBLOCK as O_NONBLOCK
, O_NOCTTY as O_NOCTTY
, O_TRUNC as O_TRUNC
-- I/O operating modes
, O_APPEND as O_APPEND
, O_NDELAY as O_NDELAY
} deriving (Show, Eq)
#}
-----------------------------------------------------------
-- Advisory and mandatory locking
-- | Allocate a flock structure. The allocated memory will be garbage collected
-- automatically.
newFlock :: IO Flock
newFlock = Flock <$> mallocForeignPtrBytes {# sizeof flock #}
{# enum define FlockType
{ F_RDLCK as F_RDLCK
, F_WRLCK as F_WRLCK
, F_UNLCK as F_UNLCK
} deriving (Show, Eq)
#}
flockType :: Flock -> Var FlockType
flockType flock = Var get set
where
get = toEnum . fromIntegral <$> withFlock flock {# get flock.l_type #}
set ty = withFlock flock $ \p ->
{# set flock.l_type #} p (fromIntegral $ fromEnum ty)
{# enum define FlockWhence
{ SEEK_SET as SEEK_SET
, SEEK_CUR as SEEK_CUR
, SEEK_END as SEEK_END
} deriving (Show, Eq)
#}
flockWhence :: Flock -> Var FlockWhence
flockWhence flock = Var get set
where
get = toEnum . fromIntegral <$> withFlock flock {# get flock.l_whence #}
set ty = withFlock flock $ \p ->
{# set flock.l_whence #} p (fromIntegral $ fromEnum ty)
flockStart :: Flock -> Var FileOffset
flockStart flock = Var get set
where
get = fromIntegral <$> withFlock flock {# get flock.l_start #}
set ty = withFlock flock $ \p ->
{# set flock.l_start #} p (fromIntegral ty)
flockLen :: Flock -> Var FileOffset
flockLen flock = Var get set
where
get = fromIntegral <$> withFlock flock {# get flock.l_len #}
set ty = withFlock flock $ \p ->
{# set flock.l_len #} p (fromIntegral ty)
flockPid :: Flock -> Var ProcessID
flockPid flock = Var get set
where
get = fromIntegral <$> withFlock flock {# get flock.l_pid #}
set ty = withFlock flock $ \p ->
{# set flock.l_pid #} p (fromIntegral ty)
-----------------------------------------------------------
-- File sealing
#if defined(F_GET_SEALS)
newtype Seal = Seal CInt deriving Eq
pattern F_SEAL_SEAL :: Seal
pattern F_SEAL_SEAL <- ((\(Seal n) -> n .&. _F_SEAL_SEAL > 0) -> True)
where
F_SEAL_SEAL = Seal _F_SEAL_SEAL
pattern F_SEAL_SHRINK :: Seal
pattern F_SEAL_SHRINK <- ((\(Seal n) -> n .&. _F_SEAL_SHRINK > 0) -> True)
where
F_SEAL_SHRINK = Seal _F_SEAL_SHRINK
pattern F_SEAL_GROW :: Seal
pattern F_SEAL_GROW <- ((\(Seal n) -> n .&. _F_SEAL_GROW > 0) -> True)
where
F_SEAL_GROW = Seal _F_SEAL_GROW
pattern F_SEAL_WRITE :: Seal
pattern F_SEAL_WRITE <- ((\(Seal n) -> n .&. _F_SEAL_WRITE > 0) -> True)
where
F_SEAL_WRITE = Seal _F_SEAL_WRITE
_F_SEAL_SEAL :: CInt
_F_SEAL_SEAL = {# const F_SEAL_SEAL #}
_F_SEAL_SHRINK :: CInt
_F_SEAL_SHRINK = {# const F_SEAL_SHRINK #}
_F_SEAL_GROW :: CInt
_F_SEAL_GROW = {# const F_SEAL_GROW #}
_F_SEAL_WRITE :: CInt
_F_SEAL_WRITE = {# const F_SEAL_WRITE #}
#endif -- defined(F_GET_SEALS)