1//  error_code support implementation file  ----------------------------------//
2
3//  Copyright Beman Dawes 2002, 2006
4//  Copyright (c) Microsoft Corporation 2014
5//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8//  See library home page at http://www.boost.org/libs/system
9
10//----------------------------------------------------------------------------//
11
12#include <boost/config/warning_disable.hpp>
13
14#include <boost/system/config.hpp>
15#include <boost/system/error_code.hpp>
16#include <boost/cerrno.hpp>
17#include <vector>
18#include <cstdlib>
19#include <cassert>
20
21#include <cstring> // for strerror/strerror_r
22
23# if defined( BOOST_WINDOWS_API )
24#   include <windows.h>
25#   if !BOOST_PLAT_WINDOWS_RUNTIME
26#     include <boost/system/detail/local_free_on_destruction.hpp>
27#   endif
28#   ifndef ERROR_INCORRECT_SIZE
29#     define ERROR_INCORRECT_SIZE ERROR_BAD_ARGUMENTS
30#   endif
31# endif
32
33//----------------------------------------------------------------------------//
34namespace boost
35{
36    namespace system
37    {
38
39namespace
40{
41
42  //  standard error categories  ---------------------------------------------//
43
44  class generic_error_category : public error_category
45  {
46  public:
47    generic_error_category(){}
48    const char *   name() const BOOST_SYSTEM_NOEXCEPT;
49    std::string    message( int ev ) const;
50  };
51
52  class system_error_category : public error_category
53  {
54  public:
55    system_error_category(){}
56    const char *        name() const BOOST_SYSTEM_NOEXCEPT;
57    std::string         message( int ev ) const;
58    error_condition     default_error_condition( int ev ) const BOOST_SYSTEM_NOEXCEPT;
59  };
60
61  //  generic_error_category implementation  ---------------------------------//
62
63  const char * generic_error_category::name() const BOOST_SYSTEM_NOEXCEPT
64  {
65    return "generic";
66  }
67
68  std::string generic_error_category::message( int ev ) const
69  {
70    using namespace boost::system::errc;
71#if defined(__PGI)
72      using boost::system::errc::invalid_argument;
73#endif
74
75    static std::string unknown_err( "Unknown error" );
76  // strerror_r is preferred because it is always thread safe,
77  // however, we fallback to strerror in certain cases because:
78  //   -- Windows doesn't provide strerror_r.
79  //   -- HP and Sun do provide strerror_r on newer systems, but there is
80  //      no way to tell if is available at runtime and in any case their
81  //      versions of strerror are thread safe anyhow.
82  //   -- Linux only sometimes provides strerror_r.
83  //   -- Tru64 provides strerror_r only when compiled -pthread.
84  //   -- VMS doesn't provide strerror_r, but on this platform, strerror is
85  //      thread safe.
86  # if defined(BOOST_WINDOWS_API) || defined(__hpux) || defined(__sun)\
87     || (defined(__linux) && (!defined(__USE_XOPEN2K) || defined(BOOST_SYSTEM_USE_STRERROR)))\
88     || (defined(__osf__) && !defined(_REENTRANT))\
89     || (defined(__INTEGRITY))\
90     || (defined(__vms))\
91     || (defined(__QNXNTO__))
92      const char * c_str = std::strerror( ev );
93      return  c_str
94        ? std::string( c_str )
95        : unknown_err;
96  # else  // use strerror_r
97      char buf[64];
98      char * bp = buf;
99      std::size_t sz = sizeof(buf);
100  #  if defined(__CYGWIN__) || defined(__USE_GNU)
101      // Oddball version of strerror_r
102      const char * c_str = strerror_r( ev, bp, sz );
103      return  c_str
104        ? std::string( c_str )
105        : unknown_err;
106  #  else
107      // POSIX version of strerror_r
108      int result;
109      for (;;)
110      {
111        // strerror_r returns 0 on success, otherwise ERANGE if buffer too small,
112        // invalid_argument if ev not a valid error number
113  #  if defined (__sgi)
114        const char * c_str = strerror( ev );
115        result = 0;
116      return  c_str
117        ? std::string( c_str )
118        : unknown_err;
119  #  else
120        result = strerror_r( ev, bp, sz );
121  #  endif
122        if (result == 0 )
123          break;
124        else
125        {
126  #  if defined(__linux)
127          // Linux strerror_r returns -1 on error, with error number in errno
128          result = errno;
129  #  endif
130          if ( result !=  ERANGE ) break;
131          if ( sz > sizeof(buf) ) std::free( bp );
132          sz *= 2;
133          if ( (bp = static_cast<char*>(std::malloc( sz ))) == 0 )
134            return std::string( "ENOMEM" );
135        }
136      }
137      std::string msg;
138#   ifndef BOOST_NO_EXCEPTIONS
139      try
140#   endif
141      {
142        msg = ( ( result == invalid_argument ) ? "Unknown error" : bp );
143      }
144
145#   ifndef BOOST_NO_EXCEPTIONS
146      // See ticket #2098
147      catch(...)
148      {
149        // just eat the exception
150      }
151#   endif
152
153      if ( sz > sizeof(buf) ) std::free( bp );
154      sz = 0;
155      return msg;
156  #  endif   // else POSIX version of strerror_r
157  # endif  // else use strerror_r
158  }
159  //  system_error_category implementation  --------------------------------//
160
161  const char * system_error_category::name() const BOOST_SYSTEM_NOEXCEPT
162  {
163    return "system";
164  }
165
166  error_condition system_error_category::default_error_condition( int ev ) const BOOST_SYSTEM_NOEXCEPT
167  {
168    using namespace boost::system::errc;
169#if defined(__PGI)
170      using boost::system::errc::invalid_argument;
171#endif
172
173# if defined(BOOST_WINDOWS_API)
174#   if defined(WINAPI_FAMILY) && ((WINAPI_FAMILY & WINAPI_PARTITION_APP) != 0)
175    // When using the Windows Runtime, most system errors are reported as HRESULTs.
176    // We want to map the common Win32 errors to their equivalent error condition,
177    // whether or not they are reported via an HRESULT.
178    if ( ev < 0 ) // Check for failed HRESULTs only.
179      if ( HRESULT_FACILITY( ev ) == FACILITY_WIN32 )
180        ev = HRESULT_CODE( ev );
181#   endif
182# endif
183
184    switch ( ev )
185    {
186    case 0: return make_error_condition( success );
187# if defined(BOOST_POSIX_API)
188    // POSIX-like O/S -> posix_errno decode table  ---------------------------//
189    case E2BIG: return make_error_condition( argument_list_too_long );
190    case EACCES: return make_error_condition( permission_denied );
191    case EADDRINUSE: return make_error_condition( address_in_use );
192    case EADDRNOTAVAIL: return make_error_condition( address_not_available );
193    case EAFNOSUPPORT: return make_error_condition( address_family_not_supported );
194    case EAGAIN: return make_error_condition( resource_unavailable_try_again );
195#   if EALREADY != EBUSY  //  EALREADY and EBUSY are the same on QNX Neutrino
196    case EALREADY: return make_error_condition( connection_already_in_progress );
197#   endif
198    case EBADF: return make_error_condition( bad_file_descriptor );
199    case EBADMSG: return make_error_condition( bad_message );
200    case EBUSY: return make_error_condition( device_or_resource_busy );
201    case ECANCELED: return make_error_condition( operation_canceled );
202    case ECHILD: return make_error_condition( no_child_process );
203    case ECONNABORTED: return make_error_condition( connection_aborted );
204    case ECONNREFUSED: return make_error_condition( connection_refused );
205    case ECONNRESET: return make_error_condition( connection_reset );
206    case EDEADLK: return make_error_condition( resource_deadlock_would_occur );
207    case EDESTADDRREQ: return make_error_condition( destination_address_required );
208    case EDOM: return make_error_condition( argument_out_of_domain );
209    case EEXIST: return make_error_condition( file_exists );
210    case EFAULT: return make_error_condition( bad_address );
211    case EFBIG: return make_error_condition( file_too_large );
212    case EHOSTUNREACH: return make_error_condition( host_unreachable );
213    case EIDRM: return make_error_condition( identifier_removed );
214    case EILSEQ: return make_error_condition( illegal_byte_sequence );
215    case EINPROGRESS: return make_error_condition( operation_in_progress );
216    case EINTR: return make_error_condition( interrupted );
217    case EINVAL: return make_error_condition( invalid_argument );
218    case EIO: return make_error_condition( io_error );
219    case EISCONN: return make_error_condition( already_connected );
220    case EISDIR: return make_error_condition( is_a_directory );
221    case ELOOP: return make_error_condition( too_many_symbolic_link_levels );
222    case EMFILE: return make_error_condition( too_many_files_open );
223    case EMLINK: return make_error_condition( too_many_links );
224    case EMSGSIZE: return make_error_condition( message_size );
225    case ENAMETOOLONG: return make_error_condition( filename_too_long );
226    case ENETDOWN: return make_error_condition( network_down );
227    case ENETRESET: return make_error_condition( network_reset );
228    case ENETUNREACH: return make_error_condition( network_unreachable );
229    case ENFILE: return make_error_condition( too_many_files_open_in_system );
230    case ENOBUFS: return make_error_condition( no_buffer_space );
231    case ENODATA: return make_error_condition( no_message_available );
232    case ENODEV: return make_error_condition( no_such_device );
233    case ENOENT: return make_error_condition( no_such_file_or_directory );
234    case ENOEXEC: return make_error_condition( executable_format_error );
235    case ENOLCK: return make_error_condition( no_lock_available );
236    case ENOLINK: return make_error_condition( no_link );
237    case ENOMEM: return make_error_condition( not_enough_memory );
238    case ENOMSG: return make_error_condition( no_message );
239    case ENOPROTOOPT: return make_error_condition( no_protocol_option );
240    case ENOSPC: return make_error_condition( no_space_on_device );
241    case ENOSR: return make_error_condition( no_stream_resources );
242    case ENOSTR: return make_error_condition( not_a_stream );
243    case ENOSYS: return make_error_condition( function_not_supported );
244    case ENOTCONN: return make_error_condition( not_connected );
245    case ENOTDIR: return make_error_condition( not_a_directory );
246  # if ENOTEMPTY != EEXIST // AIX treats ENOTEMPTY and EEXIST as the same value
247    case ENOTEMPTY: return make_error_condition( directory_not_empty );
248  # endif // ENOTEMPTY != EEXIST
249  # if ENOTRECOVERABLE != ECONNRESET // the same on some Broadcom chips
250    case ENOTRECOVERABLE: return make_error_condition( state_not_recoverable );
251  # endif // ENOTRECOVERABLE != ECONNRESET
252    case ENOTSOCK: return make_error_condition( not_a_socket );
253    case ENOTSUP: return make_error_condition( not_supported );
254    case ENOTTY: return make_error_condition( inappropriate_io_control_operation );
255    case ENXIO: return make_error_condition( no_such_device_or_address );
256  # if EOPNOTSUPP != ENOTSUP
257    case EOPNOTSUPP: return make_error_condition( operation_not_supported );
258  # endif // EOPNOTSUPP != ENOTSUP
259    case EOVERFLOW: return make_error_condition( value_too_large );
260  # if EOWNERDEAD != ECONNABORTED // the same on some Broadcom chips
261    case EOWNERDEAD: return make_error_condition( owner_dead );
262  # endif // EOWNERDEAD != ECONNABORTED
263    case EPERM: return make_error_condition( operation_not_permitted );
264    case EPIPE: return make_error_condition( broken_pipe );
265    case EPROTO: return make_error_condition( protocol_error );
266    case EPROTONOSUPPORT: return make_error_condition( protocol_not_supported );
267    case EPROTOTYPE: return make_error_condition( wrong_protocol_type );
268    case ERANGE: return make_error_condition( result_out_of_range );
269    case EROFS: return make_error_condition( read_only_file_system );
270    case ESPIPE: return make_error_condition( invalid_seek );
271    case ESRCH: return make_error_condition( no_such_process );
272    case ETIME: return make_error_condition( stream_timeout );
273    case ETIMEDOUT: return make_error_condition( timed_out );
274    case ETXTBSY: return make_error_condition( text_file_busy );
275  # if EAGAIN != EWOULDBLOCK
276    case EWOULDBLOCK: return make_error_condition( operation_would_block );
277  # endif // EAGAIN != EWOULDBLOCK
278    case EXDEV: return make_error_condition( cross_device_link );
279  #else
280    // Windows system -> posix_errno decode table  ---------------------------//
281    // see WinError.h comments for descriptions of errors
282    case ERROR_ACCESS_DENIED: return make_error_condition( permission_denied );
283    case ERROR_ALREADY_EXISTS: return make_error_condition( file_exists );
284    case ERROR_BAD_UNIT: return make_error_condition( no_such_device );
285    case ERROR_BUFFER_OVERFLOW: return make_error_condition( filename_too_long );
286    case ERROR_BUSY: return make_error_condition( device_or_resource_busy );
287    case ERROR_BUSY_DRIVE: return make_error_condition( device_or_resource_busy );
288    case ERROR_CANNOT_MAKE: return make_error_condition( permission_denied );
289    case ERROR_CANTOPEN: return make_error_condition( io_error );
290    case ERROR_CANTREAD: return make_error_condition( io_error );
291    case ERROR_CANTWRITE: return make_error_condition( io_error );
292    case ERROR_CURRENT_DIRECTORY: return make_error_condition( permission_denied );
293    case ERROR_DEV_NOT_EXIST: return make_error_condition( no_such_device );
294    case ERROR_DEVICE_IN_USE: return make_error_condition( device_or_resource_busy );
295    case ERROR_DIR_NOT_EMPTY: return make_error_condition( directory_not_empty );
296    case ERROR_DIRECTORY: return make_error_condition( invalid_argument ); // WinError.h: "The directory name is invalid"
297    case ERROR_DISK_FULL: return make_error_condition( no_space_on_device );
298    case ERROR_FILE_EXISTS: return make_error_condition( file_exists );
299    case ERROR_FILE_NOT_FOUND: return make_error_condition( no_such_file_or_directory );
300    case ERROR_HANDLE_DISK_FULL: return make_error_condition( no_space_on_device );
301    case ERROR_INVALID_ACCESS: return make_error_condition( permission_denied );
302    case ERROR_INVALID_DRIVE: return make_error_condition( no_such_device );
303    case ERROR_INVALID_FUNCTION: return make_error_condition( function_not_supported );
304    case ERROR_INVALID_HANDLE: return make_error_condition( invalid_argument );
305    case ERROR_INVALID_NAME: return make_error_condition( invalid_argument );
306    case ERROR_LOCK_VIOLATION: return make_error_condition( no_lock_available );
307    case ERROR_LOCKED: return make_error_condition( no_lock_available );
308    case ERROR_NEGATIVE_SEEK: return make_error_condition( invalid_argument );
309    case ERROR_NOACCESS: return make_error_condition( permission_denied );
310    case ERROR_NOT_ENOUGH_MEMORY: return make_error_condition( not_enough_memory );
311    case ERROR_NOT_READY: return make_error_condition( resource_unavailable_try_again );
312    case ERROR_NOT_SAME_DEVICE: return make_error_condition( cross_device_link );
313    case ERROR_OPEN_FAILED: return make_error_condition( io_error );
314    case ERROR_OPEN_FILES: return make_error_condition( device_or_resource_busy );
315    case ERROR_OPERATION_ABORTED: return make_error_condition( operation_canceled );
316    case ERROR_OUTOFMEMORY: return make_error_condition( not_enough_memory );
317    case ERROR_PATH_NOT_FOUND: return make_error_condition( no_such_file_or_directory );
318    case ERROR_READ_FAULT: return make_error_condition( io_error );
319    case ERROR_RETRY: return make_error_condition( resource_unavailable_try_again );
320    case ERROR_SEEK: return make_error_condition( io_error );
321    case ERROR_SHARING_VIOLATION: return make_error_condition( permission_denied );
322    case ERROR_TOO_MANY_OPEN_FILES: return make_error_condition( too_many_files_open );
323    case ERROR_WRITE_FAULT: return make_error_condition( io_error );
324    case ERROR_WRITE_PROTECT: return make_error_condition( permission_denied );
325    case WSAEACCES: return make_error_condition( permission_denied );
326    case WSAEADDRINUSE: return make_error_condition( address_in_use );
327    case WSAEADDRNOTAVAIL: return make_error_condition( address_not_available );
328    case WSAEAFNOSUPPORT: return make_error_condition( address_family_not_supported );
329    case WSAEALREADY: return make_error_condition( connection_already_in_progress );
330    case WSAEBADF: return make_error_condition( bad_file_descriptor );
331    case WSAECONNABORTED: return make_error_condition( connection_aborted );
332    case WSAECONNREFUSED: return make_error_condition( connection_refused );
333    case WSAECONNRESET: return make_error_condition( connection_reset );
334    case WSAEDESTADDRREQ: return make_error_condition( destination_address_required );
335    case WSAEFAULT: return make_error_condition( bad_address );
336    case WSAEHOSTUNREACH: return make_error_condition( host_unreachable );
337    case WSAEINPROGRESS: return make_error_condition( operation_in_progress );
338    case WSAEINTR: return make_error_condition( interrupted );
339    case WSAEINVAL: return make_error_condition( invalid_argument );
340    case WSAEISCONN: return make_error_condition( already_connected );
341    case WSAEMFILE: return make_error_condition( too_many_files_open );
342    case WSAEMSGSIZE: return make_error_condition( message_size );
343    case WSAENAMETOOLONG: return make_error_condition( filename_too_long );
344    case WSAENETDOWN: return make_error_condition( network_down );
345    case WSAENETRESET: return make_error_condition( network_reset );
346    case WSAENETUNREACH: return make_error_condition( network_unreachable );
347    case WSAENOBUFS: return make_error_condition( no_buffer_space );
348    case WSAENOPROTOOPT: return make_error_condition( no_protocol_option );
349    case WSAENOTCONN: return make_error_condition( not_connected );
350    case WSAENOTSOCK: return make_error_condition( not_a_socket );
351    case WSAEOPNOTSUPP: return make_error_condition( operation_not_supported );
352    case WSAEPROTONOSUPPORT: return make_error_condition( protocol_not_supported );
353    case WSAEPROTOTYPE: return make_error_condition( wrong_protocol_type );
354    case WSAETIMEDOUT: return make_error_condition( timed_out );
355    case WSAEWOULDBLOCK: return make_error_condition( operation_would_block );
356  #endif
357    default: return error_condition( ev, system_category() );
358    }
359  }
360
361# if !defined( BOOST_WINDOWS_API )
362
363  std::string system_error_category::message( int ev ) const
364  {
365    return generic_category().message( ev );
366  }
367# else
368
369  std::string system_error_category::message( int ev ) const
370  {
371#if defined(UNDER_CE) || BOOST_PLAT_WINDOWS_RUNTIME || defined(BOOST_NO_ANSI_APIS)
372    std::wstring buf(128, wchar_t());
373    for (;;)
374    {
375        DWORD retval = ::FormatMessageW(
376            FORMAT_MESSAGE_FROM_SYSTEM |
377            FORMAT_MESSAGE_IGNORE_INSERTS,
378            NULL,
379            ev,
380            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
381            &buf[0],
382            buf.size(),
383            NULL
384        );
385
386        if (retval > 0)
387        {
388            buf.resize(retval);
389            break;
390        }
391        else if ( ::GetLastError() != ERROR_INSUFFICIENT_BUFFER )
392        {
393            return std::string("Unknown error");
394        }
395        else
396        {
397            buf.resize(buf.size() + buf.size() / 2);
398        }
399    }
400
401    int num_chars = (buf.size() + 1) * 2;
402    LPSTR narrow_buffer = (LPSTR)_alloca( num_chars );
403    if (::WideCharToMultiByte(CP_ACP, 0, buf.c_str(), -1, narrow_buffer, num_chars, NULL, NULL) == 0)
404    {
405        return std::string("Unknown error");
406    }
407
408    std::string str( narrow_buffer );
409#else
410    LPVOID lpMsgBuf = 0;
411    DWORD retval = ::FormatMessageA(
412        FORMAT_MESSAGE_ALLOCATE_BUFFER |
413        FORMAT_MESSAGE_FROM_SYSTEM |
414        FORMAT_MESSAGE_IGNORE_INSERTS,
415        NULL,
416        ev,
417        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
418        (LPSTR) &lpMsgBuf,
419        0,
420        NULL
421    );
422    detail::local_free_on_destruction lfod(lpMsgBuf);
423    if (retval == 0)
424        return std::string("Unknown error");
425
426    std::string str( static_cast<LPCSTR>(lpMsgBuf) );
427# endif
428    while ( str.size()
429      && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') )
430        str.erase( str.size()-1 );
431    if ( str.size() && str[str.size()-1] == '.' )
432      { str.erase( str.size()-1 ); }
433    return str;
434  }
435# endif
436
437} // unnamed namespace
438
439
440# ifndef BOOST_SYSTEM_NO_DEPRECATED
441    BOOST_SYSTEM_DECL error_code throws; // "throw on error" special error_code;
442                                         //  note that it doesn't matter if this
443                                         //  isn't initialized before use since
444                                         //  the only use is to take its
445                                         //  address for comparison purposes
446# endif
447
448# ifdef BOOST_ERROR_CODE_HEADER_ONLY
449#   define BOOST_SYSTEM_LINKAGE inline
450# else
451#   define BOOST_SYSTEM_LINKAGE BOOST_SYSTEM_DECL
452# endif
453
454    BOOST_SYSTEM_LINKAGE const error_category & system_category() BOOST_SYSTEM_NOEXCEPT
455    {
456      static const system_error_category  system_category_const;
457      return system_category_const;
458    }
459
460    BOOST_SYSTEM_LINKAGE const error_category & generic_category() BOOST_SYSTEM_NOEXCEPT
461    {
462      static const generic_error_category generic_category_const;
463      return generic_category_const;
464    }
465
466  } // namespace system
467} // namespace boost
468