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