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