Reactos
at listview 351 lines 11 kB view raw
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}