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