diff --git a/toolsrc/include/vcpkg/base/files.h b/toolsrc/include/vcpkg/base/files.h index a5e04db25..ae699036c 100644 --- a/toolsrc/include/vcpkg/base/files.h +++ b/toolsrc/include/vcpkg/base/files.h @@ -31,7 +31,7 @@ namespace fs struct symlink_status_t { file_status operator()(const path& p, std::error_code& ec) const noexcept; - file_status operator()(const path& p, vcpkg::LineInfo li) const noexcept; + file_status operator()(vcpkg::LineInfo li, const path& p) const noexcept; }; struct is_symlink_t { diff --git a/toolsrc/include/vcpkg/base/work_queue.h b/toolsrc/include/vcpkg/base/work_queue.h index 70142e110..1c49cc1a7 100644 --- a/toolsrc/include/vcpkg/base/work_queue.h +++ b/toolsrc/include/vcpkg/base/work_queue.h @@ -12,17 +12,23 @@ namespace vcpkg namespace detail { // for SFINAE purposes, keep out of the class - template - auto call_moved_action(Action& action, + // also this sfinae is so weird because Backwards Compatibility with VS2015 + template()(std::declval(), + std::declval&>()))> + void call_moved_action(Action& action, const WorkQueue& work_queue, - ThreadLocalData& tld) -> decltype(static_cast(std::move(action)(tld, work_queue))) + ThreadLocalData& tld) { std::move(action)(tld, work_queue); } - template - auto call_moved_action(Action& action, const WorkQueue&, ThreadLocalData& tld) - -> decltype(static_cast(std::move(action)(tld))) + template()(std::declval())), + class = void> + void call_moved_action(Action& action, const WorkQueue&, ThreadLocalData& tld) { std::move(action)(tld); } @@ -32,7 +38,7 @@ namespace vcpkg struct WorkQueue { template - WorkQueue(std::uint16_t num_threads, LineInfo li, const F& tld_init) noexcept + WorkQueue(LineInfo li, std::uint16_t num_threads, const F& tld_init) noexcept { m_line_info = li; diff --git a/toolsrc/src/vcpkg-test/files.cpp b/toolsrc/src/vcpkg-test/files.cpp index 9e14cec0c..ff0176a93 100644 --- a/toolsrc/src/vcpkg-test/files.cpp +++ b/toolsrc/src/vcpkg-test/files.cpp @@ -115,7 +115,9 @@ TEST_CASE ("remove all", "[files]") fs::path fp; fs.remove_all(temp_dir, ec, fp); - REQUIRE_FALSE(ec); + if (ec) { + FAIL("remove_all failure on file: " << fp); + } REQUIRE_FALSE(fs.exists(temp_dir)); } diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 6c6945e44..4a5d3caf1 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -28,16 +28,9 @@ namespace fs::detail #if defined(_WIN32) static_cast(ec); - /* - do not find the permissions of the file -- it's unnecessary for the - things that vcpkg does. - if one were to add support for this in the future, one should look - into GetFileSecurityW - */ - perms permissions = perms::unknown; - WIN32_FILE_ATTRIBUTE_DATA file_attributes; file_type ft = file_type::unknown; + perms permissions = perms::unknown; if (!GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &file_attributes)) { ft = file_type::not_found; @@ -64,7 +57,7 @@ namespace fs::detail #endif } - file_status symlink_status_t::operator()(const path& p, vcpkg::LineInfo li) const noexcept + file_status symlink_status_t::operator()(vcpkg::LineInfo li, const path& p) const noexcept { std::error_code ec; auto result = symlink_status(p, ec); @@ -78,6 +71,41 @@ namespace vcpkg::Files { static const std::regex FILESYSTEM_INVALID_CHARACTERS_REGEX = std::regex(R"([\/:*?"<>|])"); + namespace { + // does _not_ follow symlinks + void set_writeable(const fs::path& path, std::error_code& ec) noexcept { +#if defined(_WIN32) + auto const file_name = path.c_str(); + WIN32_FILE_ATTRIBUTE_DATA attributes; + if (!GetFileAttributesExW(file_name, GetFileExInfoStandard, &attributes)) { + ec.assign(GetLastError(), std::system_category()); + return; + } + + auto dw_attributes = attributes.dwFileAttributes; + dw_attributes &= ~FILE_ATTRIBUTE_READONLY; + if (!SetFileAttributesW(file_name, dw_attributes)) { + ec.assign(GetLastError(), std::system_category()); + } +#else + struct stat s; + if (lstat(path.c_str(), &s)) { + ec.assign(errno, std::system_category()); + return; + } + + auto mode = s.st_mode; + // if the file is a symlink, perms don't matter + if (!(mode & S_IFLNK)) { + mode |= S_IWUSR; + if (chmod(path.c_str(), mode)) { + ec.assign(errno, std::system_category()); + } + } +#endif + } + } + std::string Filesystem::read_contents(const fs::path& path, LineInfo linfo) const { auto maybe_contents = this->read_contents(path); @@ -384,6 +412,9 @@ namespace vcpkg::Files } } + set_writeable(current_path, ec); + if (check_ec(ec, info, queue, current_path)) return; + if (fs::stdfs::remove(current_path, ec)) { info.files_deleted.fetch_add(1, std::memory_order_relaxed); @@ -447,7 +478,7 @@ namespace vcpkg::Files return remove::tld{path, index, files_deleted, ec_mutex, ec, failure_point}; }; - remove::queue queue{4, VCPKG_LINE_INFO, tld_gen}; + remove::queue queue{VCPKG_LINE_INFO, 4, tld_gen}; // note: we don't actually start the queue running until the // `join()`. This allows us to rename all the top-level files in diff --git a/toolsrc/vcpkgtest/vcpkgtest.vcxproj b/toolsrc/vcpkgtest/vcpkgtest.vcxproj index 530dfbc5d..d656de747 100644 --- a/toolsrc/vcpkgtest/vcpkgtest.vcxproj +++ b/toolsrc/vcpkgtest/vcpkgtest.vcxproj @@ -19,19 +19,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -39,8 +39,8 @@ - - + + {F27B8DB0-1279-4AF8-A2E3-1D49C4F0220D} diff --git a/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters b/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters index d9808ca89..74a746af1 100644 --- a/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters +++ b/toolsrc/vcpkgtest/vcpkgtest.vcxproj.filters @@ -15,43 +15,43 @@ - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files @@ -63,4 +63,4 @@ Header Files - \ No newline at end of file +