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