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