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