ReactOS 0.4.16-dev-1020-gf135cab
searchenv.cpp File Reference
#include <direct.h>
#include <corecrt_internal_traits.h>
#include <io.h>
#include <stdlib.h>
#include <string.h>
Include dependency graph for searchenv.cpp:

Go to the source code of this file.

Functions

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 ()
 
errno_t __cdecl _searchenv_s (char const *const file_name, char const *const environment_variable, char *const result_buffer, size_t const result_count)
 
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)
 
void __cdecl _searchenv (char const *const file_name, char const *const environment_variable, char *const result_buffer)
 
void __cdecl _wsearchenv (wchar_t const *const file_name, wchar_t const *const environment_variable, wchar_t *const result_buffer)
 

Function Documentation

◆ _searchenv()

void __cdecl _searchenv ( char const *const  file_name,
char const *const  environment_variable,
char *const  result_buffer 
)

Definition at line 199 of file searchenv.cpp.

204{
205 common_searchenv_s(file_name, environment_variable, result_buffer, _MAX_PATH);
206}
result_buffer_count char *const result_buffer
Definition: cvt.cpp:111
#define _MAX_PATH
Definition: utility.h:77
static LPCWSTR file_name
Definition: protocol.c:147
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)
Definition: searchenv.cpp:27

◆ _searchenv_s()

errno_t __cdecl _searchenv_s ( char const *const  file_name,
char const *const  environment_variable,
char *const  result_buffer,
size_t const  result_count 
)

Definition at line 177 of file searchenv.cpp.

183{
184 return common_searchenv_s(file_name, environment_variable, result_buffer, result_count);
185}

◆ _wsearchenv()

void __cdecl _wsearchenv ( wchar_t const *const  file_name,
wchar_t const *const  environment_variable,
wchar_t *const  result_buffer 
)

Definition at line 208 of file searchenv.cpp.

213{
214 common_searchenv_s(file_name, environment_variable, result_buffer, _MAX_PATH);
215}

◆ _wsearchenv_s()

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 
)

Definition at line 187 of file searchenv.cpp.

193{
194 return common_searchenv_s(file_name, environment_variable, result_buffer, result_count);
195}

◆ common_searchenv_s()

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 (
)
static

Definition at line 27 of file searchenv.cpp.

33{
34 typedef __crt_char_traits<Character> traits;
35
37 _VALIDATE_RETURN_ERRCODE(result_count > 0, EINVAL);
38 if (!file_name)
39 {
40 result_buffer[0] = '\0';
42 }
43
44 // Special case: If the file name is an empty string, we'll just return an
45 // empty result_buffer and set errno:
46 if (file_name[0] == '\0')
47 {
48 result_buffer[0] = '\0';
49 return errno = ENOENT;
50 }
51
52 errno_t saved_errno = errno;
53 int const access_result = traits::taccess_s(file_name, 0);
54 errno = saved_errno;
55
56 // If the file name exists, convert it to a fully qualified result_buffer name:
57 if (access_result == 0)
58 {
59 if (traits::tfullpath(result_buffer, file_name, result_count) == nullptr)
60 {
61 result_buffer[0] = '\0';
62 return errno; // fullpath will set errno
63 }
64
65 return 0;
66 }
67
68 Character* path_string = nullptr;
69 if (_ERRCHECK_EINVAL(traits::tdupenv_s_crt(&path_string, nullptr, environment_variable)) != 0 || path_string == nullptr)
70 {
71 result_buffer[0] = '\0';
72 return errno = ENOENT; // The environment variable doesn't exist
73 }
74
75 __crt_unique_heap_ptr<Character> const path_string_cleanup(path_string);
76
77 size_t const file_name_length = traits::tcslen(file_name);
78
79 size_t const local_path_count = _MAX_PATH + 4;
80 Character local_path_buffer[local_path_count];
81
82 size_t path_count = local_path_count;
83 Character* path_buffer = local_path_buffer;
84 if (file_name_length >= result_count)
85 {
86 // The local buffer is not large enough; dynamically allocate a new
87 // buffer. We add two to the size to account for a trailing slash
88 // that we may need to add and for the null terminator:
89 path_count = traits::tcslen(path_string) + file_name_length + 2;
90 path_buffer = _calloc_crt_t(Character, path_count).detach(); // We'll retake ownership below
91 if (!path_buffer)
92 {
93 result_buffer[0] = '\0';
94 return errno = ENOMEM;
95 }
96 }
97
98 __crt_unique_heap_ptr<Character> path_buffer_cleanup(path_buffer == local_path_buffer
99 ? nullptr
100 : path_buffer);
101
102 saved_errno = errno;
103 while (path_string)
104 {
105 Character* const previous_path_string = path_string;
106 path_string = traits::tgetpath(path_string, path_buffer, path_count - file_name_length - 1);
107 if (!path_string && path_buffer == local_path_buffer && errno == ERANGE)
108 {
109 // If the getpath operation failed because the buffer was not large
110 // enough, try allocating a larger buffer:
111 size_t const required_count = traits::tcslen(previous_path_string) + file_name_length + 2;
112
113 path_buffer_cleanup = _calloc_crt_t(Character, required_count);
114 if (!path_buffer_cleanup)
115 {
116 result_buffer[0] = '\0';
117 return errno = ENOMEM;
118 }
119
120 path_count = required_count;
121 path_buffer = path_buffer_cleanup.get();
122
123 path_string = traits::tgetpath(previous_path_string, path_buffer, path_count - file_name_length);
124 }
125
126 if (!path_string || path_buffer[0] == '\0')
127 {
128 result_buffer[0] = '\0';
129 return errno = ENOENT;
130 }
131
132 // The result_buffer now holds a non-empty path name from path_string
133 // and we know that the buffer is large enough to hold the concatenation
134 // of the path with the file name (if not, the call to getpath would
135 // have failed. So, we concatenate the path and file names:
136 size_t path_length = traits::tcslen(path_buffer);
137 Character* path_it = path_buffer + path_length;
138
139 // Add a trailing '\' if one is required:
140 Character const last_character = *(path_it - 1);
141 if (last_character != '/' && last_character != '\\' && last_character != ':')
142 {
143 *path_it++ = '\\';
144 ++path_length;
145 }
146
147 // The path_it now points to the character following the trailing '\',
148 // '/', or ':'; this is where we copy the file name:
149 _ERRCHECK(traits::tcscpy_s(path_it, path_count - path_length, file_name));
150
151 // If we can't access the file at this path, it isn't a match:
152 if (traits::taccess_s(path_buffer, 0) != 0)
153 continue;
154
155 // Otherwise, we can access the file, and we copy the full path into the
156 // caller-provided buffer:
157 if (path_length + file_name_length + 1 > result_count)
158 {
159 result_buffer[0] = '\0';
160 return errno = ERANGE;
161 }
162
163 errno = saved_errno;
164
165 _ERRCHECK(traits::tcscpy_s(result_buffer, result_count, path_buffer));
166 return 0;
167 }
168
169 // If we get here, we must have tried every path in the environment and not
170 // found the file name:
171 result_buffer[0] = '\0';
172 return errno = ENOENT;
173}
#define ENOENT
Definition: acclib.h:79
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
#define ERANGE
Definition: acclib.h:92
static long path_length
Definition: maze.c:116
#define _ERRCHECK(e)
#define _ERRCHECK_EINVAL(e)
#define _VALIDATE_RETURN_ERRCODE(expr, errorcode)
#define errno
Definition: errno.h:18
int errno_t
Definition: corecrt.h:615

Referenced by _searchenv(), _searchenv_s(), _wsearchenv(), and _wsearchenv_s().