1 //
2 // corecrt_internal_lowio.h
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // This internal header defines internal utilities for working with the lowio
7 // library. This header may only be included in C++ translation units.
8 //
9 #pragma once
10
11 #include <fcntl.h>
12 #include <io.h>
13 #include <corecrt_internal_traits.h>
14 #include <share.h>
15 #include <stdint.h>
16 #include <stdlib.h>
17
18 _CRT_BEGIN_C_HEADER
19
20
21
22 #define LF 10 /* line feed */
23 #define CR 13 /* carriage return */
24 #define CTRLZ 26 /* ctrl-z means eof for text */
25
26 // Real default size for stdio buffers
27 #define _INTERNAL_BUFSIZ 4096
28 #define _SMALL_BUFSIZ 512
29
30 /* Most significant Bit */
31 #define _msbit(c) ((c) & 0x80)
32
33 /* Independent byte has most significant bit set to 0 */
34 #define _utf8_is_independent(c) (_msbit(c) == 0)
35
36 /* Get no of trailing bytes from the lookup table */
37 // 1 for pattern 110xxxxx - 1 trailbyte
38 // 2 for pattern 1110xxxx - 2 trailbytes
39 // 3 for pattern 11110xxx - 3 trailbytes
40 // 0 for everything else, including invalid patterns.
41 // We return 0 for invalid patterns because we rely on MultiByteToWideChar to
42 // do the validations.
43
44 extern char _lookuptrailbytes[256];
_utf8_no_of_trailbytes(const unsigned char c)45 __inline char _utf8_no_of_trailbytes(const unsigned char c)
46 {
47 return _lookuptrailbytes[c];
48 }
49 // It may be faster to just look up the bytes than to use the lookup table.
50 //__inline char _utf8_no_of_trailbytes(const unsigned char c)
51 //{
52 // // ASCII range is a single character
53 // if ((c & 0x80) == 0) return 0;
54 // // Trail bytes 10xxxxxx aren't lead bytes
55 // if ((c & 0x40) == 0) return 0;
56 // // 110xxxxx is a 2 byte sequence (1 trail byte)
57 // if ((c & 0x20) == 0) return 1;
58 // // 1110xxxx is a 3 byte sequence (2 trail bytes)
59 // if ((c & 0x10) == 0) return 2;
60 // // 11110xxx is a 4 byte sequence (3 trail bytes)
61 // if ((c & 0x08) == 0) return 3;
62 // // Anything with 5 or more lead bits is illegal
63 // return 0;
64 //}
65
66 /* Any leadbyte will have the patterns 11000xxx 11100xxx or 11110xxx */
67 #define _utf8_is_leadbyte(c) (_utf8_no_of_trailbytes(static_cast<const unsigned char>(c)) != 0)
68
69 enum class __crt_lowio_text_mode : char
70 {
71 ansi = 0, // Regular text
72 utf8 = 1, // UTF-8 encoded
73 utf16le = 2, // UTF-16LE encoded
74 };
75
76 // osfile flag values
77 enum : unsigned char
78 {
79 FOPEN = 0x01, // file handle open
80 FEOFLAG = 0x02, // end of file has been encountered
81 FCRLF = 0x04, // CR-LF across read buffer (in text mode)
82 FPIPE = 0x08, // file handle refers to a pipe
83 FNOINHERIT = 0x10, // file handle opened _O_NOINHERIT
84 FAPPEND = 0x20, // file handle opened O_APPEND
85 FDEV = 0x40, // file handle refers to device
86 FTEXT = 0x80, // file handle is in text mode
87 };
88
89 typedef char __crt_lowio_pipe_lookahead[3];
90
91 /*
92 * Control structure for lowio file handles
93 */
94 struct __crt_lowio_handle_data
95 {
96 CRITICAL_SECTION lock;
97 intptr_t osfhnd; // underlying OS file HANDLE
98 __int64 startpos; // File position that matches buffer start
99 unsigned char osfile; // Attributes of file (e.g., open in text mode?)
100 __crt_lowio_text_mode textmode;
101 __crt_lowio_pipe_lookahead _pipe_lookahead;
102
103 uint8_t unicode : 1; // Was the file opened as unicode?
104 uint8_t utf8translations : 1; // Buffer contains translations other than CRLF
105 uint8_t dbcsBufferUsed : 1; // Is the dbcsBuffer in use?
106 char mbBuffer[MB_LEN_MAX]; // Buffer for the lead byte of DBCS when converting from DBCS to Unicode
107 // Or for the first up to 3 bytes of a UTF-8 character
108 };
109
110 // The log-base-2 of the number of elements in each array of lowio file objects
111 #define IOINFO_L2E 6
112
113 // The number of elements in each array of lowio file objects
114 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
115
116 // The hard maximum number of arrays of lowio file objects that may be allocated
117 #define IOINFO_ARRAYS 128
118
119 // The maximum number of lowio file objects that may be allocated at any one time
120 #define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
121
122
123
124 #define STDIO_HANDLES_COUNT 3
125 /*
126 * Access macros for getting at an __crt_lowio_handle_data struct and its fields from a
127 * file handle
128 */
129 #define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)))
130 #define _osfhnd(i) (_pioinfo(i)->osfhnd)
131 #define _osfile(i) (_pioinfo(i)->osfile)
132 #define _pipe_lookahead(i) (_pioinfo(i)->_pipe_lookahead)
133 #define _textmode(i) (_pioinfo(i)->textmode)
134 #define _tm_unicode(i) (_pioinfo(i)->unicode)
135 #define _startpos(i) (_pioinfo(i)->startpos)
136 #define _utf8translations(i) (_pioinfo(i)->utf8translations)
137 #define _mbBuffer(i) (_pioinfo(i)->mbBuffer)
138 #define _dbcsBuffer(i) (_pioinfo(i)->mbBuffer[0])
139 #define _dbcsBufferUsed(i) (_pioinfo(i)->dbcsBufferUsed)
140
141 /*
142 * Safer versions of the above macros. Currently, only _osfile_safe is
143 * used.
144 */
145 #define _pioinfo_safe(i) ((((i) != -1) && ((i) != -2)) ? _pioinfo(i) : &__badioinfo)
146 #define _osfile_safe(i) (_pioinfo_safe(i)->osfile)
147 #define _textmode_safe(i) (_pioinfo_safe(i)->textmode)
148 #define _tm_unicode_safe(i) (_pioinfo_safe(i)->unicode)
149
150 typedef __crt_lowio_handle_data* __crt_lowio_handle_data_array[IOINFO_ARRAYS];
151
152 // Special, static lowio file object used only for more graceful handling
153 // of a C file handle value of -1 (results from common errors at the stdio
154 // level).
155 extern __crt_lowio_handle_data __badioinfo;
156
157 // The umask value
158 extern int _umaskval;
159
160 // Global array of pointers to the arrays of lowio file objects.
161 extern __crt_lowio_handle_data_array __pioinfo;
162
163 // The number of handles for which file objects have been allocated. This
164 // number is such that for any fh in [0, _nhandle), _pioinfo(fh) is well-
165 // formed.
166 extern int _nhandle;
167
168
169
170 int __cdecl _alloc_osfhnd(void);
171 int __cdecl _free_osfhnd(int);
172 int __cdecl __acrt_lowio_set_os_handle(int, intptr_t);
173
174 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175 //
176 // Internal lowio functions
177 //
178 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179
180 _Success_(return == 0)
181 errno_t __cdecl _sopen_nolock(
182 _Out_ int* _UnlockFlag,
183 _Out_ int* _FileHandle,
184 _In_z_ char const* _FileName,
185 _In_ int _OpenFlag,
186 _In_ int _ShareFlag,
187 _In_ int _PermissionFlag,
188 _In_ int _SecureFlag
189 );
190
191 _Success_(return == 0)
192 errno_t __cdecl _wsopen_nolock(
193 _Out_ int* _UnlockFlag,
194 _Out_ int* _FileHandle,
195 _In_z_ wchar_t const* _FileName,
196 _In_ int _OpenFlag,
197 _In_ int _ShareFlag,
198 _In_ int _PermissionFlag,
199 _In_ int _SecureFlag
200 );
201
202
203 _Check_return_
204 __crt_lowio_handle_data* __cdecl __acrt_lowio_create_handle_array();
205
206 void __cdecl __acrt_lowio_destroy_handle_array(
207 _Pre_maybenull_ _Post_invalid_ _In_reads_opt_(IOINFO_ARRAY_ELTS) __crt_lowio_handle_data* _Array
208 );
209
210 _Check_return_opt_
211 errno_t __cdecl __acrt_lowio_ensure_fh_exists(
212 _In_ int _FileHandle
213 );
214
215 void __cdecl __acrt_lowio_lock_fh (_In_ int _FileHandle);
216 void __cdecl __acrt_lowio_unlock_fh(_In_ int _FileHandle);
217
218 extern "C++"
219 {
220 template <typename Action>
221 auto __acrt_lowio_lock_fh_and_call(int const fh, Action&& action) throw()
222 -> decltype(action())
223 {
224 return __crt_seh_guarded_call<decltype(action())>()(
225 [fh]() { __acrt_lowio_lock_fh(fh); },
226 action,
227 [fh]() { __acrt_lowio_unlock_fh(fh); });
228 }
229 }
230
231 // console_invalid_handle indicates that CONOUT$ or CONIN$ could not be created
232 // console_uninitialized_handle indicates that the handle has not yet been initialized
233 const HANDLE _console_invalid_handle = reinterpret_cast<HANDLE>(-1);
234 const HANDLE _console_uninitialized_handle = reinterpret_cast<HANDLE>(-2);
235
236 BOOL __cdecl __dcrt_lowio_ensure_console_input_initialized(void);
237
238 BOOL __cdecl __dcrt_read_console_input(
239 _Out_ PINPUT_RECORD lpBuffer,
240 _In_ DWORD nLength,
241 _Out_ LPDWORD lpNumberOfEventsRead
242 );
243
244 BOOL __cdecl __dcrt_read_console(
245 _Out_ LPVOID lpBuffer,
246 _In_ DWORD nNumberOfCharsToRead,
247 _Out_ LPDWORD lpNumberOfCharsRead
248 );
249
250 BOOL __cdecl __dcrt_get_number_of_console_input_events(
251 _Out_ LPDWORD lpcNumberOfEvents
252 );
253
254 BOOL __cdecl __dcrt_peek_console_input_a(
255 _Out_ PINPUT_RECORD lpBuffer,
256 _In_ DWORD nLength,
257 _Out_ LPDWORD lpNumberOfEventsRead
258 );
259
260 BOOL __cdecl __dcrt_get_input_console_mode(
261 _Out_ LPDWORD lpMode
262 );
263
264 BOOL __cdecl __dcrt_set_input_console_mode(
265 _In_ DWORD dwMode
266 );
267
268 BOOL __cdecl __dcrt_lowio_ensure_console_output_initialized(void);
269
270 BOOL __cdecl __dcrt_write_console(
271 _In_ void const * lpBuffer,
272 _In_ DWORD nNumberOfCharsToWrite,
273 _Out_ LPDWORD lpNumberOfCharsWritten
274 );
275
276 _Check_return_ int __cdecl _chsize_nolock(_In_ int _FileHandle,_In_ __int64 _Size);
277 _Check_return_opt_ int __cdecl _close_nolock(_In_ int _FileHandle);
278 _Check_return_opt_ long __cdecl _lseek_nolock(_In_ int _FileHandle, _In_ long _Offset, _In_ int _Origin);
279 _Check_return_ int __cdecl _setmode_nolock(_In_ int _FileHandle, _In_ int _Mode);
280 _Check_return_ _Success_(return >= 0 && return <= _MaxCharCount) int __cdecl _read_nolock(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void * _DstBuf, _In_ unsigned int _MaxCharCount);
281 _Check_return_ int __cdecl _write_nolock(_In_ int _FileHandle, _In_reads_bytes_(_MaxCharCount) const void * _Buf, _In_ unsigned int _MaxCharCount, __crt_cached_ptd_host& _Ptd);
282 _Check_return_opt_ __int64 __cdecl _lseeki64_nolock(_In_ int _FileHandle, _In_ __int64 _Offset, _In_ int _Origin);
283
284 // Temporary until non-PTD propagating versions can be replaced:
285 _Check_return_ int __cdecl _chsize_nolock_internal(_In_ int _FileHandle, _In_ __int64 _Size, _Inout_ __crt_cached_ptd_host& _Ptd);
286 _Check_return_opt_ __int64 __cdecl _lseeki64_nolock_internal(_In_ int _FileHandle, _In_ __int64 _Offset, _In_ int _Origin, _Inout_ __crt_cached_ptd_host& _Ptd);
287 _Check_return_opt_ int __cdecl _close_nolock_internal(_In_ int _FileHandle, _Inout_ __crt_cached_ptd_host& _Ptd);
288
289 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290 //
291 // Internal stdio functions with PTD propagation
292 //
293 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
294
295 _Check_return_opt_
296 int __cdecl _close_internal(
297 _In_ int _FileHandle,
298 _Inout_ __crt_cached_ptd_host& _Ptd
299 );
300
301 _Check_return_opt_
302 long __cdecl _lseek_internal(
303 _In_ int _FileHandle,
304 _In_ long _Offset,
305 _In_ int _Origin,
306 _Inout_ __crt_cached_ptd_host& _Ptd
307 );
308
309 _Check_return_opt_
310 __int64 __cdecl _lseeki64_internal(
311 _In_ int _FileHandle,
312 _In_ __int64 _Offset,
313 _In_ int _Origin,
314 _Inout_ __crt_cached_ptd_host& _Ptd
315 );
316
317 int __cdecl _write_internal(
318 _In_ int _FileHandle,
319 _In_reads_bytes_(_MaxCharCount) void const* _Buf,
320 _In_ unsigned int _MaxCharCount,
321 _Inout_ __crt_cached_ptd_host& _Ptd
322 );
323
324 // fileno for stdout, stdin & stderr when there is no console
325 #define _NO_CONSOLE_FILENO ((intptr_t)-2)
326
327
328 _CRT_END_C_HEADER
329