1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // ============================================================ |
5 | // |
6 | // Utils.cpp |
7 | // |
8 | |
9 | |
10 | // |
11 | // Implements a bunch of binder auxilary functions |
12 | // |
13 | // ============================================================ |
14 | |
15 | #define DISABLE_BINDER_DEBUG_LOGGING |
16 | |
17 | #include "utils.hpp" |
18 | |
19 | #include <shlwapi.h> |
20 | |
21 | #include "strongname.h" |
22 | #include "corpriv.h" |
23 | |
24 | namespace BINDER_SPACE |
25 | { |
26 | namespace |
27 | { |
28 | inline BOOL IsPathSeparator(WCHAR wcChar) |
29 | { |
30 | // Invariant: Valid only for MutateUrlToPath treated pathes |
31 | return (wcChar == W('\\')); |
32 | } |
33 | |
34 | inline const WCHAR *GetPlatformPathSeparator() |
35 | { |
36 | #ifdef PLATFORM_UNIX |
37 | return W("/" ); |
38 | #else |
39 | return W("\\" ); |
40 | #endif // PLATFORM_UNIX |
41 | } |
42 | |
43 | inline WCHAR ToPlatformPathSepator(WCHAR wcChar) |
44 | { |
45 | #ifdef PLATFORM_UNIX |
46 | if (IsPathSeparator(wcChar)) |
47 | { |
48 | wcChar = W('/'); |
49 | } |
50 | #endif // PLATFORM_UNIX |
51 | |
52 | return wcChar; |
53 | } |
54 | |
55 | inline BOOL IsDoublePathSeparator(SString::CIterator &cur) |
56 | { |
57 | return (IsPathSeparator(cur[0]) && IsPathSeparator(cur[1])); |
58 | } |
59 | |
60 | bool NeedToRemoveDoubleAndNormalizePathSeparators(SString const &path) |
61 | { |
62 | #ifdef PLATFORM_UNIX |
63 | return true; |
64 | #else |
65 | SString::CIterator begin = path.Begin(); |
66 | SString::CIterator end = path.End(); |
67 | SString::CIterator cur = path.Begin(); |
68 | |
69 | while (cur < end) |
70 | { |
71 | if ((cur != begin) && ((cur + 2) < end) && IsDoublePathSeparator(cur)) |
72 | { |
73 | return true; |
74 | } |
75 | |
76 | cur++; |
77 | } |
78 | |
79 | return false; |
80 | #endif |
81 | } |
82 | |
83 | void RemoveDoubleAndNormalizePathSeparators(SString &path) |
84 | { |
85 | BINDER_LOG_ENTER(W("Utils::RemoveDoubleAndNormalizePathSeparators" )); |
86 | |
87 | SString::Iterator begin = path.Begin(); |
88 | SString::Iterator end = path.End(); |
89 | SString::Iterator cur = path.Begin(); |
90 | PathString resultPath; |
91 | |
92 | BINDER_LOG_STRING(W("path" ), path); |
93 | |
94 | while (cur < end) |
95 | { |
96 | if ((cur != begin) && ((cur + 2) < end) && IsDoublePathSeparator(cur)) |
97 | { |
98 | // Skip the doublette |
99 | cur++; |
100 | } |
101 | |
102 | resultPath.Append(ToPlatformPathSepator(cur[0])); |
103 | cur++; |
104 | } |
105 | |
106 | BINDER_LOG_STRING(W("resultPath" ), resultPath); |
107 | |
108 | path.Set(resultPath); |
109 | |
110 | BINDER_LOG_LEAVE(W("Utils::RemoveDoubleAndNormalizePathSeparators" )); |
111 | } |
112 | } |
113 | |
114 | HRESULT FileOrDirectoryExists(PathString &path) |
115 | { |
116 | HRESULT hr = S_FALSE; |
117 | |
118 | DWORD dwFileAttributes = WszGetFileAttributes(path.GetUnicode()); |
119 | if (dwFileAttributes == INVALID_FILE_ATTRIBUTES) |
120 | { |
121 | hr = HRESULT_FROM_GetLastError(); |
122 | |
123 | if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || |
124 | (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))) |
125 | { |
126 | hr = S_FALSE; |
127 | } |
128 | } |
129 | else |
130 | { |
131 | hr = S_TRUE; |
132 | } |
133 | |
134 | return hr; |
135 | } |
136 | |
137 | HRESULT FileOrDirectoryExistsLog(PathString &path) |
138 | { |
139 | HRESULT hr = S_FALSE; |
140 | BINDER_LOG_ENTER(W("Utils::FileOrDirectoryExistsLog" )); |
141 | BINDER_LOG_STRING(W("path" ), path); |
142 | |
143 | hr = FileOrDirectoryExists(path); |
144 | |
145 | BINDER_LOG_LEAVE_HR(W("Utils::FileOrDirectoryExistsLog" ), hr); |
146 | return hr; |
147 | } |
148 | |
149 | void MutateUrlToPath(SString &urlOrPath) |
150 | { |
151 | BINDER_LOG_ENTER(W("Utils::MutateUrlToPath" )); |
152 | const SString fileUrlPrefix(SString::Literal, W("file://" )); |
153 | SString::Iterator i = urlOrPath.Begin(); |
154 | |
155 | BINDER_LOG_STRING(W("URL" ), urlOrPath); |
156 | |
157 | if (urlOrPath.MatchCaseInsensitive(i, fileUrlPrefix)) |
158 | { |
159 | urlOrPath.Delete(i, fileUrlPrefix.GetCount()); |
160 | |
161 | i = urlOrPath.Begin() + 1; |
162 | if (i[0] == W(':')) |
163 | { |
164 | // CLR erroneously passes in file:// prepended to file paths, |
165 | // so we can't tell the difference between UNC and local file. |
166 | goto Exit; |
167 | } |
168 | |
169 | i = urlOrPath.Begin(); |
170 | #if !defined(PLATFORM_UNIX) |
171 | if (i[0] == W('/')) |
172 | { |
173 | // Disk path file:/// |
174 | urlOrPath.Delete(i, 1); |
175 | } |
176 | else if (i[0] != W('\\')) |
177 | { |
178 | // UNC Path, re-insert "//" if not the wrong file://\\... |
179 | urlOrPath.Insert(i, W("//" )); |
180 | } |
181 | #else |
182 | // Unix doesn't have a distinction between local and network path |
183 | _ASSERTE(i[0] == W('\\') || i[0] == W('/')); |
184 | #endif |
185 | } |
186 | |
187 | Exit: |
188 | while (urlOrPath.Find(i, W('/'))) |
189 | { |
190 | urlOrPath.Replace(i, W('\\')); |
191 | } |
192 | |
193 | BINDER_LOG_STRING(W("Path" ), urlOrPath); |
194 | BINDER_LOG_LEAVE(W("Utils::MutateUrlToPath" )); |
195 | } |
196 | |
197 | void MutatePathToUrl(SString &pathOrUrl) |
198 | { |
199 | BINDER_LOG_ENTER(W("Utils::MutatePathToUrl" )); |
200 | SString::Iterator i = pathOrUrl.Begin(); |
201 | |
202 | BINDER_LOG_STRING(W("Path" ), pathOrUrl); |
203 | |
204 | #if !defined(PLATFORM_UNIX) |
205 | // Network path \\server --> file://server |
206 | // Disk path c:\dir --> file:///c:/dir |
207 | if (i[0] == W('\\')) |
208 | { |
209 | const SString networkUrlPrefix(SString::Literal, W("file:" )); |
210 | |
211 | // Network path |
212 | pathOrUrl.Insert(i, networkUrlPrefix); |
213 | pathOrUrl.Skip(i, networkUrlPrefix); |
214 | } |
215 | else |
216 | { |
217 | const SString diskPathUrlPrefix(SString::Literal, W("file:///" )); |
218 | |
219 | // Disk path |
220 | pathOrUrl.Insert(i, diskPathUrlPrefix); |
221 | pathOrUrl.Skip(i, diskPathUrlPrefix); |
222 | } |
223 | #else |
224 | // Unix doesn't have a distinction between a network or a local path |
225 | _ASSERTE(i[0] == W('\\') || i[0] == W('/')); |
226 | const SString fileUrlPrefix(SString::Literal, W("file://" )); |
227 | |
228 | pathOrUrl.Insert(i, fileUrlPrefix); |
229 | pathOrUrl.Skip(i, fileUrlPrefix); |
230 | #endif |
231 | |
232 | while (pathOrUrl.Find(i, W('\\'))) |
233 | { |
234 | pathOrUrl.Replace(i, W('/')); |
235 | } |
236 | |
237 | BINDER_LOG_STRING(W("URL" ), pathOrUrl); |
238 | BINDER_LOG_LEAVE(W("Utils::MutatePathToUrl" )); |
239 | } |
240 | |
241 | void PlatformPath(SString &path) |
242 | { |
243 | BINDER_LOG_ENTER(W("Utils::PlatformPath" )); |
244 | BINDER_LOG_STRING(W("input path" ), path); |
245 | |
246 | // Create platform representation |
247 | MutateUrlToPath(path); |
248 | if (NeedToRemoveDoubleAndNormalizePathSeparators(path)) |
249 | RemoveDoubleAndNormalizePathSeparators(path); |
250 | |
251 | BINDER_LOG_STRING(W("platform path" ), path); |
252 | |
253 | BINDER_LOG_LEAVE(W("Utils::PlatformPath" )); |
254 | } |
255 | |
256 | void CombinePath(SString &pathA, |
257 | SString &pathB, |
258 | SString &combinedPath) |
259 | { |
260 | BINDER_LOG_ENTER(W("Utils::CombinePath" )); |
261 | |
262 | BINDER_LOG_STRING(W("path A" ), pathA); |
263 | BINDER_LOG_STRING(W("path B" ), pathB); |
264 | |
265 | SString platformPathSeparator(SString::Literal, GetPlatformPathSeparator()); |
266 | combinedPath.Set(pathA); |
267 | |
268 | if (!combinedPath.EndsWith(platformPathSeparator)) |
269 | { |
270 | combinedPath.Append(platformPathSeparator); |
271 | } |
272 | |
273 | combinedPath.Append(pathB); |
274 | |
275 | BINDER_LOG_LEAVE(W("Utils::CombinePath" )); |
276 | } |
277 | |
278 | HRESULT GetTokenFromPublicKey(SBuffer &publicKeyBLOB, |
279 | SBuffer &publicKeyTokenBLOB) |
280 | { |
281 | HRESULT hr = S_OK; |
282 | BINDER_LOG_ENTER(W("GetTokenFromPublicKey" )); |
283 | |
284 | const BYTE *pByteKey = publicKeyBLOB; |
285 | DWORD dwKeyLen = publicKeyBLOB.GetSize(); |
286 | BYTE *pByteToken = NULL; |
287 | DWORD dwTokenLen = 0; |
288 | |
289 | if (!StrongNameTokenFromPublicKey(const_cast<BYTE *>(pByteKey), |
290 | dwKeyLen, |
291 | &pByteToken, |
292 | &dwTokenLen)) |
293 | { |
294 | BINDER_LOG(W("StrongNameTokenFromPublicKey failed!" )); |
295 | IF_FAIL_GO(StrongNameErrorInfo()); |
296 | } |
297 | else |
298 | { |
299 | _ASSERTE(pByteToken != NULL); |
300 | publicKeyTokenBLOB.Set(pByteToken, dwTokenLen); |
301 | StrongNameFreeBuffer(pByteToken); |
302 | } |
303 | |
304 | Exit: |
305 | BINDER_LOG_LEAVE_HR(W("GetTokenFromPublicKey" ), hr); |
306 | return hr; |
307 | } |
308 | |
309 | BOOL IsFileNotFound(HRESULT hr) |
310 | { |
311 | return RuntimeFileNotFound(hr); |
312 | } |
313 | }; |
314 | |