Error.hs 12.3 KB
Newer Older
1
{-# LANGUAGE Trustworthy #-}
2
{-# LANGUAGE NoImplicitPrelude #-}
3 4

-----------------------------------------------------------------------------
5
-- |
6 7
-- Module      :  System.IO.Error
-- Copyright   :  (c) The University of Glasgow 2001
8
-- License     :  BSD-style (see the file libraries/base/LICENSE)
9
--
10 11 12 13 14 15 16 17 18 19
-- Maintainer  :  libraries@haskell.org
-- Stability   :  provisional
-- Portability :  portable
--
-- Standard IO Errors.
--
-----------------------------------------------------------------------------

module System.IO.Error (

ross's avatar
ross committed
20
    -- * I\/O errors
21
    IOError,
ross's avatar
ross committed
22

23
    userError,
24

25
    mkIOError,
26

27
    annotateIOError,
28

ross's avatar
ross committed
29
    -- ** Classifying I\/O errors
30
    isAlreadyExistsError,
ross's avatar
ross committed
31 32
    isDoesNotExistError,
    isAlreadyInUseError,
33
    isFullError,
ross's avatar
ross committed
34
    isEOFError,
35
    isIllegalOperation,
ross's avatar
ross committed
36 37
    isPermissionError,
    isUserError,
38
    isResourceVanishedError,
ross's avatar
ross committed
39 40

    -- ** Attributes of I\/O errors
41 42 43 44 45 46 47 48 49 50 51
    ioeGetErrorType,
    ioeGetLocation,
    ioeGetErrorString,
    ioeGetHandle,
    ioeGetFileName,

    ioeSetErrorType,
    ioeSetErrorString,
    ioeSetLocation,
    ioeSetHandle,
    ioeSetFileName,
52

ross's avatar
ross committed
53
    -- * Types of I\/O error
Don Stewart's avatar
Don Stewart committed
54
    IOErrorType,                -- abstract
ross's avatar
ross committed
55

56
    alreadyExistsErrorType,
57 58 59 60
    doesNotExistErrorType,
    alreadyInUseErrorType,
    fullErrorType,
    eofErrorType,
61
    illegalOperationErrorType,
62 63
    permissionErrorType,
    userErrorType,
64
    resourceVanishedErrorType,
65

ross's avatar
ross committed
66
    -- ** 'IOErrorType' predicates
67
    isAlreadyExistsErrorType,
68 69
    isDoesNotExistErrorType,
    isAlreadyInUseErrorType,
70
    isFullErrorType,
71
    isEOFErrorType,
72
    isIllegalOperationErrorType,
73
    isPermissionErrorType,
74
    isUserErrorType,
75
    isResourceVanishedErrorType,
76

ross's avatar
ross committed
77
    -- * Throwing and catching I\/O errors
78

79
    ioError,
ross's avatar
ross committed
80

81 82
    catchIOError,
    tryIOError,
83

84
    modifyIOError,
85 86
  ) where

87
import Control.Exception.Base
88

ross's avatar
ross committed
89
import Data.Either
ross's avatar
ross committed
90
import Data.Maybe
91 92

import GHC.Base
93 94 95
import GHC.IO
import GHC.IO.Exception
import GHC.IO.Handle.Types
96 97
import Text.Show

98
-- | The construct 'tryIOError' @comp@ exposes IO errors which occur within a
ross's avatar
ross committed
99
-- computation, and which are not fully handled.
ross's avatar
ross committed
100 101 102
--
-- Non-I\/O exceptions are not caught by this variant; to catch all
-- exceptions, use 'Control.Exception.try' from "Control.Exception".
103
--
104
-- @since 4.4.0.0
105 106 107 108
tryIOError     :: IO a -> IO (Either IOError a)
tryIOError f   =  catch (do r <- f
                            return (Right r))
                        (return . Left)
ross's avatar
ross committed
109

110 111 112
-- -----------------------------------------------------------------------------
-- Constructing an IOError

ross's avatar
ross committed
113 114 115 116
-- | Construct an 'IOError' of the given type where the second argument
-- describes the error location and the third and fourth argument
-- contain the file handle and file path of the file involved in the
-- error if applicable.
117 118
mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> IOError
mkIOError t location maybe_hdl maybe_filename =
119
               IOError{ ioe_type = t,
Don Stewart's avatar
Don Stewart committed
120 121
                        ioe_location = location,
                        ioe_description = "",
Ian Lynagh's avatar
Ian Lynagh committed
122
                        ioe_errno = Nothing,
123
                        ioe_handle = maybe_hdl,
Don Stewart's avatar
Don Stewart committed
124 125
                        ioe_filename = maybe_filename
                        }
126

127 128 129
-- -----------------------------------------------------------------------------
-- IOErrorType

ross's avatar
ross committed
130 131 132
-- | An error indicating that an 'IO' operation failed because
-- one of its arguments already exists.
isAlreadyExistsError :: IOError -> Bool
133
isAlreadyExistsError = isAlreadyExistsErrorType    . ioeGetErrorType
ross's avatar
ross committed
134 135 136 137

-- | An error indicating that an 'IO' operation failed because
-- one of its arguments does not exist.
isDoesNotExistError :: IOError -> Bool
138
isDoesNotExistError  = isDoesNotExistErrorType     . ioeGetErrorType
ross's avatar
ross committed
139 140 141 142 143 144

-- | An error indicating that an 'IO' operation failed because
-- one of its arguments is a single-use resource, which is already
-- being used (for example, opening the same file twice for writing
-- might give this error).
isAlreadyInUseError :: IOError -> Bool
145
isAlreadyInUseError  = isAlreadyInUseErrorType     . ioeGetErrorType
ross's avatar
ross committed
146 147 148 149

-- | An error indicating that an 'IO' operation failed because
-- the device is full.
isFullError         :: IOError -> Bool
150
isFullError          = isFullErrorType             . ioeGetErrorType
ross's avatar
ross committed
151 152 153 154

-- | An error indicating that an 'IO' operation failed because
-- the end of file has been reached.
isEOFError          :: IOError -> Bool
155
isEOFError           = isEOFErrorType              . ioeGetErrorType
ross's avatar
ross committed
156 157 158 159 160 161 162 163

-- | An error indicating that an 'IO' operation failed because
-- the operation was not possible.
-- Any computation which returns an 'IO' result may fail with
-- 'isIllegalOperation'.  In some cases, an implementation will not be
-- able to distinguish between the possible error causes.  In this case
-- it should fail with 'isIllegalOperation'.
isIllegalOperation  :: IOError -> Bool
164
isIllegalOperation   = isIllegalOperationErrorType . ioeGetErrorType
ross's avatar
ross committed
165 166 167 168 169

-- | An error indicating that an 'IO' operation failed because
-- the user does not have sufficient operating system privilege
-- to perform that operation.
isPermissionError   :: IOError -> Bool
170
isPermissionError    = isPermissionErrorType       . ioeGetErrorType
ross's avatar
ross committed
171 172 173

-- | A programmer-defined error value constructed using 'userError'.
isUserError         :: IOError -> Bool
174 175
isUserError          = isUserErrorType             . ioeGetErrorType

176 177 178
-- | An error indicating that the operation failed because the
-- resource vanished. See 'resourceVanishedErrorType'.
--
179
-- @since 4.14.0.0
180 181 182
isResourceVanishedError :: IOError -> Bool
isResourceVanishedError = isResourceVanishedErrorType . ioeGetErrorType

183 184 185
-- -----------------------------------------------------------------------------
-- IOErrorTypes

ross's avatar
ross committed
186 187 188
-- | I\/O error where the operation failed because one of its arguments
-- already exists.
alreadyExistsErrorType   :: IOErrorType
189
alreadyExistsErrorType    = AlreadyExists
ross's avatar
ross committed
190 191 192 193

-- | I\/O error where the operation failed because one of its arguments
-- does not exist.
doesNotExistErrorType    :: IOErrorType
194
doesNotExistErrorType     = NoSuchThing
ross's avatar
ross committed
195 196 197 198

-- | I\/O error where the operation failed because one of its arguments
-- is a single-use resource, which is already being used.
alreadyInUseErrorType    :: IOErrorType
199
alreadyInUseErrorType     = ResourceBusy
ross's avatar
ross committed
200 201 202

-- | I\/O error where the operation failed because the device is full.
fullErrorType            :: IOErrorType
203
fullErrorType             = ResourceExhausted
ross's avatar
ross committed
204 205 206 207

-- | I\/O error where the operation failed because the end of file has
-- been reached.
eofErrorType             :: IOErrorType
208
eofErrorType              = EOF
ross's avatar
ross committed
209 210 211

-- | I\/O error where the operation is not possible.
illegalOperationErrorType :: IOErrorType
212
illegalOperationErrorType = IllegalOperation
ross's avatar
ross committed
213 214 215 216

-- | I\/O error where the operation failed because the user does not
-- have sufficient operating system privilege to perform that operation.
permissionErrorType      :: IOErrorType
217
permissionErrorType       = PermissionDenied
ross's avatar
ross committed
218 219

-- | I\/O error that is programmer-defined.
Don Stewart's avatar
Don Stewart committed
220 221
userErrorType            :: IOErrorType
userErrorType             = UserError
222

223 224 225 226
-- | I\/O error where the operation failed because the resource vanished.
-- This happens when, for example, attempting to write to a closed
-- socket or attempting to write to a named pipe that was deleted.
--
227
-- @since 4.14.0.0
228 229 230
resourceVanishedErrorType :: IOErrorType
resourceVanishedErrorType = ResourceVanished

231 232 233
-- -----------------------------------------------------------------------------
-- IOErrorType predicates

ross's avatar
ross committed
234 235 236
-- | I\/O error where the operation failed because one of its arguments
-- already exists.
isAlreadyExistsErrorType :: IOErrorType -> Bool
237 238 239
isAlreadyExistsErrorType AlreadyExists = True
isAlreadyExistsErrorType _ = False

ross's avatar
ross committed
240 241 242
-- | I\/O error where the operation failed because one of its arguments
-- does not exist.
isDoesNotExistErrorType :: IOErrorType -> Bool
243 244 245
isDoesNotExistErrorType NoSuchThing = True
isDoesNotExistErrorType _ = False

ross's avatar
ross committed
246 247 248
-- | I\/O error where the operation failed because one of its arguments
-- is a single-use resource, which is already being used.
isAlreadyInUseErrorType :: IOErrorType -> Bool
249 250 251
isAlreadyInUseErrorType ResourceBusy = True
isAlreadyInUseErrorType _ = False

ross's avatar
ross committed
252 253
-- | I\/O error where the operation failed because the device is full.
isFullErrorType :: IOErrorType -> Bool
254 255 256
isFullErrorType ResourceExhausted = True
isFullErrorType _ = False

ross's avatar
ross committed
257 258 259
-- | I\/O error where the operation failed because the end of file has
-- been reached.
isEOFErrorType :: IOErrorType -> Bool
260 261 262
isEOFErrorType EOF = True
isEOFErrorType _ = False

ross's avatar
ross committed
263 264
-- | I\/O error where the operation is not possible.
isIllegalOperationErrorType :: IOErrorType -> Bool
265 266 267
isIllegalOperationErrorType IllegalOperation = True
isIllegalOperationErrorType _ = False

ross's avatar
ross committed
268 269 270
-- | I\/O error where the operation failed because the user does not
-- have sufficient operating system privilege to perform that operation.
isPermissionErrorType :: IOErrorType -> Bool
271 272 273
isPermissionErrorType PermissionDenied = True
isPermissionErrorType _ = False

ross's avatar
ross committed
274 275
-- | I\/O error that is programmer-defined.
isUserErrorType :: IOErrorType -> Bool
276 277 278
isUserErrorType UserError = True
isUserErrorType _ = False

279 280 281
-- | I\/O error where the operation failed because the resource vanished.
-- See 'resourceVanishedErrorType'.
--
282
-- @since 4.14.0.0
283 284 285 286
isResourceVanishedErrorType :: IOErrorType -> Bool
isResourceVanishedErrorType ResourceVanished = True
isResourceVanishedErrorType _ = False

287 288 289
-- -----------------------------------------------------------------------------
-- Miscellaneous

Don Stewart's avatar
Don Stewart committed
290
ioeGetErrorType       :: IOError -> IOErrorType
291
ioeGetErrorString     :: IOError -> String
292
ioeGetLocation        :: IOError -> String
293
ioeGetHandle          :: IOError -> Maybe Handle
294
ioeGetFileName        :: IOError -> Maybe FilePath
295

ross's avatar
ross committed
296
ioeGetErrorType ioe = ioe_type ioe
297

ross's avatar
ross committed
298
ioeGetErrorString ioe
ross's avatar
ross committed
299
   | isUserErrorType (ioe_type ioe) = ioe_description ioe
300 301
   | otherwise                      = show (ioe_type ioe)

302 303
ioeGetLocation ioe = ioe_location ioe

304 305
ioeGetHandle ioe = ioe_handle ioe

ross's avatar
ross committed
306
ioeGetFileName ioe = ioe_filename ioe
307

308 309 310 311 312
ioeSetErrorType   :: IOError -> IOErrorType -> IOError
ioeSetErrorString :: IOError -> String      -> IOError
ioeSetLocation    :: IOError -> String      -> IOError
ioeSetHandle      :: IOError -> Handle      -> IOError
ioeSetFileName    :: IOError -> FilePath    -> IOError
313 314 315

ioeSetErrorType   ioe errtype  = ioe{ ioe_type = errtype }
ioeSetErrorString ioe str      = ioe{ ioe_description = str }
316
ioeSetLocation    ioe str      = ioe{ ioe_location = str }
317 318 319
ioeSetHandle      ioe hdl      = ioe{ ioe_handle = Just hdl }
ioeSetFileName    ioe filename = ioe{ ioe_filename = Just filename }

ross's avatar
ross committed
320 321
-- | Catch any 'IOError' that occurs in the computation and throw a
-- modified version.
322
modifyIOError :: (IOError -> IOError) -> IO a -> IO a
ross's avatar
ross committed
323
modifyIOError f io = catch io (\e -> ioError (f e))
324

325 326 327
-- -----------------------------------------------------------------------------
-- annotating an IOError

ross's avatar
ross committed
328 329 330
-- | Adds a location description and maybe a file path and file handle
-- to an 'IOError'.  If any of the file handle or file path is not given
-- the corresponding value in the 'IOError' remains unaltered.
331 332 333 334 335 336
annotateIOError :: IOError
              -> String
              -> Maybe Handle
              -> Maybe FilePath
              -> IOError
annotateIOError ioe loc hdl path =
Ian Lynagh's avatar
Ian Lynagh committed
337 338
  ioe{ ioe_handle = hdl `mplus` ioe_handle ioe,
       ioe_location = loc, ioe_filename = path `mplus` ioe_filename ioe }
339

340 341 342 343 344
-- | The 'catchIOError' function establishes a handler that receives any
-- 'IOError' raised in the action protected by 'catchIOError'.
-- An 'IOError' is caught by
-- the most recent handler established by one of the exception handling
-- functions.  These handlers are
345 346 347 348
-- not selective: all 'IOError's are caught.  Exception propagation
-- must be explicitly provided in a handler by re-raising any unwanted
-- exceptions.  For example, in
--
349
-- > f = catchIOError g (\e -> if IO.isEOFError e then return [] else ioError e)
350 351 352 353 354 355 356 357 358 359
--
-- the function @f@ returns @[]@ when an end-of-file exception
-- (cf. 'System.IO.Error.isEOFError') occurs in @g@; otherwise, the
-- exception is propagated to the next outer handler.
--
-- When an exception propagates outside the main program, the Haskell
-- system prints the associated 'IOError' value and exits the program.
--
-- Non-I\/O exceptions are not caught by this variant; to catch all
-- exceptions, use 'Control.Exception.catch' from "Control.Exception".
360
--
361
-- @since 4.4.0.0
362
catchIOError :: IO a -> (IOError -> IO a) -> IO a
363
catchIOError = catch