Merge TempDir and system_temp_directory.
[oota-llvm.git] / lib / Support / Windows / Path.inc
1 //===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Windows specific implementation of the Path API.
11 //
12 //===----------------------------------------------------------------------===//
13
14 //===----------------------------------------------------------------------===//
15 //=== WARNING: Implementation here must contain only generic Windows code that
16 //===          is guaranteed to work on *all* Windows variants.
17 //===----------------------------------------------------------------------===//
18
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/Support/WindowsError.h"
21 #include <fcntl.h>
22 #include <io.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 // These two headers must be included last, and make sure shlobj is required
27 // after Windows.h to make sure it picks up our definition of _WIN32_WINNT
28 #include "WindowsSupport.h"
29 #include <shlobj.h>
30
31 #undef max
32
33 // MinGW doesn't define this.
34 #ifndef _ERRNO_T_DEFINED
35 #define _ERRNO_T_DEFINED
36 typedef int errno_t;
37 #endif
38
39 #ifdef _MSC_VER
40 # pragma comment(lib, "advapi32.lib")  // This provides CryptAcquireContextW.
41 #endif
42
43 using namespace llvm;
44
45 using llvm::sys::windows::UTF8ToUTF16;
46 using llvm::sys::windows::UTF16ToUTF8;
47
48 static std::error_code windows_error(DWORD E) {
49   return mapWindowsError(E);
50 }
51
52 static bool is_separator(const wchar_t value) {
53   switch (value) {
54   case L'\\':
55   case L'/':
56     return true;
57   default:
58     return false;
59   }
60 }
61
62 namespace llvm {
63 namespace sys  {
64 namespace fs {
65
66 std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
67   SmallVector<wchar_t, MAX_PATH> PathName;
68   DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity());
69
70   // A zero return value indicates a failure other than insufficient space.
71   if (Size == 0)
72     return "";
73
74   // Insufficient space is determined by a return value equal to the size of
75   // the buffer passed in.
76   if (Size == PathName.capacity())
77     return "";
78
79   // On success, GetModuleFileNameW returns the number of characters written to
80   // the buffer not including the NULL terminator.
81   PathName.set_size(Size);
82
83   // Convert the result from UTF-16 to UTF-8.
84   SmallVector<char, MAX_PATH> PathNameUTF8;
85   if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8))
86     return "";
87
88   return std::string(PathNameUTF8.data());
89 }
90
91 UniqueID file_status::getUniqueID() const {
92   // The file is uniquely identified by the volume serial number along
93   // with the 64-bit file identifier.
94   uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) |
95                     static_cast<uint64_t>(FileIndexLow);
96
97   return UniqueID(VolumeSerialNumber, FileID);
98 }
99
100 TimeValue file_status::getLastModificationTime() const {
101   ULARGE_INTEGER UI;
102   UI.LowPart = LastWriteTimeLow;
103   UI.HighPart = LastWriteTimeHigh;
104
105   TimeValue Ret;
106   Ret.fromWin32Time(UI.QuadPart);
107   return Ret;
108 }
109
110 std::error_code current_path(SmallVectorImpl<char> &result) {
111   SmallVector<wchar_t, MAX_PATH> cur_path;
112   DWORD len = MAX_PATH;
113
114   do {
115     cur_path.reserve(len);
116     len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data());
117
118     // A zero return value indicates a failure other than insufficient space.
119     if (len == 0)
120       return windows_error(::GetLastError());
121
122     // If there's insufficient space, the len returned is larger than the len
123     // given.
124   } while (len > cur_path.capacity());
125
126   // On success, GetCurrentDirectoryW returns the number of characters not
127   // including the null-terminator.
128   cur_path.set_size(len);
129   return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result);
130 }
131
132 std::error_code create_directory(const Twine &path, bool IgnoreExisting) {
133   SmallString<128> path_storage;
134   SmallVector<wchar_t, 128> path_utf16;
135
136   if (std::error_code ec =
137           UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))
138     return ec;
139
140   if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
141     DWORD LastError = ::GetLastError();
142     if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting)
143       return windows_error(LastError);
144   }
145
146   return std::error_code();
147 }
148
149 // We can't use symbolic links for windows.
150 std::error_code create_link(const Twine &to, const Twine &from) {
151   // Get arguments.
152   SmallString<128> from_storage;
153   SmallString<128> to_storage;
154   StringRef f = from.toStringRef(from_storage);
155   StringRef t = to.toStringRef(to_storage);
156
157   // Convert to utf-16.
158   SmallVector<wchar_t, 128> wide_from;
159   SmallVector<wchar_t, 128> wide_to;
160   if (std::error_code ec = UTF8ToUTF16(f, wide_from))
161     return ec;
162   if (std::error_code ec = UTF8ToUTF16(t, wide_to))
163     return ec;
164
165   if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
166     return windows_error(::GetLastError());
167
168   return std::error_code();
169 }
170
171 std::error_code remove(const Twine &path, bool IgnoreNonExisting) {
172   SmallString<128> path_storage;
173   SmallVector<wchar_t, 128> path_utf16;
174
175   file_status ST;
176   if (std::error_code EC = status(path, ST)) {
177     if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting)
178       return EC;
179     return std::error_code();
180   }
181
182   if (std::error_code ec =
183           UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))
184     return ec;
185
186   if (ST.type() == file_type::directory_file) {
187     if (!::RemoveDirectoryW(c_str(path_utf16))) {
188       std::error_code EC = windows_error(::GetLastError());
189       if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting)
190         return EC;
191     }
192     return std::error_code();
193   }
194   if (!::DeleteFileW(c_str(path_utf16))) {
195     std::error_code EC = windows_error(::GetLastError());
196     if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting)
197       return EC;
198   }
199   return std::error_code();
200 }
201
202 std::error_code rename(const Twine &from, const Twine &to) {
203   // Get arguments.
204   SmallString<128> from_storage;
205   SmallString<128> to_storage;
206   StringRef f = from.toStringRef(from_storage);
207   StringRef t = to.toStringRef(to_storage);
208
209   // Convert to utf-16.
210   SmallVector<wchar_t, 128> wide_from;
211   SmallVector<wchar_t, 128> wide_to;
212   if (std::error_code ec = UTF8ToUTF16(f, wide_from))
213     return ec;
214   if (std::error_code ec = UTF8ToUTF16(t, wide_to))
215     return ec;
216
217   std::error_code ec = std::error_code();
218   for (int i = 0; i < 2000; i++) {
219     if (::MoveFileExW(wide_from.begin(), wide_to.begin(),
220                       MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
221       return std::error_code();
222     DWORD LastError = ::GetLastError();
223     if (LastError != ERROR_ACCESS_DENIED)
224       break;
225     // Retry MoveFile() at ACCESS_DENIED.
226     // System scanners (eg. indexer) might open the source file when
227     // It is written and closed.
228     ::Sleep(1);
229   }
230
231   return ec;
232 }
233
234 std::error_code resize_file(const Twine &path, uint64_t size) {
235   SmallString<128> path_storage;
236   SmallVector<wchar_t, 128> path_utf16;
237
238   if (std::error_code ec =
239           UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))
240     return ec;
241
242   int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE);
243   if (fd == -1)
244     return std::error_code(errno, std::generic_category());
245 #ifdef HAVE__CHSIZE_S
246   errno_t error = ::_chsize_s(fd, size);
247 #else
248   errno_t error = ::_chsize(fd, size);
249 #endif
250   ::close(fd);
251   return std::error_code(error, std::generic_category());
252 }
253
254 std::error_code exists(const Twine &path, bool &result) {
255   SmallString<128> path_storage;
256   SmallVector<wchar_t, 128> path_utf16;
257
258   if (std::error_code ec =
259           UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))
260     return ec;
261
262   DWORD attributes = ::GetFileAttributesW(path_utf16.begin());
263
264   if (attributes == INVALID_FILE_ATTRIBUTES) {
265     // See if the file didn't actually exist.
266     DWORD LastError = ::GetLastError();
267     if (LastError != ERROR_FILE_NOT_FOUND &&
268         LastError != ERROR_PATH_NOT_FOUND)
269       return windows_error(LastError);
270     result = false;
271   } else
272     result = true;
273   return std::error_code();
274 }
275
276 bool can_write(const Twine &Path) {
277   // FIXME: take security attributes into account.
278   SmallString<128> PathStorage;
279   SmallVector<wchar_t, 128> PathUtf16;
280
281   if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
282     return false;
283
284   DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
285   return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY);
286 }
287
288 bool can_execute(const Twine &Path) {
289   SmallString<128> PathStorage;
290   SmallVector<wchar_t, 128> PathUtf16;
291
292   if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
293     return false;
294
295   DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
296   return Attr != INVALID_FILE_ATTRIBUTES;
297 }
298
299 bool equivalent(file_status A, file_status B) {
300   assert(status_known(A) && status_known(B));
301   return A.FileIndexHigh      == B.FileIndexHigh &&
302          A.FileIndexLow       == B.FileIndexLow &&
303          A.FileSizeHigh       == B.FileSizeHigh &&
304          A.FileSizeLow        == B.FileSizeLow &&
305          A.LastWriteTimeHigh  == B.LastWriteTimeHigh &&
306          A.LastWriteTimeLow   == B.LastWriteTimeLow &&
307          A.VolumeSerialNumber == B.VolumeSerialNumber;
308 }
309
310 std::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
311   file_status fsA, fsB;
312   if (std::error_code ec = status(A, fsA))
313     return ec;
314   if (std::error_code ec = status(B, fsB))
315     return ec;
316   result = equivalent(fsA, fsB);
317   return std::error_code();
318 }
319
320 static bool isReservedName(StringRef path) {
321   // This list of reserved names comes from MSDN, at:
322   // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
323   static const char *sReservedNames[] = { "nul", "con", "prn", "aux",
324                               "com1", "com2", "com3", "com4", "com5", "com6",
325                               "com7", "com8", "com9", "lpt1", "lpt2", "lpt3",
326                               "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" };
327
328   // First, check to see if this is a device namespace, which always
329   // starts with \\.\, since device namespaces are not legal file paths.
330   if (path.startswith("\\\\.\\"))
331     return true;
332
333   // Then compare against the list of ancient reserved names
334   for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) {
335     if (path.equals_lower(sReservedNames[i]))
336       return true;
337   }
338
339   // The path isn't what we consider reserved.
340   return false;
341 }
342
343 static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
344   if (FileHandle == INVALID_HANDLE_VALUE)
345     goto handle_status_error;
346
347   switch (::GetFileType(FileHandle)) {
348   default:
349     llvm_unreachable("Don't know anything about this file type");
350   case FILE_TYPE_UNKNOWN: {
351     DWORD Err = ::GetLastError();
352     if (Err != NO_ERROR)
353       return windows_error(Err);
354     Result = file_status(file_type::type_unknown);
355     return std::error_code();
356   }
357   case FILE_TYPE_DISK:
358     break;
359   case FILE_TYPE_CHAR:
360     Result = file_status(file_type::character_file);
361     return std::error_code();
362   case FILE_TYPE_PIPE:
363     Result = file_status(file_type::fifo_file);
364     return std::error_code();
365   }
366
367   BY_HANDLE_FILE_INFORMATION Info;
368   if (!::GetFileInformationByHandle(FileHandle, &Info))
369     goto handle_status_error;
370
371   {
372     file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
373                          ? file_type::directory_file
374                          : file_type::regular_file;
375     Result =
376         file_status(Type, Info.ftLastWriteTime.dwHighDateTime,
377                     Info.ftLastWriteTime.dwLowDateTime,
378                     Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
379                     Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
380     return std::error_code();
381   }
382
383 handle_status_error:
384   DWORD LastError = ::GetLastError();
385   if (LastError == ERROR_FILE_NOT_FOUND ||
386       LastError == ERROR_PATH_NOT_FOUND)
387     Result = file_status(file_type::file_not_found);
388   else if (LastError == ERROR_SHARING_VIOLATION)
389     Result = file_status(file_type::type_unknown);
390   else
391     Result = file_status(file_type::status_error);
392   return windows_error(LastError);
393 }
394
395 std::error_code status(const Twine &path, file_status &result) {
396   SmallString<128> path_storage;
397   SmallVector<wchar_t, 128> path_utf16;
398
399   StringRef path8 = path.toStringRef(path_storage);
400   if (isReservedName(path8)) {
401     result = file_status(file_type::character_file);
402     return std::error_code();
403   }
404
405   if (std::error_code ec = UTF8ToUTF16(path8, path_utf16))
406     return ec;
407
408   DWORD attr = ::GetFileAttributesW(path_utf16.begin());
409   if (attr == INVALID_FILE_ATTRIBUTES)
410     return getStatus(INVALID_HANDLE_VALUE, result);
411
412   // Handle reparse points.
413   if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
414     ScopedFileHandle h(
415       ::CreateFileW(path_utf16.begin(),
416                     0, // Attributes only.
417                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
418                     NULL,
419                     OPEN_EXISTING,
420                     FILE_FLAG_BACKUP_SEMANTICS,
421                     0));
422     if (!h)
423       return getStatus(INVALID_HANDLE_VALUE, result);
424   }
425
426   ScopedFileHandle h(
427       ::CreateFileW(path_utf16.begin(), 0, // Attributes only.
428                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
429                     NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
430     if (!h)
431       return getStatus(INVALID_HANDLE_VALUE, result);
432
433     return getStatus(h, result);
434 }
435
436 std::error_code status(int FD, file_status &Result) {
437   HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
438   return getStatus(FileHandle, Result);
439 }
440
441 std::error_code setLastModificationAndAccessTime(int FD, TimeValue Time) {
442   ULARGE_INTEGER UI;
443   UI.QuadPart = Time.toWin32Time();
444   FILETIME FT;
445   FT.dwLowDateTime = UI.LowPart;
446   FT.dwHighDateTime = UI.HighPart;
447   HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
448   if (!SetFileTime(FileHandle, NULL, &FT, &FT))
449     return windows_error(::GetLastError());
450   return std::error_code();
451 }
452
453 std::error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
454   FileDescriptor = FD;
455   // Make sure that the requested size fits within SIZE_T.
456   if (Size > std::numeric_limits<SIZE_T>::max()) {
457     if (FileDescriptor) {
458       if (CloseFD)
459         _close(FileDescriptor);
460     } else
461       ::CloseHandle(FileHandle);
462     return make_error_code(errc::invalid_argument);
463   }
464
465   DWORD flprotect;
466   switch (Mode) {
467   case readonly:  flprotect = PAGE_READONLY; break;
468   case readwrite: flprotect = PAGE_READWRITE; break;
469   case priv:      flprotect = PAGE_WRITECOPY; break;
470   }
471
472   FileMappingHandle =
473       ::CreateFileMappingW(FileHandle, 0, flprotect,
474                            (Offset + Size) >> 32,
475                            (Offset + Size) & 0xffffffff,
476                            0);
477   if (FileMappingHandle == NULL) {
478     std::error_code ec = windows_error(GetLastError());
479     if (FileDescriptor) {
480       if (CloseFD)
481         _close(FileDescriptor);
482     } else
483       ::CloseHandle(FileHandle);
484     return ec;
485   }
486
487   DWORD dwDesiredAccess;
488   switch (Mode) {
489   case readonly:  dwDesiredAccess = FILE_MAP_READ; break;
490   case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
491   case priv:      dwDesiredAccess = FILE_MAP_COPY; break;
492   }
493   Mapping = ::MapViewOfFile(FileMappingHandle,
494                             dwDesiredAccess,
495                             Offset >> 32,
496                             Offset & 0xffffffff,
497                             Size);
498   if (Mapping == NULL) {
499     std::error_code ec = windows_error(GetLastError());
500     ::CloseHandle(FileMappingHandle);
501     if (FileDescriptor) {
502       if (CloseFD)
503         _close(FileDescriptor);
504     } else
505       ::CloseHandle(FileHandle);
506     return ec;
507   }
508
509   if (Size == 0) {
510     MEMORY_BASIC_INFORMATION mbi;
511     SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
512     if (Result == 0) {
513       std::error_code ec = windows_error(GetLastError());
514       ::UnmapViewOfFile(Mapping);
515       ::CloseHandle(FileMappingHandle);
516       if (FileDescriptor) {
517         if (CloseFD)
518           _close(FileDescriptor);
519       } else
520         ::CloseHandle(FileHandle);
521       return ec;
522     }
523     Size = mbi.RegionSize;
524   }
525
526   // Close all the handles except for the view. It will keep the other handles
527   // alive.
528   ::CloseHandle(FileMappingHandle);
529   if (FileDescriptor) {
530     if (CloseFD)
531       _close(FileDescriptor); // Also closes FileHandle.
532   } else
533     ::CloseHandle(FileHandle);
534   return std::error_code();
535 }
536
537 mapped_file_region::mapped_file_region(const Twine &path,
538                                        mapmode mode,
539                                        uint64_t length,
540                                        uint64_t offset,
541                                        std::error_code &ec)
542   : Mode(mode)
543   , Size(length)
544   , Mapping()
545   , FileDescriptor()
546   , FileHandle(INVALID_HANDLE_VALUE)
547   , FileMappingHandle() {
548   SmallString<128> path_storage;
549   SmallVector<wchar_t, 128> path_utf16;
550
551   // Convert path to UTF-16.
552   if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)))
553     return;
554
555   // Get file handle for creating a file mapping.
556   FileHandle = ::CreateFileW(c_str(path_utf16),
557                              Mode == readonly ? GENERIC_READ
558                                               : GENERIC_READ | GENERIC_WRITE,
559                              Mode == readonly ? FILE_SHARE_READ
560                                               : 0,
561                              0,
562                              Mode == readonly ? OPEN_EXISTING
563                                               : OPEN_ALWAYS,
564                              Mode == readonly ? FILE_ATTRIBUTE_READONLY
565                                               : FILE_ATTRIBUTE_NORMAL,
566                              0);
567   if (FileHandle == INVALID_HANDLE_VALUE) {
568     ec = windows_error(::GetLastError());
569     return;
570   }
571
572   FileDescriptor = 0;
573   ec = init(FileDescriptor, true, offset);
574   if (ec) {
575     Mapping = FileMappingHandle = 0;
576     FileHandle = INVALID_HANDLE_VALUE;
577     FileDescriptor = 0;
578   }
579 }
580
581 mapped_file_region::mapped_file_region(int fd,
582                                        bool closefd,
583                                        mapmode mode,
584                                        uint64_t length,
585                                        uint64_t offset,
586                                        std::error_code &ec)
587   : Mode(mode)
588   , Size(length)
589   , Mapping()
590   , FileDescriptor(fd)
591   , FileHandle(INVALID_HANDLE_VALUE)
592   , FileMappingHandle() {
593   FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
594   if (FileHandle == INVALID_HANDLE_VALUE) {
595     if (closefd)
596       _close(FileDescriptor);
597     FileDescriptor = 0;
598     ec = make_error_code(errc::bad_file_descriptor);
599     return;
600   }
601
602   ec = init(FileDescriptor, closefd, offset);
603   if (ec) {
604     Mapping = FileMappingHandle = 0;
605     FileHandle = INVALID_HANDLE_VALUE;
606     FileDescriptor = 0;
607   }
608 }
609
610 mapped_file_region::~mapped_file_region() {
611   if (Mapping)
612     ::UnmapViewOfFile(Mapping);
613 }
614
615 mapped_file_region::mapped_file_region(mapped_file_region &&other)
616   : Mode(other.Mode)
617   , Size(other.Size)
618   , Mapping(other.Mapping)
619   , FileDescriptor(other.FileDescriptor)
620   , FileHandle(other.FileHandle)
621   , FileMappingHandle(other.FileMappingHandle) {
622   other.Mapping = other.FileMappingHandle = 0;
623   other.FileHandle = INVALID_HANDLE_VALUE;
624   other.FileDescriptor = 0;
625 }
626
627 mapped_file_region::mapmode mapped_file_region::flags() const {
628   assert(Mapping && "Mapping failed but used anyway!");
629   return Mode;
630 }
631
632 uint64_t mapped_file_region::size() const {
633   assert(Mapping && "Mapping failed but used anyway!");
634   return Size;
635 }
636
637 char *mapped_file_region::data() const {
638   assert(Mode != readonly && "Cannot get non-const data for readonly mapping!");
639   assert(Mapping && "Mapping failed but used anyway!");
640   return reinterpret_cast<char*>(Mapping);
641 }
642
643 const char *mapped_file_region::const_data() const {
644   assert(Mapping && "Mapping failed but used anyway!");
645   return reinterpret_cast<const char*>(Mapping);
646 }
647
648 int mapped_file_region::alignment() {
649   SYSTEM_INFO SysInfo;
650   ::GetSystemInfo(&SysInfo);
651   return SysInfo.dwAllocationGranularity;
652 }
653
654 std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
655                                                 StringRef path){
656   SmallVector<wchar_t, 128> path_utf16;
657
658   if (std::error_code ec = UTF8ToUTF16(path, path_utf16))
659     return ec;
660
661   // Convert path to the format that Windows is happy with.
662   if (path_utf16.size() > 0 &&
663       !is_separator(path_utf16[path.size() - 1]) &&
664       path_utf16[path.size() - 1] != L':') {
665     path_utf16.push_back(L'\\');
666     path_utf16.push_back(L'*');
667   } else {
668     path_utf16.push_back(L'*');
669   }
670
671   //  Get the first directory entry.
672   WIN32_FIND_DATAW FirstFind;
673   ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
674   if (!FindHandle)
675     return windows_error(::GetLastError());
676
677   size_t FilenameLen = ::wcslen(FirstFind.cFileName);
678   while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') ||
679          (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' &&
680                               FirstFind.cFileName[1] == L'.'))
681     if (!::FindNextFileW(FindHandle, &FirstFind)) {
682       DWORD LastError = ::GetLastError();
683       // Check for end.
684       if (LastError == ERROR_NO_MORE_FILES)
685         return detail::directory_iterator_destruct(it);
686       return windows_error(LastError);
687     } else
688       FilenameLen = ::wcslen(FirstFind.cFileName);
689
690   // Construct the current directory entry.
691   SmallString<128> directory_entry_name_utf8;
692   if (std::error_code ec =
693           UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName),
694                       directory_entry_name_utf8))
695     return ec;
696
697   it.IterationHandle = intptr_t(FindHandle.take());
698   SmallString<128> directory_entry_path(path);
699   path::append(directory_entry_path, directory_entry_name_utf8.str());
700   it.CurrentEntry = directory_entry(directory_entry_path.str());
701
702   return std::error_code();
703 }
704
705 std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
706   if (it.IterationHandle != 0)
707     // Closes the handle if it's valid.
708     ScopedFindHandle close(HANDLE(it.IterationHandle));
709   it.IterationHandle = 0;
710   it.CurrentEntry = directory_entry();
711   return std::error_code();
712 }
713
714 std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
715   WIN32_FIND_DATAW FindData;
716   if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
717     DWORD LastError = ::GetLastError();
718     // Check for end.
719     if (LastError == ERROR_NO_MORE_FILES)
720       return detail::directory_iterator_destruct(it);
721     return windows_error(LastError);
722   }
723
724   size_t FilenameLen = ::wcslen(FindData.cFileName);
725   if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
726       (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
727                            FindData.cFileName[1] == L'.'))
728     return directory_iterator_increment(it);
729
730   SmallString<128> directory_entry_path_utf8;
731   if (std::error_code ec =
732           UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName),
733                       directory_entry_path_utf8))
734     return ec;
735
736   it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
737   return std::error_code();
738 }
739
740 std::error_code openFileForRead(const Twine &Name, int &ResultFD) {
741   SmallString<128> PathStorage;
742   SmallVector<wchar_t, 128> PathUTF16;
743
744   if (std::error_code EC =
745           UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16))
746     return EC;
747
748   HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
749                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
750                            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
751   if (H == INVALID_HANDLE_VALUE) {
752     DWORD LastError = ::GetLastError();
753     std::error_code EC = windows_error(LastError);
754     // Provide a better error message when trying to open directories.
755     // This only runs if we failed to open the file, so there is probably
756     // no performances issues.
757     if (LastError != ERROR_ACCESS_DENIED)
758       return EC;
759     if (is_directory(Name))
760       return make_error_code(errc::is_a_directory);
761     return EC;
762   }
763
764   int FD = ::_open_osfhandle(intptr_t(H), 0);
765   if (FD == -1) {
766     ::CloseHandle(H);
767     return windows_error(ERROR_INVALID_HANDLE);
768   }
769
770   ResultFD = FD;
771   return std::error_code();
772 }
773
774 std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
775                             sys::fs::OpenFlags Flags, unsigned Mode) {
776   // Verify that we don't have both "append" and "excl".
777   assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
778          "Cannot specify both 'excl' and 'append' file creation flags!");
779
780   SmallString<128> PathStorage;
781   SmallVector<wchar_t, 128> PathUTF16;
782
783   if (std::error_code EC =
784           UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16))
785     return EC;
786
787   DWORD CreationDisposition;
788   if (Flags & F_Excl)
789     CreationDisposition = CREATE_NEW;
790   else if (Flags & F_Append)
791     CreationDisposition = OPEN_ALWAYS;
792   else
793     CreationDisposition = CREATE_ALWAYS;
794
795   DWORD Access = GENERIC_WRITE;
796   if (Flags & F_RW)
797     Access |= GENERIC_READ;
798
799   HANDLE H = ::CreateFileW(PathUTF16.begin(), Access,
800                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
801                            CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
802
803   if (H == INVALID_HANDLE_VALUE) {
804     DWORD LastError = ::GetLastError();
805     std::error_code EC = windows_error(LastError);
806     // Provide a better error message when trying to open directories.
807     // This only runs if we failed to open the file, so there is probably
808     // no performances issues.
809     if (LastError != ERROR_ACCESS_DENIED)
810       return EC;
811     if (is_directory(Name))
812       return make_error_code(errc::is_a_directory);
813     return EC;
814   }
815
816   int OpenFlags = 0;
817   if (Flags & F_Append)
818     OpenFlags |= _O_APPEND;
819
820   if (Flags & F_Text)
821     OpenFlags |= _O_TEXT;
822
823   int FD = ::_open_osfhandle(intptr_t(H), OpenFlags);
824   if (FD == -1) {
825     ::CloseHandle(H);
826     return windows_error(ERROR_INVALID_HANDLE);
827   }
828
829   ResultFD = FD;
830   return std::error_code();
831 }
832 } // end namespace fs
833
834 namespace path {
835
836 bool home_directory(SmallVectorImpl<char> &result) {
837   wchar_t Path[MAX_PATH];
838   if (::SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0,
839                          /*SHGFP_TYPE_CURRENT*/0, Path) != S_OK)
840     return false;
841
842   if (UTF16ToUTF8(Path, ::wcslen(Path), result))
843     return false;
844
845   return true;
846 }
847
848 static bool getTempDirEnvVar(const char *Var, SmallVectorImpl<char> &Res) {
849   SmallVector<wchar_t, 128> NameUTF16;
850   if (windows::UTF8ToUTF16(Var, NameUTF16))
851     return false;
852
853   SmallVector<wchar_t, 1024> Buf;
854   size_t Size = 1024;
855   do {
856     Buf.reserve(Size);
857     Size =
858         GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity());
859     if (Size == 0)
860       return false;
861
862     // Try again with larger buffer.
863   } while (Size > Buf.capacity());
864   Buf.set_size(Size);
865
866   if (windows::UTF16ToUTF8(Buf.data(), Size, Res))
867     return false;
868   return true;
869 }
870
871 static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) {
872   const char *EnvironmentVariables[] = {"TMP", "TEMP", "USERPROFILE"};
873   for (const char *Env : EnvironmentVariables) {
874     if (getTempDirEnvVar(Env, Res))
875       return true;
876   }
877   return false;
878 }
879
880 void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
881   (void)ErasedOnReboot;
882   Result.clear();
883
884   // Check whether the temporary directory is specified by an environment
885   // variable.
886   if (getTempDirEnvVar(Result))
887     return;
888
889   // Fall back to a system default.
890   const char *DefaultResult = "C:\\TEMP";
891   Result.append(DefaultResult, DefaultResult + strlen(DefaultResult));
892 }
893 } // end namespace path
894
895 namespace windows {
896 std::error_code UTF8ToUTF16(llvm::StringRef utf8,
897                             llvm::SmallVectorImpl<wchar_t> &utf16) {
898   if (!utf8.empty()) {
899     int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
900                                     utf8.size(), utf16.begin(), 0);
901
902     if (len == 0)
903       return windows_error(::GetLastError());
904
905     utf16.reserve(len + 1);
906     utf16.set_size(len);
907
908     len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
909                                 utf8.size(), utf16.begin(), utf16.size());
910
911     if (len == 0)
912       return windows_error(::GetLastError());
913   }
914
915   // Make utf16 null terminated.
916   utf16.push_back(0);
917   utf16.pop_back();
918
919   return std::error_code();
920 }
921
922 std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
923                             llvm::SmallVectorImpl<char> &utf8) {
924   if (utf16_len) {
925     // Get length.
926     int len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.begin(),
927                                     0, NULL, NULL);
928
929     if (len == 0)
930       return windows_error(::GetLastError());
931
932     utf8.reserve(len);
933     utf8.set_size(len);
934
935     // Now do the actual conversion.
936     len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.data(),
937                                 utf8.size(), NULL, NULL);
938
939     if (len == 0)
940       return windows_error(::GetLastError());
941   }
942
943   // Make utf8 null terminated.
944   utf8.push_back(0);
945   utf8.pop_back();
946
947   return std::error_code();
948 }
949 } // end namespace windows
950 } // end namespace sys
951 } // end namespace llvm