mirror of
https://github.com/reactos/reactos.git
synced 2025-08-09 01:13:20 +00:00
351 lines
11 KiB
C++
351 lines
11 KiB
C++
//
|
|
// osfinfo.cpp
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Defines the functions used to control allocation, locking, and freeing of CRT
|
|
// file handles.
|
|
//
|
|
#include <corecrt_internal_lowio.h>
|
|
|
|
|
|
|
|
extern "C" __crt_lowio_handle_data* __cdecl __acrt_lowio_create_handle_array()
|
|
{
|
|
__crt_unique_heap_ptr<__crt_lowio_handle_data> array(_calloc_crt_t(
|
|
__crt_lowio_handle_data,
|
|
IOINFO_ARRAY_ELTS));
|
|
|
|
if (!array)
|
|
return nullptr;
|
|
|
|
__crt_lowio_handle_data* const first = array.get();
|
|
__crt_lowio_handle_data* const last = first + IOINFO_ARRAY_ELTS;
|
|
for (auto it = first; it != last; ++it)
|
|
{
|
|
__acrt_InitializeCriticalSectionEx(&it->lock, _CORECRT_SPINCOUNT, 0);
|
|
it->osfhnd = reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE);
|
|
it->startpos = 0;
|
|
it->osfile = 0;
|
|
it->textmode = __crt_lowio_text_mode::ansi;
|
|
it->_pipe_lookahead[0] = LF;
|
|
it->_pipe_lookahead[1] = LF;
|
|
it->_pipe_lookahead[2] = LF;
|
|
it->unicode = false;
|
|
it->utf8translations = false;
|
|
it->dbcsBufferUsed = false;
|
|
for (int i = 0; i < sizeof(it->mbBuffer); ++i)
|
|
{
|
|
it->mbBuffer[i] = '\0';
|
|
}
|
|
}
|
|
|
|
return array.detach();
|
|
}
|
|
|
|
extern "C" void __cdecl __acrt_lowio_destroy_handle_array(__crt_lowio_handle_data* const array)
|
|
{
|
|
if (!array)
|
|
return;
|
|
|
|
__crt_lowio_handle_data* const first = array;
|
|
__crt_lowio_handle_data* const last = first + IOINFO_ARRAY_ELTS;
|
|
for (auto it = first; it != last; ++it)
|
|
{
|
|
DeleteCriticalSection(&it->lock);
|
|
}
|
|
|
|
_free_crt(array);
|
|
}
|
|
|
|
// Ensures that a lowio handle data object has been created for file handle 'fh'.
|
|
// The 'fh' must be less than the hard maximum, _NHANDLE_. If 'fh' is already
|
|
// backed by a handle data object, this function has no effect. Otherwise, this
|
|
// function extends the global arrays of handle data objects until 'fh' is backed
|
|
// by a handle data object.
|
|
extern "C" errno_t __cdecl __acrt_lowio_ensure_fh_exists(int const fh)
|
|
{
|
|
_VALIDATE_RETURN_ERRCODE(static_cast<unsigned>(fh) < _NHANDLE_, EBADF);
|
|
|
|
errno_t status = 0;
|
|
|
|
__acrt_lock(__acrt_lowio_index_lock);
|
|
__try
|
|
{
|
|
for (size_t i = 0; fh >= _nhandle; ++i)
|
|
{
|
|
if (__pioinfo[i])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
__pioinfo[i] = __acrt_lowio_create_handle_array();
|
|
if (!__pioinfo[i])
|
|
{
|
|
status = ENOMEM;
|
|
__leave;
|
|
}
|
|
|
|
_nhandle += IOINFO_ARRAY_ELTS;
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
__acrt_unlock(__acrt_lowio_index_lock);
|
|
}
|
|
__endtry
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
// Allocates a CRT file handle. This function finds the first free entry in
|
|
// the arrays of file objects and returns the index of that entry (that index
|
|
// is the CRT file handle) to the caller. The FOPEN flag is set in the new
|
|
// entry, to pevent multithreaded race conditions and deadlocks.
|
|
//
|
|
// Returns the CRT file handle on success; returns -1 on failure (e.g. if no
|
|
// more file handles are available or if memory allocation is required but
|
|
// fails).
|
|
//
|
|
// MULTITHREADING NOTE: If this function is successful and returns a CRT file
|
|
// handle, the handle is locked when it is returned and the FOPEN flag has been
|
|
// set. The caller must be sure to release the lock, and if the caller abandons
|
|
// the file handle, it must clear the FOPEN flag to free the handle.
|
|
extern "C" int __cdecl _alloc_osfhnd()
|
|
{
|
|
__acrt_lock(__acrt_lowio_index_lock);
|
|
int result = -1;
|
|
__try
|
|
{
|
|
// Search the arrays of file objects, in order, looking for the first
|
|
// free entry. The compound index of this free entry is the return
|
|
// value.
|
|
//
|
|
// The compound index of the file object entry *(__pioinfo[i] + j) is
|
|
// k = i * IOINFO_ARRAY_ELTS + j.
|
|
for (int i = 0; i < IOINFO_ARRAYS; ++i)
|
|
{
|
|
// If this __crt_lowio_handle_data array does not yet exist, create a new one:
|
|
if (!__pioinfo[i])
|
|
{
|
|
__pioinfo[i] = __acrt_lowio_create_handle_array();
|
|
if (!__pioinfo[i])
|
|
__leave;
|
|
|
|
_nhandle += IOINFO_ARRAY_ELTS;
|
|
|
|
// The first element of the newly allocated array of handle data
|
|
// objects is our first free entry. Note that since we hold the
|
|
// index lock, no one else can allocate this handle.
|
|
int const fh = i * IOINFO_ARRAY_ELTS;
|
|
|
|
__acrt_lowio_lock_fh(fh);
|
|
_osfile(fh) = FOPEN;
|
|
result = fh;
|
|
__leave;
|
|
}
|
|
|
|
// Otherwise, this file object array already exists. Search it looking
|
|
// for the first free entry:
|
|
__crt_lowio_handle_data* const first = __pioinfo[i];
|
|
__crt_lowio_handle_data* const last = first + IOINFO_ARRAY_ELTS;
|
|
for (__crt_lowio_handle_data* pio = first; pio != last; ++pio)
|
|
{
|
|
if (pio->osfile & FOPEN)
|
|
continue;
|
|
|
|
// Another thread may have grabbed this file handle out from
|
|
// under us while we waited for the lock. If so, continue on
|
|
// searching through the array.
|
|
//
|
|
// CRT_REFACTOR TODO: Resolve lowio synchronization issues.
|
|
EnterCriticalSection(&pio->lock);
|
|
if ((pio->osfile & FOPEN) != 0)
|
|
{
|
|
LeaveCriticalSection(&pio->lock);
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, this entry is ours: we hold the lock, so we can
|
|
// initialize it and return its handle:
|
|
int const fh = i * IOINFO_ARRAY_ELTS + static_cast<int>(pio - first);
|
|
_osfile(fh) = FOPEN;
|
|
_osfhnd(fh) = reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE);
|
|
result = fh;
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
// All entries are in use if we fall out of the loop. return -1 in this case (which result is already set to)
|
|
}
|
|
__finally
|
|
{
|
|
__acrt_unlock(__acrt_lowio_index_lock);
|
|
}
|
|
__endtry
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
// Sets the Win32 HANDLE associated with the specified CRT file. Returns 0
|
|
// on success; returns -1 and sets errno on failure.
|
|
extern "C" int __cdecl __acrt_lowio_set_os_handle(int const fh, intptr_t const value)
|
|
{
|
|
if (fh >= 0 &&
|
|
static_cast<unsigned>(fh) < static_cast<unsigned>(_nhandle) &&
|
|
_osfhnd(fh) == reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE))
|
|
{
|
|
if (_query_app_type() == _crt_console_app)
|
|
{
|
|
HANDLE const handle_value = reinterpret_cast<HANDLE>(value);
|
|
switch (fh)
|
|
{
|
|
case 0: SetStdHandle(STD_INPUT_HANDLE, handle_value); break;
|
|
case 1: SetStdHandle(STD_OUTPUT_HANDLE, handle_value); break;
|
|
case 2: SetStdHandle(STD_ERROR_HANDLE, handle_value); break;
|
|
}
|
|
}
|
|
|
|
_osfhnd(fh) = value;
|
|
return 0 ;
|
|
}
|
|
else
|
|
{
|
|
errno = EBADF; // Bad handle
|
|
_doserrno = 0; // This is not an OS error
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Marks the specified CRT file handle as free and available for allocation.
|
|
// Returns 0 on success; returns -1 and sets errno on failure.
|
|
extern "C" int __cdecl _free_osfhnd(int const fh)
|
|
{
|
|
if (fh >= 0 &&
|
|
static_cast<unsigned>(fh) < static_cast<unsigned>(_nhandle) &&
|
|
(_osfile(fh) & FOPEN) &&
|
|
_osfhnd(fh) != reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE))
|
|
{
|
|
if (_query_app_type() == _crt_console_app)
|
|
{
|
|
switch (fh)
|
|
{
|
|
case 0: SetStdHandle(STD_INPUT_HANDLE, nullptr); break;
|
|
case 1: SetStdHandle(STD_OUTPUT_HANDLE, nullptr); break;
|
|
case 2: SetStdHandle(STD_ERROR_HANDLE, nullptr); break;
|
|
}
|
|
}
|
|
|
|
_osfhnd(fh) = reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
errno = EBADF; // Bad handle
|
|
_doserrno = 0; // This is not an OS error
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Gets the Win32 HANDLE with which the given CRT file handle is associated.
|
|
// On success, returns the Win32 HANDLE; on failure, returns -1 and sets errno.
|
|
extern "C" intptr_t __cdecl _get_osfhandle(int const fh)
|
|
{
|
|
_CHECK_FH_CLEAR_OSSERR_RETURN(fh, EBADF, -1 );
|
|
_VALIDATE_CLEAR_OSSERR_RETURN(fh >= 0 && (unsigned)fh < (unsigned)_nhandle, EBADF, -1);
|
|
_VALIDATE_CLEAR_OSSERR_RETURN(_osfile(fh) & FOPEN, EBADF, -1);
|
|
|
|
return _osfhnd(fh);
|
|
}
|
|
|
|
|
|
|
|
// Allocates a free CRT file handle and associates it with the provided Win32
|
|
// HANDLE and sets its flags to the given flags. Returns the CRT file handle
|
|
// on success; returns -1 on failure.
|
|
extern "C" int __cdecl _open_osfhandle(intptr_t const osfhandle, int const source_flags)
|
|
{
|
|
// Copy relevant source_flags from second parameter
|
|
unsigned char file_flags = 0;
|
|
|
|
if (source_flags & _O_APPEND)
|
|
file_flags |= FAPPEND;
|
|
|
|
if (source_flags & _O_TEXT)
|
|
file_flags |= FTEXT;
|
|
|
|
if (source_flags & _O_NOINHERIT)
|
|
file_flags |= FNOINHERIT;
|
|
|
|
// Find out what type of file (file/device/pipe):
|
|
DWORD const file_type = GetFileType(reinterpret_cast<HANDLE>(osfhandle));
|
|
if (file_type == FILE_TYPE_UNKNOWN)
|
|
{
|
|
__acrt_errno_map_os_error(GetLastError());
|
|
return -1;
|
|
}
|
|
|
|
if (file_type == FILE_TYPE_CHAR)
|
|
file_flags |= FDEV;
|
|
|
|
else if (file_type == FILE_TYPE_PIPE)
|
|
file_flags |= FPIPE;
|
|
|
|
// Attempt to allocate a CRT file handle:
|
|
int const fh = _alloc_osfhnd();
|
|
if (fh == -1)
|
|
{
|
|
errno = EMFILE; // Too many open files
|
|
_doserrno = 0L; // This is not an OS error
|
|
return -1;
|
|
}
|
|
|
|
bool success = false;
|
|
__try
|
|
{
|
|
// The file is open. now set the info in _osfhnd array:
|
|
__acrt_lowio_set_os_handle(fh, osfhandle);
|
|
|
|
file_flags |= FOPEN;
|
|
|
|
_osfile(fh) = file_flags;
|
|
_textmode(fh) = __crt_lowio_text_mode::ansi;
|
|
_tm_unicode(fh) = false;
|
|
|
|
success = true;
|
|
}
|
|
__finally
|
|
{
|
|
if (!success)
|
|
{
|
|
_osfile(fh) &= ~FOPEN;
|
|
}
|
|
|
|
__acrt_lowio_unlock_fh(fh);
|
|
}
|
|
__endtry
|
|
return fh;
|
|
}
|
|
|
|
|
|
|
|
// Acquires the lock associated with the given file handle.
|
|
extern "C" void __cdecl __acrt_lowio_lock_fh(int const fh)
|
|
{
|
|
EnterCriticalSection(&_pioinfo(fh)->lock);
|
|
}
|
|
|
|
|
|
|
|
// Releases the lock associated with the given file handle.
|
|
extern "C" void __cdecl __acrt_lowio_unlock_fh(int const fh)
|
|
{
|
|
LeaveCriticalSection(&_pioinfo(fh)->lock);
|
|
}
|