1 /***
2 *fullpath.c -
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose: contains the function _fullpath which makes an absolute path out
7 * of a relative path. i.e. ..\pop\..\main.c => c:\src\main.c if the
8 * current directory is c:\src\src
9 *
10 *******************************************************************************/
11
12 #include <stdio.h>
13 #include <direct.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <corecrt_internal_traits.h>
17 #include <windows.h>
18
19 /***
20 *_TCHAR *_fullpath( _TCHAR *buf, const _TCHAR *path, maxlen );
21 *
22 *Purpose:
23 *
24 * _fullpath - combines the current directory with path to form
25 * an absolute path. i.e. _fullpath takes care of .\ and ..\
26 * in the path.
27 *
28 * The result is placed in buf. If the length of the result
29 * is greater than maxlen nullptr is returned, otherwise
30 * the address of buf is returned.
31 *
32 * If buf is nullptr then a buffer is malloc'ed and maxlen is
33 * ignored. If there are no errors then the address of this
34 * buffer is returned.
35 *
36 * If path specifies a drive, the curent directory of this
37 * drive is combined with path. If the drive is not valid
38 * and _fullpath needs the current directory of this drive
39 * then nullptr is returned. If the current directory of this
40 * non existant drive is not needed then a proper value is
41 * returned.
42 * For example: path = "z:\\pop" does not need z:'s current
43 * directory but path = "z:pop" does.
44 *
45 *
46 *
47 *Entry:
48 * _TCHAR *buf - pointer to a buffer maintained by the user;
49 * _TCHAR *path - path to "add" to the current directory
50 * int maxlen - length of the buffer pointed to by buf
51 *
52 *Exit:
53 * Returns pointer to the buffer containing the absolute path
54 * (same as buf if non-nullptr; otherwise, malloc is
55 * used to allocate a buffer)
56 *
57 *Exceptions:
58 *
59 *******************************************************************************/
60
61 template <typename Character>
62 _Success_(return != 0)
common_fullpath(_Out_writes_z_ (max_count)Character * const user_buffer,Character const * const path,size_t const max_count,int const block_use,char const * const file_name,int const line_number)63 static Character* __cdecl common_fullpath(
64 _Out_writes_z_(max_count) Character* const user_buffer,
65 Character const* const path,
66 size_t const max_count,
67 int const block_use,
68 char const* const file_name,
69 int const line_number
70 ) throw()
71 {
72 // These are referenced only in the Debug CRT build
73 UNREFERENCED_PARAMETER(block_use);
74 UNREFERENCED_PARAMETER(file_name);
75 UNREFERENCED_PARAMETER(line_number);
76
77 typedef __crt_char_traits<Character> traits;
78
79 // If the path is empty, we have no work to do:
80 if (path == nullptr || path[0] == '\0')
81 {
82 #pragma warning(suppress:__WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION) // 26036 Prefast does not understand perfect forwarding.
83 return traits::tgetcwd(user_buffer, static_cast<int>(__min(max_count, INT_MAX)));
84 }
85
86 if (user_buffer != nullptr) {
87 // Using user buffer. Fail if not enough space.
88 __crt_no_alloc_win32_buffer<Character> buffer(user_buffer, max_count);
89 if (!traits::get_full_path_name(path, buffer)) {
90 return user_buffer;
91 } else {
92 return nullptr;
93 }
94 } else {
95 // Always new memory suitable for debug mode and releasing to the user.
96 __crt_public_win32_buffer<Character> buffer(
97 __crt_win32_buffer_debug_info(block_use, file_name, line_number)
98 );
99 traits::get_full_path_name(path, buffer);
100 return buffer.detach();
101 }
102 }
103
104
105
_fullpath(char * const user_buffer,char const * const path,size_t const max_count)106 extern "C" char* __cdecl _fullpath(
107 char* const user_buffer,
108 char const* const path,
109 size_t const max_count
110 )
111 {
112 return common_fullpath(user_buffer, path, max_count, _NORMAL_BLOCK, nullptr, 0);
113 }
114
_wfullpath(wchar_t * const user_buffer,wchar_t const * const path,size_t const max_count)115 extern "C" wchar_t* __cdecl _wfullpath(
116 wchar_t* const user_buffer,
117 wchar_t const* const path,
118 size_t const max_count
119 )
120 {
121 return common_fullpath(user_buffer, path, max_count, _NORMAL_BLOCK, nullptr, 0);
122 }
123
124 #ifdef _DEBUG
125
126 #undef _fullpath_dbg
127 #undef _wfullpath_dbg
128
_fullpath_dbg(char * const user_buffer,char const * const path,size_t const max_count,int const block_use,char const * const file_name,int const line_number)129 extern "C" char* __cdecl _fullpath_dbg(
130 char* const user_buffer,
131 char const* const path,
132 size_t const max_count,
133 int const block_use,
134 char const* const file_name,
135 int const line_number
136 )
137 {
138 return common_fullpath(user_buffer, path, max_count, block_use, file_name, line_number);
139 }
140
_wfullpath_dbg(wchar_t * const user_buffer,wchar_t const * const path,size_t const max_count,int const block_use,char const * const file_name,int const line_number)141 extern "C" wchar_t* __cdecl _wfullpath_dbg(
142 wchar_t* const user_buffer,
143 wchar_t const* const path,
144 size_t const max_count,
145 int const block_use,
146 char const* const file_name,
147 int const line_number
148 )
149 {
150 return common_fullpath(user_buffer, path, max_count, block_use, file_name, line_number);
151 }
152
153 #endif // _DEBUG
154