Reactos
1//
2// osfinfo.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines the functions used to control allocation, locking, and freeing of CRT
7// file handles.
8//
9#include <corecrt_internal_lowio.h>
10
11
12
13extern "C" __crt_lowio_handle_data* __cdecl __acrt_lowio_create_handle_array()
14{
15 __crt_unique_heap_ptr<__crt_lowio_handle_data> array(_calloc_crt_t(
16 __crt_lowio_handle_data,
17 IOINFO_ARRAY_ELTS));
18
19 if (!array)
20 return nullptr;
21
22 __crt_lowio_handle_data* const first = array.get();
23 __crt_lowio_handle_data* const last = first + IOINFO_ARRAY_ELTS;
24 for (auto it = first; it != last; ++it)
25 {
26 __acrt_InitializeCriticalSectionEx(&it->lock, _CORECRT_SPINCOUNT, 0);
27 it->osfhnd = reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE);
28 it->startpos = 0;
29 it->osfile = 0;
30 it->textmode = __crt_lowio_text_mode::ansi;
31 it->_pipe_lookahead[0] = LF;
32 it->_pipe_lookahead[1] = LF;
33 it->_pipe_lookahead[2] = LF;
34 it->unicode = false;
35 it->utf8translations = false;
36 it->dbcsBufferUsed = false;
37 for (int i = 0; i < sizeof(it->mbBuffer); ++i)
38 {
39 it->mbBuffer[i] = '\0';
40 }
41 }
42
43 return array.detach();
44}
45
46extern "C" void __cdecl __acrt_lowio_destroy_handle_array(__crt_lowio_handle_data* const array)
47{
48 if (!array)
49 return;
50
51 __crt_lowio_handle_data* const first = array;
52 __crt_lowio_handle_data* const last = first + IOINFO_ARRAY_ELTS;
53 for (auto it = first; it != last; ++it)
54 {
55 DeleteCriticalSection(&it->lock);
56 }
57
58 _free_crt(array);
59}
60
61// Ensures that a lowio handle data object has been created for file handle 'fh'.
62// The 'fh' must be less than the hard maximum, _NHANDLE_. If 'fh' is already
63// backed by a handle data object, this function has no effect. Otherwise, this
64// function extends the global arrays of handle data objects until 'fh' is backed
65// by a handle data object.
66extern "C" errno_t __cdecl __acrt_lowio_ensure_fh_exists(int const fh)
67{
68 _VALIDATE_RETURN_ERRCODE(static_cast<unsigned>(fh) < _NHANDLE_, EBADF);
69
70 errno_t status = 0;
71
72 __acrt_lock(__acrt_lowio_index_lock);
73 __try
74 {
75 for (size_t i = 0; fh >= _nhandle; ++i)
76 {
77 if (__pioinfo[i])
78 {
79 continue;
80 }
81
82 __pioinfo[i] = __acrt_lowio_create_handle_array();
83 if (!__pioinfo[i])
84 {
85 status = ENOMEM;
86 __leave;
87 }
88
89 _nhandle += IOINFO_ARRAY_ELTS;
90 }
91 }
92 __finally
93 {
94 __acrt_unlock(__acrt_lowio_index_lock);
95 }
96 __endtry
97
98 return status;
99}
100
101
102
103// Allocates a CRT file handle. This function finds the first free entry in
104// the arrays of file objects and returns the index of that entry (that index
105// is the CRT file handle) to the caller. The FOPEN flag is set in the new
106// entry, to pevent multithreaded race conditions and deadlocks.
107//
108// Returns the CRT file handle on success; returns -1 on failure (e.g. if no
109// more file handles are available or if memory allocation is required but
110// fails).
111//
112// MULTITHREADING NOTE: If this function is successful and returns a CRT file
113// handle, the handle is locked when it is returned and the FOPEN flag has been
114// set. The caller must be sure to release the lock, and if the caller abandons
115// the file handle, it must clear the FOPEN flag to free the handle.
116extern "C" int __cdecl _alloc_osfhnd()
117{
118 __acrt_lock(__acrt_lowio_index_lock);
119 int result = -1;
120 __try
121 {
122 // Search the arrays of file objects, in order, looking for the first
123 // free entry. The compound index of this free entry is the return
124 // value.
125 //
126 // The compound index of the file object entry *(__pioinfo[i] + j) is
127 // k = i * IOINFO_ARRAY_ELTS + j.
128 for (int i = 0; i < IOINFO_ARRAYS; ++i)
129 {
130 // If this __crt_lowio_handle_data array does not yet exist, create a new one:
131 if (!__pioinfo[i])
132 {
133 __pioinfo[i] = __acrt_lowio_create_handle_array();
134 if (!__pioinfo[i])
135 __leave;
136
137 _nhandle += IOINFO_ARRAY_ELTS;
138
139 // The first element of the newly allocated array of handle data
140 // objects is our first free entry. Note that since we hold the
141 // index lock, no one else can allocate this handle.
142 int const fh = i * IOINFO_ARRAY_ELTS;
143
144 __acrt_lowio_lock_fh(fh);
145 _osfile(fh) = FOPEN;
146 result = fh;
147 __leave;
148 }
149
150 // Otherwise, this file object array already exists. Search it looking
151 // for the first free entry:
152 __crt_lowio_handle_data* const first = __pioinfo[i];
153 __crt_lowio_handle_data* const last = first + IOINFO_ARRAY_ELTS;
154 for (__crt_lowio_handle_data* pio = first; pio != last; ++pio)
155 {
156 if (pio->osfile & FOPEN)
157 continue;
158
159 // Another thread may have grabbed this file handle out from
160 // under us while we waited for the lock. If so, continue on
161 // searching through the array.
162 //
163 // CRT_REFACTOR TODO: Resolve lowio synchronization issues.
164 EnterCriticalSection(&pio->lock);
165 if ((pio->osfile & FOPEN) != 0)
166 {
167 LeaveCriticalSection(&pio->lock);
168 continue;
169 }
170
171 // Otherwise, this entry is ours: we hold the lock, so we can
172 // initialize it and return its handle:
173 int const fh = i * IOINFO_ARRAY_ELTS + static_cast<int>(pio - first);
174 _osfile(fh) = FOPEN;
175 _osfhnd(fh) = reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE);
176 result = fh;
177 __leave;
178 }
179 }
180
181 // All entries are in use if we fall out of the loop. return -1 in this case (which result is already set to)
182 }
183 __finally
184 {
185 __acrt_unlock(__acrt_lowio_index_lock);
186 }
187 __endtry
188 return result;
189}
190
191
192
193// Sets the Win32 HANDLE associated with the specified CRT file. Returns 0
194// on success; returns -1 and sets errno on failure.
195extern "C" int __cdecl __acrt_lowio_set_os_handle(int const fh, intptr_t const value)
196{
197 if (fh >= 0 &&
198 static_cast<unsigned>(fh) < static_cast<unsigned>(_nhandle) &&
199 _osfhnd(fh) == reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE))
200 {
201 if (_query_app_type() == _crt_console_app)
202 {
203 HANDLE const handle_value = reinterpret_cast<HANDLE>(value);
204 switch (fh)
205 {
206 case 0: SetStdHandle(STD_INPUT_HANDLE, handle_value); break;
207 case 1: SetStdHandle(STD_OUTPUT_HANDLE, handle_value); break;
208 case 2: SetStdHandle(STD_ERROR_HANDLE, handle_value); break;
209 }
210 }
211
212 _osfhnd(fh) = value;
213 return 0 ;
214 }
215 else
216 {
217 errno = EBADF; // Bad handle
218 _doserrno = 0; // This is not an OS error
219 return -1;
220 }
221}
222
223
224
225// Marks the specified CRT file handle as free and available for allocation.
226// Returns 0 on success; returns -1 and sets errno on failure.
227extern "C" int __cdecl _free_osfhnd(int const fh)
228{
229 if (fh >= 0 &&
230 static_cast<unsigned>(fh) < static_cast<unsigned>(_nhandle) &&
231 (_osfile(fh) & FOPEN) &&
232 _osfhnd(fh) != reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE))
233 {
234 if (_query_app_type() == _crt_console_app)
235 {
236 switch (fh)
237 {
238 case 0: SetStdHandle(STD_INPUT_HANDLE, nullptr); break;
239 case 1: SetStdHandle(STD_OUTPUT_HANDLE, nullptr); break;
240 case 2: SetStdHandle(STD_ERROR_HANDLE, nullptr); break;
241 }
242 }
243
244 _osfhnd(fh) = reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE);
245 return 0;
246 }
247 else
248 {
249 errno = EBADF; // Bad handle
250 _doserrno = 0; // This is not an OS error
251 return -1;
252 }
253}
254
255
256
257// Gets the Win32 HANDLE with which the given CRT file handle is associated.
258// On success, returns the Win32 HANDLE; on failure, returns -1 and sets errno.
259extern "C" intptr_t __cdecl _get_osfhandle(int const fh)
260{
261 _CHECK_FH_CLEAR_OSSERR_RETURN(fh, EBADF, -1 );
262 _VALIDATE_CLEAR_OSSERR_RETURN(fh >= 0 && (unsigned)fh < (unsigned)_nhandle, EBADF, -1);
263 _VALIDATE_CLEAR_OSSERR_RETURN(_osfile(fh) & FOPEN, EBADF, -1);
264
265 return _osfhnd(fh);
266}
267
268
269
270// Allocates a free CRT file handle and associates it with the provided Win32
271// HANDLE and sets its flags to the given flags. Returns the CRT file handle
272// on success; returns -1 on failure.
273extern "C" int __cdecl _open_osfhandle(intptr_t const osfhandle, int const source_flags)
274{
275 // Copy relevant source_flags from second parameter
276 unsigned char file_flags = 0;
277
278 if (source_flags & _O_APPEND)
279 file_flags |= FAPPEND;
280
281 if (source_flags & _O_TEXT)
282 file_flags |= FTEXT;
283
284 if (source_flags & _O_NOINHERIT)
285 file_flags |= FNOINHERIT;
286
287 // Find out what type of file (file/device/pipe):
288 DWORD const file_type = GetFileType(reinterpret_cast<HANDLE>(osfhandle));
289 if (file_type == FILE_TYPE_UNKNOWN)
290 {
291 __acrt_errno_map_os_error(GetLastError());
292 return -1;
293 }
294
295 if (file_type == FILE_TYPE_CHAR)
296 file_flags |= FDEV;
297
298 else if (file_type == FILE_TYPE_PIPE)
299 file_flags |= FPIPE;
300
301 // Attempt to allocate a CRT file handle:
302 int const fh = _alloc_osfhnd();
303 if (fh == -1)
304 {
305 errno = EMFILE; // Too many open files
306 _doserrno = 0L; // This is not an OS error
307 return -1;
308 }
309
310 bool success = false;
311 __try
312 {
313 // The file is open. now set the info in _osfhnd array:
314 __acrt_lowio_set_os_handle(fh, osfhandle);
315
316 file_flags |= FOPEN;
317
318 _osfile(fh) = file_flags;
319 _textmode(fh) = __crt_lowio_text_mode::ansi;
320 _tm_unicode(fh) = false;
321
322 success = true;
323 }
324 __finally
325 {
326 if (!success)
327 {
328 _osfile(fh) &= ~FOPEN;
329 }
330
331 __acrt_lowio_unlock_fh(fh);
332 }
333 __endtry
334 return fh;
335}
336
337
338
339// Acquires the lock associated with the given file handle.
340extern "C" void __cdecl __acrt_lowio_lock_fh(int const fh)
341{
342 EnterCriticalSection(&_pioinfo(fh)->lock);
343}
344
345
346
347// Releases the lock associated with the given file handle.
348extern "C" void __cdecl __acrt_lowio_unlock_fh(int const fh)
349{
350 LeaveCriticalSection(&_pioinfo(fh)->lock);
351}