Reactos
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.
26static 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
107template <typename Character>
108_Success_(return != 0)
109_Ret_z_
110static 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
180extern "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
188extern "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
196extern "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
205extern "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
219extern "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
230extern "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
241extern "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
253extern "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