mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 18:23:07 +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
215
sdk/lib/ucrt/env/searchenv.cpp
vendored
Normal file
215
sdk/lib/ucrt/env/searchenv.cpp
vendored
Normal file
|
@ -0,0 +1,215 @@
|
|||
//
|
||||
// searchenv.cpp
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Defines the searchenv() family of functions, which search for a file in the
|
||||
// paths contained in an environment variable (like %PATH%).
|
||||
//
|
||||
#include <direct.h>
|
||||
#include <corecrt_internal_traits.h>
|
||||
#include <io.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma warning(disable:__WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION) // 26036 Prefast doesn't understand perfect forwarding so annotations are lost.
|
||||
#pragma warning(disable:__WARNING_MISSING_ZERO_TERMINATION2) // 6054 Prefast doesn't understand perfect forwarding so annotations are lost.
|
||||
|
||||
// These functions search for a file in the paths in an environment variable.
|
||||
// The environment variable named 'environment_variable' is retrieved from the
|
||||
// environment. It is expected to contain a semicolon-delimited sequence of
|
||||
// directories, similar to %PATH%. The file name is concatenated onto the end
|
||||
// of each directory string in sequence and its existence is tested for. When
|
||||
// a file is found, the search stops and the buffer is filled with the full path
|
||||
// to the file. If the file is not found for whatever reason, a zero-length
|
||||
// string is placed in the buffer and an error code is returned.
|
||||
template <typename Character>
|
||||
static errno_t __cdecl common_searchenv_s(
|
||||
_In_z_ Character const* const file_name,
|
||||
_In_z_ Character const* const environment_variable,
|
||||
_Out_writes_z_(result_count) Character* const result_buffer,
|
||||
_In_ size_t const result_count
|
||||
) throw()
|
||||
{
|
||||
typedef __crt_char_traits<Character> traits;
|
||||
|
||||
_VALIDATE_RETURN_ERRCODE(result_buffer != nullptr, EINVAL);
|
||||
_VALIDATE_RETURN_ERRCODE(result_count > 0, EINVAL);
|
||||
if (!file_name)
|
||||
{
|
||||
result_buffer[0] = '\0';
|
||||
_VALIDATE_RETURN_ERRCODE(file_name != nullptr, EINVAL);
|
||||
}
|
||||
|
||||
// Special case: If the file name is an empty string, we'll just return an
|
||||
// empty result_buffer and set errno:
|
||||
if (file_name[0] == '\0')
|
||||
{
|
||||
result_buffer[0] = '\0';
|
||||
return errno = ENOENT;
|
||||
}
|
||||
|
||||
errno_t saved_errno = errno;
|
||||
int const access_result = traits::taccess_s(file_name, 0);
|
||||
errno = saved_errno;
|
||||
|
||||
// If the file name exists, convert it to a fully qualified result_buffer name:
|
||||
if (access_result == 0)
|
||||
{
|
||||
if (traits::tfullpath(result_buffer, file_name, result_count) == nullptr)
|
||||
{
|
||||
result_buffer[0] = '\0';
|
||||
return errno; // fullpath will set errno
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Character* path_string = nullptr;
|
||||
if (_ERRCHECK_EINVAL(traits::tdupenv_s_crt(&path_string, nullptr, environment_variable)) != 0 || path_string == nullptr)
|
||||
{
|
||||
result_buffer[0] = '\0';
|
||||
return errno = ENOENT; // The environment variable doesn't exist
|
||||
}
|
||||
|
||||
__crt_unique_heap_ptr<Character> const path_string_cleanup(path_string);
|
||||
|
||||
size_t const file_name_length = traits::tcslen(file_name);
|
||||
|
||||
size_t const local_path_count = _MAX_PATH + 4;
|
||||
Character local_path_buffer[local_path_count];
|
||||
|
||||
size_t path_count = local_path_count;
|
||||
Character* path_buffer = local_path_buffer;
|
||||
if (file_name_length >= result_count)
|
||||
{
|
||||
// The local buffer is not large enough; dynamically allocate a new
|
||||
// buffer. We add two to the size to account for a trailing slash
|
||||
// that we may need to add and for the null terminator:
|
||||
path_count = traits::tcslen(path_string) + file_name_length + 2;
|
||||
path_buffer = _calloc_crt_t(Character, path_count).detach(); // We'll retake ownership below
|
||||
if (!path_buffer)
|
||||
{
|
||||
result_buffer[0] = '\0';
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
__crt_unique_heap_ptr<Character> path_buffer_cleanup(path_buffer == local_path_buffer
|
||||
? nullptr
|
||||
: path_buffer);
|
||||
|
||||
saved_errno = errno;
|
||||
while (path_string)
|
||||
{
|
||||
Character* const previous_path_string = path_string;
|
||||
path_string = traits::tgetpath(path_string, path_buffer, path_count - file_name_length - 1);
|
||||
if (!path_string && path_buffer == local_path_buffer && errno == ERANGE)
|
||||
{
|
||||
// If the getpath operation failed because the buffer was not large
|
||||
// enough, try allocating a larger buffer:
|
||||
size_t const required_count = traits::tcslen(previous_path_string) + file_name_length + 2;
|
||||
|
||||
path_buffer_cleanup = _calloc_crt_t(Character, required_count);
|
||||
if (!path_buffer_cleanup)
|
||||
{
|
||||
result_buffer[0] = '\0';
|
||||
return errno = ENOMEM;
|
||||
}
|
||||
|
||||
path_count = required_count;
|
||||
path_buffer = path_buffer_cleanup.get();
|
||||
|
||||
path_string = traits::tgetpath(previous_path_string, path_buffer, path_count - file_name_length);
|
||||
}
|
||||
|
||||
if (!path_string || path_buffer[0] == '\0')
|
||||
{
|
||||
result_buffer[0] = '\0';
|
||||
return errno = ENOENT;
|
||||
}
|
||||
|
||||
// The result_buffer now holds a non-empty path name from path_string
|
||||
// and we know that the buffer is large enough to hold the concatenation
|
||||
// of the path with the file name (if not, the call to getpath would
|
||||
// have failed. So, we concatenate the path and file names:
|
||||
size_t path_length = traits::tcslen(path_buffer);
|
||||
Character* path_it = path_buffer + path_length;
|
||||
|
||||
// Add a trailing '\' if one is required:
|
||||
Character const last_character = *(path_it - 1);
|
||||
if (last_character != '/' && last_character != '\\' && last_character != ':')
|
||||
{
|
||||
*path_it++ = '\\';
|
||||
++path_length;
|
||||
}
|
||||
|
||||
// The path_it now points to the character following the trailing '\',
|
||||
// '/', or ':'; this is where we copy the file name:
|
||||
_ERRCHECK(traits::tcscpy_s(path_it, path_count - path_length, file_name));
|
||||
|
||||
// If we can't access the file at this path, it isn't a match:
|
||||
if (traits::taccess_s(path_buffer, 0) != 0)
|
||||
continue;
|
||||
|
||||
// Otherwise, we can access the file, and we copy the full path into the
|
||||
// caller-provided buffer:
|
||||
if (path_length + file_name_length + 1 > result_count)
|
||||
{
|
||||
result_buffer[0] = '\0';
|
||||
return errno = ERANGE;
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
|
||||
_ERRCHECK(traits::tcscpy_s(result_buffer, result_count, path_buffer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If we get here, we must have tried every path in the environment and not
|
||||
// found the file name:
|
||||
result_buffer[0] = '\0';
|
||||
return errno = ENOENT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" errno_t __cdecl _searchenv_s(
|
||||
char const* const file_name,
|
||||
char const* const environment_variable,
|
||||
char* const result_buffer,
|
||||
size_t const result_count
|
||||
)
|
||||
{
|
||||
return common_searchenv_s(file_name, environment_variable, result_buffer, result_count);
|
||||
}
|
||||
|
||||
extern "C" errno_t __cdecl _wsearchenv_s(
|
||||
wchar_t const* const file_name,
|
||||
wchar_t const* const environment_variable,
|
||||
wchar_t* const result_buffer,
|
||||
size_t const result_count
|
||||
)
|
||||
{
|
||||
return common_searchenv_s(file_name, environment_variable, result_buffer, result_count);
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" void __cdecl _searchenv(
|
||||
char const* const file_name,
|
||||
char const* const environment_variable,
|
||||
char* const result_buffer
|
||||
)
|
||||
{
|
||||
common_searchenv_s(file_name, environment_variable, result_buffer, _MAX_PATH);
|
||||
}
|
||||
|
||||
extern "C" void __cdecl _wsearchenv(
|
||||
wchar_t const* const file_name,
|
||||
wchar_t const* const environment_variable,
|
||||
wchar_t* const result_buffer
|
||||
)
|
||||
{
|
||||
common_searchenv_s(file_name, environment_variable, result_buffer, _MAX_PATH);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue