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