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