1 {-# OPTIONS -fno-implicit-prelude -#include "HsBase.h" #-}
2 -----------------------------------------------------------------------------
4 -- Module : Foreign.C.Error
5 -- Copyright : (c) The FFI task force 2001
6 -- License : BSD-style (see the file libraries/base/LICENSE)
8 -- Maintainer : ffi@haskell.org
9 -- Stability : provisional
10 -- Portability : portable
12 -- C-specific Marshalling support: Handling of C "errno" error codes
14 -----------------------------------------------------------------------------
16 module Foreign.C.Error (
18 -- Haskell representation for "errno" values
20 Errno(..), -- instance: Eq
21 eOK, e2BIG, eACCES, eADDRINUSE, eADDRNOTAVAIL, eADV, eAFNOSUPPORT, eAGAIN,
22 eALREADY, eBADF, eBADMSG, eBADRPC, eBUSY, eCHILD, eCOMM, eCONNABORTED,
23 eCONNREFUSED, eCONNRESET, eDEADLK, eDESTADDRREQ, eDIRTY, eDOM, eDQUOT,
24 eEXIST, eFAULT, eFBIG, eFTYPE, eHOSTDOWN, eHOSTUNREACH, eIDRM, eILSEQ,
25 eINPROGRESS, eINTR, eINVAL, eIO, eISCONN, eISDIR, eLOOP, eMFILE, eMLINK,
26 eMSGSIZE, eMULTIHOP, eNAMETOOLONG, eNETDOWN, eNETRESET, eNETUNREACH,
27 eNFILE, eNOBUFS, eNODATA, eNODEV, eNOENT, eNOEXEC, eNOLCK, eNOLINK,
28 eNOMEM, eNOMSG, eNONET, eNOPROTOOPT, eNOSPC, eNOSR, eNOSTR, eNOSYS,
29 eNOTBLK, eNOTCONN, eNOTDIR, eNOTEMPTY, eNOTSOCK, eNOTTY, eNXIO,
30 eOPNOTSUPP, ePERM, ePFNOSUPPORT, ePIPE, ePROCLIM, ePROCUNAVAIL,
31 ePROGMISMATCH, ePROGUNAVAIL, ePROTO, ePROTONOSUPPORT, ePROTOTYPE,
32 eRANGE, eREMCHG, eREMOTE, eROFS, eRPCMISMATCH, eRREMOTE, eSHUTDOWN,
33 eSOCKTNOSUPPORT, eSPIPE, eSRCH, eSRMNT, eSTALE, eTIME, eTIMEDOUT,
34 eTOOMANYREFS, eTXTBSY, eUSERS, eWOULDBLOCK, eXDEV,
36 isValidErrno, -- :: Errno -> Bool
38 -- access to the current thread's "errno" value
40 getErrno, -- :: IO Errno
41 resetErrno, -- :: IO ()
43 -- conversion of an "errno" value into IO error
45 errnoToIOError, -- :: String -- location
47 -- -> Maybe Handle -- handle
48 -- -> Maybe String -- filename
51 -- throw current "errno" value
53 throwErrno, -- :: String -> IO a
55 -- guards for IO operations that may fail
57 throwErrnoIf, -- :: (a -> Bool) -> String -> IO a -> IO a
58 throwErrnoIf_, -- :: (a -> Bool) -> String -> IO a -> IO ()
59 throwErrnoIfRetry, -- :: (a -> Bool) -> String -> IO a -> IO a
60 throwErrnoIfRetry_, -- :: (a -> Bool) -> String -> IO a -> IO ()
61 throwErrnoIfMinus1, -- :: Num a
62 -- => String -> IO a -> IO a
63 throwErrnoIfMinus1_, -- :: Num a
64 -- => String -> IO a -> IO ()
65 throwErrnoIfMinus1Retry,
67 -- => String -> IO a -> IO a
68 throwErrnoIfMinus1Retry_,
70 -- => String -> IO a -> IO ()
71 throwErrnoIfNull, -- :: String -> IO (Ptr a) -> IO (Ptr a)
72 throwErrnoIfNullRetry,-- :: String -> IO (Ptr a) -> IO (Ptr a)
74 throwErrnoIfRetryMayBlock,
75 throwErrnoIfRetryMayBlock_,
76 throwErrnoIfMinus1RetryMayBlock,
77 throwErrnoIfMinus1RetryMayBlock_,
78 throwErrnoIfNullRetryMayBlock
82 -- this is were we get the CCONST_XXX definitions from that configure
89 -- system dependent imports
90 -- ------------------------
92 -- GHC allows us to get at the guts inside IO errors/exceptions
94 #if __GLASGOW_HASKELL__
95 import GHC.IOBase (IOException(..), IOErrorType(..))
96 #endif /* __GLASGOW_HASKELL__ */
102 import Foreign.Storable
104 import Foreign.C.Types
105 import Foreign.C.String
106 import Foreign.Marshal.Error ( void )
109 #if __GLASGOW_HASKELL__
115 import System.IO ( IOError, Handle, ioError )
116 import System.IO.Unsafe ( unsafePerformIO )
122 -- import of C function that gives address of errno
123 -- This function exists because errno is a variable on some systems, but on
124 -- Windows it is a macro for a function...
125 -- [yes, global variables and thread safety don't really go hand-in-hand. -- sof]
127 foreign import ccall unsafe "errno.h &errno" _errno :: Ptr CInt
129 foreign import ccall unsafe "HsBase.h ghcErrno" _errno :: Ptr CInt
132 -- Haskell representation for "errno" values
134 newtype Errno = Errno CInt
136 instance Eq Errno where
137 errno1@(Errno no1) == errno2@(Errno no2)
138 | isValidErrno errno1 && isValidErrno errno2 = no1 == no2
141 -- common "errno" symbols
143 eOK, e2BIG, eACCES, eADDRINUSE, eADDRNOTAVAIL, eADV, eAFNOSUPPORT, eAGAIN,
144 eALREADY, eBADF, eBADMSG, eBADRPC, eBUSY, eCHILD, eCOMM, eCONNABORTED,
145 eCONNREFUSED, eCONNRESET, eDEADLK, eDESTADDRREQ, eDIRTY, eDOM, eDQUOT,
146 eEXIST, eFAULT, eFBIG, eFTYPE, eHOSTDOWN, eHOSTUNREACH, eIDRM, eILSEQ,
147 eINPROGRESS, eINTR, eINVAL, eIO, eISCONN, eISDIR, eLOOP, eMFILE, eMLINK,
148 eMSGSIZE, eMULTIHOP, eNAMETOOLONG, eNETDOWN, eNETRESET, eNETUNREACH,
149 eNFILE, eNOBUFS, eNODATA, eNODEV, eNOENT, eNOEXEC, eNOLCK, eNOLINK,
150 eNOMEM, eNOMSG, eNONET, eNOPROTOOPT, eNOSPC, eNOSR, eNOSTR, eNOSYS,
151 eNOTBLK, eNOTCONN, eNOTDIR, eNOTEMPTY, eNOTSOCK, eNOTTY, eNXIO,
152 eOPNOTSUPP, ePERM, ePFNOSUPPORT, ePIPE, ePROCLIM, ePROCUNAVAIL,
153 ePROGMISMATCH, ePROGUNAVAIL, ePROTO, ePROTONOSUPPORT, ePROTOTYPE,
154 eRANGE, eREMCHG, eREMOTE, eROFS, eRPCMISMATCH, eRREMOTE, eSHUTDOWN,
155 eSOCKTNOSUPPORT, eSPIPE, eSRCH, eSRMNT, eSTALE, eTIME, eTIMEDOUT,
156 eTOOMANYREFS, eTXTBSY, eUSERS, eWOULDBLOCK, eXDEV :: Errno
158 -- the cCONST_XXX identifiers are cpp symbols whose value is computed by
165 e2BIG = Errno (CCONST_E2BIG)
166 eACCES = Errno (CCONST_EACCES)
167 eADDRINUSE = Errno (CCONST_EADDRINUSE)
168 eADDRNOTAVAIL = Errno (CCONST_EADDRNOTAVAIL)
169 eADV = Errno (CCONST_EADV)
170 eAFNOSUPPORT = Errno (CCONST_EAFNOSUPPORT)
171 eAGAIN = Errno (CCONST_EAGAIN)
172 eALREADY = Errno (CCONST_EALREADY)
173 eBADF = Errno (CCONST_EBADF)
174 eBADMSG = Errno (CCONST_EBADMSG)
175 eBADRPC = Errno (CCONST_EBADRPC)
176 eBUSY = Errno (CCONST_EBUSY)
177 eCHILD = Errno (CCONST_ECHILD)
178 eCOMM = Errno (CCONST_ECOMM)
179 eCONNABORTED = Errno (CCONST_ECONNABORTED)
180 eCONNREFUSED = Errno (CCONST_ECONNREFUSED)
181 eCONNRESET = Errno (CCONST_ECONNRESET)
182 eDEADLK = Errno (CCONST_EDEADLK)
183 eDESTADDRREQ = Errno (CCONST_EDESTADDRREQ)
184 eDIRTY = Errno (CCONST_EDIRTY)
185 eDOM = Errno (CCONST_EDOM)
186 eDQUOT = Errno (CCONST_EDQUOT)
187 eEXIST = Errno (CCONST_EEXIST)
188 eFAULT = Errno (CCONST_EFAULT)
189 eFBIG = Errno (CCONST_EFBIG)
190 eFTYPE = Errno (CCONST_EFTYPE)
191 eHOSTDOWN = Errno (CCONST_EHOSTDOWN)
192 eHOSTUNREACH = Errno (CCONST_EHOSTUNREACH)
193 eIDRM = Errno (CCONST_EIDRM)
194 eILSEQ = Errno (CCONST_EILSEQ)
195 eINPROGRESS = Errno (CCONST_EINPROGRESS)
196 eINTR = Errno (CCONST_EINTR)
197 eINVAL = Errno (CCONST_EINVAL)
198 eIO = Errno (CCONST_EIO)
199 eISCONN = Errno (CCONST_EISCONN)
200 eISDIR = Errno (CCONST_EISDIR)
201 eLOOP = Errno (CCONST_ELOOP)
202 eMFILE = Errno (CCONST_EMFILE)
203 eMLINK = Errno (CCONST_EMLINK)
204 eMSGSIZE = Errno (CCONST_EMSGSIZE)
205 eMULTIHOP = Errno (CCONST_EMULTIHOP)
206 eNAMETOOLONG = Errno (CCONST_ENAMETOOLONG)
207 eNETDOWN = Errno (CCONST_ENETDOWN)
208 eNETRESET = Errno (CCONST_ENETRESET)
209 eNETUNREACH = Errno (CCONST_ENETUNREACH)
210 eNFILE = Errno (CCONST_ENFILE)
211 eNOBUFS = Errno (CCONST_ENOBUFS)
212 eNODATA = Errno (CCONST_ENODATA)
213 eNODEV = Errno (CCONST_ENODEV)
214 eNOENT = Errno (CCONST_ENOENT)
215 eNOEXEC = Errno (CCONST_ENOEXEC)
216 eNOLCK = Errno (CCONST_ENOLCK)
217 eNOLINK = Errno (CCONST_ENOLINK)
218 eNOMEM = Errno (CCONST_ENOMEM)
219 eNOMSG = Errno (CCONST_ENOMSG)
220 eNONET = Errno (CCONST_ENONET)
221 eNOPROTOOPT = Errno (CCONST_ENOPROTOOPT)
222 eNOSPC = Errno (CCONST_ENOSPC)
223 eNOSR = Errno (CCONST_ENOSR)
224 eNOSTR = Errno (CCONST_ENOSTR)
225 eNOSYS = Errno (CCONST_ENOSYS)
226 eNOTBLK = Errno (CCONST_ENOTBLK)
227 eNOTCONN = Errno (CCONST_ENOTCONN)
228 eNOTDIR = Errno (CCONST_ENOTDIR)
229 eNOTEMPTY = Errno (CCONST_ENOTEMPTY)
230 eNOTSOCK = Errno (CCONST_ENOTSOCK)
231 eNOTTY = Errno (CCONST_ENOTTY)
232 eNXIO = Errno (CCONST_ENXIO)
233 eOPNOTSUPP = Errno (CCONST_EOPNOTSUPP)
234 ePERM = Errno (CCONST_EPERM)
235 ePFNOSUPPORT = Errno (CCONST_EPFNOSUPPORT)
236 ePIPE = Errno (CCONST_EPIPE)
237 ePROCLIM = Errno (CCONST_EPROCLIM)
238 ePROCUNAVAIL = Errno (CCONST_EPROCUNAVAIL)
239 ePROGMISMATCH = Errno (CCONST_EPROGMISMATCH)
240 ePROGUNAVAIL = Errno (CCONST_EPROGUNAVAIL)
241 ePROTO = Errno (CCONST_EPROTO)
242 ePROTONOSUPPORT = Errno (CCONST_EPROTONOSUPPORT)
243 ePROTOTYPE = Errno (CCONST_EPROTOTYPE)
244 eRANGE = Errno (CCONST_ERANGE)
245 eREMCHG = Errno (CCONST_EREMCHG)
246 eREMOTE = Errno (CCONST_EREMOTE)
247 eROFS = Errno (CCONST_EROFS)
248 eRPCMISMATCH = Errno (CCONST_ERPCMISMATCH)
249 eRREMOTE = Errno (CCONST_ERREMOTE)
250 eSHUTDOWN = Errno (CCONST_ESHUTDOWN)
251 eSOCKTNOSUPPORT = Errno (CCONST_ESOCKTNOSUPPORT)
252 eSPIPE = Errno (CCONST_ESPIPE)
253 eSRCH = Errno (CCONST_ESRCH)
254 eSRMNT = Errno (CCONST_ESRMNT)
255 eSTALE = Errno (CCONST_ESTALE)
256 eTIME = Errno (CCONST_ETIME)
257 eTIMEDOUT = Errno (CCONST_ETIMEDOUT)
258 eTOOMANYREFS = Errno (CCONST_ETOOMANYREFS)
259 eTXTBSY = Errno (CCONST_ETXTBSY)
260 eUSERS = Errno (CCONST_EUSERS)
261 eWOULDBLOCK = Errno (CCONST_EWOULDBLOCK)
262 eXDEV = Errno (CCONST_EXDEV)
265 -- checks whether the given errno value is supported on the current
268 isValidErrno :: Errno -> Bool
270 -- the configure script sets all invalid "errno"s to -1
272 isValidErrno (Errno errno) = errno /= -1
275 -- access to the current thread's "errno" value
276 -- --------------------------------------------
278 -- yield the current thread's "errno" value
281 getErrno = do e <- peek _errno; return (Errno e)
283 -- set the current thread's "errno" value to 0
286 resetErrno = poke _errno 0
289 -- throw current "errno" value
290 -- ---------------------------
292 -- the common case: throw an IO error based on a textual description
293 -- of the error location and the current thread's "errno" value
295 throwErrno :: String -> IO a
299 ioError (errnoToIOError loc errno Nothing Nothing)
302 -- guards for IO operations that may fail
303 -- --------------------------------------
305 -- guard an IO operation and throw an "errno" based exception of the result
306 -- value of the IO operation meets the given predicate
308 throwErrnoIf :: (a -> Bool) -> String -> IO a -> IO a
309 throwErrnoIf pred loc f =
312 if pred res then throwErrno loc else return res
314 -- as `throwErrnoIf', but discards the result
316 throwErrnoIf_ :: (a -> Bool) -> String -> IO a -> IO ()
317 throwErrnoIf_ pred loc f = void $ throwErrnoIf pred loc f
319 -- as `throwErrnoIf', but retries interrupted IO operations (ie, those whose
322 throwErrnoIfRetry :: (a -> Bool) -> String -> IO a -> IO a
323 throwErrnoIfRetry pred loc f =
330 then throwErrnoIfRetry pred loc f
334 -- as `throwErrnoIfRetry', but checks for operations that would block and
335 -- executes an alternative action in that case.
337 throwErrnoIfRetryMayBlock :: (a -> Bool) -> String -> IO a -> IO b -> IO a
338 throwErrnoIfRetryMayBlock pred loc f on_block =
345 then throwErrnoIfRetryMayBlock pred loc f on_block
346 else if err == eWOULDBLOCK || err == eAGAIN
347 then do on_block; throwErrnoIfRetryMayBlock pred loc f on_block
351 -- as `throwErrnoIfRetry', but discards the result
353 throwErrnoIfRetry_ :: (a -> Bool) -> String -> IO a -> IO ()
354 throwErrnoIfRetry_ pred loc f = void $ throwErrnoIfRetry pred loc f
356 -- as `throwErrnoIfRetryMayBlock', but discards the result
358 throwErrnoIfRetryMayBlock_ :: (a -> Bool) -> String -> IO a -> IO b -> IO ()
359 throwErrnoIfRetryMayBlock_ pred loc f on_block
360 = void $ throwErrnoIfRetryMayBlock pred loc f on_block
362 -- throws "errno" if a result of "-1" is returned
364 throwErrnoIfMinus1 :: Num a => String -> IO a -> IO a
365 throwErrnoIfMinus1 = throwErrnoIf (== -1)
367 -- as `throwErrnoIfMinus1', but discards the result
369 throwErrnoIfMinus1_ :: Num a => String -> IO a -> IO ()
370 throwErrnoIfMinus1_ = throwErrnoIf_ (== -1)
372 -- throws "errno" if a result of "-1" is returned, but retries in case of an
373 -- interrupted operation
375 throwErrnoIfMinus1Retry :: Num a => String -> IO a -> IO a
376 throwErrnoIfMinus1Retry = throwErrnoIfRetry (== -1)
378 -- as `throwErrnoIfMinus1', but discards the result
380 throwErrnoIfMinus1Retry_ :: Num a => String -> IO a -> IO ()
381 throwErrnoIfMinus1Retry_ = throwErrnoIfRetry_ (== -1)
383 -- as throwErrnoIfMinus1Retry, but checks for operations that would block
385 throwErrnoIfMinus1RetryMayBlock :: Num a => String -> IO a -> IO b -> IO a
386 throwErrnoIfMinus1RetryMayBlock = throwErrnoIfRetryMayBlock (== -1)
388 -- as `throwErrnoIfMinus1RetryMayBlock', but discards the result
390 throwErrnoIfMinus1RetryMayBlock_ :: Num a => String -> IO a -> IO b -> IO ()
391 throwErrnoIfMinus1RetryMayBlock_ = throwErrnoIfRetryMayBlock_ (== -1)
393 -- throws "errno" if a result of a NULL pointer is returned
395 throwErrnoIfNull :: String -> IO (Ptr a) -> IO (Ptr a)
396 throwErrnoIfNull = throwErrnoIf (== nullPtr)
398 -- throws "errno" if a result of a NULL pointer is returned, but retries in
399 -- case of an interrupted operation
401 throwErrnoIfNullRetry :: String -> IO (Ptr a) -> IO (Ptr a)
402 throwErrnoIfNullRetry = throwErrnoIfRetry (== nullPtr)
404 -- as throwErrnoIfNullRetry, but checks for operations that would block
406 throwErrnoIfNullRetryMayBlock :: String -> IO (Ptr a) -> IO b -> IO (Ptr a)
407 throwErrnoIfNullRetryMayBlock = throwErrnoIfRetryMayBlock (== nullPtr)
409 -- conversion of an "errno" value into IO error
410 -- --------------------------------------------
412 -- convert a location string, an "errno" value, an optional handle,
413 -- and an optional filename into a matching IO error
415 errnoToIOError :: String -> Errno -> Maybe Handle -> Maybe String -> IOError
416 errnoToIOError loc errno maybeHdl maybeName = unsafePerformIO $ do
417 str <- strerror errno >>= peekCString
418 #if __GLASGOW_HASKELL__
419 return (IOError maybeHdl errType loc str maybeName)
422 | errno == eOK = OtherError
423 | errno == e2BIG = ResourceExhausted
424 | errno == eACCES = PermissionDenied
425 | errno == eADDRINUSE = ResourceBusy
426 | errno == eADDRNOTAVAIL = UnsupportedOperation
427 | errno == eADV = OtherError
428 | errno == eAFNOSUPPORT = UnsupportedOperation
429 | errno == eAGAIN = ResourceExhausted
430 | errno == eALREADY = AlreadyExists
431 | errno == eBADF = OtherError
432 | errno == eBADMSG = InappropriateType
433 | errno == eBADRPC = OtherError
434 | errno == eBUSY = ResourceBusy
435 | errno == eCHILD = NoSuchThing
436 | errno == eCOMM = ResourceVanished
437 | errno == eCONNABORTED = OtherError
438 | errno == eCONNREFUSED = NoSuchThing
439 | errno == eCONNRESET = ResourceVanished
440 | errno == eDEADLK = ResourceBusy
441 | errno == eDESTADDRREQ = InvalidArgument
442 | errno == eDIRTY = UnsatisfiedConstraints
443 | errno == eDOM = InvalidArgument
444 | errno == eDQUOT = PermissionDenied
445 | errno == eEXIST = AlreadyExists
446 | errno == eFAULT = OtherError
447 | errno == eFBIG = PermissionDenied
448 | errno == eFTYPE = InappropriateType
449 | errno == eHOSTDOWN = NoSuchThing
450 | errno == eHOSTUNREACH = NoSuchThing
451 | errno == eIDRM = ResourceVanished
452 | errno == eILSEQ = InvalidArgument
453 | errno == eINPROGRESS = AlreadyExists
454 | errno == eINTR = Interrupted
455 | errno == eINVAL = InvalidArgument
456 | errno == eIO = HardwareFault
457 | errno == eISCONN = AlreadyExists
458 | errno == eISDIR = InappropriateType
459 | errno == eLOOP = InvalidArgument
460 | errno == eMFILE = ResourceExhausted
461 | errno == eMLINK = ResourceExhausted
462 | errno == eMSGSIZE = ResourceExhausted
463 | errno == eMULTIHOP = UnsupportedOperation
464 | errno == eNAMETOOLONG = InvalidArgument
465 | errno == eNETDOWN = ResourceVanished
466 | errno == eNETRESET = ResourceVanished
467 | errno == eNETUNREACH = NoSuchThing
468 | errno == eNFILE = ResourceExhausted
469 | errno == eNOBUFS = ResourceExhausted
470 | errno == eNODATA = NoSuchThing
471 | errno == eNODEV = UnsupportedOperation
472 | errno == eNOENT = NoSuchThing
473 | errno == eNOEXEC = InvalidArgument
474 | errno == eNOLCK = ResourceExhausted
475 | errno == eNOLINK = ResourceVanished
476 | errno == eNOMEM = ResourceExhausted
477 | errno == eNOMSG = NoSuchThing
478 | errno == eNONET = NoSuchThing
479 | errno == eNOPROTOOPT = UnsupportedOperation
480 | errno == eNOSPC = ResourceExhausted
481 | errno == eNOSR = ResourceExhausted
482 | errno == eNOSTR = InvalidArgument
483 | errno == eNOSYS = UnsupportedOperation
484 | errno == eNOTBLK = InvalidArgument
485 | errno == eNOTCONN = InvalidArgument
486 | errno == eNOTDIR = InappropriateType
487 | errno == eNOTEMPTY = UnsatisfiedConstraints
488 | errno == eNOTSOCK = InvalidArgument
489 | errno == eNOTTY = IllegalOperation
490 | errno == eNXIO = NoSuchThing
491 | errno == eOPNOTSUPP = UnsupportedOperation
492 | errno == ePERM = PermissionDenied
493 | errno == ePFNOSUPPORT = UnsupportedOperation
494 | errno == ePIPE = ResourceVanished
495 | errno == ePROCLIM = PermissionDenied
496 | errno == ePROCUNAVAIL = UnsupportedOperation
497 | errno == ePROGMISMATCH = ProtocolError
498 | errno == ePROGUNAVAIL = UnsupportedOperation
499 | errno == ePROTO = ProtocolError
500 | errno == ePROTONOSUPPORT = ProtocolError
501 | errno == ePROTOTYPE = ProtocolError
502 | errno == eRANGE = UnsupportedOperation
503 | errno == eREMCHG = ResourceVanished
504 | errno == eREMOTE = IllegalOperation
505 | errno == eROFS = PermissionDenied
506 | errno == eRPCMISMATCH = ProtocolError
507 | errno == eRREMOTE = IllegalOperation
508 | errno == eSHUTDOWN = IllegalOperation
509 | errno == eSOCKTNOSUPPORT = UnsupportedOperation
510 | errno == eSPIPE = UnsupportedOperation
511 | errno == eSRCH = NoSuchThing
512 | errno == eSRMNT = UnsatisfiedConstraints
513 | errno == eSTALE = ResourceVanished
514 | errno == eTIME = TimeExpired
515 | errno == eTIMEDOUT = TimeExpired
516 | errno == eTOOMANYREFS = ResourceExhausted
517 | errno == eTXTBSY = ResourceBusy
518 | errno == eUSERS = ResourceExhausted
519 | errno == eWOULDBLOCK = OtherError
520 | errno == eXDEV = UnsupportedOperation
521 | otherwise = OtherError
523 return (userError (loc ++ ": " ++ str ++ maybe "" (": "++) maybeName))
526 foreign import ccall unsafe "string.h" strerror :: Errno -> IO (Ptr CChar)