Path.inc revision 321369
1261991Sdim//===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10261991Sdim// This file implements the Windows specific implementation of the Path API.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim//===----------------------------------------------------------------------===//
15261991Sdim//=== WARNING: Implementation here must contain only generic Windows code that
16261991Sdim//===          is guaranteed to work on *all* Windows variants.
17218885Sdim//===----------------------------------------------------------------------===//
18218885Sdim
19261991Sdim#include "llvm/ADT/STLExtras.h"
20276479Sdim#include "llvm/Support/WindowsError.h"
21261991Sdim#include <fcntl.h>
22261991Sdim#include <io.h>
23261991Sdim#include <sys/stat.h>
24261991Sdim#include <sys/types.h>
25218885Sdim
26276479Sdim// These two headers must be included last, and make sure shlobj is required
27276479Sdim// after Windows.h to make sure it picks up our definition of _WIN32_WINNT
28276479Sdim#include "WindowsSupport.h"
29321369Sdim#include <shellapi.h>
30276479Sdim#include <shlobj.h>
31276479Sdim
32261991Sdim#undef max
33218885Sdim
34261991Sdim// MinGW doesn't define this.
35261991Sdim#ifndef _ERRNO_T_DEFINED
36261991Sdim#define _ERRNO_T_DEFINED
37261991Sdimtypedef int errno_t;
38261991Sdim#endif
39218885Sdim
40261991Sdim#ifdef _MSC_VER
41261991Sdim# pragma comment(lib, "advapi32.lib")  // This provides CryptAcquireContextW.
42296417Sdim# pragma comment(lib, "ole32.lib")     // This provides CoTaskMemFree
43261991Sdim#endif
44218885Sdim
45261991Sdimusing namespace llvm;
46218885Sdim
47261991Sdimusing llvm::sys::windows::UTF8ToUTF16;
48261991Sdimusing llvm::sys::windows::UTF16ToUTF8;
49280031Sdimusing llvm::sys::path::widenPath;
50218885Sdim
51276479Sdimstatic bool is_separator(const wchar_t value) {
52276479Sdim  switch (value) {
53276479Sdim  case L'\\':
54276479Sdim  case L'/':
55276479Sdim    return true;
56276479Sdim  default:
57276479Sdim    return false;
58218885Sdim  }
59218885Sdim}
60218885Sdim
61261991Sdimnamespace llvm {
62261991Sdimnamespace sys  {
63280031Sdimnamespace path {
64280031Sdim
65280031Sdim// Convert a UTF-8 path to UTF-16.  Also, if the absolute equivalent of the
66280031Sdim// path is longer than CreateDirectory can tolerate, make it absolute and
67280031Sdim// prefixed by '\\?\'.
68280031Sdimstd::error_code widenPath(const Twine &Path8,
69280031Sdim                          SmallVectorImpl<wchar_t> &Path16) {
70280031Sdim  const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename.
71280031Sdim
72280031Sdim  // Several operations would convert Path8 to SmallString; more efficient to
73280031Sdim  // do it once up front.
74280031Sdim  SmallString<128> Path8Str;
75280031Sdim  Path8.toVector(Path8Str);
76280031Sdim
77280031Sdim  // If we made this path absolute, how much longer would it get?
78280031Sdim  size_t CurPathLen;
79280031Sdim  if (llvm::sys::path::is_absolute(Twine(Path8Str)))
80280031Sdim    CurPathLen = 0; // No contribution from current_path needed.
81280031Sdim  else {
82280031Sdim    CurPathLen = ::GetCurrentDirectoryW(0, NULL);
83280031Sdim    if (CurPathLen == 0)
84288943Sdim      return mapWindowsError(::GetLastError());
85280031Sdim  }
86280031Sdim
87280031Sdim  // Would the absolute path be longer than our limit?
88280031Sdim  if ((Path8Str.size() + CurPathLen) >= MaxDirLen &&
89280031Sdim      !Path8Str.startswith("\\\\?\\")) {
90280031Sdim    SmallString<2*MAX_PATH> FullPath("\\\\?\\");
91280031Sdim    if (CurPathLen) {
92280031Sdim      SmallString<80> CurPath;
93280031Sdim      if (std::error_code EC = llvm::sys::fs::current_path(CurPath))
94280031Sdim        return EC;
95280031Sdim      FullPath.append(CurPath);
96280031Sdim    }
97280031Sdim    // Traverse the requested path, canonicalizing . and .. as we go (because
98280031Sdim    // the \\?\ prefix is documented to treat them as real components).
99280031Sdim    // The iterators don't report separators and append() always attaches
100280031Sdim    // preferred_separator so we don't need to call native() on the result.
101280031Sdim    for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str),
102280031Sdim                                         E = llvm::sys::path::end(Path8Str);
103280031Sdim                                         I != E; ++I) {
104280031Sdim      if (I->size() == 1 && *I == ".")
105280031Sdim        continue;
106280031Sdim      if (I->size() == 2 && *I == "..")
107280031Sdim        llvm::sys::path::remove_filename(FullPath);
108280031Sdim      else
109280031Sdim        llvm::sys::path::append(FullPath, *I);
110280031Sdim    }
111280031Sdim    return UTF8ToUTF16(FullPath, Path16);
112280031Sdim  }
113280031Sdim
114280031Sdim  // Just use the caller's original path.
115280031Sdim  return UTF8ToUTF16(Path8Str, Path16);
116280031Sdim}
117280031Sdim} // end namespace path
118280031Sdim
119261991Sdimnamespace fs {
120218885Sdim
121261991Sdimstd::string getMainExecutable(const char *argv0, void *MainExecAddr) {
122261991Sdim  SmallVector<wchar_t, MAX_PATH> PathName;
123261991Sdim  DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity());
124218885Sdim
125261991Sdim  // A zero return value indicates a failure other than insufficient space.
126261991Sdim  if (Size == 0)
127261991Sdim    return "";
128218885Sdim
129261991Sdim  // Insufficient space is determined by a return value equal to the size of
130261991Sdim  // the buffer passed in.
131261991Sdim  if (Size == PathName.capacity())
132261991Sdim    return "";
133218885Sdim
134261991Sdim  // On success, GetModuleFileNameW returns the number of characters written to
135261991Sdim  // the buffer not including the NULL terminator.
136261991Sdim  PathName.set_size(Size);
137218885Sdim
138261991Sdim  // Convert the result from UTF-16 to UTF-8.
139261991Sdim  SmallVector<char, MAX_PATH> PathNameUTF8;
140261991Sdim  if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8))
141261991Sdim    return "";
142218885Sdim
143261991Sdim  return std::string(PathNameUTF8.data());
144218885Sdim}
145218885Sdim
146261991SdimUniqueID file_status::getUniqueID() const {
147261991Sdim  // The file is uniquely identified by the volume serial number along
148261991Sdim  // with the 64-bit file identifier.
149261991Sdim  uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) |
150261991Sdim                    static_cast<uint64_t>(FileIndexLow);
151261991Sdim
152261991Sdim  return UniqueID(VolumeSerialNumber, FileID);
153218885Sdim}
154218885Sdim
155309124SdimErrorOr<space_info> disk_space(const Twine &Path) {
156309124Sdim  ULARGE_INTEGER Avail, Total, Free;
157309124Sdim  if (!::GetDiskFreeSpaceExA(Path.str().c_str(), &Avail, &Total, &Free))
158309124Sdim    return mapWindowsError(::GetLastError());
159309124Sdim  space_info SpaceInfo;
160309124Sdim  SpaceInfo.capacity =
161309124Sdim      (static_cast<uint64_t>(Total.HighPart) << 32) + Total.LowPart;
162309124Sdim  SpaceInfo.free = (static_cast<uint64_t>(Free.HighPart) << 32) + Free.LowPart;
163309124Sdim  SpaceInfo.available =
164309124Sdim      (static_cast<uint64_t>(Avail.HighPart) << 32) + Avail.LowPart;
165309124Sdim  return SpaceInfo;
166309124Sdim}
167309124Sdim
168314564SdimTimePoint<> file_status::getLastAccessedTime() const {
169314564Sdim  FILETIME Time;
170314564Sdim  Time.dwLowDateTime = LastAccessedTimeLow;
171314564Sdim  Time.dwHighDateTime = LastAccessedTimeHigh;
172314564Sdim  return toTimePoint(Time);
173309124Sdim}
174309124Sdim
175314564SdimTimePoint<> file_status::getLastModificationTime() const {
176314564Sdim  FILETIME Time;
177314564Sdim  Time.dwLowDateTime = LastWriteTimeLow;
178314564Sdim  Time.dwHighDateTime = LastWriteTimeHigh;
179314564Sdim  return toTimePoint(Time);
180218885Sdim}
181218885Sdim
182321369Sdimuint32_t file_status::getLinkCount() const {
183321369Sdim  return NumLinks;
184321369Sdim}
185321369Sdim
186276479Sdimstd::error_code current_path(SmallVectorImpl<char> &result) {
187261991Sdim  SmallVector<wchar_t, MAX_PATH> cur_path;
188261991Sdim  DWORD len = MAX_PATH;
189218885Sdim
190261991Sdim  do {
191261991Sdim    cur_path.reserve(len);
192261991Sdim    len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data());
193218885Sdim
194261991Sdim    // A zero return value indicates a failure other than insufficient space.
195261991Sdim    if (len == 0)
196288943Sdim      return mapWindowsError(::GetLastError());
197218885Sdim
198261991Sdim    // If there's insufficient space, the len returned is larger than the len
199261991Sdim    // given.
200261991Sdim  } while (len > cur_path.capacity());
201261991Sdim
202261991Sdim  // On success, GetCurrentDirectoryW returns the number of characters not
203261991Sdim  // including the null-terminator.
204261991Sdim  cur_path.set_size(len);
205261991Sdim  return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result);
206218885Sdim}
207218885Sdim
208321369Sdimstd::error_code set_current_path(const Twine &path) {
209321369Sdim  // Convert to utf-16.
210321369Sdim  SmallVector<wchar_t, 128> wide_path;
211321369Sdim  if (std::error_code ec = widenPath(path, wide_path))
212321369Sdim    return ec;
213321369Sdim
214321369Sdim  if (!::SetCurrentDirectoryW(wide_path.begin()))
215321369Sdim    return mapWindowsError(::GetLastError());
216321369Sdim
217321369Sdim  return std::error_code();
218321369Sdim}
219321369Sdim
220296417Sdimstd::error_code create_directory(const Twine &path, bool IgnoreExisting,
221296417Sdim                                 perms Perms) {
222261991Sdim  SmallVector<wchar_t, 128> path_utf16;
223218885Sdim
224280031Sdim  if (std::error_code ec = widenPath(path, path_utf16))
225261991Sdim    return ec;
226218885Sdim
227261991Sdim  if (!::CreateDirectoryW(path_utf16.begin(), NULL)) {
228276479Sdim    DWORD LastError = ::GetLastError();
229276479Sdim    if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting)
230288943Sdim      return mapWindowsError(LastError);
231276479Sdim  }
232218885Sdim
233276479Sdim  return std::error_code();
234218885Sdim}
235218885Sdim
236276479Sdim// We can't use symbolic links for windows.
237276479Sdimstd::error_code create_link(const Twine &to, const Twine &from) {
238261991Sdim  // Convert to utf-16.
239261991Sdim  SmallVector<wchar_t, 128> wide_from;
240261991Sdim  SmallVector<wchar_t, 128> wide_to;
241280031Sdim  if (std::error_code ec = widenPath(from, wide_from))
242276479Sdim    return ec;
243280031Sdim  if (std::error_code ec = widenPath(to, wide_to))
244276479Sdim    return ec;
245218885Sdim
246276479Sdim  if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL))
247288943Sdim    return mapWindowsError(::GetLastError());
248218885Sdim
249276479Sdim  return std::error_code();
250218885Sdim}
251218885Sdim
252314564Sdimstd::error_code create_hard_link(const Twine &to, const Twine &from) {
253314564Sdim	return create_link(to, from);
254314564Sdim}
255314564Sdim
256276479Sdimstd::error_code remove(const Twine &path, bool IgnoreNonExisting) {
257261991Sdim  SmallVector<wchar_t, 128> path_utf16;
258218885Sdim
259276479Sdim  file_status ST;
260276479Sdim  if (std::error_code EC = status(path, ST)) {
261276479Sdim    if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting)
262276479Sdim      return EC;
263276479Sdim    return std::error_code();
264261991Sdim  }
265261991Sdim
266280031Sdim  if (std::error_code ec = widenPath(path, path_utf16))
267261991Sdim    return ec;
268261991Sdim
269276479Sdim  if (ST.type() == file_type::directory_file) {
270261991Sdim    if (!::RemoveDirectoryW(c_str(path_utf16))) {
271288943Sdim      std::error_code EC = mapWindowsError(::GetLastError());
272276479Sdim      if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting)
273276479Sdim        return EC;
274276479Sdim    }
275276479Sdim    return std::error_code();
276261991Sdim  }
277276479Sdim  if (!::DeleteFileW(c_str(path_utf16))) {
278288943Sdim    std::error_code EC = mapWindowsError(::GetLastError());
279276479Sdim    if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting)
280276479Sdim      return EC;
281276479Sdim  }
282276479Sdim  return std::error_code();
283218885Sdim}
284218885Sdim
285321369Sdimstatic std::error_code is_local_internal(SmallVectorImpl<wchar_t> &Path,
286321369Sdim                                         bool &Result) {
287321369Sdim  SmallVector<wchar_t, 128> VolumePath;
288321369Sdim  size_t Len = 128;
289321369Sdim  while (true) {
290321369Sdim    VolumePath.resize(Len);
291321369Sdim    BOOL Success =
292321369Sdim        ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size());
293321369Sdim
294321369Sdim    if (Success)
295321369Sdim      break;
296321369Sdim
297321369Sdim    DWORD Err = ::GetLastError();
298321369Sdim    if (Err != ERROR_INSUFFICIENT_BUFFER)
299321369Sdim      return mapWindowsError(Err);
300321369Sdim
301321369Sdim    Len *= 2;
302321369Sdim  }
303321369Sdim  // If the output buffer has exactly enough space for the path name, but not
304321369Sdim  // the null terminator, it will leave the output unterminated.  Push a null
305321369Sdim  // terminator onto the end to ensure that this never happens.
306321369Sdim  VolumePath.push_back(L'\0');
307321369Sdim  VolumePath.set_size(wcslen(VolumePath.data()));
308321369Sdim  const wchar_t *P = VolumePath.data();
309321369Sdim
310321369Sdim  UINT Type = ::GetDriveTypeW(P);
311321369Sdim  switch (Type) {
312321369Sdim  case DRIVE_FIXED:
313321369Sdim    Result = true;
314321369Sdim    return std::error_code();
315321369Sdim  case DRIVE_REMOTE:
316321369Sdim  case DRIVE_CDROM:
317321369Sdim  case DRIVE_RAMDISK:
318321369Sdim  case DRIVE_REMOVABLE:
319321369Sdim    Result = false;
320321369Sdim    return std::error_code();
321321369Sdim  default:
322321369Sdim    return make_error_code(errc::no_such_file_or_directory);
323321369Sdim  }
324321369Sdim  llvm_unreachable("Unreachable!");
325321369Sdim}
326321369Sdim
327321369Sdimstd::error_code is_local(const Twine &path, bool &result) {
328321369Sdim  if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path))
329321369Sdim    return make_error_code(errc::no_such_file_or_directory);
330321369Sdim
331321369Sdim  SmallString<128> Storage;
332321369Sdim  StringRef P = path.toStringRef(Storage);
333321369Sdim
334321369Sdim  // Convert to utf-16.
335321369Sdim  SmallVector<wchar_t, 128> WidePath;
336321369Sdim  if (std::error_code ec = widenPath(P, WidePath))
337321369Sdim    return ec;
338321369Sdim  return is_local_internal(WidePath, result);
339321369Sdim}
340321369Sdim
341321369Sdimstd::error_code is_local(int FD, bool &Result) {
342321369Sdim  SmallVector<wchar_t, 128> FinalPath;
343321369Sdim  HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
344321369Sdim
345321369Sdim  size_t Len = 128;
346321369Sdim  do {
347321369Sdim    FinalPath.reserve(Len);
348321369Sdim    Len = ::GetFinalPathNameByHandleW(Handle, FinalPath.data(),
349321369Sdim                                      FinalPath.capacity() - 1, VOLUME_NAME_NT);
350321369Sdim    if (Len == 0)
351321369Sdim      return mapWindowsError(::GetLastError());
352321369Sdim  } while (Len > FinalPath.capacity());
353321369Sdim
354321369Sdim  FinalPath.set_size(Len);
355321369Sdim
356321369Sdim  return is_local_internal(FinalPath, Result);
357321369Sdim}
358321369Sdim
359276479Sdimstd::error_code rename(const Twine &from, const Twine &to) {
360261991Sdim  // Convert to utf-16.
361261991Sdim  SmallVector<wchar_t, 128> wide_from;
362261991Sdim  SmallVector<wchar_t, 128> wide_to;
363280031Sdim  if (std::error_code ec = widenPath(from, wide_from))
364276479Sdim    return ec;
365280031Sdim  if (std::error_code ec = widenPath(to, wide_to))
366276479Sdim    return ec;
367261991Sdim
368276479Sdim  std::error_code ec = std::error_code();
369296417Sdim
370309124Sdim  // Retry while we see recoverable errors.
371296417Sdim  // System scanners (eg. indexer) might open the source file when it is written
372296417Sdim  // and closed.
373296417Sdim
374309124Sdim  bool TryReplace = true;
375309124Sdim
376261991Sdim  for (int i = 0; i < 2000; i++) {
377309124Sdim    if (i > 0)
378309124Sdim      ::Sleep(1);
379296417Sdim
380309124Sdim    if (TryReplace) {
381309124Sdim      // Try ReplaceFile first, as it is able to associate a new data stream
382309124Sdim      // with the destination even if the destination file is currently open.
383309124Sdim      if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL))
384309124Sdim        return std::error_code();
385296417Sdim
386309124Sdim      DWORD ReplaceError = ::GetLastError();
387309124Sdim      ec = mapWindowsError(ReplaceError);
388309124Sdim
389309124Sdim      // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or
390309124Sdim      // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW().
391309124Sdim      if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT ||
392309124Sdim          ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) {
393309124Sdim        TryReplace = false;
394309124Sdim        continue;
395309124Sdim      }
396309124Sdim      // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry
397309124Sdim      // using ReplaceFileW().
398309124Sdim      if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED)
399309124Sdim        continue;
400309124Sdim      // We get ERROR_FILE_NOT_FOUND if the destination file is missing.
401309124Sdim      // MoveFileEx can handle this case.
402309124Sdim      if (ReplaceError != ERROR_ACCESS_DENIED &&
403309124Sdim          ReplaceError != ERROR_FILE_NOT_FOUND &&
404309124Sdim          ReplaceError != ERROR_SHARING_VIOLATION)
405309124Sdim        break;
406309124Sdim    }
407309124Sdim
408261991Sdim    if (::MoveFileExW(wide_from.begin(), wide_to.begin(),
409261991Sdim                      MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
410276479Sdim      return std::error_code();
411296417Sdim
412296417Sdim    DWORD MoveError = ::GetLastError();
413296417Sdim    ec = mapWindowsError(MoveError);
414296417Sdim    if (MoveError != ERROR_ACCESS_DENIED) break;
415261991Sdim  }
416261991Sdim
417261991Sdim  return ec;
418218885Sdim}
419218885Sdim
420280031Sdimstd::error_code resize_file(int FD, uint64_t Size) {
421261991Sdim#ifdef HAVE__CHSIZE_S
422280031Sdim  errno_t error = ::_chsize_s(FD, Size);
423261991Sdim#else
424280031Sdim  errno_t error = ::_chsize(FD, Size);
425261991Sdim#endif
426276479Sdim  return std::error_code(error, std::generic_category());
427218885Sdim}
428218885Sdim
429280031Sdimstd::error_code access(const Twine &Path, AccessMode Mode) {
430280031Sdim  SmallVector<wchar_t, 128> PathUtf16;
431218885Sdim
432280031Sdim  if (std::error_code EC = widenPath(Path, PathUtf16))
433280031Sdim    return EC;
434218885Sdim
435280031Sdim  DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin());
436218885Sdim
437280031Sdim  if (Attributes == INVALID_FILE_ATTRIBUTES) {
438261991Sdim    // See if the file didn't actually exist.
439276479Sdim    DWORD LastError = ::GetLastError();
440276479Sdim    if (LastError != ERROR_FILE_NOT_FOUND &&
441276479Sdim        LastError != ERROR_PATH_NOT_FOUND)
442288943Sdim      return mapWindowsError(LastError);
443280031Sdim    return errc::no_such_file_or_directory;
444280031Sdim  }
445218885Sdim
446280031Sdim  if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY))
447280031Sdim    return errc::permission_denied;
448218885Sdim
449280031Sdim  return std::error_code();
450261991Sdim}
451218885Sdim
452296417Sdimbool can_execute(const Twine &Path) {
453296417Sdim  return !access(Path, AccessMode::Execute) ||
454296417Sdim         !access(Path + ".exe", AccessMode::Execute);
455296417Sdim}
456296417Sdim
457261991Sdimbool equivalent(file_status A, file_status B) {
458261991Sdim  assert(status_known(A) && status_known(B));
459309124Sdim  return A.FileIndexHigh         == B.FileIndexHigh &&
460309124Sdim         A.FileIndexLow          == B.FileIndexLow &&
461309124Sdim         A.FileSizeHigh          == B.FileSizeHigh &&
462309124Sdim         A.FileSizeLow           == B.FileSizeLow &&
463309124Sdim         A.LastAccessedTimeHigh  == B.LastAccessedTimeHigh &&
464309124Sdim         A.LastAccessedTimeLow   == B.LastAccessedTimeLow &&
465309124Sdim         A.LastWriteTimeHigh     == B.LastWriteTimeHigh &&
466309124Sdim         A.LastWriteTimeLow      == B.LastWriteTimeLow &&
467309124Sdim         A.VolumeSerialNumber    == B.VolumeSerialNumber;
468218885Sdim}
469218885Sdim
470276479Sdimstd::error_code equivalent(const Twine &A, const Twine &B, bool &result) {
471261991Sdim  file_status fsA, fsB;
472276479Sdim  if (std::error_code ec = status(A, fsA))
473276479Sdim    return ec;
474276479Sdim  if (std::error_code ec = status(B, fsB))
475276479Sdim    return ec;
476261991Sdim  result = equivalent(fsA, fsB);
477276479Sdim  return std::error_code();
478261991Sdim}
479218885Sdim
480261991Sdimstatic bool isReservedName(StringRef path) {
481261991Sdim  // This list of reserved names comes from MSDN, at:
482261991Sdim  // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
483296417Sdim  static const char *const sReservedNames[] = { "nul", "con", "prn", "aux",
484296417Sdim                                                "com1", "com2", "com3", "com4",
485296417Sdim                                                "com5", "com6", "com7", "com8",
486296417Sdim                                                "com9", "lpt1", "lpt2", "lpt3",
487296417Sdim                                                "lpt4", "lpt5", "lpt6", "lpt7",
488296417Sdim                                                "lpt8", "lpt9" };
489218885Sdim
490261991Sdim  // First, check to see if this is a device namespace, which always
491261991Sdim  // starts with \\.\, since device namespaces are not legal file paths.
492261991Sdim  if (path.startswith("\\\\.\\"))
493261991Sdim    return true;
494261991Sdim
495309124Sdim  // Then compare against the list of ancient reserved names.
496261991Sdim  for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) {
497261991Sdim    if (path.equals_lower(sReservedNames[i]))
498218885Sdim      return true;
499218885Sdim  }
500218885Sdim
501261991Sdim  // The path isn't what we consider reserved.
502218885Sdim  return false;
503218885Sdim}
504218885Sdim
505276479Sdimstatic std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
506261991Sdim  if (FileHandle == INVALID_HANDLE_VALUE)
507261991Sdim    goto handle_status_error;
508261991Sdim
509261991Sdim  switch (::GetFileType(FileHandle)) {
510261991Sdim  default:
511261991Sdim    llvm_unreachable("Don't know anything about this file type");
512261991Sdim  case FILE_TYPE_UNKNOWN: {
513261991Sdim    DWORD Err = ::GetLastError();
514261991Sdim    if (Err != NO_ERROR)
515288943Sdim      return mapWindowsError(Err);
516261991Sdim    Result = file_status(file_type::type_unknown);
517276479Sdim    return std::error_code();
518218885Sdim  }
519261991Sdim  case FILE_TYPE_DISK:
520261991Sdim    break;
521261991Sdim  case FILE_TYPE_CHAR:
522261991Sdim    Result = file_status(file_type::character_file);
523276479Sdim    return std::error_code();
524261991Sdim  case FILE_TYPE_PIPE:
525261991Sdim    Result = file_status(file_type::fifo_file);
526276479Sdim    return std::error_code();
527261991Sdim  }
528218885Sdim
529261991Sdim  BY_HANDLE_FILE_INFORMATION Info;
530261991Sdim  if (!::GetFileInformationByHandle(FileHandle, &Info))
531261991Sdim    goto handle_status_error;
532261991Sdim
533261991Sdim  {
534261991Sdim    file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
535261991Sdim                         ? file_type::directory_file
536261991Sdim                         : file_type::regular_file;
537321369Sdim    perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
538321369Sdim                            ? (all_read | all_exe)
539321369Sdim                            : all_all;
540321369Sdim    Result = file_status(
541321369Sdim        Type, Permissions, Info.nNumberOfLinks,
542321369Sdim        Info.ftLastAccessTime.dwHighDateTime,
543321369Sdim        Info.ftLastAccessTime.dwLowDateTime,
544321369Sdim        Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime,
545321369Sdim        Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow,
546321369Sdim        Info.nFileIndexHigh, Info.nFileIndexLow);
547276479Sdim    return std::error_code();
548218885Sdim  }
549218885Sdim
550261991Sdimhandle_status_error:
551276479Sdim  DWORD LastError = ::GetLastError();
552276479Sdim  if (LastError == ERROR_FILE_NOT_FOUND ||
553276479Sdim      LastError == ERROR_PATH_NOT_FOUND)
554261991Sdim    Result = file_status(file_type::file_not_found);
555276479Sdim  else if (LastError == ERROR_SHARING_VIOLATION)
556261991Sdim    Result = file_status(file_type::type_unknown);
557218885Sdim  else
558261991Sdim    Result = file_status(file_type::status_error);
559288943Sdim  return mapWindowsError(LastError);
560261991Sdim}
561218885Sdim
562321369Sdimstd::error_code status(const Twine &path, file_status &result, bool Follow) {
563261991Sdim  SmallString<128> path_storage;
564261991Sdim  SmallVector<wchar_t, 128> path_utf16;
565261991Sdim
566261991Sdim  StringRef path8 = path.toStringRef(path_storage);
567261991Sdim  if (isReservedName(path8)) {
568261991Sdim    result = file_status(file_type::character_file);
569276479Sdim    return std::error_code();
570218885Sdim  }
571218885Sdim
572280031Sdim  if (std::error_code ec = widenPath(path8, path_utf16))
573261991Sdim    return ec;
574218885Sdim
575261991Sdim  DWORD attr = ::GetFileAttributesW(path_utf16.begin());
576261991Sdim  if (attr == INVALID_FILE_ATTRIBUTES)
577261991Sdim    return getStatus(INVALID_HANDLE_VALUE, result);
578261991Sdim
579321369Sdim  DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS;
580261991Sdim  // Handle reparse points.
581321369Sdim  if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT))
582321369Sdim    Flags |= FILE_FLAG_OPEN_REPARSE_POINT;
583261991Sdim
584261991Sdim  ScopedFileHandle h(
585261991Sdim      ::CreateFileW(path_utf16.begin(), 0, // Attributes only.
586261991Sdim                    FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
587321369Sdim                    NULL, OPEN_EXISTING, Flags, 0));
588321369Sdim  if (!h)
589321369Sdim    return getStatus(INVALID_HANDLE_VALUE, result);
590261991Sdim
591321369Sdim  return getStatus(h, result);
592218885Sdim}
593218885Sdim
594276479Sdimstd::error_code status(int FD, file_status &Result) {
595261991Sdim  HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
596261991Sdim  return getStatus(FileHandle, Result);
597261991Sdim}
598261991Sdim
599321369Sdimstd::error_code setPermissions(const Twine &Path, perms Permissions) {
600321369Sdim  SmallVector<wchar_t, 128> PathUTF16;
601321369Sdim  if (std::error_code EC = widenPath(Path, PathUTF16))
602321369Sdim    return EC;
603321369Sdim
604321369Sdim  DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin());
605321369Sdim  if (Attributes == INVALID_FILE_ATTRIBUTES)
606321369Sdim    return mapWindowsError(GetLastError());
607321369Sdim
608321369Sdim  // There are many Windows file attributes that are not to do with the file
609321369Sdim  // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve
610321369Sdim  // them.
611321369Sdim  if (Permissions & all_write) {
612321369Sdim    Attributes &= ~FILE_ATTRIBUTE_READONLY;
613321369Sdim    if (Attributes == 0)
614321369Sdim      // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set.
615321369Sdim      Attributes |= FILE_ATTRIBUTE_NORMAL;
616321369Sdim  }
617321369Sdim  else {
618321369Sdim    Attributes |= FILE_ATTRIBUTE_READONLY;
619321369Sdim    // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so
620321369Sdim    // remove it, if it is present.
621321369Sdim    Attributes &= ~FILE_ATTRIBUTE_NORMAL;
622321369Sdim  }
623321369Sdim
624321369Sdim  if (!::SetFileAttributesW(PathUTF16.begin(), Attributes))
625321369Sdim    return mapWindowsError(GetLastError());
626321369Sdim
627321369Sdim  return std::error_code();
628321369Sdim}
629321369Sdim
630314564Sdimstd::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
631314564Sdim  FILETIME FT = toFILETIME(Time);
632261991Sdim  HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
633261991Sdim  if (!SetFileTime(FileHandle, NULL, &FT, &FT))
634288943Sdim    return mapWindowsError(::GetLastError());
635276479Sdim  return std::error_code();
636261991Sdim}
637261991Sdim
638280031Sdimstd::error_code mapped_file_region::init(int FD, uint64_t Offset,
639280031Sdim                                         mapmode Mode) {
640261991Sdim  // Make sure that the requested size fits within SIZE_T.
641280031Sdim  if (Size > std::numeric_limits<SIZE_T>::max())
642261991Sdim    return make_error_code(errc::invalid_argument);
643261991Sdim
644280031Sdim  HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
645280031Sdim  if (FileHandle == INVALID_HANDLE_VALUE)
646280031Sdim    return make_error_code(errc::bad_file_descriptor);
647280031Sdim
648261991Sdim  DWORD flprotect;
649261991Sdim  switch (Mode) {
650261991Sdim  case readonly:  flprotect = PAGE_READONLY; break;
651261991Sdim  case readwrite: flprotect = PAGE_READWRITE; break;
652261991Sdim  case priv:      flprotect = PAGE_WRITECOPY; break;
653218885Sdim  }
654218885Sdim
655280031Sdim  HANDLE FileMappingHandle =
656261991Sdim      ::CreateFileMappingW(FileHandle, 0, flprotect,
657261991Sdim                           (Offset + Size) >> 32,
658261991Sdim                           (Offset + Size) & 0xffffffff,
659261991Sdim                           0);
660261991Sdim  if (FileMappingHandle == NULL) {
661288943Sdim    std::error_code ec = mapWindowsError(GetLastError());
662261991Sdim    return ec;
663218885Sdim  }
664218885Sdim
665261991Sdim  DWORD dwDesiredAccess;
666261991Sdim  switch (Mode) {
667261991Sdim  case readonly:  dwDesiredAccess = FILE_MAP_READ; break;
668261991Sdim  case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break;
669261991Sdim  case priv:      dwDesiredAccess = FILE_MAP_COPY; break;
670261991Sdim  }
671261991Sdim  Mapping = ::MapViewOfFile(FileMappingHandle,
672261991Sdim                            dwDesiredAccess,
673261991Sdim                            Offset >> 32,
674261991Sdim                            Offset & 0xffffffff,
675261991Sdim                            Size);
676261991Sdim  if (Mapping == NULL) {
677288943Sdim    std::error_code ec = mapWindowsError(GetLastError());
678261991Sdim    ::CloseHandle(FileMappingHandle);
679261991Sdim    return ec;
680261991Sdim  }
681261991Sdim
682261991Sdim  if (Size == 0) {
683261991Sdim    MEMORY_BASIC_INFORMATION mbi;
684261991Sdim    SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi));
685261991Sdim    if (Result == 0) {
686288943Sdim      std::error_code ec = mapWindowsError(GetLastError());
687261991Sdim      ::UnmapViewOfFile(Mapping);
688261991Sdim      ::CloseHandle(FileMappingHandle);
689261991Sdim      return ec;
690218885Sdim    }
691261991Sdim    Size = mbi.RegionSize;
692218885Sdim  }
693218885Sdim
694261991Sdim  // Close all the handles except for the view. It will keep the other handles
695261991Sdim  // alive.
696261991Sdim  ::CloseHandle(FileMappingHandle);
697276479Sdim  return std::error_code();
698218885Sdim}
699218885Sdim
700280031Sdimmapped_file_region::mapped_file_region(int fd, mapmode mode, uint64_t length,
701280031Sdim                                       uint64_t offset, std::error_code &ec)
702280031Sdim    : Size(length), Mapping() {
703280031Sdim  ec = init(fd, offset, mode);
704280031Sdim  if (ec)
705280031Sdim    Mapping = 0;
706261991Sdim}
707218885Sdim
708261991Sdimmapped_file_region::~mapped_file_region() {
709261991Sdim  if (Mapping)
710261991Sdim    ::UnmapViewOfFile(Mapping);
711261991Sdim}
712218885Sdim
713261991Sdimuint64_t mapped_file_region::size() const {
714261991Sdim  assert(Mapping && "Mapping failed but used anyway!");
715261991Sdim  return Size;
716261991Sdim}
717218885Sdim
718261991Sdimchar *mapped_file_region::data() const {
719261991Sdim  assert(Mapping && "Mapping failed but used anyway!");
720261991Sdim  return reinterpret_cast<char*>(Mapping);
721261991Sdim}
722218885Sdim
723261991Sdimconst char *mapped_file_region::const_data() const {
724261991Sdim  assert(Mapping && "Mapping failed but used anyway!");
725261991Sdim  return reinterpret_cast<const char*>(Mapping);
726261991Sdim}
727218885Sdim
728261991Sdimint mapped_file_region::alignment() {
729261991Sdim  SYSTEM_INFO SysInfo;
730261991Sdim  ::GetSystemInfo(&SysInfo);
731261991Sdim  return SysInfo.dwAllocationGranularity;
732261991Sdim}
733218885Sdim
734276479Sdimstd::error_code detail::directory_iterator_construct(detail::DirIterState &it,
735321369Sdim                                                     StringRef path,
736321369Sdim                                                     bool follow_symlinks) {
737261991Sdim  SmallVector<wchar_t, 128> path_utf16;
738218885Sdim
739280031Sdim  if (std::error_code ec = widenPath(path, path_utf16))
740261991Sdim    return ec;
741218885Sdim
742261991Sdim  // Convert path to the format that Windows is happy with.
743261991Sdim  if (path_utf16.size() > 0 &&
744261991Sdim      !is_separator(path_utf16[path.size() - 1]) &&
745261991Sdim      path_utf16[path.size() - 1] != L':') {
746261991Sdim    path_utf16.push_back(L'\\');
747261991Sdim    path_utf16.push_back(L'*');
748261991Sdim  } else {
749261991Sdim    path_utf16.push_back(L'*');
750261991Sdim  }
751218885Sdim
752261991Sdim  //  Get the first directory entry.
753261991Sdim  WIN32_FIND_DATAW FirstFind;
754261991Sdim  ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind));
755261991Sdim  if (!FindHandle)
756288943Sdim    return mapWindowsError(::GetLastError());
757218885Sdim
758261991Sdim  size_t FilenameLen = ::wcslen(FirstFind.cFileName);
759261991Sdim  while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') ||
760261991Sdim         (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' &&
761261991Sdim                              FirstFind.cFileName[1] == L'.'))
762261991Sdim    if (!::FindNextFileW(FindHandle, &FirstFind)) {
763276479Sdim      DWORD LastError = ::GetLastError();
764261991Sdim      // Check for end.
765276479Sdim      if (LastError == ERROR_NO_MORE_FILES)
766261991Sdim        return detail::directory_iterator_destruct(it);
767288943Sdim      return mapWindowsError(LastError);
768261991Sdim    } else
769261991Sdim      FilenameLen = ::wcslen(FirstFind.cFileName);
770218885Sdim
771261991Sdim  // Construct the current directory entry.
772261991Sdim  SmallString<128> directory_entry_name_utf8;
773276479Sdim  if (std::error_code ec =
774276479Sdim          UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName),
775276479Sdim                      directory_entry_name_utf8))
776261991Sdim    return ec;
777218885Sdim
778261991Sdim  it.IterationHandle = intptr_t(FindHandle.take());
779261991Sdim  SmallString<128> directory_entry_path(path);
780288943Sdim  path::append(directory_entry_path, directory_entry_name_utf8);
781321369Sdim  it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks);
782218885Sdim
783276479Sdim  return std::error_code();
784218885Sdim}
785218885Sdim
786276479Sdimstd::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
787261991Sdim  if (it.IterationHandle != 0)
788261991Sdim    // Closes the handle if it's valid.
789261991Sdim    ScopedFindHandle close(HANDLE(it.IterationHandle));
790261991Sdim  it.IterationHandle = 0;
791261991Sdim  it.CurrentEntry = directory_entry();
792276479Sdim  return std::error_code();
793261991Sdim}
794218885Sdim
795276479Sdimstd::error_code detail::directory_iterator_increment(detail::DirIterState &it) {
796261991Sdim  WIN32_FIND_DATAW FindData;
797261991Sdim  if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
798276479Sdim    DWORD LastError = ::GetLastError();
799261991Sdim    // Check for end.
800276479Sdim    if (LastError == ERROR_NO_MORE_FILES)
801261991Sdim      return detail::directory_iterator_destruct(it);
802288943Sdim    return mapWindowsError(LastError);
803261991Sdim  }
804218885Sdim
805261991Sdim  size_t FilenameLen = ::wcslen(FindData.cFileName);
806261991Sdim  if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') ||
807261991Sdim      (FilenameLen == 2 && FindData.cFileName[0] == L'.' &&
808261991Sdim                           FindData.cFileName[1] == L'.'))
809261991Sdim    return directory_iterator_increment(it);
810218885Sdim
811261991Sdim  SmallString<128> directory_entry_path_utf8;
812276479Sdim  if (std::error_code ec =
813276479Sdim          UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName),
814276479Sdim                      directory_entry_path_utf8))
815261991Sdim    return ec;
816218885Sdim
817261991Sdim  it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
818276479Sdim  return std::error_code();
819218885Sdim}
820218885Sdim
821321369Sdimstatic std::error_code realPathFromHandle(HANDLE H,
822321369Sdim                                          SmallVectorImpl<char> &RealPath) {
823321369Sdim  RealPath.clear();
824321369Sdim  llvm::SmallVector<wchar_t, MAX_PATH> Buffer;
825321369Sdim  DWORD CountChars = ::GetFinalPathNameByHandleW(
826321369Sdim      H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED);
827321369Sdim  if (CountChars > Buffer.capacity()) {
828321369Sdim    // The buffer wasn't big enough, try again.  In this case the return value
829321369Sdim    // *does* indicate the size of the null terminator.
830321369Sdim    Buffer.reserve(CountChars);
831321369Sdim    CountChars = ::GetFinalPathNameByHandleW(
832321369Sdim        H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED);
833321369Sdim  }
834321369Sdim  if (CountChars == 0)
835321369Sdim    return mapWindowsError(GetLastError());
836321369Sdim
837321369Sdim  const wchar_t *Data = Buffer.data();
838321369Sdim  if (CountChars >= 4) {
839321369Sdim    if (0 == ::memcmp(Data, L"\\\\?\\", 8)) {
840321369Sdim      CountChars -= 4;
841321369Sdim      Data += 4;
842321369Sdim    }
843321369Sdim  }
844321369Sdim
845321369Sdim  // Convert the result from UTF-16 to UTF-8.
846321369Sdim  return UTF16ToUTF8(Data, CountChars, RealPath);
847321369Sdim}
848321369Sdim
849321369Sdimstatic std::error_code directoryRealPath(const Twine &Name,
850321369Sdim                                         SmallVectorImpl<char> &RealPath) {
851321369Sdim  SmallVector<wchar_t, 128> PathUTF16;
852321369Sdim
853321369Sdim  if (std::error_code EC = widenPath(Name, PathUTF16))
854321369Sdim    return EC;
855321369Sdim
856321369Sdim  HANDLE H =
857321369Sdim      ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
858321369Sdim                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
859321369Sdim                    NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
860321369Sdim  if (H == INVALID_HANDLE_VALUE)
861321369Sdim    return mapWindowsError(GetLastError());
862321369Sdim  std::error_code EC = realPathFromHandle(H, RealPath);
863321369Sdim  ::CloseHandle(H);
864321369Sdim  return EC;
865321369Sdim}
866321369Sdim
867309124Sdimstd::error_code openFileForRead(const Twine &Name, int &ResultFD,
868309124Sdim                                SmallVectorImpl<char> *RealPath) {
869261991Sdim  SmallVector<wchar_t, 128> PathUTF16;
870218885Sdim
871280031Sdim  if (std::error_code EC = widenPath(Name, PathUTF16))
872261991Sdim    return EC;
873218885Sdim
874296417Sdim  HANDLE H =
875296417Sdim      ::CreateFileW(PathUTF16.begin(), GENERIC_READ,
876296417Sdim                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
877296417Sdim                    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
878261991Sdim  if (H == INVALID_HANDLE_VALUE) {
879276479Sdim    DWORD LastError = ::GetLastError();
880288943Sdim    std::error_code EC = mapWindowsError(LastError);
881261991Sdim    // Provide a better error message when trying to open directories.
882261991Sdim    // This only runs if we failed to open the file, so there is probably
883261991Sdim    // no performances issues.
884276479Sdim    if (LastError != ERROR_ACCESS_DENIED)
885261991Sdim      return EC;
886261991Sdim    if (is_directory(Name))
887276479Sdim      return make_error_code(errc::is_a_directory);
888261991Sdim    return EC;
889218885Sdim  }
890218885Sdim
891261991Sdim  int FD = ::_open_osfhandle(intptr_t(H), 0);
892261991Sdim  if (FD == -1) {
893261991Sdim    ::CloseHandle(H);
894288943Sdim    return mapWindowsError(ERROR_INVALID_HANDLE);
895218885Sdim  }
896218885Sdim
897309124Sdim  // Fetch the real name of the file, if the user asked
898321369Sdim  if (RealPath)
899321369Sdim    realPathFromHandle(H, *RealPath);
900309124Sdim
901261991Sdim  ResultFD = FD;
902276479Sdim  return std::error_code();
903218885Sdim}
904218885Sdim
905276479Sdimstd::error_code openFileForWrite(const Twine &Name, int &ResultFD,
906261991Sdim                            sys::fs::OpenFlags Flags, unsigned Mode) {
907261991Sdim  // Verify that we don't have both "append" and "excl".
908261991Sdim  assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
909261991Sdim         "Cannot specify both 'excl' and 'append' file creation flags!");
910218885Sdim
911261991Sdim  SmallVector<wchar_t, 128> PathUTF16;
912218885Sdim
913280031Sdim  if (std::error_code EC = widenPath(Name, PathUTF16))
914261991Sdim    return EC;
915218885Sdim
916261991Sdim  DWORD CreationDisposition;
917261991Sdim  if (Flags & F_Excl)
918261991Sdim    CreationDisposition = CREATE_NEW;
919261991Sdim  else if (Flags & F_Append)
920261991Sdim    CreationDisposition = OPEN_ALWAYS;
921261991Sdim  else
922261991Sdim    CreationDisposition = CREATE_ALWAYS;
923261991Sdim
924276479Sdim  DWORD Access = GENERIC_WRITE;
925276479Sdim  if (Flags & F_RW)
926276479Sdim    Access |= GENERIC_READ;
927276479Sdim
928276479Sdim  HANDLE H = ::CreateFileW(PathUTF16.begin(), Access,
929261991Sdim                           FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
930261991Sdim                           CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
931261991Sdim
932261991Sdim  if (H == INVALID_HANDLE_VALUE) {
933276479Sdim    DWORD LastError = ::GetLastError();
934288943Sdim    std::error_code EC = mapWindowsError(LastError);
935261991Sdim    // Provide a better error message when trying to open directories.
936261991Sdim    // This only runs if we failed to open the file, so there is probably
937261991Sdim    // no performances issues.
938276479Sdim    if (LastError != ERROR_ACCESS_DENIED)
939261991Sdim      return EC;
940261991Sdim    if (is_directory(Name))
941276479Sdim      return make_error_code(errc::is_a_directory);
942261991Sdim    return EC;
943221345Sdim  }
944218885Sdim
945261991Sdim  int OpenFlags = 0;
946261991Sdim  if (Flags & F_Append)
947261991Sdim    OpenFlags |= _O_APPEND;
948218885Sdim
949276479Sdim  if (Flags & F_Text)
950261991Sdim    OpenFlags |= _O_TEXT;
951218885Sdim
952261991Sdim  int FD = ::_open_osfhandle(intptr_t(H), OpenFlags);
953261991Sdim  if (FD == -1) {
954261991Sdim    ::CloseHandle(H);
955288943Sdim    return mapWindowsError(ERROR_INVALID_HANDLE);
956261991Sdim  }
957218885Sdim
958261991Sdim  ResultFD = FD;
959276479Sdim  return std::error_code();
960218885Sdim}
961309124Sdim
962309124Sdimstd::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) {
963309124Sdim  HANDLE FileHandle = reinterpret_cast<HANDLE>(::_get_osfhandle(FD));
964309124Sdim  if (FileHandle == INVALID_HANDLE_VALUE)
965309124Sdim    return make_error_code(errc::bad_file_descriptor);
966309124Sdim
967309124Sdim  DWORD CharCount;
968309124Sdim  SmallVector<wchar_t, 1024> TempPath;
969309124Sdim  do {
970309124Sdim    CharCount = ::GetFinalPathNameByHandleW(FileHandle, TempPath.begin(),
971309124Sdim                                            TempPath.capacity(),
972309124Sdim                                            FILE_NAME_NORMALIZED);
973309124Sdim    if (CharCount < TempPath.capacity())
974309124Sdim      break;
975309124Sdim
976309124Sdim    // Reserve sufficient space for the path as well as the null character. Even
977309124Sdim    // though the API does not document that it is required, if we reserve just
978309124Sdim    // CharCount space, the function call will not store the resulting path and
979309124Sdim    // still report success.
980309124Sdim    TempPath.reserve(CharCount + 1);
981309124Sdim  } while (true);
982309124Sdim
983309124Sdim  if (CharCount == 0)
984309124Sdim    return mapWindowsError(::GetLastError());
985309124Sdim
986309124Sdim  TempPath.set_size(CharCount);
987309124Sdim
988309124Sdim  // On earlier Windows releases, the character count includes the terminating
989309124Sdim  // null.
990309124Sdim  if (TempPath.back() == L'\0') {
991309124Sdim    --CharCount;
992309124Sdim    TempPath.pop_back();
993309124Sdim  }
994309124Sdim
995309124Sdim  return windows::UTF16ToUTF8(TempPath.data(), CharCount, ResultPath);
996309124Sdim}
997321369Sdim
998321369Sdimstd::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
999321369Sdim  // Convert to utf-16.
1000321369Sdim  SmallVector<wchar_t, 128> Path16;
1001321369Sdim  std::error_code EC = widenPath(path, Path16);
1002321369Sdim  if (EC && !IgnoreErrors)
1003321369Sdim    return EC;
1004321369Sdim
1005321369Sdim  // SHFileOperation() accepts a list of paths, and so must be double null-
1006321369Sdim  // terminated to indicate the end of the list.  The buffer is already null
1007321369Sdim  // terminated, but since that null character is not considered part of the
1008321369Sdim  // vector's size, pushing another one will just consume that byte.  So we
1009321369Sdim  // need to push 2 null terminators.
1010321369Sdim  Path16.push_back(0);
1011321369Sdim  Path16.push_back(0);
1012321369Sdim
1013321369Sdim  SHFILEOPSTRUCTW shfos = {};
1014321369Sdim  shfos.wFunc = FO_DELETE;
1015321369Sdim  shfos.pFrom = Path16.data();
1016321369Sdim  shfos.fFlags = FOF_NO_UI;
1017321369Sdim
1018321369Sdim  int result = ::SHFileOperationW(&shfos);
1019321369Sdim  if (result != 0 && !IgnoreErrors)
1020321369Sdim    return mapWindowsError(result);
1021321369Sdim  return std::error_code();
1022321369Sdim}
1023321369Sdim
1024321369Sdimstatic void expandTildeExpr(SmallVectorImpl<char> &Path) {
1025321369Sdim  // Path does not begin with a tilde expression.
1026321369Sdim  if (Path.empty() || Path[0] != '~')
1027321369Sdim    return;
1028321369Sdim
1029321369Sdim  StringRef PathStr(Path.begin(), Path.size());
1030321369Sdim  PathStr = PathStr.drop_front();
1031321369Sdim  StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); });
1032321369Sdim
1033321369Sdim  if (!Expr.empty()) {
1034321369Sdim    // This is probably a ~username/ expression.  Don't support this on Windows.
1035321369Sdim    return;
1036321369Sdim  }
1037321369Sdim
1038321369Sdim  SmallString<128> HomeDir;
1039321369Sdim  if (!path::home_directory(HomeDir)) {
1040321369Sdim    // For some reason we couldn't get the home directory.  Just exit.
1041321369Sdim    return;
1042321369Sdim  }
1043321369Sdim
1044321369Sdim  // Overwrite the first character and insert the rest.
1045321369Sdim  Path[0] = HomeDir[0];
1046321369Sdim  Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end());
1047321369Sdim}
1048321369Sdim
1049321369Sdimstd::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
1050321369Sdim                          bool expand_tilde) {
1051321369Sdim  dest.clear();
1052321369Sdim  if (path.isTriviallyEmpty())
1053321369Sdim    return std::error_code();
1054321369Sdim
1055321369Sdim  if (expand_tilde) {
1056321369Sdim    SmallString<128> Storage;
1057321369Sdim    path.toVector(Storage);
1058321369Sdim    expandTildeExpr(Storage);
1059321369Sdim    return real_path(Storage, dest, false);
1060321369Sdim  }
1061321369Sdim
1062321369Sdim  if (is_directory(path))
1063321369Sdim    return directoryRealPath(path, dest);
1064321369Sdim
1065321369Sdim  int fd;
1066321369Sdim  if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, &dest))
1067321369Sdim    return EC;
1068321369Sdim  ::close(fd);
1069321369Sdim  return std::error_code();
1070321369Sdim}
1071321369Sdim
1072261991Sdim} // end namespace fs
1073218885Sdim
1074276479Sdimnamespace path {
1075296417Sdimstatic bool getKnownFolderPath(KNOWNFOLDERID folderId,
1076296417Sdim                               SmallVectorImpl<char> &result) {
1077296417Sdim  wchar_t *path = nullptr;
1078296417Sdim  if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK)
1079276479Sdim    return false;
1080276479Sdim
1081296417Sdim  bool ok = !UTF16ToUTF8(path, ::wcslen(path), result);
1082296417Sdim  ::CoTaskMemFree(path);
1083296417Sdim  return ok;
1084296417Sdim}
1085276479Sdim
1086296417Sdimbool getUserCacheDir(SmallVectorImpl<char> &Result) {
1087296417Sdim  return getKnownFolderPath(FOLDERID_LocalAppData, Result);
1088276479Sdim}
1089276479Sdim
1090296417Sdimbool home_directory(SmallVectorImpl<char> &result) {
1091296417Sdim  return getKnownFolderPath(FOLDERID_Profile, result);
1092296417Sdim}
1093280031Sdim
1094296417Sdimstatic bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl<char> &Res) {
1095280031Sdim  SmallVector<wchar_t, 1024> Buf;
1096280031Sdim  size_t Size = 1024;
1097280031Sdim  do {
1098280031Sdim    Buf.reserve(Size);
1099296417Sdim    Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity());
1100280031Sdim    if (Size == 0)
1101280031Sdim      return false;
1102280031Sdim
1103280031Sdim    // Try again with larger buffer.
1104280031Sdim  } while (Size > Buf.capacity());
1105280031Sdim  Buf.set_size(Size);
1106280031Sdim
1107296417Sdim  return !windows::UTF16ToUTF8(Buf.data(), Size, Res);
1108280031Sdim}
1109280031Sdim
1110280031Sdimstatic bool getTempDirEnvVar(SmallVectorImpl<char> &Res) {
1111296417Sdim  const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"};
1112296417Sdim  for (auto *Env : EnvironmentVariables) {
1113280031Sdim    if (getTempDirEnvVar(Env, Res))
1114280031Sdim      return true;
1115280031Sdim  }
1116280031Sdim  return false;
1117280031Sdim}
1118280031Sdim
1119280031Sdimvoid system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) {
1120280031Sdim  (void)ErasedOnReboot;
1121280031Sdim  Result.clear();
1122280031Sdim
1123296417Sdim  // Check whether the temporary directory is specified by an environment var.
1124296417Sdim  // This matches GetTempPath logic to some degree. GetTempPath is not used
1125296417Sdim  // directly as it cannot handle evn var longer than 130 chars on Windows 7
1126296417Sdim  // (fixed on Windows 8).
1127296417Sdim  if (getTempDirEnvVar(Result)) {
1128296417Sdim    assert(!Result.empty() && "Unexpected empty path");
1129296417Sdim    native(Result); // Some Unix-like shells use Unix path separator in $TMP.
1130296417Sdim    fs::make_absolute(Result); // Make it absolute if not already.
1131280031Sdim    return;
1132296417Sdim  }
1133280031Sdim
1134280031Sdim  // Fall back to a system default.
1135296417Sdim  const char *DefaultResult = "C:\\Temp";
1136280031Sdim  Result.append(DefaultResult, DefaultResult + strlen(DefaultResult));
1137280031Sdim}
1138276479Sdim} // end namespace path
1139276479Sdim
1140261991Sdimnamespace windows {
1141276479Sdimstd::error_code UTF8ToUTF16(llvm::StringRef utf8,
1142276479Sdim                            llvm::SmallVectorImpl<wchar_t> &utf16) {
1143276479Sdim  if (!utf8.empty()) {
1144276479Sdim    int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
1145276479Sdim                                    utf8.size(), utf16.begin(), 0);
1146261991Sdim
1147276479Sdim    if (len == 0)
1148288943Sdim      return mapWindowsError(::GetLastError());
1149261991Sdim
1150276479Sdim    utf16.reserve(len + 1);
1151276479Sdim    utf16.set_size(len);
1152261991Sdim
1153276479Sdim    len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(),
1154276479Sdim                                utf8.size(), utf16.begin(), utf16.size());
1155261991Sdim
1156276479Sdim    if (len == 0)
1157288943Sdim      return mapWindowsError(::GetLastError());
1158276479Sdim  }
1159261991Sdim
1160261991Sdim  // Make utf16 null terminated.
1161261991Sdim  utf16.push_back(0);
1162261991Sdim  utf16.pop_back();
1163261991Sdim
1164276479Sdim  return std::error_code();
1165218885Sdim}
1166218885Sdim
1167280031Sdimstatic
1168280031Sdimstd::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16,
1169280031Sdim                                size_t utf16_len,
1170280031Sdim                                llvm::SmallVectorImpl<char> &utf8) {
1171276479Sdim  if (utf16_len) {
1172276479Sdim    // Get length.
1173280031Sdim    int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(),
1174276479Sdim                                    0, NULL, NULL);
1175261991Sdim
1176276479Sdim    if (len == 0)
1177288943Sdim      return mapWindowsError(::GetLastError());
1178261991Sdim
1179276479Sdim    utf8.reserve(len);
1180276479Sdim    utf8.set_size(len);
1181261991Sdim
1182276479Sdim    // Now do the actual conversion.
1183280031Sdim    len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(),
1184276479Sdim                                utf8.size(), NULL, NULL);
1185261991Sdim
1186276479Sdim    if (len == 0)
1187288943Sdim      return mapWindowsError(::GetLastError());
1188276479Sdim  }
1189261991Sdim
1190261991Sdim  // Make utf8 null terminated.
1191261991Sdim  utf8.push_back(0);
1192261991Sdim  utf8.pop_back();
1193261991Sdim
1194276479Sdim  return std::error_code();
1195218885Sdim}
1196280031Sdim
1197280031Sdimstd::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
1198280031Sdim                            llvm::SmallVectorImpl<char> &utf8) {
1199280031Sdim  return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8);
1200280031Sdim}
1201280031Sdim
1202280031Sdimstd::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
1203280031Sdim                             llvm::SmallVectorImpl<char> &utf8) {
1204280031Sdim  return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8);
1205280031Sdim}
1206309124Sdim
1207261991Sdim} // end namespace windows
1208261991Sdim} // end namespace sys
1209261991Sdim} // end namespace llvm
1210