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