xref: /reactos/sdk/lib/ucrt/misc/chdir.cpp (revision 53d808d2)
1 /***
2 *chdir.c - change directory
3 *
4 *       Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:
7 *       This file has the _chdir() function - change current directory.
8 *
9 *******************************************************************************/
10 
11 #include <direct.h>
12 #include <corecrt_internal_traits.h>
13 #include <corecrt_internal_win32_buffer.h>
14 #include <malloc.h>
15 #include <stdlib.h>
16 
17 /***
18 *int _chdir(path) - change current directory
19 *
20 *Purpose:
21 *       Changes the current working directory to that given in path.
22 *
23 *Entry:
24 *       _TSCHAR *path - directory to change to
25 *
26 *Exit:
27 *       returns 0 if successful,
28 *       returns -1 and sets errno if unsuccessful
29 *
30 *Exceptions:
31 *
32 *******************************************************************************/
33 template <typename Character>
34 _Success_(return == 0)
35 static int __cdecl set_cwd_environment_variable(_In_z_ Character const* const path) throw()
36 {
37     typedef __crt_char_traits<Character> traits;
38 
39     // If the path is a UNC name, no need to update:
40     if ((path[0] == '\\' || path[0] == '/') && path[0] == path[1])
41         return 0;
42 
43 #pragma warning(suppress:28931) // unused assignment of variable drive_letter
44     Character const drive_letter = static_cast<Character>(toupper(static_cast<char>(path[0])));
45     Character const name[] = { '=', drive_letter, ':', '\0' };
46 
47     if (traits::set_environment_variable(name, path))
48         return 0;
49 
50     __acrt_errno_map_os_error(GetLastError());
51     return -1;
52 }
53 
54 
55 
56 template <typename Character>
57 _Success_(return == 0)
58 static int __cdecl common_chdir(_In_z_ Character const* const path) throw()
59 {
60     typedef __crt_char_traits<Character> traits;
61 
62     _VALIDATE_CLEAR_OSSERR_RETURN(path != nullptr, EINVAL, -1);
63 
64     if (!traits::set_current_directory(path))
65     {
66         __acrt_errno_map_os_error(GetLastError());
67         return -1;
68     }
69 
70     // If the new current directory path is not a UNC path, we must update the
71     // OS environment variable specifying the current full current directory,
72     // build the environment variable string, and call SetEnvironmentVariable().
73     // We need to do this because the SetCurrentDirectory() API does not update
74     // the environment variables, and other functions (fullpath, spawn, etc.)
75     // need them to be set.
76     //
77     // If associated with a 'drive', the current directory should have the
78     // form of the example below:
79     //
80     //     D:\nt\private\mytests
81     //
82     // So that the environment variable should be of the form:
83     //
84     //     =D:=D:\nt\private\mytests
85 
86     Character buffer_initial_storage[MAX_PATH + 1];
87     __crt_internal_win32_buffer<Character> current_directory_buffer(buffer_initial_storage);
88 
89     errno_t const err = traits::get_current_directory(current_directory_buffer);
90 
91     if (err != 0) {
92         // Appropriate error already set
93         return -1;
94     }
95 
96     return set_cwd_environment_variable(current_directory_buffer.data());
97 }
98 
99 
100 
101 extern "C" int __cdecl _chdir(char const* const path)
102 {
103     return common_chdir(path);
104 }
105 
106 extern "C" int __cdecl _wchdir(wchar_t const* const path)
107 {
108     return common_chdir(path);
109 }
110