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