We now always create files with the correct permissions. Simplify the interface.
[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 file_size(const Twine &path, uint64_t &result) {
559   SmallString<128> path_storage;
560   SmallVector<wchar_t, 128> path_utf16;
561
562   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
563                                   path_utf16))
564     return ec;
565
566   WIN32_FILE_ATTRIBUTE_DATA FileData;
567   if (!::GetFileAttributesExW(path_utf16.begin(),
568                               ::GetFileExInfoStandard,
569                               &FileData))
570     return windows_error(::GetLastError());
571
572   result =
573     (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8))
574     + FileData.nFileSizeLow;
575
576   return error_code::success();
577 }
578
579 error_code getUniqueID(const Twine Path, uint64_t &Result) {
580   file_status Status;
581   if (error_code E = status(Path, Status))
582     return E;
583
584   // The file is uniquely identified by the volume serial number along
585   // with the 64-bit file identifier.
586   Result = (static_cast<uint64_t>(Status.FileIndexHigh) << 32ULL) |
587            static_cast<uint64_t>(Status.FileIndexLow);
588   
589   // Because the serial number is 32-bits, but we've already used up all 64
590   // bits for the file index, XOR the serial number into the high 32 bits of
591   // the resulting value.  We could potentially get collisons from this, but
592   // the likelihood is low.
593   Result ^= (static_cast<uint64_t>(Status.VolumeSerialNumber) << 32ULL);
594
595   return error_code::success();
596 }
597
598 static bool isReservedName(StringRef path) {
599   // This list of reserved names comes from MSDN, at:
600   // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
601   static const char *sReservedNames[] = { "nul", "con", "prn", "aux",
602                               "com1", "com2", "com3", "com4", "com5", "com6",
603                               "com7", "com8", "com9", "lpt1", "lpt2", "lpt3",
604                               "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" };
605
606   // First, check to see if this is a device namespace, which always
607   // starts with \\.\, since device namespaces are not legal file paths.
608   if (path.startswith("\\\\.\\"))
609     return true;
610
611   // Then compare against the list of ancient reserved names
612   for (size_t i = 0; i < sizeof(sReservedNames) / sizeof(const char *); ++i) {
613     if (path.equals_lower(sReservedNames[i]))
614       return true;
615   }
616
617   // The path isn't what we consider reserved.
618   return false;
619 }
620
621 error_code status(const Twine &path, file_status &result) {
622   SmallString<128> path_storage;
623   SmallVector<wchar_t, 128> path_utf16;
624
625   StringRef path8 = path.toStringRef(path_storage);
626   if (isReservedName(path8)) {
627     result = file_status(file_type::character_file);
628     return error_code::success();
629   }
630
631   if (error_code ec = UTF8ToUTF16(path8, path_utf16))
632     return ec;
633
634   DWORD attr = ::GetFileAttributesW(path_utf16.begin());
635   if (attr == INVALID_FILE_ATTRIBUTES)
636     goto handle_status_error;
637
638   // Handle reparse points.
639   if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
640     ScopedFileHandle h(
641       ::CreateFileW(path_utf16.begin(),
642                     0, // Attributes only.
643                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
644                     NULL,
645                     OPEN_EXISTING,
646                     FILE_FLAG_BACKUP_SEMANTICS,
647                     0));
648     if (!h)
649       goto handle_status_error;
650   }
651
652   if (attr & FILE_ATTRIBUTE_DIRECTORY)
653     result = file_status(file_type::directory_file);
654   else {
655     result = file_status(file_type::regular_file);
656     ScopedFileHandle h(
657       ::CreateFileW(path_utf16.begin(),
658                     0, // Attributes only.
659                     FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
660                     NULL,
661                     OPEN_EXISTING,
662                     FILE_FLAG_BACKUP_SEMANTICS,
663                     0));
664     if (!h)
665       goto handle_status_error;
666     BY_HANDLE_FILE_INFORMATION Info;
667     if (!::GetFileInformationByHandle(h, &Info))
668       goto handle_status_error;
669     result.FileIndexHigh      = Info.nFileIndexHigh;
670     result.FileIndexLow       = Info.nFileIndexLow;
671     result.FileSizeHigh       = Info.nFileSizeHigh;
672     result.FileSizeLow        = Info.nFileSizeLow;
673     result.LastWriteTimeHigh  = Info.ftLastWriteTime.dwHighDateTime;
674     result.LastWriteTimeLow   = Info.ftLastWriteTime.dwLowDateTime;
675     result.VolumeSerialNumber = Info.dwVolumeSerialNumber;
676   }
677
678   return error_code::success();
679
680 handle_status_error:
681   error_code ec = windows_error(::GetLastError());
682   if (ec == windows_error::file_not_found ||
683       ec == windows_error::path_not_found)
684     result = file_status(file_type::file_not_found);
685   else if (ec == windows_error::sharing_violation)
686     result = file_status(file_type::type_unknown);
687   else {
688     result = file_status(file_type::status_error);
689     return ec;
690   }
691
692   return error_code::success();
693 }
694
695 error_code setLastModificationAndAccessTime(int FD, TimeValue Time) {
696   ULARGE_INTEGER UI;
697   UI.QuadPart = Time.toWin32Time();
698   FILETIME FT;
699   FT.dwLowDateTime = UI.LowPart;
700   FT.dwHighDateTime = UI.HighPart;
701   HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
702   if (!SetFileTime(FileHandle, NULL, &FT, &FT))
703     return windows_error(::GetLastError());
704   return error_code::success();
705 }
706
707 error_code get_magic(const Twine &path, uint32_t len,
708                      SmallVectorImpl<char> &result) {
709   SmallString<128> path_storage;
710   SmallVector<wchar_t, 128> path_utf16;
711   result.set_size(0);
712
713   // Convert path to UTF-16.
714   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
715                                   path_utf16))
716     return ec;
717
718   // Open file.
719   HANDLE file = ::CreateFileW(c_str(path_utf16),
720                               GENERIC_READ,
721                               FILE_SHARE_READ,
722                               NULL,
723                               OPEN_EXISTING,
724                               FILE_ATTRIBUTE_READONLY,
725                               NULL);
726   if (file == INVALID_HANDLE_VALUE)
727     return windows_error(::GetLastError());
728
729   // Allocate buffer.
730   result.reserve(len);
731
732   // Get magic!
733   DWORD bytes_read = 0;
734   BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL);
735   error_code ec = windows_error(::GetLastError());
736   ::CloseHandle(file);
737   if (!read_success || (bytes_read != len)) {
738     // Set result size to the number of bytes read if it's valid.
739     if (bytes_read <= len)
740       result.set_size(bytes_read);
741     // ERROR_HANDLE_EOF is mapped to errc::value_too_large.
742     return ec;
743   }
744
745   result.set_size(len);
746   return error_code::success();
747 }
748
749 error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) {
750   FileDescriptor = FD;
751   // Make sure that the requested size fits within SIZE_T.
752   if (Size > std::numeric_limits<SIZE_T>::max()) {
753     if (FileDescriptor) {
754       if (CloseFD)
755         _close(FileDescriptor);
756     } else
757       ::CloseHandle(FileHandle);
758     return make_error_code(errc::invalid_argument);
759   }
760
761   DWORD flprotect;
762   switch (Mode) {
763   case readonly:  flprotect = PAGE_READONLY; break;
764   case readwrite: flprotect = PAGE_READWRITE; break;
765   case priv:      flprotect = PAGE_WRITECOPY; break;
766   default: llvm_unreachable("invalid mapping mode");
767   }
768
769   FileMappingHandle = ::CreateFileMapping(FileHandle,
770                                           0,
771                                           flprotect,
772                                           Size >> 32,
773                                           Size & 0xffffffff,
774                                           0);
775   if (FileMappingHandle == NULL) {
776     error_code ec = windows_error(GetLastError());
777     if (FileDescriptor) {
778       if (CloseFD)
779         _close(FileDescriptor);
780     } else
781       ::CloseHandle(FileHandle);
782     return ec;
783   }
784
785   DWORD dwDesiredAccess;
786   switch (Mode) {
787   case readonly:  dwDesiredAccess = FILE_MAP_READ; break;
788   case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
789   case priv:      dwDesiredAccess = FILE_MAP_COPY; break;
790   default: llvm_unreachable("invalid mapping mode");
791   }
792   Mapping = ::MapViewOfFile(FileMappingHandle,
793                             dwDesiredAccess,
794                             Offset >> 32,
795                             Offset & 0xffffffff,
796                             Size);
797   if (Mapping == NULL) {
798     error_code ec = windows_error(GetLastError());
799     ::CloseHandle(FileMappingHandle);
800     if (FileDescriptor) {
801       if (CloseFD)
802         _close(FileDescriptor);
803     } else
804       ::CloseHandle(FileHandle);
805     return ec;
806   }
807
808   if (Size == 0) {
809     MEMORY_BASIC_INFORMATION mbi;
810     SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
811     if (Result == 0) {
812       error_code ec = windows_error(GetLastError());
813       ::UnmapViewOfFile(Mapping);
814       ::CloseHandle(FileMappingHandle);
815       if (FileDescriptor) {
816         if (CloseFD)
817           _close(FileDescriptor);
818       } else
819         ::CloseHandle(FileHandle);
820       return ec;
821     }
822     Size = mbi.RegionSize;
823   }
824
825   // Close all the handles except for the view. It will keep the other handles
826   // alive.
827   ::CloseHandle(FileMappingHandle);
828   if (FileDescriptor) {
829     if (CloseFD)
830       _close(FileDescriptor); // Also closes FileHandle.
831   } else
832     ::CloseHandle(FileHandle);
833   return error_code::success();
834 }
835
836 mapped_file_region::mapped_file_region(const Twine &path,
837                                        mapmode mode,
838                                        uint64_t length,
839                                        uint64_t offset,
840                                        error_code &ec) 
841   : Mode(mode)
842   , Size(length)
843   , Mapping()
844   , FileDescriptor()
845   , FileHandle(INVALID_HANDLE_VALUE)
846   , FileMappingHandle() {
847   SmallString<128> path_storage;
848   SmallVector<wchar_t, 128> path_utf16;
849
850   // Convert path to UTF-16.
851   if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)))
852     return;
853
854   // Get file handle for creating a file mapping.
855   FileHandle = ::CreateFileW(c_str(path_utf16),
856                              Mode == readonly ? GENERIC_READ
857                                               : GENERIC_READ | GENERIC_WRITE,
858                              Mode == readonly ? FILE_SHARE_READ
859                                               : 0,
860                              0,
861                              Mode == readonly ? OPEN_EXISTING
862                                               : OPEN_ALWAYS,
863                              Mode == readonly ? FILE_ATTRIBUTE_READONLY
864                                               : FILE_ATTRIBUTE_NORMAL,
865                              0);
866   if (FileHandle == INVALID_HANDLE_VALUE) {
867     ec = windows_error(::GetLastError());
868     return;
869   }
870
871   FileDescriptor = 0;
872   ec = init(FileDescriptor, true, offset);
873   if (ec) {
874     Mapping = FileMappingHandle = 0;
875     FileHandle = INVALID_HANDLE_VALUE;
876     FileDescriptor = 0;
877   }
878 }
879
880 mapped_file_region::mapped_file_region(int fd,
881                                        bool closefd,
882                                        mapmode mode,
883                                        uint64_t length,
884                                        uint64_t offset,
885                                        error_code &ec)
886   : Mode(mode)
887   , Size(length)
888   , Mapping()
889   , FileDescriptor(fd)
890   , FileHandle(INVALID_HANDLE_VALUE)
891   , FileMappingHandle() {
892   FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
893   if (FileHandle == INVALID_HANDLE_VALUE) {
894     if (closefd)
895       _close(FileDescriptor);
896     FileDescriptor = 0;
897     ec = make_error_code(errc::bad_file_descriptor);
898     return;
899   }
900
901   ec = init(FileDescriptor, closefd, offset);
902   if (ec) {
903     Mapping = FileMappingHandle = 0;
904     FileHandle = INVALID_HANDLE_VALUE;
905     FileDescriptor = 0;
906   }
907 }
908
909 mapped_file_region::~mapped_file_region() {
910   if (Mapping)
911     ::UnmapViewOfFile(Mapping);
912 }
913
914 #if LLVM_HAS_RVALUE_REFERENCES
915 mapped_file_region::mapped_file_region(mapped_file_region &&other)
916   : Mode(other.Mode)
917   , Size(other.Size)
918   , Mapping(other.Mapping)
919   , FileDescriptor(other.FileDescriptor)
920   , FileHandle(other.FileHandle)
921   , FileMappingHandle(other.FileMappingHandle) {
922   other.Mapping = other.FileMappingHandle = 0;
923   other.FileHandle = INVALID_HANDLE_VALUE;
924   other.FileDescriptor = 0;
925 }
926 #endif
927
928 mapped_file_region::mapmode mapped_file_region::flags() const {
929   assert(Mapping && "Mapping failed but used anyway!");
930   return Mode;
931 }
932
933 uint64_t mapped_file_region::size() const {
934   assert(Mapping && "Mapping failed but used anyway!");
935   return Size;
936 }
937
938 char *mapped_file_region::data() const {
939   assert(Mode != readonly && "Cannot get non const data for readonly mapping!");
940   assert(Mapping && "Mapping failed but used anyway!");
941   return reinterpret_cast<char*>(Mapping);
942 }
943
944 const char *mapped_file_region::const_data() const {
945   assert(Mapping && "Mapping failed but used anyway!");
946   return reinterpret_cast<const char*>(Mapping);
947 }
948
949 int mapped_file_region::alignment() {
950   SYSTEM_INFO SysInfo;
951   ::GetSystemInfo(&SysInfo);
952   return SysInfo.dwAllocationGranularity;
953 }
954
955 error_code detail::directory_iterator_construct(detail::DirIterState &it,
956                                                 StringRef path){
957   SmallVector<wchar_t, 128> path_utf16;
958
959   if (error_code ec = UTF8ToUTF16(path,
960                                   path_utf16))
961     return ec;
962
963   // Convert path to the format that Windows is happy with.
964   if (path_utf16.size() > 0 &&
965       !is_separator(path_utf16[path.size() - 1]) &&
966       path_utf16[path.size() - 1] != L':') {
967     path_utf16.push_back(L'\\');
968     path_utf16.push_back(L'*');
969   } else {
970     path_utf16.push_back(L'*');
971   }
972
973   //  Get the first directory entry.
974   WIN32_FIND_DATAW FirstFind;
975   ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
976   if (!FindHandle)
977     return windows_error(::GetLastError());
978
979   size_t FilenameLen = ::wcslen(FirstFind.cFileName);
980   while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') ||
981          (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' &&
982                               FirstFind.cFileName[1] == L'.'))
983     if (!::FindNextFileW(FindHandle, &FirstFind)) {
984       error_code ec = windows_error(::GetLastError());
985       // Check for end.
986       if (ec == windows_error::no_more_files)
987         return detail::directory_iterator_destruct(it);
988       return ec;
989     } else
990       FilenameLen = ::wcslen(FirstFind.cFileName);
991
992   // Construct the current directory entry.
993   SmallString<128> directory_entry_name_utf8;
994   if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
995                                   ::wcslen(FirstFind.cFileName),
996                                   directory_entry_name_utf8))
997     return ec;
998
999   it.IterationHandle = intptr_t(FindHandle.take());
1000   SmallString<128> directory_entry_path(path);
1001   path::append(directory_entry_path, directory_entry_name_utf8.str());
1002   it.CurrentEntry = directory_entry(directory_entry_path.str());
1003
1004   return error_code::success();
1005 }
1006
1007 error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
1008   if (it.IterationHandle != 0)
1009     // Closes the handle if it's valid.
1010     ScopedFindHandle close(HANDLE(it.IterationHandle));
1011   it.IterationHandle = 0;
1012   it.CurrentEntry = directory_entry();
1013   return error_code::success();
1014 }
1015
1016 error_code detail::directory_iterator_increment(detail::DirIterState &it) {
1017   WIN32_FIND_DATAW FindData;
1018   if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
1019     error_code ec = windows_error(::GetLastError());
1020     // Check for end.
1021     if (ec == windows_error::no_more_files)
1022       return detail::directory_iterator_destruct(it);
1023     return ec;
1024   }
1025
1026   size_t FilenameLen = ::wcslen(FindData.cFileName);
1027   if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
1028       (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
1029                            FindData.cFileName[1] == L'.'))
1030     return directory_iterator_increment(it);
1031
1032   SmallString<128> directory_entry_path_utf8;
1033   if (error_code ec = UTF16ToUTF8(FindData.cFileName,
1034                                   ::wcslen(FindData.cFileName),
1035                                   directory_entry_path_utf8))
1036     return ec;
1037
1038   it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
1039   return error_code::success();
1040 }
1041
1042 error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,  
1043                                             bool map_writable, void *&result) {
1044   assert(0 && "NOT IMPLEMENTED");
1045   return windows_error::invalid_function;
1046 }
1047
1048 error_code unmap_file_pages(void *base, size_t size) {
1049   assert(0 && "NOT IMPLEMENTED");
1050   return windows_error::invalid_function;
1051 }
1052
1053
1054
1055 } // end namespace fs
1056 } // end namespace sys
1057 } // end namespace llvm