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