1 // 2 // makepath.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Defines the makepath family of functions, which compose a path string. 7 // 8 #include <corecrt_internal_securecrt.h> 9 #include <mbstring.h> 10 #include <stdlib.h> 11 12 13 14 static char const* previous_character(char const* const first, char const* const current) throw() 15 { 16 return reinterpret_cast<char const*>(_mbsdec( 17 reinterpret_cast<unsigned char const*>(first), 18 reinterpret_cast<unsigned char const*>(current))); 19 } 20 21 static wchar_t const* previous_character(wchar_t const*, wchar_t const* const current) throw() 22 { 23 return current - 1; 24 } 25 26 27 28 template <typename Character> 29 static errno_t __cdecl cleanup_after_error( 30 _Out_writes_z_(count) Character* const buffer, 31 size_t const count) throw() 32 { 33 // This is referenced only in the Debug CRT build 34 UNREFERENCED_PARAMETER(count); 35 36 _RESET_STRING(buffer, count); 37 _RETURN_BUFFER_TOO_SMALL(buffer, count); 38 return EINVAL; // This is unreachable 39 } 40 41 42 43 // These functions compose a path string from its component parts. They 44 // concatenate the drive, directory, file_name, and extension into the provided 45 // result_buffer. For the functions that do not have a buffer count parameter, 46 // the buffer is assumed to be large enough to hold however many characters are 47 // required. 48 // 49 // The drive may or may not contain a ':'. The directory may or may not contain 50 // a leading or trailing '/' or '\'. The extension may or may not contain a 51 // leading '.'. 52 template <typename Character> 53 static errno_t __cdecl common_makepath_s( 54 _Out_writes_z_(result_count) Character* const result_buffer, 55 _In_ size_t const result_count, 56 _In_opt_z_ Character const* const drive, 57 _In_opt_z_ Character const* const directory, 58 _In_opt_z_ Character const* const file_name, 59 _In_opt_z_ Character const* const extension 60 ) throw() 61 { 62 _VALIDATE_STRING(result_buffer, result_count); 63 64 Character* result_it = result_buffer; 65 66 // For the non-secure makepath functions, result_count is _CRT_UNBOUNDED_BUFFER_SIZE. 67 // In this case, we do not want to perform arithmetic with the result_count. Instead, 68 // we set the result_end to nullptr: result_it will never be a null pointer, 69 // and when we need to perform arithmetic with result_end we can check it for 70 // null first. 71 Character* const result_end = result_count != _CRT_UNBOUNDED_BUFFER_SIZE 72 ? result_buffer + result_count 73 : nullptr; 74 75 CRT_WARNING_DISABLE_PUSH(26015, "Silence prefast about overflow - covered by result_end for secure callers") 76 77 // Copy the drive: 78 if (drive && drive[0] != '\0') 79 { 80 if (result_end != nullptr && result_end - result_it < 2) 81 return cleanup_after_error(result_buffer, result_count); 82 83 *result_it++ = *drive; 84 *result_it++ = ':'; 85 } 86 87 // Copy the directory: 88 if (directory && directory[0] != '\0') 89 { 90 Character const* source_it = directory; 91 while (*source_it != '\0') 92 { 93 if ((result_end != nullptr) && (result_it >= result_end)) 94 return cleanup_after_error(result_buffer, result_count); 95 96 *result_it++ = *source_it++; 97 } 98 99 // Write a trailing backslash if there isn't one: 100 source_it = previous_character(directory, source_it); 101 if (*source_it != '/' && *source_it != '\\') 102 { 103 if ((result_end != nullptr) && (result_it >= result_end)) 104 return cleanup_after_error(result_buffer, result_count); 105 106 *result_it++ = '\\'; 107 } 108 } 109 110 // Copy the file name: 111 if (file_name) 112 { 113 Character const* source_it = file_name; 114 while (*source_it != '\0') 115 { 116 if ((result_end != nullptr) && (result_it >= result_end)) 117 return cleanup_after_error(result_buffer, result_count); 118 119 *result_it++ = *source_it++; 120 } 121 } 122 123 // Copy the extension: 124 if (extension) 125 { 126 // Add a '.' if one is required: 127 if (extension[0] != '\0' && extension[0] != '.') 128 { 129 if ((result_end != nullptr) && (result_it >= result_end)) 130 return cleanup_after_error(result_buffer, result_count); 131 132 *result_it++ = '.'; 133 } 134 135 Character const* source_it = extension; 136 while (*source_it != '\0') 137 { 138 if ((result_end != nullptr) && (result_it >= result_end)) 139 return cleanup_after_error(result_buffer, result_count); 140 141 *result_it++ = *source_it++; 142 } 143 } 144 145 // Copy the null terminator: 146 if ((result_end != nullptr) && (result_it >= result_end)) 147 return cleanup_after_error(result_buffer, result_count); 148 149 *result_it++ = '\0'; 150 151 CRT_WARNING_POP 152 153 _FILL_STRING(result_buffer, result_count, result_it - result_buffer); 154 return 0; 155 } 156 157 158 159 extern "C" void __cdecl _makepath( 160 char* const result_buffer, 161 char const* const drive, 162 char const* const directory, 163 char const* const file_name, 164 char const* const extension 165 ) 166 { 167 _makepath_s(result_buffer, _CRT_UNBOUNDED_BUFFER_SIZE, drive, directory, file_name, extension); 168 } 169 170 extern "C" void __cdecl _wmakepath( 171 wchar_t* const result_buffer, 172 wchar_t const* const drive, 173 wchar_t const* const directory, 174 wchar_t const* const file_name, 175 wchar_t const* const extension 176 ) 177 { 178 _wmakepath_s(result_buffer, _CRT_UNBOUNDED_BUFFER_SIZE, drive, directory, file_name, extension); 179 } 180 181 182 183 extern "C" errno_t __cdecl _makepath_s( 184 char* const result_buffer, 185 size_t const result_count, 186 char const* const drive, 187 char const* const directory, 188 char const* const file_name, 189 char const* const extension 190 ) 191 { 192 return common_makepath_s(result_buffer, result_count, drive, directory, file_name, extension); 193 } 194 195 extern "C" errno_t __cdecl _wmakepath_s( 196 wchar_t* const result_buffer, 197 size_t const result_count, 198 wchar_t const* const drive, 199 wchar_t const* const directory, 200 wchar_t const* const file_name, 201 wchar_t const* const extension 202 ) 203 { 204 return common_makepath_s(result_buffer, result_count, drive, directory, file_name, extension); 205 } 206