Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/llfio.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2021-03-15 14:37:37 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2021-03-15 14:37:37 +0300
commit17a15470b8d079625732bccfc96a3dd45e18f1c1 (patch)
tree7313433d449358ac1a5094b6fcf97de275b4e9cd
parent545a722a055dcc38e7f80520a7a34008bfa9a86f (diff)
Fix inability to open directory junctions on Windows using `symlink_handle` (issue #73).
-rw-r--r--cmake/tests.cmake1
-rw-r--r--include/llfio/revision.hpp6
-rw-r--r--include/llfio/v2.0/detail/impl/windows/symlink_handle.ipp29
-rw-r--r--include/llfio/v2.0/symlink_handle.hpp7
-rw-r--r--test/tests/issue0073.cpp67
5 files changed, 95 insertions, 15 deletions
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
index 8448643e..b216ccba 100644
--- a/cmake/tests.cmake
+++ b/cmake/tests.cmake
@@ -15,6 +15,7 @@ set(llfio_TESTS
"test/tests/issue0009.cpp"
"test/tests/issue0027.cpp"
"test/tests/issue0028.cpp"
+ "test/tests/issue0073.cpp"
"test/tests/large_pages.cpp"
"test/tests/map_handle_create_close/kernel_map_handle.cpp.hpp"
"test/tests/map_handle_create_close/runner.cpp"
diff --git a/include/llfio/revision.hpp b/include/llfio/revision.hpp
index ef743f15..4f6234d6 100644
--- a/include/llfio/revision.hpp
+++ b/include/llfio/revision.hpp
@@ -1,4 +1,4 @@
// Note the second line of this file must ALWAYS be the git SHA, third line ALWAYS the git SHA update time
-#define LLFIO_PREVIOUS_COMMIT_REF 17d8156ac89e3b8c6aa19a14e0dd723bd65e0902
-#define LLFIO_PREVIOUS_COMMIT_DATE "2021-03-09 09:38:56 +00:00"
-#define LLFIO_PREVIOUS_COMMIT_UNIQUE 17d8156a
+#define LLFIO_PREVIOUS_COMMIT_REF 545a722a055dcc38e7f80520a7a34008bfa9a86f
+#define LLFIO_PREVIOUS_COMMIT_DATE "2021-03-15 10:40:32 +00:00"
+#define LLFIO_PREVIOUS_COMMIT_UNIQUE 545a722a
diff --git a/include/llfio/v2.0/detail/impl/windows/symlink_handle.ipp b/include/llfio/v2.0/detail/impl/windows/symlink_handle.ipp
index 54ec1daf..97dde7b3 100644
--- a/include/llfio/v2.0/detail/impl/windows/symlink_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/windows/symlink_handle.ipp
@@ -35,7 +35,9 @@ result<symlink_handle> symlink_handle::reopen(mode mode_, deadline /*unused*/) c
return ret;
}
-LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<symlink_handle> symlink_handle::symlink(const path_handle &base, symlink_handle::path_view_type path, symlink_handle::mode _mode, symlink_handle::creation _creation, flag flags) noexcept
+LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<symlink_handle> symlink_handle::symlink(const path_handle &base, symlink_handle::path_view_type path,
+ symlink_handle::mode _mode, symlink_handle::creation _creation,
+ flag flags) noexcept
{
windows_nt_kernel::init();
using namespace windows_nt_kernel;
@@ -104,7 +106,6 @@ LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<symlink_handle> symlink_handle::symlink(c
attribs &= 0x00ffffff; // the real attributes only, not the win32 flags
OUTCOME_TRY(auto &&ntflags, ntflags_from_handle_caching_and_flags(nativeh, caching::all, flags));
ntflags |= 0x4000 /*FILE_OPEN_FOR_BACKUP_INTENT*/ | 0x00200000 /*FILE_OPEN_REPARSE_POINT*/;
- ntflags |= 0x040 /*FILE_NON_DIRECTORY_FILE*/; // do not open a directory
IO_STATUS_BLOCK isb = make_iostatus();
path_view::c_str<> zpath(path, path_view::not_zero_terminated);
@@ -195,7 +196,8 @@ result<symlink_handle::buffers_type> symlink_handle::read(symlink_handle::io_req
size_t bytes;
for(;;)
{
- rpd = req.kernelbuffer.empty() ? reinterpret_cast<REPARSE_DATA_BUFFER *>(tofill._kernel_buffer.get()) : reinterpret_cast<REPARSE_DATA_BUFFER *>(req.kernelbuffer.data());
+ rpd = req.kernelbuffer.empty() ? reinterpret_cast<REPARSE_DATA_BUFFER *>(tofill._kernel_buffer.get()) :
+ reinterpret_cast<REPARSE_DATA_BUFFER *>(req.kernelbuffer.data());
bytes = req.kernelbuffer.empty() ? static_cast<ULONG>(tofill._kernel_buffer_size) : static_cast<ULONG>(req.kernelbuffer.size());
DWORD written = 0;
if(!DeviceIoControl(_v.h, FSCTL_GET_REPARSE_POINT, NULL, 0, rpd, (DWORD) bytes, &written, NULL))
@@ -235,7 +237,8 @@ result<symlink_handle::buffers_type> symlink_handle::read(symlink_handle::io_req
}
}
-result<symlink_handle::const_buffers_type> symlink_handle::write(symlink_handle::io_request<symlink_handle::const_buffers_type> req, deadline /*unused*/) noexcept
+result<symlink_handle::const_buffers_type> symlink_handle::write(symlink_handle::io_request<symlink_handle::const_buffers_type> req,
+ deadline /*unused*/) noexcept
{
windows_nt_kernel::init();
using namespace windows_nt_kernel;
@@ -267,7 +270,8 @@ result<symlink_handle::const_buffers_type> symlink_handle::write(symlink_handle:
rpd->SymbolicLinkReparseBuffer.SubstituteNameLength = (USHORT) destpathbytes - 6;
rpd->SymbolicLinkReparseBuffer.PrintNameOffset = (USHORT)(destpathbytes - 6 + sizeof(wchar_t));
rpd->SymbolicLinkReparseBuffer.PrintNameLength = (USHORT) destpathbytes - 6;
- memcpy(rpd->SymbolicLinkReparseBuffer.PathBuffer + rpd->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t), zpath.buffer + 3, rpd->SymbolicLinkReparseBuffer.PrintNameLength - 6 + sizeof(wchar_t));
+ memcpy(rpd->SymbolicLinkReparseBuffer.PathBuffer + rpd->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t), zpath.buffer + 3,
+ rpd->SymbolicLinkReparseBuffer.PrintNameLength - 6 + sizeof(wchar_t));
}
else
{
@@ -276,10 +280,12 @@ result<symlink_handle::const_buffers_type> symlink_handle::write(symlink_handle:
rpd->SymbolicLinkReparseBuffer.SubstituteNameLength = (USHORT) destpathbytes;
rpd->SymbolicLinkReparseBuffer.PrintNameOffset = (USHORT)(destpathbytes + sizeof(wchar_t));
rpd->SymbolicLinkReparseBuffer.PrintNameLength = (USHORT) destpathbytes;
- memcpy(rpd->SymbolicLinkReparseBuffer.PathBuffer + rpd->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t), zpath.buffer, rpd->SymbolicLinkReparseBuffer.PrintNameLength + sizeof(wchar_t));
+ memcpy(rpd->SymbolicLinkReparseBuffer.PathBuffer + rpd->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t), zpath.buffer,
+ rpd->SymbolicLinkReparseBuffer.PrintNameLength + sizeof(wchar_t));
}
rpd->SymbolicLinkReparseBuffer.Flags = req.buffers.path().is_relative() ? 0x1 /*SYMLINK_FLAG_RELATIVE*/ : 0;
- rpd->ReparseDataLength = (USHORT)(rpd->SymbolicLinkReparseBuffer.SubstituteNameLength + rpd->SymbolicLinkReparseBuffer.PrintNameLength + 2 * sizeof(wchar_t) + reparsebufferheaderlen);
+ rpd->ReparseDataLength = (USHORT)(rpd->SymbolicLinkReparseBuffer.SubstituteNameLength + rpd->SymbolicLinkReparseBuffer.PrintNameLength +
+ 2 * sizeof(wchar_t) + reparsebufferheaderlen);
break;
}
case symlink_type::win_wsl:
@@ -296,7 +302,8 @@ result<symlink_handle::const_buffers_type> symlink_handle::write(symlink_handle:
rpd->MountPointReparseBuffer.SubstituteNameLength = (USHORT) destpathbytes - 6;
rpd->MountPointReparseBuffer.PrintNameOffset = (USHORT)(destpathbytes - 6 + sizeof(wchar_t));
rpd->MountPointReparseBuffer.PrintNameLength = (USHORT) destpathbytes - 6;
- memcpy(rpd->MountPointReparseBuffer.PathBuffer + rpd->MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t), zpath.buffer + 3, rpd->MountPointReparseBuffer.PrintNameLength - 6 + sizeof(wchar_t));
+ memcpy(rpd->MountPointReparseBuffer.PathBuffer + rpd->MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t), zpath.buffer + 3,
+ rpd->MountPointReparseBuffer.PrintNameLength - 6 + sizeof(wchar_t));
}
else
{
@@ -305,9 +312,11 @@ result<symlink_handle::const_buffers_type> symlink_handle::write(symlink_handle:
rpd->MountPointReparseBuffer.SubstituteNameLength = (USHORT) destpathbytes;
rpd->MountPointReparseBuffer.PrintNameOffset = (USHORT)(destpathbytes + sizeof(wchar_t));
rpd->MountPointReparseBuffer.PrintNameLength = (USHORT) destpathbytes;
- memcpy(rpd->MountPointReparseBuffer.PathBuffer + rpd->MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t), zpath.buffer, rpd->MountPointReparseBuffer.PrintNameLength + sizeof(wchar_t));
+ memcpy(rpd->MountPointReparseBuffer.PathBuffer + rpd->MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t), zpath.buffer,
+ rpd->MountPointReparseBuffer.PrintNameLength + sizeof(wchar_t));
}
- rpd->ReparseDataLength = (USHORT)(rpd->MountPointReparseBuffer.SubstituteNameLength + rpd->MountPointReparseBuffer.PrintNameLength + 2 * sizeof(wchar_t) + reparsebufferheaderlen);
+ rpd->ReparseDataLength =
+ (USHORT)(rpd->MountPointReparseBuffer.SubstituteNameLength + rpd->MountPointReparseBuffer.PrintNameLength + 2 * sizeof(wchar_t) + reparsebufferheaderlen);
break;
}
}
diff --git a/include/llfio/v2.0/symlink_handle.hpp b/include/llfio/v2.0/symlink_handle.hpp
index 9190f109..a5d662bd 100644
--- a/include/llfio/v2.0/symlink_handle.hpp
+++ b/include/llfio/v2.0/symlink_handle.hpp
@@ -1,5 +1,5 @@
/* A handle to a symbolic link
-(C) 2018 Niall Douglas <http://www.nedproductions.biz/> (20 commits)
+(C) 2018-2021 Niall Douglas <http://www.nedproductions.biz/> (20 commits)
File Created: Jul 2018
@@ -78,6 +78,9 @@ code comparing equal to `errc::protocol_not_supported`. One should note that mod
links was not historically permitted by users with ordinary permissions on Microsoft Windows,
however recent versions of Windows 10 do support symbolic links for ordinary users. All versions
of Windows support directory symbolic links (junctions), these work for all users in any configuration.
+
+(Note that to create a directory junction on Windows, first create a directory, open that
+empty directory for modification using symlink_handle, then write using `symlink_type::win_junction`)
*/
class LLFIO_DECL symlink_handle : public handle, public fs_handle
{
@@ -112,7 +115,7 @@ public:
none, //!<! No link
symbolic, //!< Standard symbolic link
- win_wsl, //!< WSL symbolic link (Windows only)
+ win_wsl, //!< WSL symbolic link (Windows only, not actually implemented currently)
win_junction //!< NTFS directory junction (Windows only, directories and volumes only)
};
diff --git a/test/tests/issue0073.cpp b/test/tests/issue0073.cpp
new file mode 100644
index 00000000..75f82ce2
--- /dev/null
+++ b/test/tests/issue0073.cpp
@@ -0,0 +1,67 @@
+/* Integration test kernel for issue #73 Windows directory junctions cannot be opened with symlink_handle
+(C) 2021 Niall Douglas <http://www.nedproductions.biz/> (2 commits)
+File Created: Mar 2021
+
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License in the accompanying file
+Licence.txt or at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file Licence.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+*/
+
+#include "../test_kernel_decl.hpp"
+
+static inline void TestIssue0073()
+{
+#ifndef _WIN32
+ return;
+#endif
+ namespace llfio = LLFIO_V2_NAMESPACE;
+
+ auto tempdirh = llfio::temp_directory().value();
+ auto untempdir = llfio::make_scope_exit([&]() noexcept { (void) llfio::algorithm::reduce(std::move(tempdirh)); });
+ std::cout << "NOTE: Test directory can be found at " << tempdirh.current_path().value() << std::endl;
+
+ // Test windows junctions
+ {
+ auto dirh =
+ llfio::directory_handle::directory(tempdirh, "testjunction", llfio::symlink_handle::mode::write, llfio::symlink_handle::creation::if_needed).value();
+ auto h = llfio::symlink_handle::symlink(dirh, {}, llfio::symlink_handle::mode::write).value();
+ h.write({llfio::symlink_handle::const_buffers_type("linkcontent", llfio::symlink_handle::symlink_type::win_junction)}).value();
+ auto rb = h.read().value();
+ BOOST_CHECK(rb.type() == llfio::symlink_handle::symlink_type::win_junction);
+ BOOST_CHECK(rb.path().path() == "linkcontent");
+ h.unlink().value();
+ }
+
+ // Test normal symbolic links
+ {
+ auto h_ = llfio::symlink_handle::symlink(tempdirh, "testlink", llfio::symlink_handle::mode::write, llfio::symlink_handle::creation::if_needed);
+ if(!h_ && h_.error() == llfio::errc::function_not_supported)
+ {
+ std::cout << "NOTE: Failed to create symbolic link, assuming lack of SeCreateSymbolicLinkPrivilege privileges." << std::endl;
+ return;
+ }
+ auto h = std::move(h_).value();
+ h.write("linkcontent").value();
+ auto rb = h.read().value();
+ BOOST_CHECK(rb.type() == llfio::symlink_handle::symlink_type::symbolic);
+ BOOST_CHECK(rb.path().path() == "linkcontent");
+ h.unlink().value();
+ }
+}
+
+KERNELTEST_TEST_KERNEL(regression, llfio, issues, 0073, "Tests issue #0073 Windows directory junctions cannot be opened with symlink_handle", TestIssue0073())