]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/lib/Support/Windows/PathV2.inc
MFC r244628:
[FreeBSD/stable/9.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, S_IREAD | 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   // Try to create + open the path.
597 retry_create_file:
598   HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(),
599                                         GENERIC_READ | GENERIC_WRITE,
600                                         FILE_SHARE_READ,
601                                         NULL,
602                                         // Return ERROR_FILE_EXISTS if the file
603                                         // already exists.
604                                         CREATE_NEW,
605                                         FILE_ATTRIBUTE_TEMPORARY,
606                                         NULL);
607   if (TempFileHandle == INVALID_HANDLE_VALUE) {
608     // If the file existed, try again, otherwise, error.
609     error_code ec = windows_error(::GetLastError());
610     if (ec == windows_error::file_exists)
611       goto retry_random_path;
612     // Check for non-existing parent directories.
613     if (ec == windows_error::path_not_found) {
614       // Create the directories using result_path as temp storage.
615       if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
616                                       random_path_utf16.size(), result_path))
617         return ec;
618       StringRef p(result_path.begin(), result_path.size());
619       SmallString<64> dir_to_create;
620       for (path::const_iterator i = path::begin(p),
621                                 e = --path::end(p); i != e; ++i) {
622         path::append(dir_to_create, *i);
623         bool Exists;
624         if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec;
625         if (!Exists) {
626           // If c: doesn't exist, bail.
627           if (i->endswith(":"))
628             return ec;
629
630           SmallVector<wchar_t, 64> dir_to_create_utf16;
631           if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16))
632             return ec;
633
634           // Create the directory.
635           if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL))
636             return windows_error(::GetLastError());
637         }
638       }
639       goto retry_create_file;
640     }
641     return ec;
642   }
643
644   // Set result_path to the utf-8 representation of the path.
645   if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(),
646                                   random_path_utf16.size(), result_path)) {
647     ::CloseHandle(TempFileHandle);
648     ::DeleteFileW(random_path_utf16.begin());
649     return ec;
650   }
651
652   // Convert the Windows API file handle into a C-runtime handle.
653   int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0);
654   if (fd == -1) {
655     ::CloseHandle(TempFileHandle);
656     ::DeleteFileW(random_path_utf16.begin());
657     // MSDN doesn't say anything about _open_osfhandle setting errno or
658     // GetLastError(), so just return invalid_handle.
659     return windows_error::invalid_handle;
660   }
661
662   result_fd = fd;
663   return error_code::success();
664 }
665
666 error_code get_magic(const Twine &path, uint32_t len,
667                      SmallVectorImpl<char> &result) {
668   SmallString<128> path_storage;
669   SmallVector<wchar_t, 128> path_utf16;
670   result.set_size(0);
671
672   // Convert path to UTF-16.
673   if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage),
674                                   path_utf16))
675     return ec;
676
677   // Open file.
678   HANDLE file = ::CreateFileW(c_str(path_utf16),
679                               GENERIC_READ,
680                               FILE_SHARE_READ,
681                               NULL,
682                               OPEN_EXISTING,
683                               FILE_ATTRIBUTE_READONLY,
684                               NULL);
685   if (file == INVALID_HANDLE_VALUE)
686     return windows_error(::GetLastError());
687
688   // Allocate buffer.
689   result.reserve(len);
690
691   // Get magic!
692   DWORD bytes_read = 0;
693   BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL);
694   error_code ec = windows_error(::GetLastError());
695   ::CloseHandle(file);
696   if (!read_success || (bytes_read != len)) {
697     // Set result size to the number of bytes read if it's valid.
698     if (bytes_read <= len)
699       result.set_size(bytes_read);
700     // ERROR_HANDLE_EOF is mapped to errc::value_too_large.
701     return ec;
702   }
703
704   result.set_size(len);
705   return error_code::success();
706 }
707
708 error_code mapped_file_region::init(int FD, uint64_t Offset) {
709   FileDescriptor = FD;
710   // Make sure that the requested size fits within SIZE_T.
711   if (Size > std::numeric_limits<SIZE_T>::max()) {
712     if (FileDescriptor)
713       _close(FileDescriptor);
714     else
715       ::CloseHandle(FileHandle);
716     return make_error_code(errc::invalid_argument);
717   }
718
719   DWORD flprotect;
720   switch (Mode) {
721   case readonly:  flprotect = PAGE_READONLY; break;
722   case readwrite: flprotect = PAGE_READWRITE; break;
723   case priv:      flprotect = PAGE_WRITECOPY; break;
724   default: llvm_unreachable("invalid mapping mode");
725   }
726
727   FileMappingHandle = ::CreateFileMapping(FileHandle,
728                                           0,
729                                           flprotect,
730                                           Size >> 32,
731                                           Size & 0xffffffff,
732                                           0);
733   if (FileMappingHandle == NULL) {
734     error_code ec = windows_error(GetLastError());
735     if (FileDescriptor)
736       _close(FileDescriptor);
737     else
738       ::CloseHandle(FileHandle);
739     return ec;
740   }
741
742   DWORD dwDesiredAccess;
743   switch (Mode) {
744   case readonly:  dwDesiredAccess = FILE_MAP_READ; break;
745   case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
746   case priv:      dwDesiredAccess = FILE_MAP_COPY; break;
747   default: llvm_unreachable("invalid mapping mode");
748   }
749   Mapping = ::MapViewOfFile(FileMappingHandle,
750                             dwDesiredAccess,
751                             Offset >> 32,
752                             Offset & 0xffffffff,
753                             Size);
754   if (Mapping == NULL) {
755     error_code ec = windows_error(GetLastError());
756     ::CloseHandle(FileMappingHandle);
757     if (FileDescriptor)
758       _close(FileDescriptor);
759     else
760       ::CloseHandle(FileHandle);
761     return ec;
762   }
763
764   if (Size == 0) {
765     MEMORY_BASIC_INFORMATION mbi;
766     SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
767     if (Result == 0) {
768       error_code ec = windows_error(GetLastError());
769       ::UnmapViewOfFile(Mapping);
770       ::CloseHandle(FileMappingHandle);
771       if (FileDescriptor)
772         _close(FileDescriptor);
773       else
774         ::CloseHandle(FileHandle);
775       return ec;
776     }
777     Size = mbi.RegionSize;
778   }
779   return error_code::success();
780 }
781
782 mapped_file_region::mapped_file_region(const Twine &path,
783                                        mapmode mode,
784                                        uint64_t length,
785                                        uint64_t offset,
786                                        error_code &ec) 
787   : Mode(mode)
788   , Size(length)
789   , Mapping()
790   , FileDescriptor()
791   , FileHandle(INVALID_HANDLE_VALUE)
792   , FileMappingHandle() {
793   SmallString<128> path_storage;
794   SmallVector<wchar_t, 128> path_utf16;
795
796   // Convert path to UTF-16.
797   if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)))
798     return;
799
800   // Get file handle for creating a file mapping.
801   FileHandle = ::CreateFileW(c_str(path_utf16),
802                              Mode == readonly ? GENERIC_READ
803                                               : GENERIC_READ | GENERIC_WRITE,
804                              Mode == readonly ? FILE_SHARE_READ
805                                               : 0,
806                              0,
807                              Mode == readonly ? OPEN_EXISTING
808                                               : OPEN_ALWAYS,
809                              Mode == readonly ? FILE_ATTRIBUTE_READONLY
810                                               : FILE_ATTRIBUTE_NORMAL,
811                              0);
812   if (FileHandle == INVALID_HANDLE_VALUE) {
813     ec = windows_error(::GetLastError());
814     return;
815   }
816
817   FileDescriptor = 0;
818   ec = init(FileDescriptor, offset);
819   if (ec) {
820     Mapping = FileMappingHandle = 0;
821     FileHandle = INVALID_HANDLE_VALUE;
822     FileDescriptor = 0;
823   }
824 }
825
826 mapped_file_region::mapped_file_region(int fd,
827                                        mapmode mode,
828                                        uint64_t length,
829                                        uint64_t offset,
830                                        error_code &ec)
831   : Mode(mode)
832   , Size(length)
833   , Mapping()
834   , FileDescriptor(fd)
835   , FileHandle(INVALID_HANDLE_VALUE)
836   , FileMappingHandle() {
837   FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
838   if (FileHandle == INVALID_HANDLE_VALUE) {
839     _close(FileDescriptor);
840     FileDescriptor = 0;
841     ec = make_error_code(errc::bad_file_descriptor);
842     return;
843   }
844
845   ec = init(FileDescriptor, offset);
846   if (ec) {
847     Mapping = FileMappingHandle = 0;
848     FileHandle = INVALID_HANDLE_VALUE;
849     FileDescriptor = 0;
850   }
851 }
852
853 mapped_file_region::~mapped_file_region() {
854   if (Mapping)
855     ::UnmapViewOfFile(Mapping);
856   if (FileMappingHandle)
857     ::CloseHandle(FileMappingHandle);
858   if (FileDescriptor)
859     _close(FileDescriptor);
860   else if (FileHandle != INVALID_HANDLE_VALUE)
861     ::CloseHandle(FileHandle);
862 }
863
864 #if LLVM_USE_RVALUE_REFERENCES
865 mapped_file_region::mapped_file_region(mapped_file_region &&other)
866   : Mode(other.Mode)
867   , Size(other.Size)
868   , Mapping(other.Mapping)
869   , FileDescriptor(other.FileDescriptor)
870   , FileHandle(other.FileHandle)
871   , FileMappingHandle(other.FileMappingHandle) {
872   other.Mapping = other.FileMappingHandle = 0;
873   other.FileHandle = INVALID_HANDLE_VALUE;
874   other.FileDescriptor = 0;
875 }
876 #endif
877
878 mapped_file_region::mapmode mapped_file_region::flags() const {
879   assert(Mapping && "Mapping failed but used anyway!");
880   return Mode;
881 }
882
883 uint64_t mapped_file_region::size() const {
884   assert(Mapping && "Mapping failed but used anyway!");
885   return Size;
886 }
887
888 char *mapped_file_region::data() const {
889   assert(Mode != readonly && "Cannot get non const data for readonly mapping!");
890   assert(Mapping && "Mapping failed but used anyway!");
891   return reinterpret_cast<char*>(Mapping);
892 }
893
894 const char *mapped_file_region::const_data() const {
895   assert(Mapping && "Mapping failed but used anyway!");
896   return reinterpret_cast<const char*>(Mapping);
897 }
898
899 int mapped_file_region::alignment() {
900   SYSTEM_INFO SysInfo;
901   ::GetSystemInfo(&SysInfo);
902   return SysInfo.dwAllocationGranularity;
903 }
904
905 error_code detail::directory_iterator_construct(detail::DirIterState &it,
906                                                 StringRef path){
907   SmallVector<wchar_t, 128> path_utf16;
908
909   if (error_code ec = UTF8ToUTF16(path,
910                                   path_utf16))
911     return ec;
912
913   // Convert path to the format that Windows is happy with.
914   if (path_utf16.size() > 0 &&
915       !is_separator(path_utf16[path.size() - 1]) &&
916       path_utf16[path.size() - 1] != L':') {
917     path_utf16.push_back(L'\\');
918     path_utf16.push_back(L'*');
919   } else {
920     path_utf16.push_back(L'*');
921   }
922
923   //  Get the first directory entry.
924   WIN32_FIND_DATAW FirstFind;
925   ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
926   if (!FindHandle)
927     return windows_error(::GetLastError());
928
929   size_t FilenameLen = ::wcslen(FirstFind.cFileName);
930   while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') ||
931          (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' &&
932                               FirstFind.cFileName[1] == L'.'))
933     if (!::FindNextFileW(FindHandle, &FirstFind)) {
934       error_code ec = windows_error(::GetLastError());
935       // Check for end.
936       if (ec == windows_error::no_more_files)
937         return detail::directory_iterator_destruct(it);
938       return ec;
939     } else
940       FilenameLen = ::wcslen(FirstFind.cFileName);
941
942   // Construct the current directory entry.
943   SmallString<128> directory_entry_name_utf8;
944   if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
945                                   ::wcslen(FirstFind.cFileName),
946                                   directory_entry_name_utf8))
947     return ec;
948
949   it.IterationHandle = intptr_t(FindHandle.take());
950   SmallString<128> directory_entry_path(path);
951   path::append(directory_entry_path, directory_entry_name_utf8.str());
952   it.CurrentEntry = directory_entry(directory_entry_path.str());
953
954   return error_code::success();
955 }
956
957 error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
958   if (it.IterationHandle != 0)
959     // Closes the handle if it's valid.
960     ScopedFindHandle close(HANDLE(it.IterationHandle));
961   it.IterationHandle = 0;
962   it.CurrentEntry = directory_entry();
963   return error_code::success();
964 }
965
966 error_code detail::directory_iterator_increment(detail::DirIterState &it) {
967   WIN32_FIND_DATAW FindData;
968   if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
969     error_code ec = windows_error(::GetLastError());
970     // Check for end.
971     if (ec == windows_error::no_more_files)
972       return detail::directory_iterator_destruct(it);
973     return ec;
974   }
975
976   size_t FilenameLen = ::wcslen(FindData.cFileName);
977   if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
978       (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
979                            FindData.cFileName[1] == L'.'))
980     return directory_iterator_increment(it);
981
982   SmallString<128> directory_entry_path_utf8;
983   if (error_code ec = UTF16ToUTF8(FindData.cFileName,
984                                   ::wcslen(FindData.cFileName),
985                                   directory_entry_path_utf8))
986     return ec;
987
988   it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
989   return error_code::success();
990 }
991
992 error_code map_file_pages(const Twine &path, off_t file_offset, size_t size,  
993                                             bool map_writable, void *&result) {
994   assert(0 && "NOT IMPLEMENTED");
995   return windows_error::invalid_function;
996 }
997
998 error_code unmap_file_pages(void *base, size_t size) {
999   assert(0 && "NOT IMPLEMENTED");
1000   return windows_error::invalid_function;
1001 }
1002
1003
1004
1005 } // end namespace fs
1006 } // end namespace sys
1007 } // end namespace llvm