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 | #include "stdafx.h" |
6 | #include "windows.h" |
7 | #include "longfilepathwrappers.h" |
8 | #include "sstring.h" |
9 | #include "ex.h" |
10 | |
11 | class LongFile |
12 | { |
13 | private: |
14 | #ifndef FEATURE_PAL |
15 | static const WCHAR* ExtendedPrefix; |
16 | static const WCHAR* DevicePathPrefix; |
17 | static const WCHAR* UNCPathPrefix; |
18 | static const WCHAR* UNCExtendedPathPrefix; |
19 | static const WCHAR VolumeSeparatorChar; |
20 | #define UNCPATHPREFIX W("\\\\") |
21 | #endif //FEATURE_PAL |
22 | static const WCHAR DirectorySeparatorChar; |
23 | static const WCHAR AltDirectorySeparatorChar; |
24 | public: |
25 | static BOOL IsExtended(SString & path); |
26 | static BOOL IsUNCExtended(SString & path); |
27 | static BOOL ContainsDirectorySeparator(SString & path); |
28 | static BOOL IsDirectorySeparator(WCHAR c); |
29 | static BOOL IsPathNotFullyQualified(SString & path); |
30 | static BOOL IsDevice(SString & path); |
31 | |
32 | static HRESULT NormalizePath(SString& path); |
33 | }; |
34 | |
35 | HMODULE |
36 | LoadLibraryExWrapper( |
37 | LPCWSTR lpLibFileName, |
38 | HANDLE hFile, |
39 | DWORD dwFlags |
40 | ) |
41 | { |
42 | CONTRACTL |
43 | { |
44 | NOTHROW; |
45 | SO_TOLERANT; |
46 | } |
47 | CONTRACTL_END; |
48 | |
49 | HRESULT hr = S_OK; |
50 | HMODULE ret = NULL; |
51 | DWORD lastError; |
52 | |
53 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return NULL;) |
54 | EX_TRY |
55 | { |
56 | |
57 | LongPathString path(LongPathString::Literal, lpLibFileName); |
58 | |
59 | if (LongFile::IsPathNotFullyQualified(path) || SUCCEEDED(LongFile::NormalizePath(path))) |
60 | { |
61 | #ifndef FEATURE_PAL |
62 | //Adding the assert to ensure relative paths which are not just filenames are not used for LoadLibrary Calls |
63 | _ASSERTE(!LongFile::IsPathNotFullyQualified(path) || !LongFile::ContainsDirectorySeparator(path)); |
64 | #endif //FEATURE_PAL |
65 | |
66 | ret = LoadLibraryExW(path.GetUnicode(), hFile, dwFlags); |
67 | } |
68 | |
69 | lastError = GetLastError(); |
70 | } |
71 | EX_CATCH_HRESULT(hr); |
72 | END_SO_INTOLERANT_CODE |
73 | |
74 | if (hr != S_OK) |
75 | { |
76 | SetLastError(hr); |
77 | } |
78 | else if(ret == NULL) |
79 | { |
80 | SetLastError(lastError); |
81 | } |
82 | |
83 | return ret; |
84 | } |
85 | |
86 | HANDLE |
87 | CreateFileWrapper( |
88 | _In_ LPCWSTR lpFileName, |
89 | _In_ DWORD dwDesiredAccess, |
90 | _In_ DWORD dwShareMode, |
91 | _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, |
92 | _In_ DWORD dwCreationDisposition, |
93 | _In_ DWORD dwFlagsAndAttributes, |
94 | _In_opt_ HANDLE hTemplateFile |
95 | ) |
96 | { |
97 | CONTRACTL |
98 | { |
99 | NOTHROW; |
100 | SO_TOLERANT; |
101 | } |
102 | CONTRACTL_END; |
103 | |
104 | HRESULT hr = S_OK; |
105 | DWORD lastError; |
106 | HANDLE ret = INVALID_HANDLE_VALUE; |
107 | |
108 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return NULL;) |
109 | |
110 | EX_TRY |
111 | { |
112 | LongPathString path(LongPathString::Literal, lpFileName); |
113 | |
114 | if (SUCCEEDED(LongFile::NormalizePath(path))) |
115 | { |
116 | ret = CreateFileW(path.GetUnicode(), |
117 | dwDesiredAccess, |
118 | dwShareMode, |
119 | lpSecurityAttributes, |
120 | dwCreationDisposition, |
121 | dwFlagsAndAttributes, |
122 | hTemplateFile); |
123 | |
124 | } |
125 | |
126 | lastError = GetLastError(); |
127 | } |
128 | EX_CATCH_HRESULT(hr); |
129 | END_SO_INTOLERANT_CODE |
130 | |
131 | if (hr != S_OK ) |
132 | { |
133 | SetLastError(hr); |
134 | } |
135 | else if(ret == INVALID_HANDLE_VALUE) |
136 | { |
137 | SetLastError(lastError); |
138 | } |
139 | |
140 | return ret; |
141 | } |
142 | |
143 | BOOL |
144 | SetFileAttributesWrapper( |
145 | _In_ LPCWSTR lpFileName, |
146 | _In_ DWORD dwFileAttributes |
147 | ) |
148 | { |
149 | CONTRACTL |
150 | { |
151 | NOTHROW; |
152 | SO_TOLERANT; |
153 | } |
154 | CONTRACTL_END; |
155 | |
156 | HRESULT hr = S_OK; |
157 | BOOL ret = FALSE; |
158 | DWORD lastError; |
159 | |
160 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
161 | |
162 | EX_TRY |
163 | { |
164 | LongPathString path(LongPathString::Literal, lpFileName); |
165 | |
166 | if (SUCCEEDED(LongFile::NormalizePath(path))) |
167 | { |
168 | ret = SetFileAttributesW( |
169 | path.GetUnicode(), |
170 | dwFileAttributes |
171 | ); |
172 | } |
173 | |
174 | lastError = GetLastError(); |
175 | } |
176 | EX_CATCH_HRESULT(hr); |
177 | END_SO_INTOLERANT_CODE |
178 | |
179 | if (hr != S_OK ) |
180 | { |
181 | SetLastError(hr); |
182 | } |
183 | else if(ret == FALSE) |
184 | { |
185 | SetLastError(lastError); |
186 | } |
187 | |
188 | return ret; |
189 | } |
190 | |
191 | DWORD |
192 | GetFileAttributesWrapper( |
193 | _In_ LPCWSTR lpFileName |
194 | ) |
195 | { |
196 | CONTRACTL |
197 | { |
198 | NOTHROW; |
199 | SO_TOLERANT; |
200 | } |
201 | CONTRACTL_END; |
202 | |
203 | HRESULT hr = S_OK; |
204 | DWORD ret = INVALID_FILE_ATTRIBUTES; |
205 | DWORD lastError; |
206 | |
207 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return INVALID_FILE_ATTRIBUTES;) |
208 | |
209 | EX_TRY |
210 | { |
211 | LongPathString path(LongPathString::Literal, lpFileName); |
212 | |
213 | if (SUCCEEDED(LongFile::NormalizePath(path))) |
214 | { |
215 | ret = GetFileAttributesW( |
216 | path.GetUnicode() |
217 | ); |
218 | } |
219 | |
220 | lastError = GetLastError(); |
221 | } |
222 | EX_CATCH_HRESULT(hr); |
223 | END_SO_INTOLERANT_CODE |
224 | |
225 | if (hr != S_OK ) |
226 | { |
227 | SetLastError(hr); |
228 | } |
229 | else if(ret == INVALID_FILE_ATTRIBUTES) |
230 | { |
231 | SetLastError(lastError); |
232 | } |
233 | |
234 | return ret; |
235 | } |
236 | |
237 | BOOL |
238 | GetFileAttributesExWrapper( |
239 | _In_ LPCWSTR lpFileName, |
240 | _In_ GET_FILEEX_INFO_LEVELS fInfoLevelId, |
241 | _Out_writes_bytes_(sizeof(WIN32_FILE_ATTRIBUTE_DATA)) LPVOID lpFileInformation |
242 | ) |
243 | { |
244 | CONTRACTL |
245 | { |
246 | NOTHROW; |
247 | SO_TOLERANT; |
248 | } |
249 | CONTRACTL_END; |
250 | |
251 | HRESULT hr = S_OK; |
252 | BOOL ret = FALSE; |
253 | DWORD lastError; |
254 | |
255 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
256 | |
257 | EX_TRY |
258 | { |
259 | LongPathString path(LongPathString::Literal, lpFileName); |
260 | |
261 | if (SUCCEEDED(LongFile::NormalizePath(path))) |
262 | { |
263 | ret = GetFileAttributesExW( |
264 | path.GetUnicode(), |
265 | fInfoLevelId, |
266 | lpFileInformation |
267 | ); |
268 | |
269 | } |
270 | |
271 | lastError = GetLastError(); |
272 | } |
273 | EX_CATCH_HRESULT(hr); |
274 | END_SO_INTOLERANT_CODE |
275 | |
276 | if (hr != S_OK ) |
277 | { |
278 | SetLastError(hr); |
279 | } |
280 | else if(ret == FALSE) |
281 | { |
282 | SetLastError(lastError); |
283 | } |
284 | |
285 | return ret; |
286 | } |
287 | |
288 | BOOL |
289 | DeleteFileWrapper( |
290 | _In_ LPCWSTR lpFileName |
291 | ) |
292 | { |
293 | CONTRACTL |
294 | { |
295 | NOTHROW; |
296 | SO_TOLERANT; |
297 | } |
298 | CONTRACTL_END; |
299 | |
300 | HRESULT hr = S_OK; |
301 | BOOL ret = FALSE; |
302 | DWORD lastError; |
303 | |
304 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
305 | |
306 | EX_TRY |
307 | { |
308 | LongPathString path(LongPathString::Literal, lpFileName); |
309 | |
310 | if (SUCCEEDED(LongFile::NormalizePath(path))) |
311 | { |
312 | ret = DeleteFileW( |
313 | path.GetUnicode() |
314 | ); |
315 | } |
316 | |
317 | lastError = GetLastError(); |
318 | } |
319 | EX_CATCH_HRESULT(hr); |
320 | END_SO_INTOLERANT_CODE |
321 | |
322 | if (hr != S_OK ) |
323 | { |
324 | SetLastError(hr); |
325 | } |
326 | else if(ret == FALSE) |
327 | { |
328 | SetLastError(lastError); |
329 | } |
330 | |
331 | return ret; |
332 | } |
333 | |
334 | |
335 | BOOL |
336 | CopyFileWrapper( |
337 | _In_ LPCWSTR lpExistingFileName, |
338 | _In_ LPCWSTR lpNewFileName, |
339 | _In_ BOOL bFailIfExists |
340 | ) |
341 | { |
342 | CONTRACTL |
343 | { |
344 | NOTHROW; |
345 | SO_TOLERANT; |
346 | } |
347 | CONTRACTL_END; |
348 | |
349 | HRESULT hr = S_OK; |
350 | BOOL ret = FALSE; |
351 | DWORD lastError; |
352 | |
353 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
354 | |
355 | EX_TRY |
356 | { |
357 | LongPathString Existingpath(LongPathString::Literal, lpExistingFileName); |
358 | LongPathString Newpath(LongPathString::Literal, lpNewFileName); |
359 | |
360 | if (SUCCEEDED(LongFile::NormalizePath(Existingpath)) && SUCCEEDED(LongFile::NormalizePath(Newpath))) |
361 | { |
362 | ret = CopyFileW( |
363 | Existingpath.GetUnicode(), |
364 | Newpath.GetUnicode(), |
365 | bFailIfExists |
366 | ); |
367 | } |
368 | |
369 | lastError = GetLastError(); |
370 | } |
371 | EX_CATCH_HRESULT(hr); |
372 | END_SO_INTOLERANT_CODE |
373 | |
374 | if (hr != S_OK ) |
375 | { |
376 | SetLastError(hr); |
377 | } |
378 | else if(ret == FALSE) |
379 | { |
380 | SetLastError(lastError); |
381 | } |
382 | |
383 | return ret; |
384 | } |
385 | |
386 | BOOL |
387 | MoveFileExWrapper( |
388 | _In_ LPCWSTR lpExistingFileName, |
389 | _In_opt_ LPCWSTR lpNewFileName, |
390 | _In_ DWORD dwFlags |
391 | ) |
392 | { |
393 | CONTRACTL |
394 | { |
395 | NOTHROW; |
396 | SO_TOLERANT; |
397 | } |
398 | CONTRACTL_END; |
399 | |
400 | HRESULT hr = S_OK; |
401 | BOOL ret = FALSE; |
402 | DWORD lastError; |
403 | |
404 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
405 | |
406 | EX_TRY |
407 | { |
408 | LongPathString Existingpath(LongPathString::Literal, lpExistingFileName); |
409 | LongPathString Newpath(LongPathString::Literal, lpNewFileName); |
410 | |
411 | if (SUCCEEDED(LongFile::NormalizePath(Existingpath)) && SUCCEEDED(LongFile::NormalizePath(Newpath))) |
412 | { |
413 | ret = MoveFileExW( |
414 | Existingpath.GetUnicode(), |
415 | Newpath.GetUnicode(), |
416 | dwFlags |
417 | ); |
418 | } |
419 | |
420 | lastError = GetLastError(); |
421 | } |
422 | EX_CATCH_HRESULT(hr); |
423 | END_SO_INTOLERANT_CODE |
424 | |
425 | if (hr != S_OK ) |
426 | { |
427 | SetLastError(hr); |
428 | } |
429 | else if(ret == FALSE) |
430 | { |
431 | SetLastError(lastError); |
432 | } |
433 | |
434 | return ret; |
435 | |
436 | } |
437 | |
438 | DWORD |
439 | SearchPathWrapper( |
440 | _In_opt_ LPCWSTR lpPath, |
441 | _In_ LPCWSTR lpFileName, |
442 | _In_opt_ LPCWSTR lpExtension, |
443 | _In_ BOOL getPath, |
444 | SString& lpBuffer, |
445 | _Out_opt_ LPWSTR * lpFilePart |
446 | ) |
447 | { |
448 | CONTRACTL |
449 | { |
450 | NOTHROW; |
451 | SO_TOLERANT; |
452 | } |
453 | CONTRACTL_END; |
454 | |
455 | HRESULT hr = S_OK; |
456 | DWORD ret = 0; |
457 | DWORD lastError; |
458 | |
459 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return 0;) |
460 | |
461 | EX_TRY |
462 | { |
463 | LongPathString Existingpath(LongPathString::Literal, lpPath); |
464 | |
465 | if (lpPath != NULL) |
466 | { |
467 | if (FAILED(LongFile::NormalizePath(Existingpath))) |
468 | { |
469 | ret = FALSE; |
470 | } |
471 | else |
472 | { |
473 | lpPath = Existingpath.GetUnicode(); |
474 | } |
475 | } |
476 | |
477 | if (!getPath) |
478 | { |
479 | ret = SearchPathW( |
480 | lpPath, |
481 | lpFileName, |
482 | lpExtension, |
483 | 0, |
484 | NULL, |
485 | NULL |
486 | ); |
487 | } |
488 | else |
489 | { |
490 | COUNT_T size = lpBuffer.GetUnicodeAllocation() + 1; |
491 | |
492 | ret = SearchPathW( |
493 | lpPath, |
494 | lpFileName, |
495 | lpExtension, |
496 | size, |
497 | lpBuffer.OpenUnicodeBuffer(size - 1), |
498 | lpFilePart |
499 | ); |
500 | |
501 | if (ret > size) |
502 | { |
503 | lpBuffer.CloseBuffer(); |
504 | ret = SearchPathW( |
505 | lpPath, |
506 | lpFileName, |
507 | lpExtension, |
508 | ret, |
509 | lpBuffer.OpenUnicodeBuffer(ret - 1), |
510 | lpFilePart |
511 | ); |
512 | } |
513 | |
514 | lpBuffer.CloseBuffer(ret); |
515 | |
516 | } |
517 | |
518 | lastError = GetLastError(); |
519 | } |
520 | EX_CATCH_HRESULT(hr); |
521 | END_SO_INTOLERANT_CODE |
522 | |
523 | if (hr != S_OK) |
524 | { |
525 | SetLastError(hr); |
526 | } |
527 | else if (ret == 0) |
528 | { |
529 | SetLastError(lastError); |
530 | } |
531 | |
532 | return ret; |
533 | |
534 | } |
535 | |
536 | DWORD |
537 | GetShortPathNameWrapper( |
538 | _In_ LPCWSTR lpszLongPath, |
539 | SString& lpszShortPath |
540 | ) |
541 | { |
542 | CONTRACTL |
543 | { |
544 | NOTHROW; |
545 | SO_TOLERANT; |
546 | } |
547 | CONTRACTL_END; |
548 | |
549 | DWORD ret = 0; |
550 | HRESULT hr = S_OK; |
551 | DWORD lastError; |
552 | |
553 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return 0;) |
554 | |
555 | EX_TRY |
556 | { |
557 | LongPathString longPath(LongPathString::Literal, lpszLongPath); |
558 | |
559 | if (SUCCEEDED(LongFile::NormalizePath(longPath))) |
560 | { |
561 | COUNT_T size = lpszShortPath.GetUnicodeAllocation() + 1; |
562 | |
563 | ret = GetShortPathNameW( |
564 | longPath.GetUnicode(), |
565 | lpszShortPath.OpenUnicodeBuffer(size - 1), |
566 | (DWORD)size |
567 | ); |
568 | |
569 | if (ret > size) |
570 | { |
571 | lpszShortPath.CloseBuffer(); |
572 | ret = GetShortPathNameW( |
573 | longPath.GetUnicode(), |
574 | lpszShortPath.OpenUnicodeBuffer(ret -1), |
575 | ret |
576 | ); |
577 | } |
578 | |
579 | lpszShortPath.CloseBuffer(ret); |
580 | } |
581 | |
582 | lastError = GetLastError(); |
583 | } |
584 | EX_CATCH_HRESULT(hr); |
585 | END_SO_INTOLERANT_CODE |
586 | |
587 | if (hr != S_OK ) |
588 | { |
589 | SetLastError(hr); |
590 | } |
591 | else if(ret == 0) |
592 | { |
593 | SetLastError(lastError); |
594 | } |
595 | |
596 | return ret; |
597 | } |
598 | |
599 | DWORD |
600 | GetLongPathNameWrapper( |
601 | _In_ LPCWSTR lpszShortPath, |
602 | SString& lpszLongPath |
603 | ) |
604 | { |
605 | CONTRACTL |
606 | { |
607 | NOTHROW; |
608 | SO_TOLERANT; |
609 | } |
610 | CONTRACTL_END; |
611 | |
612 | DWORD ret = 0; |
613 | HRESULT hr = S_OK; |
614 | DWORD lastError; |
615 | |
616 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return 0;) |
617 | |
618 | EX_TRY |
619 | { |
620 | LongPathString shortPath(LongPathString::Literal, lpszShortPath); |
621 | |
622 | if (SUCCEEDED(LongFile::NormalizePath(shortPath))) |
623 | { |
624 | COUNT_T size = lpszLongPath.GetUnicodeAllocation() + 1; |
625 | |
626 | ret = GetLongPathNameW( |
627 | shortPath.GetUnicode(), |
628 | lpszLongPath.OpenUnicodeBuffer(size - 1), |
629 | (DWORD)size |
630 | ); |
631 | |
632 | if (ret > size) |
633 | { |
634 | lpszLongPath.CloseBuffer(); |
635 | ret = GetLongPathNameW( |
636 | shortPath.GetUnicode(), |
637 | lpszLongPath.OpenUnicodeBuffer(ret - 1), |
638 | ret |
639 | ); |
640 | |
641 | } |
642 | |
643 | lpszLongPath.CloseBuffer(ret); |
644 | } |
645 | |
646 | lastError = GetLastError(); |
647 | } |
648 | EX_CATCH_HRESULT(hr); |
649 | END_SO_INTOLERANT_CODE |
650 | |
651 | if (hr != S_OK ) |
652 | { |
653 | SetLastError(hr); |
654 | } |
655 | else if(ret == 0) |
656 | { |
657 | SetLastError(lastError); |
658 | } |
659 | |
660 | return ret; |
661 | } |
662 | |
663 | BOOL |
664 | CreateDirectoryWrapper( |
665 | _In_ LPCWSTR lpPathName, |
666 | _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes |
667 | ) |
668 | { |
669 | CONTRACTL |
670 | { |
671 | NOTHROW; |
672 | SO_TOLERANT; |
673 | } |
674 | CONTRACTL_END; |
675 | |
676 | HRESULT hr = S_OK; |
677 | BOOL ret = FALSE; |
678 | DWORD lastError; |
679 | |
680 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
681 | |
682 | EX_TRY |
683 | { |
684 | LongPathString path(LongPathString::Literal, lpPathName); |
685 | |
686 | if (SUCCEEDED(LongFile::NormalizePath(path))) |
687 | { |
688 | ret = CreateDirectoryW( |
689 | path.GetUnicode(), |
690 | lpSecurityAttributes |
691 | ); |
692 | } |
693 | |
694 | lastError = GetLastError(); |
695 | } |
696 | EX_CATCH_HRESULT(hr); |
697 | END_SO_INTOLERANT_CODE |
698 | |
699 | if (hr != S_OK ) |
700 | { |
701 | SetLastError(hr); |
702 | } |
703 | else if(ret == FALSE) |
704 | { |
705 | SetLastError(lastError); |
706 | } |
707 | |
708 | return ret; |
709 | } |
710 | |
711 | BOOL |
712 | RemoveDirectoryWrapper( |
713 | _In_ LPCWSTR lpPathName |
714 | ) |
715 | { |
716 | CONTRACTL |
717 | { |
718 | NOTHROW; |
719 | SO_TOLERANT; |
720 | } |
721 | CONTRACTL_END; |
722 | |
723 | HRESULT hr = S_OK; |
724 | BOOL ret = FALSE; |
725 | DWORD lastError; |
726 | |
727 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
728 | |
729 | EX_TRY |
730 | { |
731 | LongPathString path(LongPathString::Literal, lpPathName); |
732 | |
733 | if (SUCCEEDED(LongFile::NormalizePath(path))) |
734 | { |
735 | ret = RemoveDirectoryW( |
736 | path.GetUnicode() |
737 | ); |
738 | } |
739 | |
740 | lastError = GetLastError(); |
741 | } |
742 | EX_CATCH_HRESULT(hr); |
743 | END_SO_INTOLERANT_CODE |
744 | |
745 | if (hr != S_OK ) |
746 | { |
747 | SetLastError(hr); |
748 | } |
749 | else if(ret == FALSE) |
750 | { |
751 | SetLastError(lastError); |
752 | } |
753 | |
754 | return ret; |
755 | } |
756 | DWORD |
757 | GetModuleFileNameWrapper( |
758 | _In_opt_ HMODULE hModule, |
759 | SString& buffer |
760 | ) |
761 | { |
762 | CONTRACTL |
763 | { |
764 | NOTHROW; |
765 | SO_TOLERANT; |
766 | } |
767 | CONTRACTL_END; |
768 | |
769 | HRESULT hr = S_OK; |
770 | DWORD ret = 0; |
771 | DWORD lastError; |
772 | |
773 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return 0;) |
774 | |
775 | EX_TRY |
776 | { |
777 | COUNT_T size = buffer.GetUnicodeAllocation() + 1; |
778 | |
779 | ret = GetModuleFileNameW( |
780 | hModule, |
781 | buffer.OpenUnicodeBuffer(size - 1), |
782 | (DWORD)size |
783 | ); |
784 | |
785 | |
786 | while (ret == size ) |
787 | { |
788 | buffer.CloseBuffer(); |
789 | size = size * 2; |
790 | ret = GetModuleFileNameW( |
791 | hModule, |
792 | buffer.OpenUnicodeBuffer(size - 1), |
793 | (DWORD)size |
794 | ); |
795 | |
796 | } |
797 | |
798 | |
799 | lastError = GetLastError(); |
800 | buffer.CloseBuffer(ret); |
801 | } |
802 | EX_CATCH_HRESULT(hr); |
803 | END_SO_INTOLERANT_CODE |
804 | |
805 | if (hr != S_OK) |
806 | { |
807 | SetLastError(hr); |
808 | } |
809 | else if (ret == 0) |
810 | { |
811 | SetLastError(lastError); |
812 | } |
813 | |
814 | return ret; |
815 | } |
816 | |
817 | UINT WINAPI GetTempFileNameWrapper( |
818 | _In_ LPCTSTR lpPathName, |
819 | _In_ LPCTSTR lpPrefixString, |
820 | _In_ UINT uUnique, |
821 | SString& lpTempFileName |
822 | ) |
823 | { |
824 | CONTRACTL |
825 | { |
826 | NOTHROW; |
827 | SO_TOLERANT; |
828 | } |
829 | CONTRACTL_END; |
830 | |
831 | HRESULT hr = S_OK; |
832 | UINT ret = 0; |
833 | DWORD lastError; |
834 | |
835 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return 0;) |
836 | |
837 | EX_TRY |
838 | { |
839 | //Change the behaviour in Redstone to retry |
840 | COUNT_T size = MAX_LONGPATH; |
841 | WCHAR* buffer = lpTempFileName.OpenUnicodeBuffer(size - 1); |
842 | ret = GetTempFileNameW( |
843 | lpPathName, |
844 | lpPrefixString, |
845 | uUnique, |
846 | buffer |
847 | ); |
848 | |
849 | lastError = GetLastError(); |
850 | size = (COUNT_T)wcslen(buffer); |
851 | lpTempFileName.CloseBuffer(size); |
852 | |
853 | } |
854 | EX_CATCH_HRESULT(hr); |
855 | END_SO_INTOLERANT_CODE |
856 | |
857 | if (hr != S_OK) |
858 | { |
859 | SetLastError(hr); |
860 | } |
861 | else if (ret == 0) |
862 | { |
863 | SetLastError(lastError); |
864 | } |
865 | |
866 | return ret; |
867 | } |
868 | DWORD WINAPI GetTempPathWrapper( |
869 | SString& lpBuffer |
870 | ) |
871 | { |
872 | CONTRACTL |
873 | { |
874 | NOTHROW; |
875 | SO_TOLERANT; |
876 | } |
877 | CONTRACTL_END; |
878 | |
879 | HRESULT hr = S_OK; |
880 | DWORD ret = 0; |
881 | DWORD lastError; |
882 | |
883 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return 0;) |
884 | |
885 | EX_TRY |
886 | { |
887 | //Change the behaviour in Redstone to retry |
888 | COUNT_T size = MAX_LONGPATH; |
889 | |
890 | ret = GetTempPathW( |
891 | size, |
892 | lpBuffer.OpenUnicodeBuffer(size - 1) |
893 | ); |
894 | |
895 | lastError = GetLastError(); |
896 | lpBuffer.CloseBuffer(ret); |
897 | } |
898 | EX_CATCH_HRESULT(hr); |
899 | END_SO_INTOLERANT_CODE |
900 | |
901 | if (hr != S_OK) |
902 | { |
903 | SetLastError(hr); |
904 | } |
905 | else if (ret == 0) |
906 | { |
907 | SetLastError(lastError); |
908 | } |
909 | |
910 | return ret; |
911 | } |
912 | |
913 | DWORD WINAPI GetCurrentDirectoryWrapper( |
914 | SString& lpBuffer |
915 | ) |
916 | { |
917 | CONTRACTL |
918 | { |
919 | NOTHROW; |
920 | SO_TOLERANT; |
921 | } |
922 | CONTRACTL_END; |
923 | |
924 | HRESULT hr = S_OK; |
925 | DWORD ret = 0; |
926 | DWORD lastError; |
927 | |
928 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return 0;) |
929 | |
930 | EX_TRY |
931 | { |
932 | //Change the behaviour in Redstone to retry |
933 | COUNT_T size = MAX_LONGPATH; |
934 | |
935 | ret = GetCurrentDirectoryW( |
936 | size, |
937 | lpBuffer.OpenUnicodeBuffer(size - 1) |
938 | ); |
939 | |
940 | lastError = GetLastError(); |
941 | lpBuffer.CloseBuffer(ret); |
942 | } |
943 | EX_CATCH_HRESULT(hr); |
944 | END_SO_INTOLERANT_CODE |
945 | |
946 | if (hr != S_OK) |
947 | { |
948 | SetLastError(hr); |
949 | } |
950 | else if (ret == 0) |
951 | { |
952 | SetLastError(lastError); |
953 | } |
954 | |
955 | return ret; |
956 | } |
957 | |
958 | DWORD WINAPI GetEnvironmentVariableWrapper( |
959 | _In_opt_ LPCTSTR lpName, |
960 | _Out_opt_ SString& lpBuffer |
961 | ) |
962 | { |
963 | CONTRACTL |
964 | { |
965 | NOTHROW; |
966 | SO_TOLERANT; |
967 | } |
968 | CONTRACTL_END; |
969 | |
970 | HRESULT hr = S_OK; |
971 | DWORD ret = 0; |
972 | DWORD lastError; |
973 | |
974 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return 0;) |
975 | |
976 | EX_TRY |
977 | { |
978 | |
979 | COUNT_T size = lpBuffer.GetUnicodeAllocation() + 1; |
980 | |
981 | ret = GetEnvironmentVariableW( |
982 | lpName, |
983 | lpBuffer.OpenUnicodeBuffer(size - 1), |
984 | size |
985 | ); |
986 | |
987 | // We loop round getting the length of the env var and then trying to copy |
988 | // the value into a the allocated buffer. Usually we'll go through this loop |
989 | // precisely once, but the caution is ncessary in case the variable mutates |
990 | // beneath us, as the environment variable can be modified by another thread |
991 | //between two calls to GetEnvironmentVariableW |
992 | |
993 | while (ret > size) |
994 | { |
995 | size = ret; |
996 | lpBuffer.CloseBuffer(); |
997 | ret = GetEnvironmentVariableW( |
998 | lpName, |
999 | lpBuffer.OpenUnicodeBuffer(size - 1), |
1000 | size); |
1001 | } |
1002 | |
1003 | lastError = GetLastError(); |
1004 | lpBuffer.CloseBuffer(ret); |
1005 | } |
1006 | EX_CATCH_HRESULT(hr); |
1007 | END_SO_INTOLERANT_CODE |
1008 | |
1009 | if (hr != S_OK) |
1010 | { |
1011 | SetLastError(hr); |
1012 | } |
1013 | else if (ret == 0) |
1014 | { |
1015 | SetLastError(lastError); |
1016 | } |
1017 | |
1018 | return ret; |
1019 | } |
1020 | |
1021 | |
1022 | #ifndef FEATURE_PAL |
1023 | |
1024 | BOOL |
1025 | CreateHardLinkWrapper( |
1026 | _In_ LPCWSTR lpFileName, |
1027 | _In_ LPCWSTR lpExistingFileName, |
1028 | _Reserved_ LPSECURITY_ATTRIBUTES lpSecurityAttributes |
1029 | ) |
1030 | { |
1031 | CONTRACTL |
1032 | { |
1033 | NOTHROW; |
1034 | SO_TOLERANT; |
1035 | } |
1036 | CONTRACTL_END; |
1037 | |
1038 | HRESULT hr = S_OK; |
1039 | BOOL ret = FALSE; |
1040 | DWORD lastError; |
1041 | |
1042 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
1043 | |
1044 | EX_TRY |
1045 | { |
1046 | LongPathString Existingpath(LongPathString::Literal, lpExistingFileName); |
1047 | LongPathString FileName(LongPathString::Literal, lpFileName); |
1048 | |
1049 | if (SUCCEEDED(LongFile::NormalizePath(Existingpath)) && SUCCEEDED(LongFile::NormalizePath(FileName))) |
1050 | { |
1051 | ret = CreateHardLinkW( |
1052 | Existingpath.GetUnicode(), |
1053 | FileName.GetUnicode(), |
1054 | lpSecurityAttributes |
1055 | ); |
1056 | } |
1057 | |
1058 | lastError = GetLastError(); |
1059 | } |
1060 | EX_CATCH_HRESULT(hr); |
1061 | END_SO_INTOLERANT_CODE |
1062 | |
1063 | if (hr != S_OK ) |
1064 | { |
1065 | SetLastError(hr); |
1066 | } |
1067 | else if(ret == FALSE) |
1068 | { |
1069 | SetLastError(lastError); |
1070 | } |
1071 | |
1072 | return ret; |
1073 | } |
1074 | |
1075 | BOOL |
1076 | CopyFileExWrapper( |
1077 | _In_ LPCWSTR lpExistingFileName, |
1078 | _In_ LPCWSTR lpNewFileName, |
1079 | _In_opt_ LPPROGRESS_ROUTINE lpProgressRoutine, |
1080 | _In_opt_ LPVOID lpData, |
1081 | _When_(pbCancel != NULL, _Pre_satisfies_(*pbCancel == FALSE)) |
1082 | _Inout_opt_ LPBOOL pbCancel, |
1083 | _In_ DWORD dwCopyFlags |
1084 | ) |
1085 | { |
1086 | CONTRACTL |
1087 | { |
1088 | NOTHROW; |
1089 | SO_TOLERANT; |
1090 | } |
1091 | CONTRACTL_END; |
1092 | |
1093 | HRESULT hr = S_OK; |
1094 | BOOL ret = FALSE; |
1095 | DWORD lastError; |
1096 | |
1097 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
1098 | |
1099 | EX_TRY |
1100 | { |
1101 | LongPathString Existingpath(LongPathString::Literal, lpExistingFileName); |
1102 | LongPathString Newpath(LongPathString::Literal, lpNewFileName); |
1103 | |
1104 | if (SUCCEEDED(LongFile::NormalizePath(Existingpath)) && SUCCEEDED(LongFile::NormalizePath(Newpath))) |
1105 | { |
1106 | ret = CopyFileExW( |
1107 | Existingpath.GetUnicode(), |
1108 | Newpath.GetUnicode(), |
1109 | lpProgressRoutine, |
1110 | lpData, |
1111 | pbCancel, |
1112 | dwCopyFlags |
1113 | ); |
1114 | } |
1115 | |
1116 | lastError = GetLastError(); |
1117 | } |
1118 | EX_CATCH_HRESULT(hr); |
1119 | END_SO_INTOLERANT_CODE |
1120 | |
1121 | if (hr != S_OK ) |
1122 | { |
1123 | SetLastError(hr); |
1124 | } |
1125 | else if(ret == FALSE) |
1126 | { |
1127 | SetLastError(lastError); |
1128 | } |
1129 | |
1130 | return ret; |
1131 | } |
1132 | |
1133 | HANDLE |
1134 | FindFirstFileExWrapper( |
1135 | _In_ LPCWSTR lpFileName, |
1136 | _In_ FINDEX_INFO_LEVELS fInfoLevelId, |
1137 | _Out_writes_bytes_(sizeof(WIN32_FIND_DATAW)) LPVOID lpFindFileData, |
1138 | _In_ FINDEX_SEARCH_OPS fSearchOp, |
1139 | _Reserved_ LPVOID lpSearchFilter, |
1140 | _In_ DWORD dwAdditionalFlags |
1141 | ) |
1142 | { |
1143 | CONTRACTL |
1144 | { |
1145 | NOTHROW; |
1146 | SO_TOLERANT; |
1147 | } |
1148 | CONTRACTL_END; |
1149 | |
1150 | HRESULT hr = S_OK; |
1151 | HANDLE ret = INVALID_HANDLE_VALUE; |
1152 | DWORD lastError; |
1153 | |
1154 | BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return FALSE;) |
1155 | |
1156 | EX_TRY |
1157 | { |
1158 | LongPathString path(LongPathString::Literal, lpFileName); |
1159 | |
1160 | if (SUCCEEDED(LongFile::NormalizePath(path))) |
1161 | { |
1162 | ret = FindFirstFileExW( |
1163 | path.GetUnicode(), |
1164 | fInfoLevelId, |
1165 | lpFindFileData, |
1166 | fSearchOp, |
1167 | lpSearchFilter, |
1168 | dwAdditionalFlags |
1169 | ); |
1170 | } |
1171 | |
1172 | lastError = GetLastError(); |
1173 | } |
1174 | EX_CATCH_HRESULT(hr); |
1175 | END_SO_INTOLERANT_CODE |
1176 | |
1177 | if (hr != S_OK ) |
1178 | { |
1179 | SetLastError(hr); |
1180 | } |
1181 | else if(ret == INVALID_HANDLE_VALUE) |
1182 | { |
1183 | SetLastError(lastError); |
1184 | } |
1185 | |
1186 | return ret; |
1187 | } |
1188 | #endif //!FEATURE_PAL |
1189 | |
1190 | |
1191 | #ifndef FEATURE_PAL |
1192 | |
1193 | #if ! defined(DACCESS_COMPILE) && !defined(SELF_NO_HOST) |
1194 | extern HINSTANCE g_pMSCorEE; |
1195 | #endif// ! defined(DACCESS_COMPILE) && !defined(SELF_NO_HOST) |
1196 | |
1197 | BOOL PAL_GetPALDirectoryWrapper(SString& pbuffer) |
1198 | { |
1199 | |
1200 | HRESULT hr = S_OK; |
1201 | |
1202 | PathString pPath; |
1203 | DWORD dwPath; |
1204 | HINSTANCE hinst = NULL; |
1205 | |
1206 | #if ! defined(DACCESS_COMPILE) && !defined(SELF_NO_HOST) |
1207 | hinst = g_pMSCorEE; |
1208 | #endif// ! defined(DACCESS_COMPILE) && !defined(SELF_NO_HOST) |
1209 | |
1210 | #ifndef CROSSGEN_COMPILE |
1211 | _ASSERTE(hinst != NULL); |
1212 | #endif |
1213 | |
1214 | dwPath = WszGetModuleFileName(hinst, pPath); |
1215 | |
1216 | if(dwPath == 0) |
1217 | { |
1218 | hr = HRESULT_FROM_GetLastErrorNA(); |
1219 | } |
1220 | else |
1221 | { |
1222 | hr = CopySystemDirectory(pPath, pbuffer); |
1223 | } |
1224 | |
1225 | return (hr == S_OK); |
1226 | } |
1227 | |
1228 | #else |
1229 | |
1230 | BOOL PAL_GetPALDirectoryWrapper(SString& pbuffer) |
1231 | { |
1232 | BOOL retval = FALSE; |
1233 | COUNT_T size = MAX_LONGPATH; |
1234 | |
1235 | if(!(retval = PAL_GetPALDirectoryW(pbuffer.OpenUnicodeBuffer(size - 1), &size))) |
1236 | { |
1237 | pbuffer.CloseBuffer(0); |
1238 | retval = PAL_GetPALDirectoryW(pbuffer.OpenUnicodeBuffer(size - 1), &size); |
1239 | } |
1240 | |
1241 | pbuffer.CloseBuffer(size); |
1242 | |
1243 | return retval; |
1244 | } |
1245 | |
1246 | #endif // FEATURE_PAL |
1247 | |
1248 | |
1249 | //Implementation of LongFile Helpers |
1250 | const WCHAR LongFile::DirectorySeparatorChar = W('\\'); |
1251 | const WCHAR LongFile::AltDirectorySeparatorChar = W('/'); |
1252 | #ifndef FEATURE_PAL |
1253 | const WCHAR LongFile::VolumeSeparatorChar = W(':'); |
1254 | const WCHAR* LongFile::ExtendedPrefix = W("\\\\?\\" ); |
1255 | const WCHAR* LongFile::DevicePathPrefix = W("\\\\.\\" ); |
1256 | const WCHAR* LongFile::UNCExtendedPathPrefix = W("\\\\?\\UNC\\" ); |
1257 | const WCHAR* LongFile::UNCPathPrefix = UNCPATHPREFIX; |
1258 | |
1259 | BOOL LongFile::IsExtended(SString & path) |
1260 | { |
1261 | return path.BeginsWith(ExtendedPrefix); |
1262 | } |
1263 | |
1264 | BOOL LongFile::IsUNCExtended(SString & path) |
1265 | { |
1266 | |
1267 | return path.BeginsWith(UNCExtendedPathPrefix); |
1268 | } |
1269 | |
1270 | // Relative here means it could be relative to current directory on the relevant drive |
1271 | // NOTE: Relative segments ( \..\) are not considered relative |
1272 | // Returns true if the path specified is relative to the current drive or working directory. |
1273 | // Returns false if the path is fixed to a specific drive or UNC path. This method does no |
1274 | // validation of the path (URIs will be returned as relative as a result). |
1275 | // Handles paths that use the alternate directory separator. It is a frequent mistake to |
1276 | // assume that rooted paths (Path.IsPathRooted) are not relative. This isn't the case. |
1277 | |
1278 | BOOL LongFile::IsPathNotFullyQualified(SString & path) |
1279 | { |
1280 | if (path.GetCount() < 2) |
1281 | { |
1282 | return TRUE; // It isn't fixed, it must be relative. There is no way to specify a fixed path with one character (or less). |
1283 | } |
1284 | |
1285 | if (IsDirectorySeparator(path[0])) |
1286 | { |
1287 | return !IsDirectorySeparator(path[1]); // There is no valid way to specify a relative path with two initial slashes |
1288 | } |
1289 | |
1290 | return !((path.GetCount() >= 3) //The only way to specify a fixed path that doesn't begin with two slashes is the drive, colon, slash format- i.e. "C:\" |
1291 | && (path[1] == VolumeSeparatorChar) |
1292 | && IsDirectorySeparator(path[2])); |
1293 | } |
1294 | |
1295 | BOOL LongFile::IsDevice(SString & path) |
1296 | { |
1297 | return path.BeginsWith(DevicePathPrefix); |
1298 | } |
1299 | |
1300 | // This function will normalize paths if the path length exceeds MAX_PATH |
1301 | // The normalization examples are : |
1302 | // C:\foo\<long>\bar => \\?\C:\foo\<long>\bar |
1303 | // \\server\<long>\bar => \\?\UNC\server\<long>\bar |
1304 | HRESULT LongFile::NormalizePath(SString & path) |
1305 | { |
1306 | HRESULT hr = S_OK; |
1307 | DWORD ret = 0; |
1308 | COUNT_T prefixLen = 0; |
1309 | if (path.IsEmpty()|| IsDevice(path) || IsExtended(path) || IsUNCExtended(path)) |
1310 | return S_OK; |
1311 | |
1312 | if (!IsPathNotFullyQualified(path) && path.GetCount() < MAX_LONGPATH) |
1313 | return S_OK; |
1314 | |
1315 | //Now the path will be normalized |
1316 | |
1317 | SString originalPath(path); |
1318 | SString prefix(ExtendedPrefix); |
1319 | prefixLen = prefix.GetCount(); |
1320 | |
1321 | if (path.BeginsWith(UNCPathPrefix)) |
1322 | { |
1323 | prefix.Set(UNCExtendedPathPrefix); |
1324 | //In this case if path is \\server the extended syntax should be like \\?\UNC\server |
1325 | //The below logic populates the path from prefixLen offset from the start. This ensures that first 2 characters are overwritten |
1326 | // |
1327 | prefixLen = prefix.GetCount() - (COUNT_T)wcslen(UNCPATHPREFIX); |
1328 | _ASSERTE(prefixLen > 0 ); |
1329 | } |
1330 | |
1331 | |
1332 | COUNT_T size = path.GetUnicodeAllocation() + 1; |
1333 | WCHAR* buffer = path.OpenUnicodeBuffer(size - 1); |
1334 | |
1335 | ret = GetFullPathNameW( |
1336 | originalPath.GetUnicode(), |
1337 | size - prefixLen, //memory avilable for path after reserving for prefix |
1338 | (buffer + prefixLen), //reserve memory for prefix |
1339 | NULL |
1340 | ); |
1341 | |
1342 | if (ret == 0) |
1343 | { |
1344 | return E_FAIL; |
1345 | } |
1346 | |
1347 | if (ret > size - prefixLen) |
1348 | { |
1349 | path.CloseBuffer(); |
1350 | size = ret + prefixLen; |
1351 | buffer = path.OpenUnicodeBuffer(size -1); |
1352 | |
1353 | ret = GetFullPathNameW( |
1354 | originalPath.GetUnicode(), |
1355 | ret, // memory required for the path |
1356 | (buffer + prefixLen), //reserve memory for prefix |
1357 | NULL |
1358 | ); |
1359 | |
1360 | _ASSERTE(ret < size - prefixLen); |
1361 | |
1362 | if (ret == 0) |
1363 | { |
1364 | return E_FAIL; |
1365 | } |
1366 | } |
1367 | |
1368 | SString fullpath(SString::Literal,buffer + prefixLen); |
1369 | |
1370 | //Check if the resolved path is a UNC. By default we assume relative path to resolve to disk |
1371 | if (fullpath.BeginsWith(UNCPathPrefix) && prefixLen != prefix.GetCount() - (COUNT_T)wcslen(UNCPATHPREFIX)) |
1372 | { |
1373 | |
1374 | //Remove the leading '\\' from the UNC path to be replaced with UNCExtendedPathPrefix |
1375 | fullpath.Replace(fullpath.Begin(), (COUNT_T)wcslen(UNCPATHPREFIX), UNCExtendedPathPrefix); |
1376 | path.CloseBuffer(); |
1377 | path.Set(fullpath); |
1378 | } |
1379 | else |
1380 | { |
1381 | //wcscpy_s always termintes with NULL, so we are saving the character that will be overwriiten |
1382 | WCHAR temp = buffer[prefix.GetCount()]; |
1383 | wcscpy_s(buffer, prefix.GetCount() + 1, prefix.GetUnicode()); |
1384 | buffer[prefix.GetCount()] = temp; |
1385 | path.CloseBuffer(ret + prefixLen); |
1386 | } |
1387 | |
1388 | return S_OK; |
1389 | } |
1390 | #else |
1391 | BOOL LongFile::IsExtended(SString & path) |
1392 | { |
1393 | return FALSE; |
1394 | } |
1395 | |
1396 | BOOL LongFile::IsUNCExtended(SString & path) |
1397 | { |
1398 | return FALSE; |
1399 | } |
1400 | |
1401 | BOOL LongFile::IsPathNotFullyQualified(SString & path) |
1402 | { |
1403 | return TRUE; |
1404 | } |
1405 | |
1406 | BOOL LongFile::IsDevice(SString & path) |
1407 | { |
1408 | return FALSE; |
1409 | } |
1410 | |
1411 | //Don't need to do anything For XPlat |
1412 | HRESULT LongFile::NormalizePath(SString & path) |
1413 | { |
1414 | return S_OK; |
1415 | } |
1416 | #endif //FEATURE_PAL |
1417 | |
1418 | BOOL LongFile::ContainsDirectorySeparator(SString & path) |
1419 | { |
1420 | return path.Find(path.Begin(), DirectorySeparatorChar) || path.Find(path.Begin(), AltDirectorySeparatorChar); |
1421 | } |
1422 | |
1423 | BOOL LongFile::IsDirectorySeparator(WCHAR c) |
1424 | { |
1425 | return c == DirectorySeparatorChar || c == AltDirectorySeparatorChar; |
1426 | } |
1427 | |
1428 | |
1429 | |
1430 | |