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