mirror of
https://github.com/reactos/reactos.git
synced 2025-08-01 23:42:56 +00:00
[UCRT] Import Microsoft.Windows.SDK.CRTSource version 10.0.22621.3
Imported from https://www.nuget.org/packages/Microsoft.Windows.SDK.CRTSource/10.0.22621.3 License: MIT
This commit is contained in:
parent
f1b60c66f0
commit
04e0dc4a7a
568 changed files with 115483 additions and 0 deletions
34
sdk/lib/ucrt/filesystem/access.cpp
Normal file
34
sdk/lib/ucrt/filesystem/access.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// access.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _access() and _access_s() functions, which test file accessibility.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <io.h>
|
||||
#include <corecrt_internal_win32_buffer.h>
|
||||
|
||||
// See _waccess_s for information about this function's behavior.
|
||||
extern "C" errno_t __cdecl _access_s(char const* const path, int const access_mode)
|
||||
{
|
||||
if (path == nullptr) {
|
||||
return _waccess_s(nullptr, access_mode);
|
||||
}
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_path;
|
||||
|
||||
errno_t const cvt = __acrt_mbs_to_wcs_cp(path, wide_path, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
|
||||
if (cvt != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _waccess_s(wide_path.data(), access_mode);
|
||||
}
|
||||
|
||||
// The same as _access_s, but transforms all errors into a -1 return value.
|
||||
extern "C" int __cdecl _access(char const* const path, int const access_mode)
|
||||
{
|
||||
return _access_s(path, access_mode) == 0 ? 0 : -1;
|
||||
}
|
31
sdk/lib/ucrt/filesystem/chmod.cpp
Normal file
31
sdk/lib/ucrt/filesystem/chmod.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// chmod.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _chmod() function, which changes file attributes.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <io.h>
|
||||
#include <sys\stat.h>
|
||||
#include <corecrt_internal_win32_buffer.h>
|
||||
|
||||
// Changes the mode of a file. The only supported mode bit is _S_IWRITE, which
|
||||
// controls the user write (read-only) attribute of the file. Returns zero if
|
||||
// successful; returns -1 and sets errno and _doserrno on failure.
|
||||
extern "C" int __cdecl _chmod(char const* const path, int const mode)
|
||||
{
|
||||
if (path == nullptr) {
|
||||
return _wchmod(nullptr, mode);
|
||||
}
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_path;
|
||||
|
||||
errno_t const cvt = __acrt_mbs_to_wcs_cp(path, wide_path, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
|
||||
if (cvt != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _wchmod(wide_path.data(), mode);
|
||||
}
|
395
sdk/lib/ucrt/filesystem/findfile.cpp
Normal file
395
sdk/lib/ucrt/filesystem/findfile.cpp
Normal file
|
@ -0,0 +1,395 @@
|
|||
/***
|
||||
*findfile.c - C find file functions
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
*Purpose:
|
||||
* Defines _findfirst(), _findnext(), and _findclose().
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <corecrt_internal.h>
|
||||
#include <errno.h>
|
||||
#include <corecrt_internal_time.h>
|
||||
#include <io.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <corecrt_internal_win32_buffer.h>
|
||||
|
||||
|
||||
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// Utilities for working with the different file type and time data types
|
||||
//
|
||||
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
template <typename CrtTime>
|
||||
static CrtTime __cdecl convert_system_time_to_time_t(SYSTEMTIME const& st) throw();
|
||||
|
||||
template <>
|
||||
static __time32_t __cdecl convert_system_time_to_time_t(SYSTEMTIME const& st) throw()
|
||||
{
|
||||
return __loctotime32_t(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, -1);
|
||||
}
|
||||
|
||||
template <>
|
||||
static __time64_t __cdecl convert_system_time_to_time_t(SYSTEMTIME const& st) throw()
|
||||
{
|
||||
return __loctotime64_t(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, -1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename CrtTime>
|
||||
static CrtTime __cdecl convert_file_time_to_time_t(FILETIME const& ft) throw()
|
||||
{
|
||||
// A FILETIME of 0 becomes a time_t of -1:
|
||||
if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0)
|
||||
return static_cast<CrtTime>(-1);
|
||||
|
||||
SYSTEMTIME st_utc;
|
||||
if (!FileTimeToSystemTime(&ft, &st_utc))
|
||||
return static_cast<CrtTime>(-1);
|
||||
|
||||
SYSTEMTIME st_local;
|
||||
if (!SystemTimeToTzSpecificLocalTime(nullptr, &st_utc, &st_local))
|
||||
return static_cast<CrtTime>(-1);
|
||||
|
||||
return convert_system_time_to_time_t<CrtTime>(st_local);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Integer>
|
||||
static Integer convert_file_size_to_integer(DWORD const high, DWORD const low) throw();
|
||||
|
||||
template <>
|
||||
static __int64 convert_file_size_to_integer(DWORD const high, DWORD const low) throw()
|
||||
{
|
||||
return static_cast<__int64>(high) * 0x100000000i64 + static_cast<__int64>(low);
|
||||
}
|
||||
|
||||
template <>
|
||||
static unsigned long convert_file_size_to_integer(DWORD const high, DWORD const low) throw()
|
||||
{
|
||||
UNREFERENCED_PARAMETER(high);
|
||||
return low;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename WideFileData, typename NarrowFileData>
|
||||
_Success_(return)
|
||||
static bool __cdecl copy_wide_to_narrow_find_data(WideFileData const& wfd, _Out_ NarrowFileData& fd, unsigned int const code_page) throw()
|
||||
{
|
||||
__crt_internal_win32_buffer<char> name;
|
||||
|
||||
errno_t const cvt = __acrt_wcs_to_mbs_cp(wfd.name, name, code_page);
|
||||
|
||||
if (cvt != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_ERRCHECK(strcpy_s(fd.name, _countof(fd.name), name.data()));
|
||||
|
||||
fd.attrib = wfd.attrib;
|
||||
fd.time_create = wfd.time_create;
|
||||
fd.time_access = wfd.time_access;
|
||||
fd.time_write = wfd.time_write;
|
||||
fd.size = wfd.size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// The _findfirst family of functions
|
||||
//
|
||||
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// These functions find the first file matching the given wildcard pattern. If a
|
||||
// file is found, information about that file is stored in the pointed-to result
|
||||
// parameter. The return value is a handle that identifies the group of files
|
||||
// that match the pattern. If no file is found, or if an error occurs, errno is
|
||||
// set and -1 is returned.
|
||||
//
|
||||
// There are eight functions in this family, combining {wide name, narrow name}
|
||||
// x {32-bit file size, 64-bit file size} x {32-bit time_t, 64-bit time_t}.
|
||||
template <typename WideFileData>
|
||||
_Success_(return != -1)
|
||||
static intptr_t __cdecl common_find_first_wide(wchar_t const* const pattern, _Out_ WideFileData* const result) throw()
|
||||
{
|
||||
_VALIDATE_RETURN(result != nullptr, EINVAL, -1);
|
||||
_VALIDATE_RETURN(pattern != nullptr, EINVAL, -1);
|
||||
|
||||
// Ensure the underlying WIN32_FIND_DATA's file name buffer is not larger
|
||||
// than ours.
|
||||
static_assert(sizeof(WideFileData().name) <= sizeof(WIN32_FIND_DATAW().cFileName), "");
|
||||
|
||||
WIN32_FIND_DATAW wfd;
|
||||
HANDLE const hFile = FindFirstFileExW(pattern, FindExInfoStandard, &wfd, FindExSearchNameMatch, nullptr, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD const os_error = GetLastError();
|
||||
switch (os_error)
|
||||
{
|
||||
case ERROR_NO_MORE_FILES:
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
result->attrib = wfd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL
|
||||
? 0
|
||||
: wfd.dwFileAttributes;
|
||||
|
||||
typedef decltype(result->time_create) crt_time_type;
|
||||
result->time_create = convert_file_time_to_time_t<crt_time_type>(wfd.ftCreationTime);
|
||||
result->time_access = convert_file_time_to_time_t<crt_time_type>(wfd.ftLastAccessTime);
|
||||
result->time_write = convert_file_time_to_time_t<crt_time_type>(wfd.ftLastWriteTime);
|
||||
|
||||
typedef decltype(result->size) file_size_type;
|
||||
result->size = convert_file_size_to_integer<file_size_type>(wfd.nFileSizeHigh, wfd.nFileSizeLow);
|
||||
|
||||
_ERRCHECK(wcscpy_s(result->name, _countof(result->name), wfd.cFileName));
|
||||
|
||||
return reinterpret_cast<intptr_t>(hFile);
|
||||
}
|
||||
|
||||
template <typename WideFileData, typename NarrowFileData>
|
||||
_Success_(return != -1)
|
||||
static intptr_t __cdecl common_find_first_narrow(char const* const pattern, _Out_ NarrowFileData* const result, unsigned int const code_page) throw()
|
||||
{
|
||||
_VALIDATE_RETURN(result != nullptr, EINVAL, -1);
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_pattern;
|
||||
|
||||
errno_t const cvt = __acrt_mbs_to_wcs_cp(pattern, wide_pattern, code_page);
|
||||
|
||||
if (cvt != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
WideFileData wide_result;
|
||||
intptr_t const handle = common_find_first_wide(wide_pattern.data(), &wide_result);
|
||||
if (handle == -1)
|
||||
return -1;
|
||||
|
||||
if (!copy_wide_to_narrow_find_data(wide_result, *result, code_page))
|
||||
return -1;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Narrow name, 32-bit time_t, 32-bit size
|
||||
extern "C" intptr_t __cdecl _findfirst32(char const* const pattern, _finddata32_t* const result)
|
||||
{
|
||||
return common_find_first_narrow<_wfinddata32_t>(pattern, result, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
}
|
||||
|
||||
// Narrow name, 32-bit time_t, 64-bit size
|
||||
extern "C" intptr_t __cdecl _findfirst32i64(char const* const pattern, _finddata32i64_t* const result)
|
||||
{
|
||||
return common_find_first_narrow<_wfinddata32i64_t>(pattern, result, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
}
|
||||
|
||||
// Narrow name, 64-bit time_t, 32-bit size
|
||||
extern "C" intptr_t __cdecl _findfirst64i32(char const* const pattern, _finddata64i32_t* const result)
|
||||
{
|
||||
return common_find_first_narrow<_wfinddata64i32_t>(pattern, result, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
}
|
||||
|
||||
// Narrow name, 64-bit time_t, 64-bit size
|
||||
extern "C" intptr_t __cdecl _findfirst64(char const* const pattern, __finddata64_t* const result)
|
||||
{
|
||||
return common_find_first_narrow<_wfinddata64_t>(pattern, result, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
}
|
||||
|
||||
// Wide name, 32-bit time_t, 32-bit size
|
||||
extern "C" intptr_t __cdecl _wfindfirst32(wchar_t const* const pattern, _wfinddata32_t* const result)
|
||||
{
|
||||
return common_find_first_wide(pattern, result);
|
||||
}
|
||||
|
||||
// Wide name, 32-bit time_t, 64-bit size
|
||||
extern "C" intptr_t __cdecl _wfindfirst32i64(wchar_t const* const pattern, _wfinddata32i64_t* const result)
|
||||
{
|
||||
return common_find_first_wide(pattern, result);
|
||||
}
|
||||
|
||||
// Wide name, 64-bit time_t, 32-bit size
|
||||
extern "C" intptr_t __cdecl _wfindfirst64i32(wchar_t const* const pattern, _wfinddata64i32_t* const result)
|
||||
{
|
||||
return common_find_first_wide(pattern, result);
|
||||
}
|
||||
|
||||
// Wide name, 64-bit time_t, 64-bit size
|
||||
extern "C" intptr_t __cdecl _wfindfirst64(wchar_t const* const pattern, _wfinddata64_t* const result)
|
||||
{
|
||||
return common_find_first_wide(pattern, result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// The _findnext family of functions
|
||||
//
|
||||
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// These functions perform iteration over a set of files matching a wildcard
|
||||
// pattern. The handle argument must be a handle returned by a previous call to
|
||||
// one of the _findfirst functions that completed successfully. Each call to a
|
||||
// _findnext function advances the internal iterator and returns information
|
||||
// about the next file in the set.
|
||||
//
|
||||
// If iteration has not yet completed and a file is found, information about that
|
||||
// file is stored in the pointed-to result parameter. The return value is a
|
||||
// handle that identifies the group of files that match the pattern. If no file
|
||||
// is found, or if an error occurs, errno is set and -1 is returned.
|
||||
//
|
||||
// There are eight functions in this family, combining {wide name, narrow name}
|
||||
// x {32-bit file size, 64-bit file size} x {32-bit time_t, 64-bit time_t}.
|
||||
template <typename WideFileData>
|
||||
static int __cdecl common_find_next_wide(intptr_t const handle, WideFileData* const result) throw()
|
||||
{
|
||||
HANDLE const os_handle = reinterpret_cast<HANDLE>(handle);
|
||||
|
||||
_VALIDATE_RETURN(os_handle != 0 , EINVAL, -1);
|
||||
_VALIDATE_RETURN(os_handle != INVALID_HANDLE_VALUE, EINVAL, -1);
|
||||
_VALIDATE_RETURN(result != nullptr, EINVAL, -1);
|
||||
|
||||
WIN32_FIND_DATAW wfd;
|
||||
if (!FindNextFileW(os_handle, &wfd))
|
||||
{
|
||||
DWORD const os_error = GetLastError();
|
||||
switch (os_error)
|
||||
{
|
||||
case ERROR_NO_MORE_FILES:
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
result->attrib = wfd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL
|
||||
? 0
|
||||
: wfd.dwFileAttributes;
|
||||
|
||||
typedef decltype(result->time_create) crt_time_type;
|
||||
result->time_create = convert_file_time_to_time_t<crt_time_type>(wfd.ftCreationTime);
|
||||
result->time_access = convert_file_time_to_time_t<crt_time_type>(wfd.ftLastAccessTime);
|
||||
result->time_write = convert_file_time_to_time_t<crt_time_type>(wfd.ftLastWriteTime);
|
||||
|
||||
typedef decltype(result->size) file_size_type;
|
||||
result->size = convert_file_size_to_integer<file_size_type>(wfd.nFileSizeHigh, wfd.nFileSizeLow);
|
||||
|
||||
_ERRCHECK(wcscpy_s(result->name, _countof(result->name), wfd.cFileName));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename WideFileData, typename NarrowFileData>
|
||||
static int __cdecl common_find_next_narrow(intptr_t const pattern, NarrowFileData* const result, unsigned int const code_page) throw()
|
||||
{
|
||||
WideFileData wide_result;
|
||||
int const return_value = common_find_next_wide(pattern, &wide_result);
|
||||
if (return_value == -1)
|
||||
return -1;
|
||||
|
||||
if (!copy_wide_to_narrow_find_data(wide_result, *result, code_page))
|
||||
return -1;
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Narrow name, 32-bit time_t, 32-bit size
|
||||
extern "C" int __cdecl _findnext32(intptr_t const handle, _finddata32_t* const result)
|
||||
{
|
||||
return common_find_next_narrow<_wfinddata32_t>(handle, result, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
}
|
||||
|
||||
// Narrow name, 32-bit time_t, 64-bit size
|
||||
extern "C" int __cdecl _findnext32i64(intptr_t const handle, _finddata32i64_t* const result)
|
||||
{
|
||||
return common_find_next_narrow<_wfinddata32i64_t>(handle, result, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
}
|
||||
|
||||
// Narrow name, 64-bit time_t, 32-bit size
|
||||
extern "C" int __cdecl _findnext64i32(intptr_t const handle, _finddata64i32_t* const result)
|
||||
{
|
||||
return common_find_next_narrow<_wfinddata64i32_t>(handle, result, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
}
|
||||
|
||||
// Narrow name, 64-bit time_t, 64-bit size
|
||||
extern "C" int __cdecl _findnext64(intptr_t const handle, __finddata64_t* const result)
|
||||
{
|
||||
return common_find_next_narrow<_wfinddata64_t>(handle, result, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
}
|
||||
|
||||
// Wide name, 32-bit time_t, 32-bit size
|
||||
extern "C" int __cdecl _wfindnext32(intptr_t const handle, _wfinddata32_t* const result)
|
||||
{
|
||||
return common_find_next_wide(handle, result);
|
||||
}
|
||||
|
||||
// Wide name, 32-bit time_t, 64-bit size
|
||||
extern "C" int __cdecl _wfindnext32i64(intptr_t const handle, _wfinddata32i64_t* const result)
|
||||
{
|
||||
return common_find_next_wide(handle, result);
|
||||
}
|
||||
|
||||
// Wide name, 64-bit time_t, 32-bit size
|
||||
extern "C" int __cdecl _wfindnext64i32(intptr_t const handle, _wfinddata64i32_t* const result)
|
||||
{
|
||||
return common_find_next_wide(handle, result);
|
||||
}
|
||||
|
||||
// Wide name, 64-bit time_t, 64-bit size
|
||||
extern "C" int __cdecl _wfindnext64(intptr_t const handle, _wfinddata64_t* const result)
|
||||
{
|
||||
return common_find_next_wide(handle, result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// The _findclose function
|
||||
//
|
||||
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// This function releases resources associated with a _findfirst/_findnext
|
||||
// iteration. It must be called exactly once for each handle returned by
|
||||
// _findfirst. Returns 0 on success; -1 on failure.
|
||||
extern "C" int __cdecl _findclose(intptr_t const handle)
|
||||
{
|
||||
if (!FindClose(reinterpret_cast<HANDLE>(handle)))
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
153
sdk/lib/ucrt/filesystem/fullpath.cpp
Normal file
153
sdk/lib/ucrt/filesystem/fullpath.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
/***
|
||||
*fullpath.c -
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
*Purpose: contains the function _fullpath which makes an absolute path out
|
||||
* of a relative path. i.e. ..\pop\..\main.c => c:\src\main.c if the
|
||||
* current directory is c:\src\src
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <direct.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <corecrt_internal_traits.h>
|
||||
#include <windows.h>
|
||||
|
||||
/***
|
||||
*_TCHAR *_fullpath( _TCHAR *buf, const _TCHAR *path, maxlen );
|
||||
*
|
||||
*Purpose:
|
||||
*
|
||||
* _fullpath - combines the current directory with path to form
|
||||
* an absolute path. i.e. _fullpath takes care of .\ and ..\
|
||||
* in the path.
|
||||
*
|
||||
* The result is placed in buf. If the length of the result
|
||||
* is greater than maxlen nullptr is returned, otherwise
|
||||
* the address of buf is returned.
|
||||
*
|
||||
* If buf is nullptr then a buffer is malloc'ed and maxlen is
|
||||
* ignored. If there are no errors then the address of this
|
||||
* buffer is returned.
|
||||
*
|
||||
* If path specifies a drive, the curent directory of this
|
||||
* drive is combined with path. If the drive is not valid
|
||||
* and _fullpath needs the current directory of this drive
|
||||
* then nullptr is returned. If the current directory of this
|
||||
* non existant drive is not needed then a proper value is
|
||||
* returned.
|
||||
* For example: path = "z:\\pop" does not need z:'s current
|
||||
* directory but path = "z:pop" does.
|
||||
*
|
||||
*
|
||||
*
|
||||
*Entry:
|
||||
* _TCHAR *buf - pointer to a buffer maintained by the user;
|
||||
* _TCHAR *path - path to "add" to the current directory
|
||||
* int maxlen - length of the buffer pointed to by buf
|
||||
*
|
||||
*Exit:
|
||||
* Returns pointer to the buffer containing the absolute path
|
||||
* (same as buf if non-nullptr; otherwise, malloc is
|
||||
* used to allocate a buffer)
|
||||
*
|
||||
*Exceptions:
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
template <typename Character>
|
||||
_Success_(return != 0)
|
||||
static Character* __cdecl common_fullpath(
|
||||
_Out_writes_z_(max_count) Character* const user_buffer,
|
||||
Character const* const path,
|
||||
size_t const max_count,
|
||||
int const block_use,
|
||||
char const* const file_name,
|
||||
int const line_number
|
||||
) throw()
|
||||
{
|
||||
// These are referenced only in the Debug CRT build
|
||||
UNREFERENCED_PARAMETER(block_use);
|
||||
UNREFERENCED_PARAMETER(file_name);
|
||||
UNREFERENCED_PARAMETER(line_number);
|
||||
|
||||
typedef __crt_char_traits<Character> traits;
|
||||
|
||||
// If the path is empty, we have no work to do:
|
||||
if (path == nullptr || path[0] == '\0')
|
||||
{
|
||||
#pragma warning(suppress:__WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION) // 26036 Prefast does not understand perfect forwarding.
|
||||
return traits::tgetcwd(user_buffer, static_cast<int>(__min(max_count, INT_MAX)));
|
||||
}
|
||||
|
||||
if (user_buffer != nullptr) {
|
||||
// Using user buffer. Fail if not enough space.
|
||||
__crt_no_alloc_win32_buffer<Character> buffer(user_buffer, max_count);
|
||||
if (!traits::get_full_path_name(path, buffer)) {
|
||||
return user_buffer;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// Always new memory suitable for debug mode and releasing to the user.
|
||||
__crt_public_win32_buffer<Character> buffer(
|
||||
__crt_win32_buffer_debug_info(block_use, file_name, line_number)
|
||||
);
|
||||
traits::get_full_path_name(path, buffer);
|
||||
return buffer.detach();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" char* __cdecl _fullpath(
|
||||
char* const user_buffer,
|
||||
char const* const path,
|
||||
size_t const max_count
|
||||
)
|
||||
{
|
||||
return common_fullpath(user_buffer, path, max_count, _NORMAL_BLOCK, nullptr, 0);
|
||||
}
|
||||
|
||||
extern "C" wchar_t* __cdecl _wfullpath(
|
||||
wchar_t* const user_buffer,
|
||||
wchar_t const* const path,
|
||||
size_t const max_count
|
||||
)
|
||||
{
|
||||
return common_fullpath(user_buffer, path, max_count, _NORMAL_BLOCK, nullptr, 0);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#undef _fullpath_dbg
|
||||
#undef _wfullpath_dbg
|
||||
|
||||
extern "C" char* __cdecl _fullpath_dbg(
|
||||
char* const user_buffer,
|
||||
char const* const path,
|
||||
size_t const max_count,
|
||||
int const block_use,
|
||||
char const* const file_name,
|
||||
int const line_number
|
||||
)
|
||||
{
|
||||
return common_fullpath(user_buffer, path, max_count, block_use, file_name, line_number);
|
||||
}
|
||||
|
||||
extern "C" wchar_t* __cdecl _wfullpath_dbg(
|
||||
wchar_t* const user_buffer,
|
||||
wchar_t const* const path,
|
||||
size_t const max_count,
|
||||
int const block_use,
|
||||
char const* const file_name,
|
||||
int const line_number
|
||||
)
|
||||
{
|
||||
return common_fullpath(user_buffer, path, max_count, block_use, file_name, line_number);
|
||||
}
|
||||
|
||||
#endif // _DEBUG
|
205
sdk/lib/ucrt/filesystem/makepath.cpp
Normal file
205
sdk/lib/ucrt/filesystem/makepath.cpp
Normal file
|
@ -0,0 +1,205 @@
|
|||
//
|
||||
// makepath.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Defines the makepath family of functions, which compose a path string.
|
||||
//
|
||||
#include <corecrt_internal_securecrt.h>
|
||||
#include <mbstring.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
static char const* previous_character(char const* const first, char const* const current) throw()
|
||||
{
|
||||
return reinterpret_cast<char const*>(_mbsdec(
|
||||
reinterpret_cast<unsigned char const*>(first),
|
||||
reinterpret_cast<unsigned char const*>(current)));
|
||||
}
|
||||
|
||||
static wchar_t const* previous_character(wchar_t const*, wchar_t const* const current) throw()
|
||||
{
|
||||
return current - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Character>
|
||||
static errno_t __cdecl cleanup_after_error(
|
||||
_Out_writes_z_(count) Character* const buffer,
|
||||
size_t const count) throw()
|
||||
{
|
||||
// This is referenced only in the Debug CRT build
|
||||
UNREFERENCED_PARAMETER(count);
|
||||
|
||||
_RESET_STRING(buffer, count);
|
||||
_RETURN_BUFFER_TOO_SMALL(buffer, count);
|
||||
return EINVAL; // This is unreachable
|
||||
}
|
||||
|
||||
|
||||
|
||||
// These functions compose a path string from its component parts. They
|
||||
// concatenate the drive, directory, file_name, and extension into the provided
|
||||
// result_buffer. For the functions that do not have a buffer count parameter,
|
||||
// the buffer is assumed to be large enough to hold however many characters are
|
||||
// required.
|
||||
//
|
||||
// The drive may or may not contain a ':'. The directory may or may not contain
|
||||
// a leading or trailing '/' or '\'. The extension may or may not contain a
|
||||
// leading '.'.
|
||||
template <typename Character>
|
||||
static errno_t __cdecl common_makepath_s(
|
||||
_Out_writes_z_(result_count) Character* const result_buffer,
|
||||
_In_ size_t const result_count,
|
||||
_In_opt_z_ Character const* const drive,
|
||||
_In_opt_z_ Character const* const directory,
|
||||
_In_opt_z_ Character const* const file_name,
|
||||
_In_opt_z_ Character const* const extension
|
||||
) throw()
|
||||
{
|
||||
_VALIDATE_STRING(result_buffer, result_count);
|
||||
|
||||
Character* result_it = result_buffer;
|
||||
|
||||
// For the non-secure makepath functions, result_count is _CRT_UNBOUNDED_BUFFER_SIZE.
|
||||
// In this case, we do not want to perform arithmetic with the result_count. Instead,
|
||||
// we set the result_end to nullptr: result_it will never be a null pointer,
|
||||
// and when we need to perform arithmetic with result_end we can check it for
|
||||
// null first.
|
||||
Character* const result_end = result_count != _CRT_UNBOUNDED_BUFFER_SIZE
|
||||
? result_buffer + result_count
|
||||
: nullptr;
|
||||
|
||||
CRT_WARNING_DISABLE_PUSH(26015, "Silence prefast about overflow - covered by result_end for secure callers")
|
||||
|
||||
// Copy the drive:
|
||||
if (drive && drive[0] != '\0')
|
||||
{
|
||||
if (result_end != nullptr && result_end - result_it < 2)
|
||||
return cleanup_after_error(result_buffer, result_count);
|
||||
|
||||
*result_it++ = *drive;
|
||||
*result_it++ = ':';
|
||||
}
|
||||
|
||||
// Copy the directory:
|
||||
if (directory && directory[0] != '\0')
|
||||
{
|
||||
Character const* source_it = directory;
|
||||
while (*source_it != '\0')
|
||||
{
|
||||
if ((result_end != nullptr) && (result_it >= result_end))
|
||||
return cleanup_after_error(result_buffer, result_count);
|
||||
|
||||
*result_it++ = *source_it++;
|
||||
}
|
||||
|
||||
// Write a trailing backslash if there isn't one:
|
||||
source_it = previous_character(directory, source_it);
|
||||
if (*source_it != '/' && *source_it != '\\')
|
||||
{
|
||||
if ((result_end != nullptr) && (result_it >= result_end))
|
||||
return cleanup_after_error(result_buffer, result_count);
|
||||
|
||||
*result_it++ = '\\';
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the file name:
|
||||
if (file_name)
|
||||
{
|
||||
Character const* source_it = file_name;
|
||||
while (*source_it != '\0')
|
||||
{
|
||||
if ((result_end != nullptr) && (result_it >= result_end))
|
||||
return cleanup_after_error(result_buffer, result_count);
|
||||
|
||||
*result_it++ = *source_it++;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the extension:
|
||||
if (extension)
|
||||
{
|
||||
// Add a '.' if one is required:
|
||||
if (extension[0] != '\0' && extension[0] != '.')
|
||||
{
|
||||
if ((result_end != nullptr) && (result_it >= result_end))
|
||||
return cleanup_after_error(result_buffer, result_count);
|
||||
|
||||
*result_it++ = '.';
|
||||
}
|
||||
|
||||
Character const* source_it = extension;
|
||||
while (*source_it != '\0')
|
||||
{
|
||||
if ((result_end != nullptr) && (result_it >= result_end))
|
||||
return cleanup_after_error(result_buffer, result_count);
|
||||
|
||||
*result_it++ = *source_it++;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the null terminator:
|
||||
if ((result_end != nullptr) && (result_it >= result_end))
|
||||
return cleanup_after_error(result_buffer, result_count);
|
||||
|
||||
*result_it++ = '\0';
|
||||
|
||||
CRT_WARNING_POP
|
||||
|
||||
_FILL_STRING(result_buffer, result_count, result_it - result_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" void __cdecl _makepath(
|
||||
char* const result_buffer,
|
||||
char const* const drive,
|
||||
char const* const directory,
|
||||
char const* const file_name,
|
||||
char const* const extension
|
||||
)
|
||||
{
|
||||
_makepath_s(result_buffer, _CRT_UNBOUNDED_BUFFER_SIZE, drive, directory, file_name, extension);
|
||||
}
|
||||
|
||||
extern "C" void __cdecl _wmakepath(
|
||||
wchar_t* const result_buffer,
|
||||
wchar_t const* const drive,
|
||||
wchar_t const* const directory,
|
||||
wchar_t const* const file_name,
|
||||
wchar_t const* const extension
|
||||
)
|
||||
{
|
||||
_wmakepath_s(result_buffer, _CRT_UNBOUNDED_BUFFER_SIZE, drive, directory, file_name, extension);
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" errno_t __cdecl _makepath_s(
|
||||
char* const result_buffer,
|
||||
size_t const result_count,
|
||||
char const* const drive,
|
||||
char const* const directory,
|
||||
char const* const file_name,
|
||||
char const* const extension
|
||||
)
|
||||
{
|
||||
return common_makepath_s(result_buffer, result_count, drive, directory, file_name, extension);
|
||||
}
|
||||
|
||||
extern "C" errno_t __cdecl _wmakepath_s(
|
||||
wchar_t* const result_buffer,
|
||||
size_t const result_count,
|
||||
wchar_t const* const drive,
|
||||
wchar_t const* const directory,
|
||||
wchar_t const* const file_name,
|
||||
wchar_t const* const extension
|
||||
)
|
||||
{
|
||||
return common_makepath_s(result_buffer, result_count, drive, directory, file_name, extension);
|
||||
}
|
29
sdk/lib/ucrt/filesystem/mkdir.cpp
Normal file
29
sdk/lib/ucrt/filesystem/mkdir.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// mkdir.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _mkdir() function, which creates a directory.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <direct.h>
|
||||
#include <corecrt_internal_win32_buffer.h>
|
||||
|
||||
// Creates a directory. Returns 0 on success; returns -1 and sets errno and
|
||||
// _doserrno on failure.
|
||||
extern "C" int __cdecl _mkdir(char const* const path)
|
||||
{
|
||||
if (path == nullptr) {
|
||||
return _wmkdir(nullptr);
|
||||
}
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_path;
|
||||
|
||||
errno_t const cvt = __acrt_mbs_to_wcs_cp(path, wide_path, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
|
||||
if (cvt != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _wmkdir(wide_path.data());
|
||||
}
|
39
sdk/lib/ucrt/filesystem/rename.cpp
Normal file
39
sdk/lib/ucrt/filesystem/rename.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// rename.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The rename() function, which renames a file.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <io.h>
|
||||
#include <corecrt_internal_win32_buffer.h>
|
||||
|
||||
|
||||
|
||||
// See _wrename() for details about the behavior of this function. (This
|
||||
// function simply converts the multibyte strings to wide strings and calls
|
||||
// _wrename().)
|
||||
extern "C" int __cdecl rename(char const* const old_name, char const* const new_name)
|
||||
{
|
||||
unsigned int const code_page = __acrt_get_utf8_acp_compatibility_codepage();
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_old_name;
|
||||
|
||||
errno_t cvt1 = __acrt_mbs_to_wcs_cp(old_name, wide_old_name, code_page);
|
||||
if (cvt1 != 0)
|
||||
{
|
||||
errno = cvt1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_new_name;
|
||||
errno_t cvt2 = __acrt_mbs_to_wcs_cp(new_name, wide_new_name, code_page);
|
||||
if (cvt2 != 0)
|
||||
{
|
||||
errno = cvt2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _wrename(wide_old_name.data(), wide_new_name.data());
|
||||
}
|
31
sdk/lib/ucrt/filesystem/rmdir.cpp
Normal file
31
sdk/lib/ucrt/filesystem/rmdir.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// rmdir.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _rmdir() function, which removes a directory.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <direct.h>
|
||||
#include <corecrt_internal_win32_buffer.h>
|
||||
|
||||
// Removes the directory specified by the path. The directory must be empty, it
|
||||
// must not be the current working directory, and it must not be the root of any
|
||||
// drive. Returns 0 on success; returns -1 and sets errno and _doserrno on
|
||||
// failure.
|
||||
extern "C" int __cdecl _rmdir(char const* const path)
|
||||
{
|
||||
if (path == nullptr) {
|
||||
return _wrmdir(nullptr);
|
||||
}
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_path;
|
||||
|
||||
errno_t const cvt = __acrt_mbs_to_wcs_cp(path, wide_path, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
|
||||
if (cvt != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _wrmdir(wide_path.data());
|
||||
}
|
352
sdk/lib/ucrt/filesystem/splitpath.cpp
Normal file
352
sdk/lib/ucrt/filesystem/splitpath.cpp
Normal file
|
@ -0,0 +1,352 @@
|
|||
/***
|
||||
*splitpath.c - break down path name into components
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
*Purpose:
|
||||
* To provide support for accessing the individual components of an
|
||||
* arbitrary path name
|
||||
*
|
||||
*******************************************************************************/
|
||||
#include <corecrt_internal.h>
|
||||
#include <mbctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <corecrt_internal_securecrt.h>
|
||||
#include <corecrt_internal_traits.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Character>
|
||||
struct component_buffers
|
||||
{
|
||||
_Null_terminated_ _Maybenull_
|
||||
Character* _drive;
|
||||
size_t _drive_count;
|
||||
_Null_terminated_ _Maybenull_
|
||||
Character* _directory;
|
||||
size_t _directory_count;
|
||||
_Null_terminated_ _Maybenull_
|
||||
Character* _file_name;
|
||||
size_t _file_name_count;
|
||||
_Null_terminated_ _Maybenull_
|
||||
Character* _extension;
|
||||
size_t _extension_count;
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Character, typename ResetPolicy>
|
||||
static void __cdecl reset_buffers(
|
||||
component_buffers<Character>* const components,
|
||||
ResetPolicy const reset_buffer
|
||||
) throw()
|
||||
{
|
||||
reset_buffer(components->_drive, components->_drive_count );
|
||||
reset_buffer(components->_directory, components->_directory_count);
|
||||
reset_buffer(components->_file_name, components->_file_name_count);
|
||||
reset_buffer(components->_extension, components->_extension_count);
|
||||
}
|
||||
|
||||
// is_lead_byte helper
|
||||
// these functions are only used to ensure that trailing bytes that might
|
||||
// look like slashes or periods aren't misdetected.
|
||||
// UTF-8/UTF-16 don't have that problem as trail bytes never look like \ or .
|
||||
static bool __cdecl needs_trail_byte(char const c) throw()
|
||||
{
|
||||
// UTF-8 is OK here as the caller is really only concerned about trail
|
||||
// bytes that look like . or \ and UTF-8 trail bytes never will.
|
||||
return _ismbblead(c) != 0;
|
||||
}
|
||||
|
||||
static bool __cdecl needs_trail_byte(wchar_t) throw()
|
||||
{
|
||||
// UTF-16 is OK here as the caller is really only concerned about trail
|
||||
// characters that look like . or \ and UTF-16 surrogate pairs never will.
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Character, typename ResetPolicy, typename BufferCountTransformer>
|
||||
static errno_t __cdecl common_splitpath_internal(
|
||||
Character const* const path,
|
||||
component_buffers<Character>* const components,
|
||||
ResetPolicy const reset_buffer,
|
||||
BufferCountTransformer const transform_buffer_count
|
||||
) throw()
|
||||
{
|
||||
using traits = __crt_char_traits<Character>;
|
||||
|
||||
if (!path || !components)
|
||||
{
|
||||
reset_buffers(components, reset_buffer);
|
||||
_VALIDATE_RETURN_ERRCODE(false, EINVAL);
|
||||
}
|
||||
|
||||
if ((components->_drive == nullptr) != (components->_drive_count == 0) ||
|
||||
(components->_directory == nullptr) != (components->_directory_count == 0) ||
|
||||
(components->_file_name == nullptr) != (components->_file_name_count == 0) ||
|
||||
(components->_extension == nullptr) != (components->_extension_count == 0))
|
||||
{
|
||||
reset_buffers(components, reset_buffer);
|
||||
_VALIDATE_RETURN_ERRCODE(false, EINVAL);
|
||||
}
|
||||
|
||||
Character const* path_it = path;
|
||||
|
||||
// Extract drive letter and ':', if any:
|
||||
{
|
||||
size_t skip = _MAX_DRIVE - 2;
|
||||
Character const* p = path_it;
|
||||
while (skip > 0 && *p != '\0')
|
||||
{
|
||||
--skip;
|
||||
++p;
|
||||
}
|
||||
|
||||
if (*p == ':')
|
||||
{
|
||||
if (components->_drive)
|
||||
{
|
||||
if (components->_drive_count < _MAX_DRIVE)
|
||||
{
|
||||
reset_buffers(components, reset_buffer);
|
||||
return errno = ERANGE;
|
||||
}
|
||||
|
||||
traits::tcsncpy_s(components->_drive, transform_buffer_count(components->_drive_count), path_it, _MAX_DRIVE - 1);
|
||||
}
|
||||
|
||||
path_it = p + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_buffer(components->_drive, components->_drive_count);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the path string, if any. The path iterator now points to the first
|
||||
// character of the path, if there is one, or to the filename or extension if
|
||||
// no path was specified. Scan ahead for the last occurence, if any, of a '/'
|
||||
// or '\' path separator character. If none is found, there is no path. We
|
||||
// will also note the last '.' character found, if any, to aid in handling the
|
||||
// extension.
|
||||
Character const* p = path_it;
|
||||
Character const* last_slash = nullptr;
|
||||
Character const* last_dot = nullptr;
|
||||
for (; *p != '\0'; ++p)
|
||||
{
|
||||
// UTF-8 will never look like slashes or periods so this will be OK for UTF-8
|
||||
if (needs_trail_byte(*p))
|
||||
{
|
||||
// For narrow character strings, skip any multibyte characters to avoid
|
||||
// matching trail bytes that "look like" slashes or periods. This ++p
|
||||
// will skip the lead byte; the ++p in the for loop will skip the trail
|
||||
// byte.
|
||||
++p;
|
||||
|
||||
// If we've reached the end of the string, there is no trail byte.
|
||||
// (Technically, the string is malformed.)
|
||||
if (*p == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*p == '/' || *p == '\\')
|
||||
{
|
||||
last_slash = p + 1; // Point one past for later copy
|
||||
}
|
||||
else if (*p == '.')
|
||||
{
|
||||
last_dot = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (last_slash)
|
||||
{
|
||||
if (components->_directory)
|
||||
{
|
||||
size_t const length = static_cast<size_t>(last_slash - path_it);
|
||||
if (components->_directory_count <= length)
|
||||
{
|
||||
reset_buffers(components, reset_buffer);
|
||||
return errno = ERANGE;
|
||||
}
|
||||
|
||||
traits::tcsncpy_s(components->_directory, transform_buffer_count(components->_directory_count), path_it, length);
|
||||
}
|
||||
|
||||
path_it = last_slash;
|
||||
}
|
||||
else
|
||||
{
|
||||
reset_buffer(components->_directory, components->_directory_count);
|
||||
}
|
||||
|
||||
// Extract the file name and extension, if any. The path iterator now points
|
||||
// to the first character of the file name, if any, or the extension if no
|
||||
// file name was given. The dot points to the '.' beginning the extension,
|
||||
// if any.
|
||||
if (last_dot && last_dot >= path_it)
|
||||
{
|
||||
// We found a dot; it separates the file name from the extension:
|
||||
if (components->_file_name)
|
||||
{
|
||||
size_t const length = static_cast<size_t>(last_dot - path_it);
|
||||
if (components->_file_name_count <= length)
|
||||
{
|
||||
reset_buffers(components, reset_buffer);
|
||||
return errno = ERANGE;
|
||||
}
|
||||
|
||||
traits::tcsncpy_s(components->_file_name, transform_buffer_count(components->_file_name_count), path_it, length);
|
||||
}
|
||||
|
||||
if (components->_extension)
|
||||
{
|
||||
size_t const length = static_cast<size_t>(p - last_dot);
|
||||
if (components->_extension_count <= length)
|
||||
{
|
||||
reset_buffers(components, reset_buffer);
|
||||
return errno = ERANGE;
|
||||
}
|
||||
|
||||
traits::tcsncpy_s(components->_extension, transform_buffer_count(components->_extension_count), last_dot, length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No extension found; reset the extension and treat the remaining text
|
||||
// as the file name:
|
||||
if (components->_file_name)
|
||||
{
|
||||
size_t const length = static_cast<size_t>(p - path_it);
|
||||
if (components->_file_name_count <= length)
|
||||
{
|
||||
reset_buffers(components, reset_buffer);
|
||||
return errno = ERANGE;
|
||||
}
|
||||
|
||||
traits::tcsncpy_s(components->_file_name, transform_buffer_count(components->_file_name_count), path_it, length);
|
||||
}
|
||||
|
||||
if (components->_extension)
|
||||
{
|
||||
reset_buffer(components->_extension, components->_extension_count);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Character>
|
||||
_Success_(return == 0)
|
||||
static errno_t __cdecl common_splitpath_s(
|
||||
Character const* const path,
|
||||
component_buffers<Character>* const components
|
||||
) throw()
|
||||
{
|
||||
return common_splitpath_internal(path, components, [](_Out_writes_z_(buffer_count) Character* const buffer, size_t const buffer_count)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(buffer);
|
||||
UNREFERENCED_PARAMETER(buffer_count);
|
||||
if (buffer)
|
||||
{
|
||||
_RESET_STRING(buffer, buffer_count);
|
||||
}
|
||||
},
|
||||
[](size_t const n) { return n; });
|
||||
}
|
||||
|
||||
|
||||
extern "C" errno_t __cdecl _splitpath_s(
|
||||
char const* const path,
|
||||
char* const drive,
|
||||
size_t const drive_count,
|
||||
char* const directory,
|
||||
size_t const directory_count,
|
||||
char* const file_name,
|
||||
size_t const file_name_count,
|
||||
char* const extension,
|
||||
size_t const extension_count
|
||||
)
|
||||
{
|
||||
component_buffers<char> components =
|
||||
{
|
||||
drive, drive_count,
|
||||
directory, directory_count,
|
||||
file_name, file_name_count,
|
||||
extension, extension_count
|
||||
};
|
||||
|
||||
return common_splitpath_s(path, &components);
|
||||
}
|
||||
|
||||
extern "C" errno_t __cdecl _wsplitpath_s(
|
||||
wchar_t const* const path,
|
||||
wchar_t* const drive,
|
||||
size_t const drive_count,
|
||||
wchar_t* const directory,
|
||||
size_t const directory_count,
|
||||
wchar_t* const file_name,
|
||||
size_t const file_name_count,
|
||||
wchar_t* const extension,
|
||||
size_t const extension_count
|
||||
)
|
||||
{
|
||||
component_buffers<wchar_t> components =
|
||||
{
|
||||
drive, drive_count,
|
||||
directory, directory_count,
|
||||
file_name, file_name_count,
|
||||
extension, extension_count
|
||||
};
|
||||
|
||||
return common_splitpath_s(path, &components);
|
||||
}
|
||||
|
||||
template <typename Character>
|
||||
static void __cdecl common_splitpath(
|
||||
_In_z_ Character const* const path,
|
||||
_Pre_maybenull_ _Post_z_ Character* const drive,
|
||||
_Pre_maybenull_ _Post_z_ Character* const directory,
|
||||
_Pre_maybenull_ _Post_z_ Character* const file_name,
|
||||
_Pre_maybenull_ _Post_z_ Character* const extension
|
||||
) throw()
|
||||
{
|
||||
component_buffers<Character> components =
|
||||
{
|
||||
drive, drive ? _MAX_DRIVE : 0,
|
||||
directory, directory ? _MAX_DIR : 0,
|
||||
file_name, file_name ? _MAX_FNAME : 0,
|
||||
extension, extension ? _MAX_EXT : 0
|
||||
};
|
||||
|
||||
common_splitpath_internal(path, &components, [](Character* const buffer, size_t const buffer_count)
|
||||
{
|
||||
if (buffer && buffer_count != 0)
|
||||
{
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
},
|
||||
[](size_t){ return static_cast<size_t>(-1); });
|
||||
}
|
||||
|
||||
extern "C" void __cdecl _splitpath(
|
||||
char const* const path,
|
||||
char* const drive,
|
||||
char* const directory,
|
||||
char* const file_name,
|
||||
char* const extension
|
||||
)
|
||||
{
|
||||
return common_splitpath(path, drive, directory, file_name, extension);
|
||||
}
|
||||
|
||||
extern "C" void __cdecl _wsplitpath(
|
||||
wchar_t const* const path,
|
||||
wchar_t* const drive,
|
||||
wchar_t* const directory,
|
||||
wchar_t* const file_name,
|
||||
wchar_t* const extension
|
||||
)
|
||||
{
|
||||
return common_splitpath(path, drive, directory, file_name, extension);
|
||||
}
|
606
sdk/lib/ucrt/filesystem/stat.cpp
Normal file
606
sdk/lib/ucrt/filesystem/stat.cpp
Normal file
|
@ -0,0 +1,606 @@
|
|||
/***
|
||||
*stat64.c - get file status
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
*Purpose:
|
||||
* defines _stat64() - get file status
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <direct.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <corecrt_internal_lowio.h>
|
||||
#include <corecrt_internal_time.h>
|
||||
#include <corecrt_internal_win32_buffer.h>
|
||||
#include <io.h>
|
||||
#include <share.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
struct file_handle_traits
|
||||
{
|
||||
typedef int type;
|
||||
|
||||
inline static bool close(_In_ type const fh) throw()
|
||||
{
|
||||
_close(fh);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline static type get_invalid_value() throw()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
struct find_handle_traits
|
||||
{
|
||||
typedef HANDLE type;
|
||||
|
||||
static bool close(_In_ type const handle) throw()
|
||||
{
|
||||
return ::FindClose(handle) != FALSE;
|
||||
}
|
||||
|
||||
static type get_invalid_value() throw()
|
||||
{
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef __crt_unique_handle_t<file_handle_traits> scoped_file_handle;
|
||||
typedef __crt_unique_handle_t<find_handle_traits> unique_find_handle;
|
||||
}
|
||||
|
||||
static bool __cdecl is_slash(wchar_t const c) throw()
|
||||
{
|
||||
return c == L'\\' || c == L'/';
|
||||
}
|
||||
|
||||
static bool __cdecl compute_size(BY_HANDLE_FILE_INFORMATION const& file_info, long& size) throw()
|
||||
{
|
||||
size = 0;
|
||||
_VALIDATE_RETURN_NOEXC(file_info.nFileSizeHigh == 0 && file_info.nFileSizeLow <= LONG_MAX, EOVERFLOW, false);
|
||||
|
||||
size = static_cast<long>(file_info.nFileSizeLow);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __cdecl compute_size(BY_HANDLE_FILE_INFORMATION const& file_info, __int64& size) throw()
|
||||
{
|
||||
size = 0;
|
||||
_VALIDATE_RETURN_NOEXC(file_info.nFileSizeHigh <= LONG_MAX, EOVERFLOW, false);
|
||||
|
||||
size = static_cast<__int64>(
|
||||
static_cast<unsigned __int64>(file_info.nFileSizeHigh) * 0x100000000i64 +
|
||||
static_cast<unsigned __int64>(file_info.nFileSizeLow));
|
||||
return true;
|
||||
}
|
||||
|
||||
_Success_(return != 0)
|
||||
static wchar_t* __cdecl call_wfullpath(
|
||||
_Out_writes_z_(buffer_size) wchar_t* const buffer,
|
||||
wchar_t const* const path,
|
||||
size_t const buffer_size,
|
||||
_Inout_ wchar_t** const buffer_result
|
||||
) throw()
|
||||
{
|
||||
errno_t const saved_errno = errno;
|
||||
errno = 0;
|
||||
|
||||
wchar_t* const result = _wfullpath(buffer, path, buffer_size);
|
||||
if (result != nullptr)
|
||||
{
|
||||
errno = saved_errno;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (errno != ERANGE)
|
||||
return nullptr;
|
||||
|
||||
errno = saved_errno;
|
||||
|
||||
*buffer_result = _wfullpath(nullptr, path, 0);
|
||||
return *buffer_result;
|
||||
}
|
||||
|
||||
static bool __cdecl has_executable_extension(wchar_t const* const path) throw()
|
||||
{
|
||||
if (!path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t const* const last_dot = wcsrchr(path, L'.');
|
||||
if (!last_dot)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_wcsicmp(last_dot, L".exe") != 0 &&
|
||||
_wcsicmp(last_dot, L".cmd") != 0 &&
|
||||
_wcsicmp(last_dot, L".bat") != 0 &&
|
||||
_wcsicmp(last_dot, L".com") != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __cdecl is_root_or_empty(wchar_t const* const path) throw()
|
||||
{
|
||||
if (!path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool const has_drive_letter_and_colon = __ascii_iswalpha(path[0]) && path[1] == L':';
|
||||
wchar_t const* const path_start = has_drive_letter_and_colon
|
||||
? path + 2
|
||||
: path;
|
||||
|
||||
if (path_start[0] == L'\0')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_slash(path_start[0]) && path_start[1] == L'\0')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned short __cdecl convert_to_stat_mode(
|
||||
int const attributes,
|
||||
wchar_t const* const path
|
||||
) throw()
|
||||
{
|
||||
unsigned const os_mode = attributes & 0xff;
|
||||
|
||||
// check to see if this is a directory - note we must make a special
|
||||
// check for the root, which DOS thinks is not a directory:
|
||||
bool const is_directory = (os_mode & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
|
||||
unsigned short stat_mode = is_directory || is_root_or_empty(path)
|
||||
? _S_IFDIR | _S_IEXEC
|
||||
: _S_IFREG;
|
||||
|
||||
// If attribute byte does not have read-only bit, it is read-write:
|
||||
stat_mode |= (os_mode & FILE_ATTRIBUTE_READONLY) != 0
|
||||
? _S_IREAD
|
||||
: _S_IREAD | _S_IWRITE;
|
||||
|
||||
// See if file appears to be an executable by checking its extension:
|
||||
if (has_executable_extension(path))
|
||||
stat_mode |= _S_IEXEC;
|
||||
|
||||
// propagate user read/write/execute bits to group/other fields:
|
||||
stat_mode |= (stat_mode & 0700) >> 3;
|
||||
stat_mode |= (stat_mode & 0700) >> 6;
|
||||
|
||||
return stat_mode;
|
||||
}
|
||||
|
||||
// Returns false if and only if the path is invalid.
|
||||
static bool __cdecl get_drive_number_from_path(wchar_t const* const path, int& drive_number) throw()
|
||||
{
|
||||
drive_number = 0;
|
||||
|
||||
// If path has a drive letter and a colon, return the value of that drive,
|
||||
// as expected from _getdrive(). A = 1, B = 2, etc.
|
||||
// If the path is relative, then use _getdrive() to get the current drive.
|
||||
if (__ascii_iswalpha(path[0]) && path[1] == L':')
|
||||
{
|
||||
// If the path is just a drive letter followed by a colon, it is not a
|
||||
// valid input to the stat functions:
|
||||
if (path[2] == L'\0')
|
||||
{
|
||||
__acrt_errno_map_os_error(ERROR_FILE_NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
drive_number = __ascii_towlower(path[0]) - L'a' + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
drive_number = _getdrive();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __cdecl is_root_unc_name(wchar_t const* const path) throw()
|
||||
{
|
||||
// The shortest allowed string is of the form //x/y:
|
||||
if (wcslen(path) < 5)
|
||||
return 0;
|
||||
|
||||
// The string must begin with exactly two consecutive slashes:
|
||||
if (!is_slash(path[0]) || !is_slash(path[1]) || is_slash(path[2]))
|
||||
return 0;
|
||||
|
||||
// Find the slash between the server name and share name:
|
||||
wchar_t const* p = path + 2; // Account for the two slashes
|
||||
while (*++p)
|
||||
{
|
||||
if (is_slash(*p))
|
||||
break;
|
||||
}
|
||||
|
||||
// We reached the end before finding a slash, or the slash is at the end:
|
||||
if (p[0] == L'\0' || p[1] == L'\0')
|
||||
return 0;
|
||||
|
||||
// Is there a further slash?
|
||||
while (*++p)
|
||||
{
|
||||
if (is_slash(*p))
|
||||
break;
|
||||
}
|
||||
|
||||
// Just the final slash (or no final slash):
|
||||
if (p[0] == L'\0' || p[1] == L'\0')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool __cdecl is_usable_drive_or_unc_root(wchar_t const* const path) throw()
|
||||
{
|
||||
if (wcspbrk(path, L"./\\") == nullptr)
|
||||
return false;
|
||||
|
||||
wchar_t full_path_buffer[_MAX_PATH];
|
||||
__crt_unique_heap_ptr<wchar_t, __crt_public_free_policy> full_path_pointer;
|
||||
wchar_t* const full_path = call_wfullpath(
|
||||
full_path_buffer,
|
||||
path,
|
||||
_MAX_PATH,
|
||||
full_path_pointer.get_address_of());
|
||||
|
||||
if (full_path == nullptr)
|
||||
return false;
|
||||
|
||||
// Check to see if the path is a root of a directory ("C:\") or a UNC root
|
||||
// directory ("\\server\share\"):
|
||||
if (wcslen(full_path) != 3 && !is_root_unc_name(full_path))
|
||||
return false;
|
||||
|
||||
if (GetDriveTypeW(path) <= 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TimeType>
|
||||
static TimeType __cdecl convert_filetime_to_time_t(
|
||||
FILETIME const file_time,
|
||||
TimeType const fallback_time
|
||||
) throw()
|
||||
{
|
||||
using time_traits = __crt_time_time_t_traits<TimeType>;
|
||||
|
||||
if (file_time.dwLowDateTime == 0 && file_time.dwHighDateTime == 0)
|
||||
{
|
||||
return fallback_time;
|
||||
}
|
||||
|
||||
SYSTEMTIME system_time;
|
||||
SYSTEMTIME local_time;
|
||||
if (!FileTimeToSystemTime(&file_time, &system_time) ||
|
||||
!SystemTimeToTzSpecificLocalTime(nullptr, &system_time, &local_time))
|
||||
{
|
||||
// Ignore failures from these APIs, for consistency with the logic below
|
||||
// that ignores failures in the conversion from SYSTEMTIME to time_t.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If the conversion to time_t fails, it will return -1. We'll use this as
|
||||
// the time_t value instead of failing the entire stat call, to allow callers
|
||||
// to get information about files whose time information is not representable.
|
||||
// (Callers use this API to test for file existence or to get file sizes.)
|
||||
return time_traits::loctotime(
|
||||
local_time.wYear,
|
||||
local_time.wMonth,
|
||||
local_time.wDay,
|
||||
local_time.wHour,
|
||||
local_time.wMinute,
|
||||
local_time.wSecond,
|
||||
-1);
|
||||
}
|
||||
|
||||
template <typename StatStruct>
|
||||
static bool __cdecl common_stat_handle_file_not_opened(
|
||||
wchar_t const* const path,
|
||||
StatStruct& result
|
||||
) throw()
|
||||
{
|
||||
using time_traits = __crt_time_time_t_traits<decltype(result.st_mtime)>;
|
||||
|
||||
if (!is_usable_drive_or_unc_root(path))
|
||||
{
|
||||
__acrt_errno_map_os_error(ERROR_FILE_NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Root directories (such as C:\ or \\server\share\) are fabricated:
|
||||
result.st_mode = convert_to_stat_mode(FILE_ATTRIBUTE_DIRECTORY, path);
|
||||
result.st_nlink = 1;
|
||||
|
||||
// Try to get the disk from the name; if there is none, get the current disk:
|
||||
int drive_number{};
|
||||
if (!get_drive_number_from_path(path, drive_number))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result.st_rdev = static_cast<_dev_t>(drive_number - 1);
|
||||
result.st_dev = static_cast<_dev_t>(drive_number - 1); // A=0, B=1, etc.
|
||||
|
||||
result.st_mtime = time_traits::loctotime(1980, 1, 1, 0, 0, 0, -1);
|
||||
result.st_atime = result.st_mtime;
|
||||
result.st_ctime = result.st_mtime;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename StatStruct>
|
||||
static bool __cdecl common_stat_handle_file_opened(
|
||||
wchar_t const* const path,
|
||||
int const fh,
|
||||
HANDLE const handle,
|
||||
StatStruct& result
|
||||
) throw()
|
||||
{
|
||||
using time_type = decltype(result.st_mtime);
|
||||
|
||||
// Figure out what kind of file underlies the file handle:
|
||||
int const file_type = GetFileType(handle) & ~FILE_TYPE_REMOTE;
|
||||
|
||||
if (file_type == FILE_TYPE_DISK)
|
||||
{
|
||||
// Okay, it's a disk file; we'll do the normal logic below.
|
||||
}
|
||||
else if (file_type == FILE_TYPE_CHAR || file_type == FILE_TYPE_PIPE)
|
||||
{
|
||||
// We treat pipes and devices similarly: no further information is
|
||||
// available from any API, so we set the fields as reasonably as
|
||||
// possible and return.
|
||||
result.st_mode = file_type == FILE_TYPE_CHAR
|
||||
? _S_IFCHR
|
||||
: _S_IFIFO;
|
||||
|
||||
result.st_nlink = 1;
|
||||
|
||||
result.st_rdev = static_cast<unsigned>(fh);
|
||||
result.st_dev = static_cast<unsigned>(fh);
|
||||
|
||||
if (file_type != FILE_TYPE_CHAR)
|
||||
{
|
||||
unsigned long available;
|
||||
if (PeekNamedPipe(handle, nullptr, 0, nullptr, &available, nullptr))
|
||||
{
|
||||
result.st_size = static_cast<_off_t>(available);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (file_type == FILE_TYPE_UNKNOWN)
|
||||
{
|
||||
errno = EBADF;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Per the documentation we should not reach here, but we'll add
|
||||
// this just to be safe:
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// At this point, we know we have a file on disk. Set the common fields:
|
||||
result.st_nlink = 1;
|
||||
|
||||
if (path)
|
||||
{
|
||||
// Try to get the disk from the name; if there is none, get the current disk:
|
||||
int drive_number{};
|
||||
if (!get_drive_number_from_path(path, drive_number))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result.st_rdev = static_cast<_dev_t>(drive_number - 1);
|
||||
result.st_dev = static_cast<_dev_t>(drive_number - 1); // A=0, B=1, etc.
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION file_info{};
|
||||
if (!GetFileInformationByHandle(handle, &file_info))
|
||||
{
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
result.st_mode = convert_to_stat_mode(file_info.dwFileAttributes, path);
|
||||
|
||||
result.st_mtime = convert_filetime_to_time_t(file_info.ftLastWriteTime, static_cast<time_type>(0));
|
||||
result.st_atime = convert_filetime_to_time_t(file_info.ftLastAccessTime, result.st_mtime);
|
||||
result.st_ctime = convert_filetime_to_time_t(file_info.ftCreationTime, result.st_mtime);
|
||||
|
||||
if (!compute_size(file_info, result.st_size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename StatStruct>
|
||||
static int __cdecl common_stat(
|
||||
wchar_t const* const path,
|
||||
StatStruct* const result
|
||||
) throw()
|
||||
{
|
||||
_VALIDATE_CLEAR_OSSERR_RETURN(result != nullptr, EINVAL, -1);
|
||||
*result = StatStruct{};
|
||||
|
||||
_VALIDATE_CLEAR_OSSERR_RETURN(path != nullptr, EINVAL, -1);
|
||||
|
||||
__crt_unique_handle const file_handle(CreateFileW(
|
||||
path,
|
||||
FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
nullptr));
|
||||
|
||||
if (file_handle)
|
||||
{
|
||||
if (!common_stat_handle_file_opened(path, -1, file_handle.get(), *result))
|
||||
{
|
||||
*result = StatStruct{};
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!common_stat_handle_file_not_opened(path, *result))
|
||||
{
|
||||
*result = StatStruct{};
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename StatStruct>
|
||||
static int __cdecl common_stat(
|
||||
char const* const path,
|
||||
StatStruct* const result
|
||||
) throw()
|
||||
{
|
||||
if (path == nullptr) {
|
||||
return common_stat(static_cast<wchar_t const*>(nullptr), result);
|
||||
}
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_path;
|
||||
|
||||
errno_t const cvt = __acrt_mbs_to_wcs_cp(path, wide_path, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
|
||||
if (cvt != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return common_stat(wide_path.data(), result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" int __cdecl _stat32(char const* const path, struct _stat32* const result)
|
||||
{
|
||||
return common_stat(path, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _stat32i64(char const* const path, struct _stat32i64* const result)
|
||||
{
|
||||
return common_stat(path, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _stat64(char const* const path, struct _stat64* const result)
|
||||
{
|
||||
return common_stat(path, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _stat64i32(char const* const path, struct _stat64i32* const result)
|
||||
{
|
||||
return common_stat(path, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _wstat32(wchar_t const* const path, struct _stat32* const result)
|
||||
{
|
||||
return common_stat(path, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _wstat32i64(wchar_t const* const path, struct _stat32i64* const result)
|
||||
{
|
||||
return common_stat(path, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _wstat64(wchar_t const* const path, struct _stat64* const result)
|
||||
{
|
||||
return common_stat(path, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _wstat64i32(wchar_t const* const path, struct _stat64i32* const result)
|
||||
{
|
||||
return common_stat(path, result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename StatStruct>
|
||||
static int __cdecl common_fstat(int const fh, StatStruct* const result) throw()
|
||||
{
|
||||
_VALIDATE_CLEAR_OSSERR_RETURN(result != nullptr, EINVAL, -1);
|
||||
*result = StatStruct{};
|
||||
|
||||
_CHECK_FH_CLEAR_OSSERR_RETURN(fh, EBADF, -1);
|
||||
_VALIDATE_CLEAR_OSSERR_RETURN(fh >= 0 && fh < _nhandle, EBADF, -1);
|
||||
_VALIDATE_CLEAR_OSSERR_RETURN(_osfile(fh) & FOPEN, EBADF, -1);
|
||||
|
||||
return __acrt_lowio_lock_fh_and_call(fh, [&]()
|
||||
{
|
||||
if ((_osfile(fh) & FOPEN) == 0)
|
||||
{
|
||||
errno = EBADF;
|
||||
_ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!common_stat_handle_file_opened(nullptr, fh, reinterpret_cast<HANDLE>(_osfhnd(fh)), *result))
|
||||
{
|
||||
*result = StatStruct{};
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _fstat32(int const fh, struct _stat32* const result)
|
||||
{
|
||||
return common_fstat(fh, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _fstat32i64(int const fh, struct _stat32i64* const result)
|
||||
{
|
||||
return common_fstat(fh, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _fstat64(int const fh, struct _stat64* const result)
|
||||
{
|
||||
return common_fstat(fh, result);
|
||||
}
|
||||
|
||||
extern "C" int __cdecl _fstat64i32(int const fh, struct _stat64i32* const result)
|
||||
{
|
||||
return common_fstat(fh, result);
|
||||
}
|
35
sdk/lib/ucrt/filesystem/unlink.cpp
Normal file
35
sdk/lib/ucrt/filesystem/unlink.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// unlink.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The remove() and unlink() functions, which remove (delete) files.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <stdio.h>
|
||||
#include <corecrt_internal_win32_buffer.h>
|
||||
|
||||
// Deletes the specified file. Returns zero if successful; returns -1 and sets
|
||||
// errno and _doserrno on failure.
|
||||
extern "C" int __cdecl remove(char const* const path)
|
||||
{
|
||||
if (path == nullptr)
|
||||
return _wremove(nullptr);
|
||||
|
||||
__crt_internal_win32_buffer<wchar_t> wide_path;
|
||||
|
||||
errno_t const cvt = __acrt_mbs_to_wcs_cp(path, wide_path, __acrt_get_utf8_acp_compatibility_codepage());
|
||||
|
||||
if (cvt != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _wremove(wide_path.data());
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" int __cdecl _unlink(char const* const path)
|
||||
{
|
||||
return remove(path);
|
||||
}
|
55
sdk/lib/ucrt/filesystem/waccess.cpp
Normal file
55
sdk/lib/ucrt/filesystem/waccess.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// waccess.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _waccess() and _waccess_s() functions, which test file accessibility.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <io.h>
|
||||
|
||||
|
||||
|
||||
// Tests whether the specified file can be accessed with the specified mode. The
|
||||
// access_mode must be one of: 0 (exist only), 2 (write), 4 (read), 6 (read and
|
||||
// write). Returns zero if the file can be accessed with the given mode; returns
|
||||
// an error code otherwise or if an error occurs.
|
||||
extern "C" errno_t __cdecl _waccess_s(wchar_t const* const path, int const access_mode)
|
||||
{
|
||||
_VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE(path != nullptr, EINVAL);
|
||||
_VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE((access_mode & (~6)) == 0, EINVAL);
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA attributes;
|
||||
if (!GetFileAttributesExW(path, GetFileExInfoStandard, &attributes))
|
||||
{
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return errno;
|
||||
}
|
||||
|
||||
// All directories have both read and write access:
|
||||
if (attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
return 0;
|
||||
|
||||
// If we require write access, make sure the read only flag is not set:
|
||||
bool const file_is_read_only = (attributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0;
|
||||
bool const mode_requires_write = (access_mode & 2) != 0;
|
||||
|
||||
if (file_is_read_only && mode_requires_write)
|
||||
{
|
||||
_doserrno = ERROR_ACCESS_DENIED;
|
||||
errno = EACCES;
|
||||
return errno;
|
||||
}
|
||||
|
||||
// Otherwise, the file is accessible:
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The same as _waccess_s, but transforms all errors into a -1 return value.
|
||||
extern "C" int __cdecl _waccess(wchar_t const* const path, int const access_mode)
|
||||
{
|
||||
return _waccess_s(path, access_mode) == 0 ? 0 : -1;
|
||||
}
|
45
sdk/lib/ucrt/filesystem/wchmod.cpp
Normal file
45
sdk/lib/ucrt/filesystem/wchmod.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// wchmod.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _wchmod() function, which changes file attributes.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <io.h>
|
||||
#include <sys\stat.h>
|
||||
|
||||
|
||||
|
||||
// Changes the mode of a file. The only supported mode bit is _S_IWRITE, which
|
||||
// controls the user write (read-only) attribute of the file. Returns zero if
|
||||
// successful; returns -1 and sets errno and _doserrno on failure.
|
||||
extern "C" int __cdecl _wchmod(wchar_t const* const path, int const mode)
|
||||
{
|
||||
_VALIDATE_CLEAR_OSSERR_RETURN(path != nullptr, EINVAL, -1);
|
||||
|
||||
WIN32_FILE_ATTRIBUTE_DATA attributes;
|
||||
if (!GetFileAttributesExW(path, GetFileExInfoStandard, &attributes))
|
||||
{
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set or clear the read-only flag:
|
||||
if (mode & _S_IWRITE)
|
||||
{
|
||||
attributes.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
attributes.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
|
||||
if (!SetFileAttributesW(path, attributes.dwFileAttributes))
|
||||
{
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
24
sdk/lib/ucrt/filesystem/wmkdir.cpp
Normal file
24
sdk/lib/ucrt/filesystem/wmkdir.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// wmkdir.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _wmkdir() function, which creates a directory.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <direct.h>
|
||||
|
||||
|
||||
|
||||
// Creates a directory. Returns 0 on success; returns -1 and sets errno and
|
||||
// _doserrno on failure.
|
||||
extern "C" int __cdecl _wmkdir(wchar_t const* const path)
|
||||
{
|
||||
if (!CreateDirectoryW(path, nullptr))
|
||||
{
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
25
sdk/lib/ucrt/filesystem/wrename.cpp
Normal file
25
sdk/lib/ucrt/filesystem/wrename.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// wrename.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _wrename() function, which renames a file.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <io.h>
|
||||
|
||||
|
||||
|
||||
// Renames the file named 'old_name' to be named 'new_name'. Returns zero if
|
||||
// successful; returns -1 and sets errno and _doserrno on failure.
|
||||
extern "C" int __cdecl _wrename(wchar_t const* const old_name, wchar_t const* const new_name)
|
||||
{
|
||||
// The MOVEFILE_COPY_ALLOWED flag alloes moving to a different volume.
|
||||
if (!MoveFileExW(old_name, new_name, MOVEFILE_COPY_ALLOWED))
|
||||
{
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
26
sdk/lib/ucrt/filesystem/wrmdir.cpp
Normal file
26
sdk/lib/ucrt/filesystem/wrmdir.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// wrmdir.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _wrmdir() function, which removes a directory.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <direct.h>
|
||||
|
||||
|
||||
|
||||
// Removes the directory specified by the path. The directory must be empty, it
|
||||
// must not be the current working directory, and it must not be the root of any
|
||||
// drive. Returns 0 on success; returns -1 and sets errno and _doserrno on
|
||||
// failure.
|
||||
extern "C" int __cdecl _wrmdir(wchar_t const* const path)
|
||||
{
|
||||
if (!RemoveDirectoryW(path))
|
||||
{
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
31
sdk/lib/ucrt/filesystem/wunlink.cpp
Normal file
31
sdk/lib/ucrt/filesystem/wunlink.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// wunlink.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// The _wremove() and _wunlink() functions, which remove (delete) files.
|
||||
//
|
||||
#include <corecrt_internal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
// Deletes the specified file. Returns zero if successful; returns -1 and sets
|
||||
// errno and _doserrno on failure.
|
||||
extern "C" int __cdecl _wremove(wchar_t const* const path)
|
||||
{
|
||||
if (!DeleteFileW(path))
|
||||
{
|
||||
__acrt_errno_map_os_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" int __cdecl _wunlink(wchar_t const* const path)
|
||||
{
|
||||
return _wremove(path);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue