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