• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Windows implementation of system_error_category
2 //
3 // Copyright Beman Dawes 2002, 2006
4 // Copyright (c) Microsoft Corporation 2014
5 // Copyright 2018 Peter Dimov
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 // See library home page at http://www.boost.org/libs/system
11 
12 #include <boost/winapi/error_codes.hpp>
13 #include <boost/winapi/error_handling.hpp>
14 #include <boost/winapi/character_code_conversion.hpp>
15 #include <boost/winapi/local_memory.hpp>
16 #include <cstdio>
17 
18 //
19 
20 namespace boost
21 {
22 
23 namespace system
24 {
25 
26 namespace detail
27 {
28 
29 #if ( defined(_MSC_VER) && _MSC_VER < 1900 ) || ( defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) )
30 
unknown_message_win32(int ev,char * buffer,std::size_t len)31 inline char const * unknown_message_win32( int ev, char * buffer, std::size_t len )
32 {
33 # if defined( BOOST_MSVC )
34 #  pragma warning( push )
35 #  pragma warning( disable: 4996 )
36 # endif
37 
38     _snprintf( buffer, len - 1, "Unknown error (%d)", ev );
39 
40     buffer[ len - 1 ] = 0;
41     return buffer;
42 
43 # if defined( BOOST_MSVC )
44 #  pragma warning( pop )
45 # endif
46 }
47 
48 #else
49 
50 inline char const * unknown_message_win32( int ev, char * buffer, std::size_t len )
51 {
52     std::snprintf( buffer, len, "Unknown error (%d)", ev );
53     return buffer;
54 }
55 
56 #endif
57 
message_cp_win32()58 inline boost::winapi::UINT_ message_cp_win32()
59 {
60 #if defined(BOOST_SYSTEM_USE_UTF8)
61 
62     return boost::winapi::CP_UTF8_;
63 
64 #else
65 
66     return boost::winapi::CP_ACP_;
67 
68 #endif
69 }
70 
system_category_message_win32(int ev,char * buffer,std::size_t len)71 inline char const * system_category_message_win32( int ev, char * buffer, std::size_t len ) BOOST_NOEXCEPT
72 {
73     if( len == 0 )
74     {
75         return buffer;
76     }
77 
78     if( len == 1 )
79     {
80         buffer[0] = 0;
81         return buffer;
82     }
83 
84     boost::winapi::UINT_ const code_page = message_cp_win32();
85 
86     int r = 0;
87 
88 #if !defined(BOOST_NO_ANSI_APIS)
89 
90     if( code_page == boost::winapi::CP_ACP_ )
91     {
92         using namespace boost::winapi;
93 
94         DWORD_ retval = boost::winapi::FormatMessageA(
95             FORMAT_MESSAGE_FROM_SYSTEM_ | FORMAT_MESSAGE_IGNORE_INSERTS_,
96             NULL,
97             ev,
98             MAKELANGID_( LANG_NEUTRAL_, SUBLANG_DEFAULT_ ), // Default language
99             buffer,
100             static_cast<DWORD_>( len ),
101             NULL
102         );
103 
104         r = static_cast<int>( retval );
105     }
106     else
107 
108 #endif
109 
110     {
111         using namespace boost::winapi;
112 
113         wchar_t * lpMsgBuf = 0;
114 
115         DWORD_ retval = boost::winapi::FormatMessageW(
116             FORMAT_MESSAGE_ALLOCATE_BUFFER_ | FORMAT_MESSAGE_FROM_SYSTEM_ | FORMAT_MESSAGE_IGNORE_INSERTS_,
117             NULL,
118             ev,
119             MAKELANGID_( LANG_NEUTRAL_, SUBLANG_DEFAULT_ ), // Default language
120             (LPWSTR_) &lpMsgBuf,
121             0,
122             NULL
123         );
124 
125         if( retval != 0 )
126         {
127             r = boost::winapi::WideCharToMultiByte( code_page, 0, lpMsgBuf, -1, buffer, static_cast<int>( len ), NULL, NULL );
128             boost::winapi::LocalFree( lpMsgBuf );
129             if ( r != 0 ) --r; // exclude null terminator
130         }
131     }
132 
133     if( r == 0 )
134     {
135         return unknown_message_win32( ev, buffer, len );
136     }
137 
138     while( r > 0 && ( buffer[ r-1 ] == '\n' || buffer[ r-1 ] == '\r' ) )
139     {
140         buffer[ --r ] = 0;
141     }
142 
143     if( r > 0 && buffer[ r-1 ] == '.' )
144     {
145         buffer[ --r ] = 0;
146     }
147 
148     return buffer;
149 }
150 
151 struct local_free
152 {
153     void * p_;
154 
~local_freeboost::system::detail::local_free155     ~local_free()
156     {
157         boost::winapi::LocalFree( p_ );
158     }
159 };
160 
unknown_message_win32(int ev)161 inline std::string unknown_message_win32( int ev )
162 {
163     char buffer[ 38 ];
164     return unknown_message_win32( ev, buffer, sizeof( buffer ) );
165 }
166 
system_category_message_win32(int ev)167 inline std::string system_category_message_win32( int ev )
168 {
169     using namespace boost::winapi;
170 
171     wchar_t * lpMsgBuf = 0;
172 
173     DWORD_ retval = boost::winapi::FormatMessageW(
174         FORMAT_MESSAGE_ALLOCATE_BUFFER_ | FORMAT_MESSAGE_FROM_SYSTEM_ | FORMAT_MESSAGE_IGNORE_INSERTS_,
175         NULL,
176         ev,
177         MAKELANGID_( LANG_NEUTRAL_, SUBLANG_DEFAULT_ ), // Default language
178         (LPWSTR_) &lpMsgBuf,
179         0,
180         NULL
181     );
182 
183     if( retval == 0 )
184     {
185         return unknown_message_win32( ev );
186     }
187 
188     local_free lf_ = { lpMsgBuf };
189     (void)lf_;
190 
191     UINT_ const code_page = message_cp_win32();
192 
193     int r = boost::winapi::WideCharToMultiByte( code_page, 0, lpMsgBuf, -1, 0, 0, NULL, NULL );
194 
195     if( r == 0 )
196     {
197         return unknown_message_win32( ev );
198     }
199 
200     std::string buffer( r, char() );
201 
202     r = boost::winapi::WideCharToMultiByte( code_page, 0, lpMsgBuf, -1, &buffer[0], r, NULL, NULL );
203 
204     if( r == 0 )
205     {
206         return unknown_message_win32( ev );
207     }
208 
209     --r; // exclude null terminator
210 
211     while( r > 0 && ( buffer[ r-1 ] == '\n' || buffer[ r-1 ] == '\r' ) )
212     {
213         --r;
214     }
215 
216     if( r > 0 && buffer[ r-1 ] == '.' )
217     {
218         --r;
219     }
220 
221     buffer.resize( r );
222 
223     return buffer;
224 }
225 
system_category_default_error_condition_win32(int ev)226 inline error_condition system_category_default_error_condition_win32( int ev ) BOOST_NOEXCEPT
227 {
228     // When using the Windows Runtime, most system errors are reported as HRESULTs.
229     // We want to map the common Win32 errors to their equivalent error condition,
230     // whether or not they are reported via an HRESULT.
231 
232 #define BOOST_SYSTEM_FAILED(hr)           ((hr) < 0)
233 #define BOOST_SYSTEM_HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff)
234 #define BOOST_SYSTEM_HRESULT_CODE(hr)     ((hr) & 0xFFFF)
235 #define BOOST_SYSTEM_FACILITY_WIN32       7
236 
237     if( BOOST_SYSTEM_FAILED( ev ) && BOOST_SYSTEM_HRESULT_FACILITY( ev ) == BOOST_SYSTEM_FACILITY_WIN32 )
238     {
239         ev = BOOST_SYSTEM_HRESULT_CODE( ev );
240     }
241 
242 #undef BOOST_SYSTEM_FAILED
243 #undef BOOST_SYSTEM_HRESULT_FACILITY
244 #undef BOOST_SYSTEM_HRESULT_CODE
245 #undef BOOST_SYSTEM_FACILITY_WIN32
246 
247     using namespace boost::winapi;
248     using namespace errc;
249 
250     // Windows system -> posix_errno decode table
251     // see WinError.h comments for descriptions of errors
252 
253     switch ( ev )
254     {
255     case 0: return make_error_condition( success );
256 
257     case ERROR_ACCESS_DENIED_: return make_error_condition( permission_denied );
258     case ERROR_ALREADY_EXISTS_: return make_error_condition( file_exists );
259     case ERROR_BAD_UNIT_: return make_error_condition( no_such_device );
260     case ERROR_BUFFER_OVERFLOW_: return make_error_condition( filename_too_long );
261     case ERROR_BUSY_: return make_error_condition( device_or_resource_busy );
262     case ERROR_BUSY_DRIVE_: return make_error_condition( device_or_resource_busy );
263     case ERROR_CANNOT_MAKE_: return make_error_condition( permission_denied );
264     case ERROR_CANTOPEN_: return make_error_condition( io_error );
265     case ERROR_CANTREAD_: return make_error_condition( io_error );
266     case ERROR_CANTWRITE_: return make_error_condition( io_error );
267     case ERROR_CONNECTION_ABORTED_: return make_error_condition( connection_aborted );
268     case ERROR_CURRENT_DIRECTORY_: return make_error_condition( permission_denied );
269     case ERROR_DEV_NOT_EXIST_: return make_error_condition( no_such_device );
270     case ERROR_DEVICE_IN_USE_: return make_error_condition( device_or_resource_busy );
271     case ERROR_DIR_NOT_EMPTY_: return make_error_condition( directory_not_empty );
272     case ERROR_DIRECTORY_: return make_error_condition( invalid_argument ); // WinError.h: "The directory name is invalid"
273     case ERROR_DISK_FULL_: return make_error_condition( no_space_on_device );
274     case ERROR_FILE_EXISTS_: return make_error_condition( file_exists );
275     case ERROR_FILE_NOT_FOUND_: return make_error_condition( no_such_file_or_directory );
276     case ERROR_HANDLE_DISK_FULL_: return make_error_condition( no_space_on_device );
277     case ERROR_INVALID_ACCESS_: return make_error_condition( permission_denied );
278     case ERROR_INVALID_DRIVE_: return make_error_condition( no_such_device );
279     case ERROR_INVALID_FUNCTION_: return make_error_condition( function_not_supported );
280     case ERROR_INVALID_HANDLE_: return make_error_condition( invalid_argument );
281     case ERROR_INVALID_NAME_: return make_error_condition( invalid_argument );
282     case ERROR_LOCK_VIOLATION_: return make_error_condition( no_lock_available );
283     case ERROR_LOCKED_: return make_error_condition( no_lock_available );
284     case ERROR_NEGATIVE_SEEK_: return make_error_condition( invalid_argument );
285     case ERROR_NOACCESS_: return make_error_condition( permission_denied );
286     case ERROR_NOT_ENOUGH_MEMORY_: return make_error_condition( not_enough_memory );
287     case ERROR_NOT_READY_: return make_error_condition( resource_unavailable_try_again );
288     case ERROR_NOT_SAME_DEVICE_: return make_error_condition( cross_device_link );
289     case ERROR_OPEN_FAILED_: return make_error_condition( io_error );
290     case ERROR_OPEN_FILES_: return make_error_condition( device_or_resource_busy );
291     case ERROR_OPERATION_ABORTED_: return make_error_condition( operation_canceled );
292     case ERROR_OUTOFMEMORY_: return make_error_condition( not_enough_memory );
293     case ERROR_PATH_NOT_FOUND_: return make_error_condition( no_such_file_or_directory );
294     case ERROR_READ_FAULT_: return make_error_condition( io_error );
295     case ERROR_RETRY_: return make_error_condition( resource_unavailable_try_again );
296     case ERROR_SEEK_: return make_error_condition( io_error );
297     case ERROR_SHARING_VIOLATION_: return make_error_condition( permission_denied );
298     case ERROR_TOO_MANY_OPEN_FILES_: return make_error_condition( too_many_files_open );
299     case ERROR_WRITE_FAULT_: return make_error_condition( io_error );
300     case ERROR_WRITE_PROTECT_: return make_error_condition( permission_denied );
301     case WSAEACCES_: return make_error_condition( permission_denied );
302     case WSAEADDRINUSE_: return make_error_condition( address_in_use );
303     case WSAEADDRNOTAVAIL_: return make_error_condition( address_not_available );
304     case WSAEAFNOSUPPORT_: return make_error_condition( address_family_not_supported );
305     case WSAEALREADY_: return make_error_condition( connection_already_in_progress );
306     case WSAEBADF_: return make_error_condition( bad_file_descriptor );
307     case WSAECONNABORTED_: return make_error_condition( connection_aborted );
308     case WSAECONNREFUSED_: return make_error_condition( connection_refused );
309     case WSAECONNRESET_: return make_error_condition( connection_reset );
310     case WSAEDESTADDRREQ_: return make_error_condition( destination_address_required );
311     case WSAEFAULT_: return make_error_condition( bad_address );
312     case WSAEHOSTUNREACH_: return make_error_condition( host_unreachable );
313     case WSAEINPROGRESS_: return make_error_condition( operation_in_progress );
314     case WSAEINTR_: return make_error_condition( interrupted );
315     case WSAEINVAL_: return make_error_condition( invalid_argument );
316     case WSAEISCONN_: return make_error_condition( already_connected );
317     case WSAEMFILE_: return make_error_condition( too_many_files_open );
318     case WSAEMSGSIZE_: return make_error_condition( message_size );
319     case WSAENAMETOOLONG_: return make_error_condition( filename_too_long );
320     case WSAENETDOWN_: return make_error_condition( network_down );
321     case WSAENETRESET_: return make_error_condition( network_reset );
322     case WSAENETUNREACH_: return make_error_condition( network_unreachable );
323     case WSAENOBUFS_: return make_error_condition( no_buffer_space );
324     case WSAENOPROTOOPT_: return make_error_condition( no_protocol_option );
325     case WSAENOTCONN_: return make_error_condition( not_connected );
326     case WSAENOTSOCK_: return make_error_condition( not_a_socket );
327     case WSAEOPNOTSUPP_: return make_error_condition( operation_not_supported );
328     case WSAEPROTONOSUPPORT_: return make_error_condition( protocol_not_supported );
329     case WSAEPROTOTYPE_: return make_error_condition( wrong_protocol_type );
330     case WSAETIMEDOUT_: return make_error_condition( timed_out );
331     case WSAEWOULDBLOCK_: return make_error_condition( operation_would_block );
332 
333     default: return error_condition( ev, system_category() );
334     }
335 }
336 
337 } // namespace detail
338 
339 } // namespace system
340 
341 } // namespace boost
342