diff options
Diffstat (limited to 'lib/Support/Windows')
| -rw-r--r-- | lib/Support/Windows/Memory.inc | 80 | ||||
| -rw-r--r-- | lib/Support/Windows/Path.inc | 479 | ||||
| -rw-r--r-- | lib/Support/Windows/Process.inc | 5 | ||||
| -rw-r--r-- | lib/Support/Windows/Program.inc | 57 | ||||
| -rw-r--r-- | lib/Support/Windows/Signals.inc | 29 | 
5 files changed, 365 insertions, 285 deletions
| diff --git a/lib/Support/Windows/Memory.inc b/lib/Support/Windows/Memory.inc index 7eab9ff3afd2..318e65aaa9ee 100644 --- a/lib/Support/Windows/Memory.inc +++ b/lib/Support/Windows/Memory.inc @@ -160,85 +160,5 @@ void Memory::InvalidateInstructionCache(    FlushInstructionCache(GetCurrentProcess(), Addr, Len);  } - -MemoryBlock Memory::AllocateRWX(size_t NumBytes, -                                const MemoryBlock *NearBlock, -                                std::string *ErrMsg) { -  MemoryBlock MB; -  std::error_code EC; -  MB = allocateMappedMemory(NumBytes, NearBlock, -                            MF_READ|MF_WRITE|MF_EXEC, EC); -  if (EC != std::error_code() && ErrMsg) { -    MakeErrMsg(ErrMsg, EC.message()); -  } -  return MB; -} - -bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { -  std::error_code EC = releaseMappedMemory(M); -  if (EC == std::error_code()) -    return false; -  MakeErrMsg(ErrMsg, EC.message()); -  return true; -} - -static DWORD getProtection(const void *addr) { -  MEMORY_BASIC_INFORMATION info; -  if (sizeof(info) == ::VirtualQuery(addr, &info, sizeof(info))) { -    return info.Protect; -  } -  return 0; -} - -bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { -  if (!setRangeWritable(M.Address, M.Size)) { -    return MakeErrMsg(ErrMsg, "Cannot set memory to writeable"); -  } -  return true; -} - -bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { -  if (!setRangeExecutable(M.Address, M.Size)) { -    return MakeErrMsg(ErrMsg, "Cannot set memory to executable"); -  } -  return true; -} - -bool Memory::setRangeWritable(const void *Addr, size_t Size) { -  DWORD prot = getProtection(Addr); -  if (!prot) -    return false; - -  if (prot == PAGE_EXECUTE || prot == PAGE_EXECUTE_READ) { -    prot = PAGE_EXECUTE_READWRITE; -  } else if (prot == PAGE_NOACCESS || prot == PAGE_READONLY) { -    prot = PAGE_READWRITE; -  } - -  DWORD oldProt; -  Memory::InvalidateInstructionCache(Addr, Size); -  return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) -            == TRUE; -} - -bool Memory::setRangeExecutable(const void *Addr, size_t Size) { -  DWORD prot = getProtection(Addr); -  if (!prot) -    return false; - -  if (prot == PAGE_NOACCESS) { -    prot = PAGE_EXECUTE; -  } else if (prot == PAGE_READONLY) { -    prot = PAGE_EXECUTE_READ; -  } else if (prot == PAGE_READWRITE) { -    prot = PAGE_EXECUTE_READWRITE; -  } - -  DWORD oldProt; -  Memory::InvalidateInstructionCache(Addr, Size); -  return ::VirtualProtect(const_cast<LPVOID>(Addr), Size, prot, &oldProt) -            == TRUE; -} -  } // namespace sys  } // namespace llvm diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index b00d3905f658..f81790b17df5 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -94,13 +94,16 @@ std::error_code widenPath(const Twine &Path8,          return EC;        FullPath.append(CurPath);      } -    // Traverse the requested path, canonicalizing . and .. as we go (because -    // the \\?\ prefix is documented to treat them as real components). -    // The iterators don't report separators and append() always attaches -    // preferred_separator so we don't need to call native() on the result. +    // Traverse the requested path, canonicalizing . and .. (because the \\?\ +    // prefix is documented to treat them as real components).  Ignore +    // separators, which can be returned from the iterator if the path has a +    // drive name.  We don't need to call native() on the result since append() +    // always attaches preferred_separator.      for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str),                                           E = llvm::sys::path::end(Path8Str);                                           I != E; ++I) { +      if (I->size() == 1 && is_separator((*I)[0])) +        continue;        if (I->size() == 1 && *I == ".")          continue;        if (I->size() == 2 && *I == "..") @@ -165,14 +168,14 @@ ErrorOr<space_info> disk_space(const Twine &Path) {    return SpaceInfo;  } -TimePoint<> file_status::getLastAccessedTime() const { +TimePoint<> basic_file_status::getLastAccessedTime() const {    FILETIME Time;    Time.dwLowDateTime = LastAccessedTimeLow;    Time.dwHighDateTime = LastAccessedTimeHigh;    return toTimePoint(Time);  } -TimePoint<> file_status::getLastModificationTime() const { +TimePoint<> basic_file_status::getLastModificationTime() const {    FILETIME Time;    Time.dwLowDateTime = LastWriteTimeLow;    Time.dwHighDateTime = LastWriteTimeHigh; @@ -250,35 +253,38 @@ std::error_code create_link(const Twine &to, const Twine &from) {  }  std::error_code create_hard_link(const Twine &to, const Twine &from) { -	return create_link(to, from); +  return create_link(to, from);  }  std::error_code remove(const Twine &path, bool IgnoreNonExisting) {    SmallVector<wchar_t, 128> path_utf16; -  file_status ST; -  if (std::error_code EC = status(path, ST)) { -    if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) -      return EC; -    return std::error_code(); -  } -    if (std::error_code ec = widenPath(path, path_utf16))      return ec; -  if (ST.type() == file_type::directory_file) { -    if (!::RemoveDirectoryW(c_str(path_utf16))) { -      std::error_code EC = mapWindowsError(::GetLastError()); -      if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) -        return EC; -    } -    return std::error_code(); -  } -  if (!::DeleteFileW(c_str(path_utf16))) { +  // We don't know whether this is a file or a directory, and remove() can +  // accept both. The usual way to delete a file or directory is to use one of +  // the DeleteFile or RemoveDirectory functions, but that requires you to know +  // which one it is. We could stat() the file to determine that, but that would +  // cost us additional system calls, which can be slow in a directory +  // containing a large number of files. So instead we call CreateFile directly. +  // The important part is the FILE_FLAG_DELETE_ON_CLOSE flag, which causes the +  // file to be deleted once it is closed. We also use the flags +  // FILE_FLAG_BACKUP_SEMANTICS (which allows us to open directories), and +  // FILE_FLAG_OPEN_REPARSE_POINT (don't follow symlinks). +  ScopedFileHandle h(::CreateFileW( +      c_str(path_utf16), DELETE, +      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, +      OPEN_EXISTING, +      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | +          FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE, +      NULL)); +  if (!h) {      std::error_code EC = mapWindowsError(::GetLastError());      if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting)        return EC;    } +    return std::error_code();  } @@ -338,83 +344,261 @@ std::error_code is_local(const Twine &path, bool &result) {    return is_local_internal(WidePath, result);  } +static std::error_code realPathFromHandle(HANDLE H, +                                          SmallVectorImpl<wchar_t> &Buffer) { +  DWORD CountChars = ::GetFinalPathNameByHandleW( +      H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); +  if (CountChars > Buffer.capacity()) { +    // The buffer wasn't big enough, try again.  In this case the return value +    // *does* indicate the size of the null terminator. +    Buffer.reserve(CountChars); +    CountChars = ::GetFinalPathNameByHandleW( +        H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); +  } +  if (CountChars == 0) +    return mapWindowsError(GetLastError()); +  Buffer.set_size(CountChars); +  return std::error_code(); +} + +static std::error_code realPathFromHandle(HANDLE H, +                                          SmallVectorImpl<char> &RealPath) { +  RealPath.clear(); +  SmallVector<wchar_t, MAX_PATH> Buffer; +  if (std::error_code EC = realPathFromHandle(H, Buffer)) +    return EC; + +  const wchar_t *Data = Buffer.data(); +  DWORD CountChars = Buffer.size(); +  if (CountChars >= 4) { +    if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { +      CountChars -= 4; +      Data += 4; +    } +  } + +  // Convert the result from UTF-16 to UTF-8. +  return UTF16ToUTF8(Data, CountChars, RealPath); +} +  std::error_code is_local(int FD, bool &Result) {    SmallVector<wchar_t, 128> FinalPath;    HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); -  size_t Len = 128; -  do { -    FinalPath.reserve(Len); -    Len = ::GetFinalPathNameByHandleW(Handle, FinalPath.data(), -                                      FinalPath.capacity() - 1, VOLUME_NAME_NT); -    if (Len == 0) -      return mapWindowsError(::GetLastError()); -  } while (Len > FinalPath.capacity()); - -  FinalPath.set_size(Len); +  if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) +    return EC;    return is_local_internal(FinalPath, Result);  } -std::error_code rename(const Twine &from, const Twine &to) { -  // Convert to utf-16. -  SmallVector<wchar_t, 128> wide_from; -  SmallVector<wchar_t, 128> wide_to; -  if (std::error_code ec = widenPath(from, wide_from)) -    return ec; -  if (std::error_code ec = widenPath(to, wide_to)) -    return ec; +static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { +  FILE_DISPOSITION_INFO Disposition; +  Disposition.DeleteFile = Delete; +  if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition, +                                  sizeof(Disposition))) +    return mapWindowsError(::GetLastError()); +  return std::error_code(); +} -  std::error_code ec = std::error_code(); +static std::error_code removeFD(int FD) { +  HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); +  return setDeleteDisposition(Handle, true); +} -  // Retry while we see recoverable errors. -  // System scanners (eg. indexer) might open the source file when it is written -  // and closed. +/// In order to handle temporary files we want the following properties +/// +/// * The temporary file is deleted on crashes +/// * We can use (read, rename, etc) the temporary file. +/// * We can cancel the delete to keep the file. +/// +/// Using FILE_DISPOSITION_INFO with DeleteFile=true will create a file that is +/// deleted on close, but it has a few problems: +/// +/// * The file cannot be used. An attempt to open or rename the file will fail. +///   This makes the temporary file almost useless, as it cannot be part of +///   any other CreateFileW call in the current or in another process. +/// * It is not atomic. A crash just after CreateFileW or just after canceling +///   the delete will leave the file on disk. +/// +/// Using FILE_FLAG_DELETE_ON_CLOSE solves the first issues and the first part +/// of the second one, but there is no way to cancel it in place. What works is +/// to create a second handle to prevent the deletion, close the first one and +/// then clear DeleteFile with SetFileInformationByHandle. This requires +/// changing the handle and file descriptor the caller uses. +static std::error_code cancelDeleteOnClose(int &FD) { +  HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); +  SmallVector<wchar_t, MAX_PATH> Name; +  if (std::error_code EC = realPathFromHandle(Handle, Name)) +    return EC; +  HANDLE NewHandle = +      ::CreateFileW(Name.data(), GENERIC_READ | GENERIC_WRITE | DELETE, +                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, +                    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +  if (NewHandle == INVALID_HANDLE_VALUE) +    return mapWindowsError(::GetLastError()); +  if (close(FD)) +    return mapWindowsError(::GetLastError()); -  bool TryReplace = true; +  if (std::error_code EC = setDeleteDisposition(NewHandle, false)) +    return EC; -  for (int i = 0; i < 2000; i++) { -    if (i > 0) -      ::Sleep(1); +  FD = ::_open_osfhandle(intptr_t(NewHandle), 0); +  if (FD == -1) { +    ::CloseHandle(NewHandle); +    return mapWindowsError(ERROR_INVALID_HANDLE); +  } +  return std::error_code(); +} + +static std::error_code rename_internal(HANDLE FromHandle, const Twine &To, +                                       bool ReplaceIfExists) { +  SmallVector<wchar_t, 0> ToWide; +  if (auto EC = widenPath(To, ToWide)) +    return EC; + +  std::vector<char> RenameInfoBuf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + +                                  (ToWide.size() * sizeof(wchar_t))); +  FILE_RENAME_INFO &RenameInfo = +      *reinterpret_cast<FILE_RENAME_INFO *>(RenameInfoBuf.data()); +  RenameInfo.ReplaceIfExists = ReplaceIfExists; +  RenameInfo.RootDirectory = 0; +  RenameInfo.FileNameLength = ToWide.size(); +  std::copy(ToWide.begin(), ToWide.end(), &RenameInfo.FileName[0]); + +  SetLastError(ERROR_SUCCESS); +  if (!SetFileInformationByHandle(FromHandle, FileRenameInfo, &RenameInfo, +                                  RenameInfoBuf.size())) { +    unsigned Error = GetLastError(); +    if (Error == ERROR_SUCCESS) +      Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. +    return mapWindowsError(Error); +  } -    if (TryReplace) { -      // Try ReplaceFile first, as it is able to associate a new data stream -      // with the destination even if the destination file is currently open. -      if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL)) +  return std::error_code(); +} + +static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) { +  SmallVector<wchar_t, 128> WideTo; +  if (std::error_code EC = widenPath(To, WideTo)) +    return EC; + +  // We normally expect this loop to succeed after a few iterations. If it +  // requires more than 200 tries, it's more likely that the failures are due to +  // a true error, so stop trying. +  for (unsigned Retry = 0; Retry != 200; ++Retry) { +    auto EC = rename_internal(FromHandle, To, true); + +    if (EC == +        std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { +      // Wine doesn't support SetFileInformationByHandle in rename_internal. +      // Fall back to MoveFileEx. +      SmallVector<wchar_t, MAX_PATH> WideFrom; +      if (std::error_code EC2 = realPathFromHandle(FromHandle, WideFrom)) +        return EC2; +      if (::MoveFileExW(WideFrom.begin(), WideTo.begin(), +                        MOVEFILE_REPLACE_EXISTING))          return std::error_code(); +      return mapWindowsError(GetLastError()); +    } -      DWORD ReplaceError = ::GetLastError(); -      ec = mapWindowsError(ReplaceError); +    if (!EC || EC != errc::permission_denied) +      return EC; -      // If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or -      // ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW(). -      if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT || -          ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) { -        TryReplace = false; +    // The destination file probably exists and is currently open in another +    // process, either because the file was opened without FILE_SHARE_DELETE or +    // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to +    // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE +    // to arrange for the destination file to be deleted when the other process +    // closes it. +    ScopedFileHandle ToHandle( +        ::CreateFileW(WideTo.begin(), GENERIC_READ | DELETE, +                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, +                      NULL, OPEN_EXISTING, +                      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); +    if (!ToHandle) { +      auto EC = mapWindowsError(GetLastError()); +      // Another process might have raced with us and moved the existing file +      // out of the way before we had a chance to open it. If that happens, try +      // to rename the source file again. +      if (EC == errc::no_such_file_or_directory)          continue; +      return EC; +    } + +    BY_HANDLE_FILE_INFORMATION FI; +    if (!GetFileInformationByHandle(ToHandle, &FI)) +      return mapWindowsError(GetLastError()); + +    // Try to find a unique new name for the destination file. +    for (unsigned UniqueId = 0; UniqueId != 200; ++UniqueId) { +      std::string TmpFilename = (To + ".tmp" + utostr(UniqueId)).str(); +      if (auto EC = rename_internal(ToHandle, TmpFilename, false)) { +        if (EC == errc::file_exists || EC == errc::permission_denied) { +          // Again, another process might have raced with us and moved the file +          // before we could move it. Check whether this is the case, as it +          // might have caused the permission denied error. If that was the +          // case, we don't need to move it ourselves. +          ScopedFileHandle ToHandle2(::CreateFileW( +              WideTo.begin(), 0, +              FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, +              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); +          if (!ToHandle2) { +            auto EC = mapWindowsError(GetLastError()); +            if (EC == errc::no_such_file_or_directory) +              break; +            return EC; +          } +          BY_HANDLE_FILE_INFORMATION FI2; +          if (!GetFileInformationByHandle(ToHandle2, &FI2)) +            return mapWindowsError(GetLastError()); +          if (FI.nFileIndexHigh != FI2.nFileIndexHigh || +              FI.nFileIndexLow != FI2.nFileIndexLow || +              FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) +            break; +          continue; +        } +        return EC;        } -      // If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry -      // using ReplaceFileW(). -      if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED) -        continue; -      // We get ERROR_FILE_NOT_FOUND if the destination file is missing. -      // MoveFileEx can handle this case. -      if (ReplaceError != ERROR_ACCESS_DENIED && -          ReplaceError != ERROR_FILE_NOT_FOUND && -          ReplaceError != ERROR_SHARING_VIOLATION) -        break; +      break;      } -    if (::MoveFileExW(wide_from.begin(), wide_to.begin(), -                      MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) -      return std::error_code(); +    // Okay, the old destination file has probably been moved out of the way at +    // this point, so try to rename the source file again. Still, another +    // process might have raced with us to create and open the destination +    // file, so we need to keep doing this until we succeed. +  } + +  // The most likely root cause. +  return errc::permission_denied; +} + +static std::error_code rename_fd(int FromFD, const Twine &To) { +  HANDLE FromHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FromFD)); +  return rename_handle(FromHandle, To); +} + +std::error_code rename(const Twine &From, const Twine &To) { +  // Convert to utf-16. +  SmallVector<wchar_t, 128> WideFrom; +  if (std::error_code EC = widenPath(From, WideFrom)) +    return EC; -    DWORD MoveError = ::GetLastError(); -    ec = mapWindowsError(MoveError); -    if (MoveError != ERROR_ACCESS_DENIED) break; +  ScopedFileHandle FromHandle; +  // Retry this a few times to defeat badly behaved file system scanners. +  for (unsigned Retry = 0; Retry != 200; ++Retry) { +    if (Retry != 0) +      ::Sleep(10); +    FromHandle = +        ::CreateFileW(WideFrom.begin(), GENERIC_READ | DELETE, +                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, +                      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +    if (FromHandle) +      break;    } +  if (!FromHandle) +    return mapWindowsError(GetLastError()); -  return ec; +  return rename_handle(FromHandle, To);  }  std::error_code resize_file(int FD, uint64_t Size) { @@ -502,6 +686,15 @@ static bool isReservedName(StringRef path) {    return false;  } +static file_type file_type_from_attrs(DWORD Attrs) { +  return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file +                                            : file_type::regular_file; +} + +static perms perms_from_attrs(DWORD Attrs) { +  return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all; +} +  static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {    if (FileHandle == INVALID_HANDLE_VALUE)      goto handle_status_error; @@ -530,22 +723,14 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {    if (!::GetFileInformationByHandle(FileHandle, &Info))      goto handle_status_error; -  { -    file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) -                         ? file_type::directory_file -                         : file_type::regular_file; -    perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) -                            ? (all_read | all_exe) -                            : all_all; -    Result = file_status( -        Type, Permissions, Info.nNumberOfLinks, -        Info.ftLastAccessTime.dwHighDateTime, -        Info.ftLastAccessTime.dwLowDateTime, -        Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, -        Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, -        Info.nFileIndexHigh, Info.nFileIndexLow); -    return std::error_code(); -  } +  Result = file_status( +      file_type_from_attrs(Info.dwFileAttributes), +      perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks, +      Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime, +      Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, +      Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, +      Info.nFileIndexHigh, Info.nFileIndexLow); +  return std::error_code();  handle_status_error:    DWORD LastError = ::GetLastError(); @@ -637,10 +822,6 @@ std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {  std::error_code mapped_file_region::init(int FD, uint64_t Offset,                                           mapmode Mode) { -  // Make sure that the requested size fits within SIZE_T. -  if (Size > std::numeric_limits<SIZE_T>::max()) -    return make_error_code(errc::invalid_argument); -    HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));    if (FileHandle == INVALID_HANDLE_VALUE)      return make_error_code(errc::bad_file_descriptor); @@ -654,8 +835,8 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,    HANDLE FileMappingHandle =        ::CreateFileMappingW(FileHandle, 0, flprotect, -                           (Offset + Size) >> 32, -                           (Offset + Size) & 0xffffffff, +                           Hi_32(Size), +                           Lo_32(Size),                             0);    if (FileMappingHandle == NULL) {      std::error_code ec = mapWindowsError(GetLastError()); @@ -697,7 +878,7 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,    return std::error_code();  } -mapped_file_region::mapped_file_region(int fd, mapmode mode, uint64_t length, +mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,                                         uint64_t offset, std::error_code &ec)      : Size(length), Mapping() {    ec = init(fd, offset, mode); @@ -710,7 +891,7 @@ mapped_file_region::~mapped_file_region() {      ::UnmapViewOfFile(Mapping);  } -uint64_t mapped_file_region::size() const { +size_t mapped_file_region::size() const {    assert(Mapping && "Mapping failed but used anyway!");    return Size;  } @@ -731,6 +912,16 @@ int mapped_file_region::alignment() {    return SysInfo.dwAllocationGranularity;  } +static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) { +  return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes), +                           perms_from_attrs(FindData->dwFileAttributes), +                           FindData->ftLastAccessTime.dwHighDateTime, +                           FindData->ftLastAccessTime.dwLowDateTime, +                           FindData->ftLastWriteTime.dwHighDateTime, +                           FindData->ftLastWriteTime.dwLowDateTime, +                           FindData->nFileSizeHigh, FindData->nFileSizeLow); +} +  std::error_code detail::directory_iterator_construct(detail::DirIterState &it,                                                       StringRef path,                                                       bool follow_symlinks) { @@ -751,7 +942,9 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,    //  Get the first directory entry.    WIN32_FIND_DATAW FirstFind; -  ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); +  ScopedFindHandle FindHandle(::FindFirstFileExW( +      c_str(path_utf16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch, +      NULL, FIND_FIRST_EX_LARGE_FETCH));    if (!FindHandle)      return mapWindowsError(::GetLastError()); @@ -778,7 +971,8 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,    it.IterationHandle = intptr_t(FindHandle.take());    SmallString<128> directory_entry_path(path);    path::append(directory_entry_path, directory_entry_name_utf8); -  it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks); +  it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks, +                                    status_from_find_data(&FirstFind));    return std::error_code();  } @@ -814,36 +1008,13 @@ std::error_code detail::directory_iterator_increment(detail::DirIterState &it) {                        directory_entry_path_utf8))      return ec; -  it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); +  it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8), +                                   status_from_find_data(&FindData));    return std::error_code();  } -static std::error_code realPathFromHandle(HANDLE H, -                                          SmallVectorImpl<char> &RealPath) { -  RealPath.clear(); -  llvm::SmallVector<wchar_t, MAX_PATH> Buffer; -  DWORD CountChars = ::GetFinalPathNameByHandleW( -      H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); -  if (CountChars > Buffer.capacity()) { -    // The buffer wasn't big enough, try again.  In this case the return value -    // *does* indicate the size of the null terminator. -    Buffer.reserve(CountChars); -    CountChars = ::GetFinalPathNameByHandleW( -        H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); -  } -  if (CountChars == 0) -    return mapWindowsError(GetLastError()); - -  const wchar_t *Data = Buffer.data(); -  if (CountChars >= 4) { -    if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { -      CountChars -= 4; -      Data += 4; -    } -  } - -  // Convert the result from UTF-16 to UTF-8. -  return UTF16ToUTF8(Data, CountChars, RealPath); +ErrorOr<basic_file_status> directory_entry::status() const { +  return Status;  }  static std::error_code directoryRealPath(const Twine &Name, @@ -922,12 +1093,18 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,      CreationDisposition = CREATE_ALWAYS;    DWORD Access = GENERIC_WRITE; +  DWORD Attributes = FILE_ATTRIBUTE_NORMAL;    if (Flags & F_RW)      Access |= GENERIC_READ; +  if (Flags & F_Delete) { +    Access |= DELETE; +    Attributes |= FILE_FLAG_DELETE_ON_CLOSE; +  } -  HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, -                           FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, -                           CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); +  HANDLE H = +      ::CreateFileW(PathUTF16.data(), Access, +                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, +                    NULL, CreationDisposition, Attributes, NULL);    if (H == INVALID_HANDLE_VALUE) {      DWORD LastError = ::GetLastError(); @@ -959,42 +1136,6 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,    return std::error_code();  } -std::error_code getPathFromOpenFD(int FD, SmallVectorImpl<char> &ResultPath) { -  HANDLE FileHandle = reinterpret_cast<HANDLE>(::_get_osfhandle(FD)); -  if (FileHandle == INVALID_HANDLE_VALUE) -    return make_error_code(errc::bad_file_descriptor); - -  DWORD CharCount; -  SmallVector<wchar_t, 1024> TempPath; -  do { -    CharCount = ::GetFinalPathNameByHandleW(FileHandle, TempPath.begin(), -                                            TempPath.capacity(), -                                            FILE_NAME_NORMALIZED); -    if (CharCount < TempPath.capacity()) -      break; - -    // Reserve sufficient space for the path as well as the null character. Even -    // though the API does not document that it is required, if we reserve just -    // CharCount space, the function call will not store the resulting path and -    // still report success. -    TempPath.reserve(CharCount + 1); -  } while (true); - -  if (CharCount == 0) -    return mapWindowsError(::GetLastError()); - -  TempPath.set_size(CharCount); - -  // On earlier Windows releases, the character count includes the terminating -  // null. -  if (TempPath.back() == L'\0') { -    --CharCount; -    TempPath.pop_back(); -  } - -  return windows::UTF16ToUTF8(TempPath.data(), CharCount, ResultPath); -} -  std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {    // Convert to utf-16.    SmallVector<wchar_t, 128> Path16; diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index 18aef610d54a..3fe9f89f1ef5 100644 --- a/lib/Support/Windows/Process.inc +++ b/lib/Support/Windows/Process.inc @@ -129,9 +129,10 @@ Optional<std::string> Process::GetEnv(StringRef Name) {    size_t Size = MAX_PATH;    do {      Buf.reserve(Size); +    SetLastError(NO_ERROR);      Size = -        GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); -    if (Size == 0) +      GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); +    if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)        return None;      // Try again with larger buffer. diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index 721167da5b15..52921cd6a203 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -103,9 +103,10 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name,    return std::string(U8Result.begin(), U8Result.end());  } -static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) { +static HANDLE RedirectIO(Optional<StringRef> Path, int fd, +                         std::string *ErrMsg) {    HANDLE h; -  if (path == 0) { +  if (!Path) {      if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),                           GetCurrentProcess(), &h,                           0, TRUE, DUPLICATE_SAME_ACCESS)) @@ -114,10 +115,10 @@ static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) {    }    std::string fname; -  if (path->empty()) +  if (Path->empty())      fname = "NUL";    else -    fname = *path; +    fname = *Path;    SECURITY_ATTRIBUTES sa;    sa.nLength = sizeof(sa); @@ -125,7 +126,7 @@ static HANDLE RedirectIO(const StringRef *path, int fd, std::string* ErrMsg) {    sa.bInheritHandle = TRUE;    SmallVector<wchar_t, 128> fnameUnicode; -  if (path->empty()) { +  if (Path->empty()) {      // Don't play long-path tricks on "NUL".      if (windows::UTF8ToUTF16(fname, fnameUnicode))        return INVALID_HANDLE_VALUE; @@ -207,19 +208,19 @@ static unsigned int ArgLenWithQuotes(const char *Str) {  } -static std::unique_ptr<char[]> flattenArgs(const char **args) { +static std::unique_ptr<char[]> flattenArgs(const char **Args) {    // First, determine the length of the command line.    unsigned len = 0; -  for (unsigned i = 0; args[i]; i++) { -    len += ArgLenWithQuotes(args[i]) + 1; +  for (unsigned i = 0; Args[i]; i++) { +    len += ArgLenWithQuotes(Args[i]) + 1;    }    // Now build the command line.    std::unique_ptr<char[]> command(new char[len+1]);    char *p = command.get(); -  for (unsigned i = 0; args[i]; i++) { -    const char *arg = args[i]; +  for (unsigned i = 0; Args[i]; i++) { +    const char *arg = Args[i];      const char *start = arg;      bool needsQuoting = ArgNeedsQuotes(arg); @@ -248,9 +249,9 @@ static std::unique_ptr<char[]> flattenArgs(const char **args) {    return command;  } -static bool Execute(ProcessInfo &PI, StringRef Program, const char **args, -                    const char **envp, const StringRef **redirects, -                    unsigned memoryLimit, std::string *ErrMsg) { +static bool Execute(ProcessInfo &PI, StringRef Program, const char **Args, +                    const char **Envp, ArrayRef<Optional<StringRef>> Redirects, +                    unsigned MemoryLimit, std::string *ErrMsg) {    if (!sys::fs::can_execute(Program)) {      if (ErrMsg)        *ErrMsg = "program not executable"; @@ -268,18 +269,18 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,    // Windows wants a command line, not an array of args, to pass to the new    // process.  We have to concatenate them all, while quoting the args that    // have embedded spaces (or are empty). -  std::unique_ptr<char[]> command = flattenArgs(args); +  std::unique_ptr<char[]> command = flattenArgs(Args);    // The pointer to the environment block for the new process.    std::vector<wchar_t> EnvBlock; -  if (envp) { +  if (Envp) {      // An environment block consists of a null-terminated block of      // null-terminated strings. Convert the array of environment variables to      // an environment block by concatenating them. -    for (unsigned i = 0; envp[i]; ++i) { +    for (unsigned i = 0; Envp[i]; ++i) {        SmallVector<wchar_t, MAX_PATH> EnvString; -      if (std::error_code ec = windows::UTF8ToUTF16(envp[i], EnvString)) { +      if (std::error_code ec = windows::UTF8ToUTF16(Envp[i], EnvString)) {          SetLastError(ec.value());          MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16");          return false; @@ -299,21 +300,21 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,    si.hStdOutput = INVALID_HANDLE_VALUE;    si.hStdError = INVALID_HANDLE_VALUE; -  if (redirects) { +  if (!Redirects.empty()) {      si.dwFlags = STARTF_USESTDHANDLES; -    si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); +    si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg);      if (si.hStdInput == INVALID_HANDLE_VALUE) {        MakeErrMsg(ErrMsg, "can't redirect stdin");        return false;      } -    si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); +    si.hStdOutput = RedirectIO(Redirects[1], 1, ErrMsg);      if (si.hStdOutput == INVALID_HANDLE_VALUE) {        CloseHandle(si.hStdInput);        MakeErrMsg(ErrMsg, "can't redirect stdout");        return false;      } -    if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { +    if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) {        // If stdout and stderr should go to the same place, redirect stderr        // to the handle already open for stdout.        if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, @@ -326,7 +327,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,        }      } else {        // Just redirect stderr -      si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); +      si.hStdError = RedirectIO(Redirects[2], 2, ErrMsg);        if (si.hStdError == INVALID_HANDLE_VALUE) {          CloseHandle(si.hStdInput);          CloseHandle(si.hStdOutput); @@ -386,14 +387,14 @@ static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,    // Assign the process to a job if a memory limit is defined.    ScopedJobHandle hJob; -  if (memoryLimit != 0) { +  if (MemoryLimit != 0) {      hJob = CreateJobObjectW(0, 0);      bool success = false;      if (hJob) {        JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;        memset(&jeli, 0, sizeof(jeli));        jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; -      jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; +      jeli.ProcessMemoryLimit = uintptr_t(MemoryLimit) * 1048576;        if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,                                    &jeli, sizeof(jeli))) {          if (AssignProcessToJobObject(hJob, pi.hProcess)) @@ -534,16 +535,16 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,    return EC;  } -bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef<const char*> Args) { +bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, +                                                  ArrayRef<const char *> Args) {    // The documented max length of the command line passed to CreateProcess.    static const size_t MaxCommandStringLength = 32768;    // Account for the trailing space for the program path and the    // trailing NULL of the last argument.    size_t ArgLength = ArgLenWithQuotes(Program.str().c_str()) + 2; -  for (ArrayRef<const char*>::iterator I = Args.begin(), E = Args.end(); -       I != E; ++I) { +  for (const char* Arg : Args) {      // Account for the trailing space for every arg -    ArgLength += ArgLenWithQuotes(*I) + 1; +    ArgLength += ArgLenWithQuotes(Arg) + 1;      if (ArgLength > MaxCommandStringLength) {        return false;      } diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index 1ef51888baf3..21dd2dd13754 100644 --- a/lib/Support/Windows/Signals.inc +++ b/lib/Support/Windows/Signals.inc @@ -212,8 +212,14 @@ static StringRef Argv0;  enum {  #if defined(_M_X64)    NativeMachineType = IMAGE_FILE_MACHINE_AMD64 -#else +#elif defined(_M_ARM64) +  NativeMachineType = IMAGE_FILE_MACHINE_ARM64 +#elif defined(_M_IX86)    NativeMachineType = IMAGE_FILE_MACHINE_I386 +#elif defined(_M_ARM) +  NativeMachineType = IMAGE_FILE_MACHINE_ARMNT +#else +  NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN  #endif  }; @@ -318,18 +324,18 @@ static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess,      using namespace llvm;      // Print the PC in hexadecimal.      DWORD64 PC = StackFrame.AddrPC.Offset; -#if defined(_M_X64) +#if defined(_M_X64) || defined(_M_ARM64)      OS << format("0x%016llX", PC); -#elif defined(_M_IX86) +#elif defined(_M_IX86) || defined(_M_ARM)      OS << format("0x%08lX", static_cast<DWORD>(PC));  #endif  // Print the parameters.  Assume there are four. -#if defined(_M_X64) +#if defined(_M_X64) || defined(_M_ARM64)      OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)",              StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2],              StackFrame.Params[3]); -#elif defined(_M_IX86) +#elif defined(_M_IX86) || defined(_M_ARM)      OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)",              static_cast<DWORD>(StackFrame.Params[0]),              static_cast<DWORD>(StackFrame.Params[1]), @@ -526,10 +532,14 @@ void llvm::sys::PrintStackTrace(raw_ostream &OS) {    StackFrame.AddrPC.Offset = Context.Rip;    StackFrame.AddrStack.Offset = Context.Rsp;    StackFrame.AddrFrame.Offset = Context.Rbp; -#else +#elif defined(_M_IX86)    StackFrame.AddrPC.Offset = Context.Eip;    StackFrame.AddrStack.Offset = Context.Esp;    StackFrame.AddrFrame.Offset = Context.Ebp; +#elif defined(_M_ARM64) || defined(_M_ARM) +  StackFrame.AddrPC.Offset = Context.Pc; +  StackFrame.AddrStack.Offset = Context.Sp; +  StackFrame.AddrFrame.Offset = Context.Fp;  #endif    StackFrame.AddrPC.Mode = AddrModeFlat;    StackFrame.AddrStack.Mode = AddrModeFlat; @@ -804,6 +814,13 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {    StackFrame.AddrStack.Mode = AddrModeFlat;    StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;    StackFrame.AddrFrame.Mode = AddrModeFlat; +#elif defined(_M_ARM64) || defined(_M_ARM) +  StackFrame.AddrPC.Offset = ep->ContextRecord->Pc; +  StackFrame.AddrPC.Mode = AddrModeFlat; +  StackFrame.AddrStack.Offset = ep->ContextRecord->Sp; +  StackFrame.AddrStack.Mode = AddrModeFlat; +  StackFrame.AddrFrame.Offset = ep->ContextRecord->Fp; +  StackFrame.AddrFrame.Mode = AddrModeFlat;  #endif    HANDLE hProcess = GetCurrentProcess(); | 
