Fix trigger for tier 1 call counting delay (#17477)
[platform/upstream/coreclr.git] / src / binder / utils.cpp
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     BOOL IsURL(SString &urlOrPath)
150     {
151         // This is also in defined rotor pal
152         return PathIsURLW(urlOrPath);
153     }
154
155     void MutateUrlToPath(SString &urlOrPath)
156     {
157         BINDER_LOG_ENTER(W("Utils::MutateUrlToPath"));
158         const SString fileUrlPrefix(SString::Literal, W("file://"));
159         SString::Iterator i = urlOrPath.Begin();
160
161         BINDER_LOG_STRING(W("URL"), urlOrPath);
162
163         if (urlOrPath.MatchCaseInsensitive(i, fileUrlPrefix))
164         {
165             urlOrPath.Delete(i, fileUrlPrefix.GetCount());
166
167             i = urlOrPath.Begin() + 1;
168             if (i[0] ==  W(':'))
169             {
170                 // CLR erroneously passes in file:// prepended to file paths,
171                 // so we can't tell the difference between UNC and local file.
172                 goto Exit;
173             }
174
175             i = urlOrPath.Begin();
176 #if !defined(PLATFORM_UNIX)
177             if (i[0] == W('/'))
178             {
179                 // Disk path file:///
180                 urlOrPath.Delete(i, 1);
181             }
182             else if (i[0] != W('\\'))
183             {
184                 // UNC Path, re-insert "//" if not the wrong file://\\...
185                 urlOrPath.Insert(i, W("//"));
186             }
187 #else
188             // Unix doesn't have a distinction between local and network path
189             _ASSERTE(i[0] == W('\\') || i[0] == W('/'));
190 #endif
191         }
192
193     Exit:
194         while (urlOrPath.Find(i, W('/')))
195         {
196             urlOrPath.Replace(i, W('\\'));
197         }
198
199         BINDER_LOG_STRING(W("Path"), urlOrPath);
200         BINDER_LOG_LEAVE(W("Utils::MutateUrlToPath"));
201     }
202
203     void MutatePathToUrl(SString &pathOrUrl)
204     {
205         BINDER_LOG_ENTER(W("Utils::MutatePathToUrl"));
206         SString::Iterator i = pathOrUrl.Begin();
207
208         BINDER_LOG_STRING(W("Path"), pathOrUrl);
209
210 #if !defined(PLATFORM_UNIX)
211         // Network path \\server --> file://server
212         // Disk path    c:\dir   --> file:///c:/dir
213         if (i[0] == W('\\'))
214         {
215             const SString networkUrlPrefix(SString::Literal, W("file:"));
216
217             // Network path
218             pathOrUrl.Insert(i, networkUrlPrefix);
219             pathOrUrl.Skip(i, networkUrlPrefix);
220         }
221         else
222         {
223             const SString diskPathUrlPrefix(SString::Literal, W("file:///"));
224
225             // Disk path
226             pathOrUrl.Insert(i, diskPathUrlPrefix);
227             pathOrUrl.Skip(i, diskPathUrlPrefix);
228         }
229 #else
230         // Unix doesn't have a distinction between a network or a local path
231         _ASSERTE(i[0] == W('\\') || i[0] == W('/'));
232         const SString fileUrlPrefix(SString::Literal, W("file://"));
233
234         pathOrUrl.Insert(i, fileUrlPrefix);
235         pathOrUrl.Skip(i, fileUrlPrefix);
236 #endif
237
238         while (pathOrUrl.Find(i, W('\\')))
239         {
240             pathOrUrl.Replace(i, W('/'));
241         }
242
243         BINDER_LOG_STRING(W("URL"), pathOrUrl);
244         BINDER_LOG_LEAVE(W("Utils::MutatePathToUrl"));
245     }
246
247     void PlatformPath(SString &path)
248     {
249         BINDER_LOG_ENTER(W("Utils::PlatformPath"));
250         BINDER_LOG_STRING(W("input path"), path);
251
252         // Create platform representation
253         MutateUrlToPath(path);
254         if (NeedToRemoveDoubleAndNormalizePathSeparators(path))
255             RemoveDoubleAndNormalizePathSeparators(path);
256
257         BINDER_LOG_STRING(W("platform path"), path);
258
259         BINDER_LOG_LEAVE(W("Utils::PlatformPath"));
260     }
261
262     void CombinePath(SString &pathA,
263                      SString &pathB,
264                      SString &combinedPath)
265     {
266         BINDER_LOG_ENTER(W("Utils::CombinePath"));
267
268         BINDER_LOG_STRING(W("path A"), pathA);
269         BINDER_LOG_STRING(W("path B"), pathB);
270
271         SString platformPathSeparator(SString::Literal, GetPlatformPathSeparator());
272         combinedPath.Set(pathA);
273         
274         if (!combinedPath.EndsWith(platformPathSeparator))
275         {
276             combinedPath.Append(platformPathSeparator);
277         }
278         
279         combinedPath.Append(pathB);
280         
281         BINDER_LOG_LEAVE(W("Utils::CombinePath"));
282     }
283
284     HRESULT GetTokenFromPublicKey(SBuffer &publicKeyBLOB,
285                                   SBuffer &publicKeyTokenBLOB)
286     {
287         HRESULT hr = S_OK;
288         BINDER_LOG_ENTER(W("GetTokenFromPublicKey"));
289
290         const BYTE *pByteKey = publicKeyBLOB;
291         DWORD dwKeyLen = publicKeyBLOB.GetSize();
292         BYTE *pByteToken = NULL;
293         DWORD dwTokenLen = 0;
294
295         if (!StrongNameTokenFromPublicKey(const_cast<BYTE *>(pByteKey),
296                                           dwKeyLen,
297                                           &pByteToken,
298                                           &dwTokenLen))
299         {
300             BINDER_LOG(W("StrongNameTokenFromPublicKey failed!"));
301             IF_FAIL_GO(StrongNameErrorInfo());
302         }
303         else
304         {
305             _ASSERTE(pByteToken != NULL);
306             publicKeyTokenBLOB.Set(pByteToken, dwTokenLen);
307             StrongNameFreeBuffer(pByteToken);
308         }
309
310     Exit:
311         BINDER_LOG_LEAVE_HR(W("GetTokenFromPublicKey"), hr);
312         return hr;
313     }
314
315     BOOL IsFileNotFound(HRESULT hr)
316     {
317         return RuntimeFileNotFound(hr);
318     }
319 };