xref: /reactos/sdk/lib/ucrt/filesystem/fullpath.cpp (revision 04e0dc4a)
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