1 /*** 2 *getcwd.cpp - get current working directory 3 * 4 * Copyright (c) Microsoft Corporation. All rights reserved. 5 * 6 *Purpose: 7 * 8 * contains functions _getcwd, _getdcwd and _getcdrv for getting the 9 * current working directory. getcwd gets the c.w.d. for the default disk 10 * drive, whereas _getdcwd allows one to get the c.w.d. for whatever disk 11 * drive is specified. _getcdrv gets the current drive. 12 * 13 *******************************************************************************/ 14 #include <corecrt_internal.h> 15 #include <corecrt_internal_traits.h> 16 #include <direct.h> 17 #include <errno.h> 18 #include <malloc.h> 19 #include <stdlib.h> 20 21 22 23 // Tests whether the specified drive number is valid. Returns zero if the drive 24 // does not exist; returns one if the drive exists. Pass zero as an argument to 25 // check the default drive. 26 static int __cdecl is_valid_drive(unsigned const drive_number) throw() 27 { 28 if (drive_number > 26) 29 { 30 _doserrno = ERROR_INVALID_DRIVE; 31 _VALIDATE_RETURN(("Invalid Drive Index" ,0), EACCES, 0); 32 } 33 34 if (drive_number == 0) 35 return 1; 36 37 #pragma warning(suppress:__WARNING_UNUSED_ASSIGNMENT) // 28931 38 wchar_t const drive_letter = static_cast<wchar_t>(L'A' + drive_number - 1); 39 wchar_t const drive_string[] = { drive_letter, L':', L'\\', L'\0' }; 40 41 UINT const drive_type = GetDriveTypeW(drive_string); 42 if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) 43 return 0; 44 45 return 1; 46 } 47 48 49 50 /*** 51 *_TSCHAR *_getcwd(pnbuf, maxlen) - get current working directory of default drive 52 * 53 *Purpose: 54 * _getcwd gets the current working directory for the user, 55 * placing it in the buffer pointed to by pnbuf. If the length 56 * of the string exceeds the length of the buffer, maxlen, 57 * then nullptr is returned. If pnbuf = nullptr, a buffer of at 58 * least size maxlen is automatically allocated using 59 * malloc() -- a pointer to which is returned by _getcwd(). 60 * An entry point "_getdcwd()" is defined which takes the above 61 * parameters, plus a drive number. "_getcwd()" is implemented 62 * as a call to "_getdcwd()" with the default drive (0). 63 * 64 * side effects: no global data is used or affected 65 * 66 *Entry: 67 * _TSCHAR *pnbuf = pointer to a buffer maintained by the user; 68 * int maxlen = length of the buffer pointed to by pnbuf; 69 * 70 *Exit: 71 * Returns pointer to the buffer containing the c.w.d. name 72 * (same as pnbuf if non-nullptr; otherwise, malloc is 73 * used to allocate a buffer) 74 * 75 *Exceptions: 76 * 77 *******************************************************************************/ 78 79 /*** 80 *_TSCHAR *_getdcwd(drive, pnbuf, maxlen) - get c.w.d. for given drive 81 * 82 *Purpose: 83 * _getdcwd gets the current working directory for the user, 84 * placing it in the buffer pointed to by pnbuf. If the length 85 * of the string exceeds the length of the buffer, maxlen, 86 * then nullptr is returned. If pnbuf = nullptr, a buffer of at 87 * least size maxlen is automatically allocated using 88 * malloc() -- a pointer to which is returned by _getdcwd(). 89 * 90 * side effects: no global data is used or affected 91 * 92 *Entry: 93 * int drive - number of the drive being inquired about 94 * 0 = default, 1 = 'a:', 2 = 'b:', etc. 95 * _TSCHAR *pnbuf - pointer to a buffer maintained by the user; 96 * int maxlen - length of the buffer pointed to by pnbuf; 97 * 98 *Exit: 99 * Returns pointer to the buffer containing the c.w.d. name 100 * (same as pnbuf if non-nullptr; otherwise, malloc is 101 * used to allocate a buffer) 102 * 103 *Exceptions: 104 * 105 *******************************************************************************/ 106 107 template <typename Character> 108 _Success_(return != 0) 109 _Ret_z_ 110 static Character* __cdecl common_getdcwd( 111 int drive_number, 112 _Out_writes_opt_z_(max_count) Character* user_buffer, 113 int const max_count, 114 int const block_use, 115 _In_opt_z_ char const* const file_name, 116 int const line_number 117 ) throw() 118 { 119 typedef __crt_char_traits<Character> traits; 120 121 _VALIDATE_RETURN(max_count >= 0, EINVAL, nullptr); 122 123 if (drive_number != 0) 124 { 125 // A drive other than the default drive was requested; make sure it 126 // is a valid drive number: 127 if (!is_valid_drive(drive_number)) 128 { 129 _doserrno = ERROR_INVALID_DRIVE; 130 _VALIDATE_RETURN(("Invalid Drive", 0), EACCES, nullptr); 131 } 132 } 133 else 134 { 135 // Otherwise, get the drive number of the default drive: 136 drive_number = _getdrive(); 137 } 138 139 Character drive_string[4]; 140 if (drive_number != 0) 141 { 142 drive_string[0] = static_cast<Character>('A' - 1 + drive_number); 143 drive_string[1] = ':'; 144 drive_string[2] = '.'; 145 drive_string[3] = '\0'; 146 } 147 else 148 { 149 drive_string[0] = '.'; 150 drive_string[1] = '\0'; 151 } 152 153 if (user_buffer == nullptr) 154 { // Always new memory suitable for debug mode and releasing to the user. 155 __crt_public_win32_buffer<Character> buffer( 156 __crt_win32_buffer_debug_info(block_use, file_name, line_number) 157 ); 158 buffer.allocate(max_count); 159 if (!traits::get_full_path_name(drive_string, buffer)) 160 { 161 return buffer.detach(); 162 } 163 return nullptr; 164 } 165 166 // Using user buffer. Fail if not enough space. 167 _VALIDATE_RETURN(max_count > 0, EINVAL, nullptr); 168 user_buffer[0] = '\0'; 169 170 __crt_no_alloc_win32_buffer<Character> buffer(user_buffer, max_count); 171 if (!traits::get_full_path_name(drive_string, buffer)) 172 { 173 return user_buffer; 174 } 175 return nullptr; 176 }; 177 178 179 180 extern "C" char* __cdecl _getcwd( 181 char* const user_buffer, 182 int const max_length 183 ) 184 { 185 return common_getdcwd(0, user_buffer, max_length, _NORMAL_BLOCK, nullptr, 0); 186 } 187 188 extern "C" wchar_t* __cdecl _wgetcwd( 189 wchar_t* const user_buffer, 190 int const max_length 191 ) 192 { 193 return common_getdcwd(0, user_buffer, max_length, _NORMAL_BLOCK, nullptr, 0); 194 } 195 196 extern "C" char* __cdecl _getdcwd( 197 int const drive_number, 198 char* const user_buffer, 199 int const max_length 200 ) 201 { 202 return common_getdcwd(drive_number, user_buffer, max_length, _NORMAL_BLOCK, nullptr, 0); 203 } 204 205 extern "C" wchar_t* __cdecl _wgetdcwd( 206 int const drive_number, 207 wchar_t* const user_buffer, 208 int const max_length 209 ) 210 { 211 return common_getdcwd(drive_number, user_buffer, max_length, _NORMAL_BLOCK, nullptr, 0); 212 } 213 214 #ifdef _DEBUG 215 216 #undef _getcwd_dbg 217 #undef _getdcwd_dbg 218 219 extern "C" char* __cdecl _getcwd_dbg( 220 char* const user_buffer, 221 int const max_length, 222 int const block_use, 223 char const* const file_name, 224 int const line_number 225 ) 226 { 227 return common_getdcwd(0, user_buffer, max_length, block_use, file_name, line_number); 228 } 229 230 extern "C" wchar_t* __cdecl _wgetcwd_dbg( 231 wchar_t* const user_buffer, 232 int const max_length, 233 int const block_use, 234 char const* const file_name, 235 int const line_number 236 ) 237 { 238 return common_getdcwd(0, user_buffer, max_length, block_use, file_name, line_number); 239 } 240 241 extern "C" char* __cdecl _getdcwd_dbg( 242 int const drive_number, 243 char* const user_buffer, 244 int const max_length, 245 int const block_use, 246 char const* const file_name, 247 int const line_number 248 ) 249 { 250 return common_getdcwd(drive_number, user_buffer, max_length, block_use, file_name, line_number); 251 } 252 253 extern "C" wchar_t* __cdecl _wgetdcwd_dbg( 254 int const drive_number, 255 wchar_t* const user_buffer, 256 int const max_length, 257 int const block_use, 258 char const* const file_name, 259 int const line_number 260 ) 261 { 262 return common_getdcwd(drive_number, user_buffer, max_length, block_use, file_name, line_number); 263 } 264 265 #endif // _DEBUG 266