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-01-29 19:38:05 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2021-01-29 19:38:05 +0300
commitfa2e4c095d5884dfc8185e31005606443edeae69 (patch)
tree7bb3766903ba25a57afb0675666899eb7d2d9d74
parent48ee8bae656cb5d53f38feb462caa53e1128b76d (diff)
Port from AFIO v1 `normalise_path()`, whose API I have improved and made more directed as `to_win32_path()`.
-rw-r--r--include/llfio/revision.hpp6
-rw-r--r--include/llfio/v2.0/detail/impl/windows/fs_handle.ipp163
-rw-r--r--include/llfio/v2.0/detail/impl/windows/handle.ipp3
-rw-r--r--include/llfio/v2.0/fs_handle.hpp100
-rw-r--r--include/llfio/v2.0/path_view.hpp47
-rw-r--r--test/tests/current_path.cpp144
6 files changed, 405 insertions, 58 deletions
diff --git a/include/llfio/revision.hpp b/include/llfio/revision.hpp
index 2eca1678..c823736d 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 7c2fd4d1070394326b39323e9beb53823336eca9
-#define LLFIO_PREVIOUS_COMMIT_DATE "2020-11-28 17:58:14 +00:00"
-#define LLFIO_PREVIOUS_COMMIT_UNIQUE 7c2fd4d1
+#define LLFIO_PREVIOUS_COMMIT_REF 48ee8bae656cb5d53f38feb462caa53e1128b76d
+#define LLFIO_PREVIOUS_COMMIT_DATE "2021-01-27 20:37:58 +00:00"
+#define LLFIO_PREVIOUS_COMMIT_UNIQUE 48ee8bae
diff --git a/include/llfio/v2.0/detail/impl/windows/fs_handle.ipp b/include/llfio/v2.0/detail/impl/windows/fs_handle.ipp
index c08a3a89..58ef72ed 100644
--- a/include/llfio/v2.0/detail/impl/windows/fs_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/windows/fs_handle.ipp
@@ -391,4 +391,167 @@ result<void> fs_handle::unlink(deadline d) noexcept
return success();
}
+
+/**************************************** to_win32_path() *******************************************/
+
+LLFIO_HEADERS_ONLY_FUNC_SPEC result<filesystem::path> to_win32_path(const fs_handle &_h, win32_path_namespace mapping) noexcept
+{
+ windows_nt_kernel::init();
+ using namespace windows_nt_kernel;
+ HANDLE h = _h._get_handle().native_handle().h;
+ LLFIO_LOG_FUNCTION_CALL(&h);
+ // Most efficient, least memory copying method is direct fill of a wstring which is moved into filesystem::path
+ filesystem::path::string_type buffer;
+ buffer.resize(32769);
+ auto *_buffer = const_cast<wchar_t *>(buffer.data());
+ // Unlike h.current_path() which uses FILE_NAME_NORMALIZED, we shall use here FILE_NAME_OPENED
+ DWORD flags = FILE_NAME_OPENED;
+ switch(mapping)
+ {
+ case win32_path_namespace::device:
+ flags |= VOLUME_NAME_NT;
+ break;
+ case win32_path_namespace::dos:
+ flags |= VOLUME_NAME_DOS;
+ break;
+ case win32_path_namespace::any: // fallthrough
+ case win32_path_namespace::guid_volume: // fallthrough
+ // case win32_path_namespace::guid_all:
+ flags |= VOLUME_NAME_GUID;
+ break;
+ }
+ {
+ // Before Vista, I had to do this by hand, now I have a nice simple API. Thank you Microsoft!
+ DWORD len = GetFinalPathNameByHandleW(h, _buffer, (DWORD) buffer.size(), flags); // NOLINT
+ if(len == 0)
+ {
+ if(win32_path_namespace::any == mapping)
+ {
+ len = GetFinalPathNameByHandleW(h, _buffer, (DWORD) buffer.size(), FILE_NAME_OPENED | VOLUME_NAME_DOS);
+ if(len == 0)
+ {
+ return win32_error();
+ }
+ mapping = win32_path_namespace::dos;
+ }
+ else
+ {
+ return win32_error();
+ }
+ }
+ if(win32_path_namespace::any == mapping)
+ {
+ mapping = win32_path_namespace::guid_volume;
+ }
+ buffer.resize(len);
+ }
+ if(win32_path_namespace::guid_volume == mapping)
+ {
+ return filesystem::path(std::move(buffer));
+ }
+#if 0
+ if(win32_path_namespace::guid_all == mapping)
+ {
+ FILE_OBJECTID_BUFFER fob;
+ DWORD out;
+ if(!DeviceIoControl(h, FSCTL_CREATE_OR_GET_OBJECT_ID, nullptr, 0, &fob, sizeof(fob), &out, nullptr))
+ {
+ return win32_error();
+ }
+ GUID *guid = (GUID *) &fob.ObjectId;
+ /* Form is `\\?\Volume{9f9bd10e-9003-4da5-b146-70584e30854a}\{5a13b46c-44b9-40f3-9303-23cf7d918708}`
+ */
+ buffer.resize(87);
+ swprintf_s(_buffer + 49, 64, L"{%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x}", guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
+ guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
+ return filesystem::path(std::move(buffer));
+ }
+#endif
+ if(win32_path_namespace::device == mapping)
+ {
+ /* Paths of form \Device\... => \\.\ */
+ if(0 == buffer.compare(0, 8, L"\\Device\\"))
+ {
+ buffer[1] = '\\';
+ buffer[2] = '.';
+ buffer[3] = '\\';
+ memmove(&buffer[4], &buffer[8], (buffer.size() - 8) * sizeof(wchar_t));
+ buffer.resize(buffer.size() - 4);
+ }
+ else
+ {
+ return errc::no_such_file_or_directory;
+ }
+ }
+ OUTCOME_TRY(_h._fetch_inode());
+ // Ensure the mapped path exists and is the same file as our source
+ handle checkh(native_handle_type(native_handle_type::disposition::file | native_handle_type::disposition::_child_close_executed,
+ CreateFileW(buffer.c_str(), SYNCHRONIZE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, nullptr)));
+ if(INVALID_HANDLE_VALUE != checkh.native_handle().h)
+ {
+ stat_t scheck;
+ OUTCOME_TRYV(scheck.fill(checkh, stat_t::want::dev | stat_t::want::ino));
+ if(_h.st_dev() == scheck.st_dev && _h.st_ino() == scheck.st_ino)
+ {
+ if(win32_path_namespace::dos == mapping)
+ {
+ // Can we remove the \\?\ prefix safely from this DOS path?
+ bool needsExtendedPrefix = (buffer.size() > 260);
+ if(!needsExtendedPrefix)
+ {
+ // Are there any illegal Win32 characters in here?
+ static constexpr char reserved_chars[] = "\"*/:<>?|";
+ for(size_t n = 7; !needsExtendedPrefix && n < buffer.size(); n++)
+ {
+ if(buffer[n] >= 1 && buffer[n] <= 31)
+ {
+ needsExtendedPrefix = true;
+ break;
+ }
+ for(size_t x = 0; x < sizeof(reserved_chars); x++)
+ {
+ if(buffer[n] == reserved_chars[x])
+ {
+ needsExtendedPrefix = true;
+ break;
+ }
+ }
+ }
+ }
+ if(!needsExtendedPrefix)
+ {
+ // Are any segments of the filename a reserved name?
+ static constexpr const wstring_view reserved_names[] = {
+ L"\\CON\\", L"\\PRN\\", L"\\AUX\\", L"\\NUL\\", L"\\COM1\\", L"\\COM2\\", L"\\COM3\\", L"\\COM4\\", L"\\COM5\\", L"\\COM6\\", L"\\COM7\\",
+ L"\\COM8\\", L"\\COM9\\", L"\\LPT1\\", L"\\LPT2\\", L"\\LPT3\\", L"\\LPT4\\", L"\\LPT5\\", L"\\LPT6\\", L"\\LPT7\\", L"\\LPT8\\", L"\\LPT9\\"};
+ wstring_view _buffer_(buffer);
+ for(auto name : reserved_names)
+ {
+ if(_buffer_.npos != _buffer_.find(name))
+ {
+ needsExtendedPrefix = true;
+ break;
+ }
+ auto idx = _buffer_.find(name.substr(0, name.size() - 1));
+ if(_buffer_.npos != idx && idx + name.size() - 1 == _buffer_.size())
+ {
+ needsExtendedPrefix = true;
+ break;
+ }
+ }
+ }
+ if(!needsExtendedPrefix)
+ {
+ // This is safe to deprefix
+ memmove(&buffer[0], &buffer[4], (buffer.size() - 4) * sizeof(wchar_t));
+ buffer.resize(buffer.size() - 4);
+ }
+ }
+ return filesystem::path(std::move(buffer));
+ }
+ }
+ return errc::no_such_file_or_directory;
+}
+
LLFIO_V2_NAMESPACE_END
diff --git a/include/llfio/v2.0/detail/impl/windows/handle.ipp b/include/llfio/v2.0/detail/impl/windows/handle.ipp
index 75271a1d..7f3a86d9 100644
--- a/include/llfio/v2.0/detail/impl/windows/handle.ipp
+++ b/include/llfio/v2.0/detail/impl/windows/handle.ipp
@@ -51,6 +51,9 @@ result<handle::path_type> handle::current_path() const noexcept
buffer.resize(32769);
auto *_buffer = const_cast<wchar_t *>(buffer.data());
memcpy(_buffer, L"\\!!", 6);
+ // Should I use FILE_NAME_OPENED here instead of the default FILE_NAME_NORMALIZED?
+ // I think the latter more likely to trap buggy assumptions, so let's do that. If
+ // people really want FILE_NAME_OPENED, see to_win32_path().
DWORD len = GetFinalPathNameByHandleW(_v.h, _buffer + 3, (DWORD)(buffer.size() - 4 * sizeof(wchar_t)), VOLUME_NAME_NT); // NOLINT
if(len == 0)
{
diff --git a/include/llfio/v2.0/fs_handle.hpp b/include/llfio/v2.0/fs_handle.hpp
index 091f2f2e..6b0b9aeb 100644
--- a/include/llfio/v2.0/fs_handle.hpp
+++ b/include/llfio/v2.0/fs_handle.hpp
@@ -39,6 +39,91 @@ Distributed under the Boost Software License, Version 1.0.
LLFIO_V2_NAMESPACE_EXPORT_BEGIN
+class fs_handle;
+
+//! \brief The kinds of win32 path namespace possible.
+enum class win32_path_namespace
+{
+ /*! Map the input path to a valid win32 path as fast as possible for the input.
+ This is currently `guid_volume` followed by `dos`, but may change in the future.
+ */
+ any,
+ /*! Map `\!!\Device\...` form input paths to `\\.\...` for which it is _usually_
+ the case there is a mapping, which results in a valid Win32 path, but which
+ legacy code bases may not accept. This efficiently covers the vast majority of
+ what can be returned by `handle::current_path()` on Windows, but if the input
+ path cannot be mapped, a failure is returned.
+ */
+ device,
+ /*! Map the input path to a DOS drive letter prefix, possibly with `\\?\` prefix
+ to opt out of strict DOS path parsing if the mapped DOS path is incompatible with
+ traditional DOS (e.g. it contains one of the forbidden character sequences such
+ as `CON`, or it exceeds 260 codepoints, and so on). Well written software will
+ correctly handle `\\?\` prefixes, but if the code you are handing the path to is
+ particularly legacy, you ought to ensure that the prefix is not present.
+
+ \warning There is not a one-one mapping between NT kernel paths (which is what
+ LLFIO returns from `handle::current_path()`) and DOS style paths, so what you get
+ may be surprising. It is also possible that there is no mapping at all, in which
+ case a failure is returned.
+ */
+ dos,
+ /*! Map the input path replacing the volume as a GUID, such that say an input path
+ of `C:\foo\bar` might be mapped to `\\?\Volume{9f9bd10e-9003-4da5-b146-70584e30854a}\foo\bar`.
+ This is a valid Win32 path, but legacy code bases may not accept it. This eliminates
+ problems with drive letters vanishing or being ambiguous, and unlike with `dos`,
+ there is a guaranteed one-one mapping between NT kernel paths and `guid_volume` paths.
+ The mapped path is NOT checked for equivalence to the input file.
+ */
+ guid_volume
+#if 0
+ /*! Map the input path replacing the the whole path as a GUID, such that say an input
+ path of `C:\foo\bar` might be mapped to `\\?\Volume{9f9bd10e-9003-4da5-b146-70584e30854a}\{5a13b46c-44b9-40f3-9303-23cf7d918708}`.
+ This is a valid Win32 path, but legacy code bases may not accept it. This eliminates
+ problems with long paths or if the file could be renamed concurrently. Note this may
+ cause the creation of a GUID for the file on some filesystems (NTFS). The mapped path
+ is NOT checked for equivalence to the input file.
+ */
+ guid_all
+
+/*
+- `win32_path_namespace::guid_all` does the same as `guid_volume`, but additionally
+asks Windows for the GUID for the file upon the volume, creating one if one
+doesn't exist if necessary. The path returned consists of two GUIDs, and is a
+perfectly valid Win32 path which most Win32 APIs will accept.
+*/
+#endif
+};
+
+/*! \brief Maps the current path of `h` into a form suitable for Win32 APIs.
+Passes through unmodified on POSIX, so you can use this in portable code.
+\return The mapped current path of `h`, which may have been validated to refer to
+the exact same inode via `.unique_id()` (see below).
+\param h The handle whose `.current_path()` is to be mapped into a form suitable
+for Win32 APIs.
+\param mapping Which Win32 path namespace to map onto.
+
+This implementation may need to validate that the mapping of the current path of `h`
+onto the desired Win32 path namespace does indeed refer to the same file:
+
+- `win32_path_namespace::device` transforms `\!!\Device\...` => `\\.\...` and
+ensures that the mapped file's unique id matches the original, otherwise
+returning failure.
+- `win32_path_namespace::dos` enumerates all the DOS devices on the system and
+what those map onto within the NT kernel namespace. This mapping is for
+obvious reasons quite slow.
+- `win32_path_namespace::guid_volume` simply fetches the GUID of the volume of
+the handle, and constructs a valid Win32 path from that.
+- `win32_path_namespace::any` means attempt `guid_volume` first, and if it fails
+(e.g. your file is on a network share) then it attempts `dos`. This semantic may
+change in the future, however any path emitted will always be a valid Win32 path.
+*/
+#ifdef _WIN32
+LLFIO_HEADERS_ONLY_FUNC_SPEC result<filesystem::path> to_win32_path(const fs_handle &h, win32_path_namespace mapping = win32_path_namespace::any) noexcept;
+#else
+inline result<filesystem::path> to_win32_path(const fs_handle &h, win32_path_namespace mapping = win32_path_namespace::any) noexcept;
+#endif
+
/*! \class fs_handle
\brief A handle to something with a device and inode number.
@@ -46,6 +131,12 @@ LLFIO_V2_NAMESPACE_EXPORT_BEGIN
*/
class LLFIO_DECL fs_handle
{
+#ifdef _WIN32
+ friend LLFIO_HEADERS_ONLY_FUNC_SPEC result<filesystem::path> to_win32_path(const fs_handle &h, win32_path_namespace mapping) noexcept;
+#else
+ friend inline result<filesystem::path> to_win32_path(const fs_handle &h, win32_path_namespace mapping) noexcept { return h._get_handle().current_path(); }
+#endif
+
public:
using dev_t = uint64_t;
using ino_t = uint64_t;
@@ -246,7 +337,8 @@ public:
namespace detail
{
- LLFIO_HEADERS_ONLY_FUNC_SPEC result<path_handle> containing_directory(optional<std::reference_wrapper<filesystem::path>> out_filename, const handle &h, const fs_handle &fsh, deadline d) noexcept;
+ LLFIO_HEADERS_ONLY_FUNC_SPEC result<path_handle> containing_directory(optional<std::reference_wrapper<filesystem::path>> out_filename, const handle &h,
+ const fs_handle &fsh, deadline d) noexcept;
}
// BEGIN make_free_functions.py
@@ -274,9 +366,11 @@ must succeed, else `errc::timed_out` will be returned.
\mallocs Except on platforms with race free syscalls for renaming open handles (Windows), calls
`current_path()` via `parent_path_handle()` and thus is both expensive and calls malloc many times.
*/
-inline result<void> relink(fs_handle &self, const path_handle &base, fs_handle::path_view_type path, bool atomic_replace = true, deadline d = std::chrono::seconds(30)) noexcept
+inline result<void> relink(fs_handle &self, const path_handle &base, fs_handle::path_view_type path, bool atomic_replace = true,
+ deadline d = std::chrono::seconds(30)) noexcept
{
- return self.relink(std::forward<decltype(base)>(base), std::forward<decltype(path)>(path), std::forward<decltype(atomic_replace)>(atomic_replace), std::forward<decltype(d)>(d));
+ return self.relink(std::forward<decltype(base)>(base), std::forward<decltype(path)>(path), std::forward<decltype(atomic_replace)>(atomic_replace),
+ std::forward<decltype(d)>(d));
}
/*! Unlinks the current path of this open handle, causing its entry to immediately disappear from the filing system.
On Windows unless `flag::win_disable_unlink_emulation` is set, this behaviour is
diff --git a/include/llfio/v2.0/path_view.hpp b/include/llfio/v2.0/path_view.hpp
index 41589da3..b1faf800 100644
--- a/include/llfio/v2.0/path_view.hpp
+++ b/include/llfio/v2.0/path_view.hpp
@@ -2437,53 +2437,6 @@ inline filesystem::path operator/(T a, path_view_component b)
}
-namespace detail
-{
- inline filesystem::path to_win32_path(filesystem::path &&p, bool need_dos_path_form)
- {
-#ifdef _WIN32
- if(need_dos_path_form)
- {
- throw std::runtime_error("Not implemented yet");
- }
- auto &str = const_cast<filesystem::path::string_type &>(p.native());
- if(str.size() >= 4 && str[0] == '\\' && str[1] == '!' && str[2] == '!' && str[3] == '\\')
- {
- /* Paths of form \!!\Device\... => \\.\ */
- if(0 == str.compare(0, 11, L"\\!!\\Device\\"))
- {
- str[1] = '\\';
- str[2] = '.';
- memcpy(&str[4], &str[11], (str.size() - 7) * sizeof(wchar_t));
- str.resize(str.size() - 7);
- }
- else
- {
- throw std::runtime_error("cannot convert path into Win32 path");
- }
- }
-#endif
- return std::move(p);
- }
-} // namespace detail
-
-/*! \brief Transforms the input path into a form suitable for Win32 APIs.
-Passes through unmodified on POSIX.
-
-\throws If the path cannot be turned into a valid Win32 path, an exception
-is thrown.
-*/
-inline filesystem::path to_win32_path(path_view p, bool need_dos_path_form = false)
-{
- return detail::to_win32_path(p.path(), need_dos_path_form);
-}
-//! \overload
-inline filesystem::path to_win32_path(filesystem::path &&p, bool need_dos_path_form = false)
-{
- return detail::to_win32_path(std::move(p), need_dos_path_form);
-}
-
-
#ifndef NDEBUG
static_assert(std::is_trivially_copyable<path_view>::value, "path_view is not a trivially copyable!");
#endif
diff --git a/test/tests/current_path.cpp b/test/tests/current_path.cpp
index 626696c3..0048a744 100644
--- a/test/tests/current_path.cpp
+++ b/test/tests/current_path.cpp
@@ -43,8 +43,20 @@ template <class FileHandleType, class DirectoryHandleType> static inline void Te
#pragma clang diagnostic ignored "-Wmissing-braces"
#endif
llfio::path_handle null_path_handle;
- FileHandleType h1 = llfio::construct<FileHandleType>{null_path_handle, "tempfile", llfio::file_handle::mode::write, llfio::file_handle::creation::if_needed, llfio::file_handle::caching::temporary, llfio::file_handle::flag::none}().value(); // NOLINT
- DirectoryHandleType h2 = llfio::construct<DirectoryHandleType>{null_path_handle, "tempdir", llfio::file_handle::mode::write, llfio::file_handle::creation::if_needed, llfio::file_handle::caching::all, llfio::file_handle::flag::none}().value(); // NOLINT
+ FileHandleType h1 = llfio::construct<FileHandleType>{null_path_handle,
+ "tempfile",
+ llfio::file_handle::mode::write,
+ llfio::file_handle::creation::if_needed,
+ llfio::file_handle::caching::temporary,
+ llfio::file_handle::flag::none}()
+ .value(); // NOLINT
+ DirectoryHandleType h2 = llfio::construct<DirectoryHandleType>{null_path_handle,
+ "tempdir",
+ llfio::file_handle::mode::write,
+ llfio::file_handle::creation::if_needed,
+ llfio::file_handle::caching::all,
+ llfio::file_handle::flag::none}()
+ .value(); // NOLINT
#ifdef __clang__
#pragma clang diagnostic pop
#endif
@@ -261,6 +273,128 @@ template <class FileHandleType, class DirectoryHandleType> static inline void Te
h2.unlink().value();
}
-KERNELTEST_TEST_KERNEL(integration, llfio, current_path, handle, "Tests that llfio::handle::current_path() works as expected", TestHandleCurrentPath<LLFIO_V2_NAMESPACE::file_handle, LLFIO_V2_NAMESPACE::directory_handle>())
-KERNELTEST_TEST_KERNEL(integration, llfio, current_path, cached_parent_handle_adapter, "Tests that llfio::cached_parent_handle_adapter::current_path() works as expected",
- TestHandleCurrentPath<LLFIO_V2_NAMESPACE::algorithm::cached_parent_handle_adapter<LLFIO_V2_NAMESPACE::file_handle>, LLFIO_V2_NAMESPACE::algorithm::cached_parent_handle_adapter<LLFIO_V2_NAMESPACE::directory_handle>>())
+template <class FileHandleType, class DirectoryHandleType> static inline void TestToWin32Path()
+{
+ namespace llfio = LLFIO_V2_NAMESPACE;
+ {
+ std::error_code ec;
+ llfio::filesystem::current_path(llfio::filesystem::temp_directory_path());
+ llfio::filesystem::remove_all("tempfile", ec);
+ llfio::filesystem::remove_all("tempfile2", ec);
+ llfio::filesystem::remove_all("tempfile3", ec);
+ llfio::filesystem::remove_all("tempfile4", ec);
+ llfio::filesystem::remove_all("tempdir", ec);
+ llfio::filesystem::remove_all("tempdir2", ec);
+ llfio::filesystem::remove_all("tempdir3", ec);
+ } // namespace ;
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-braces"
+#endif
+ llfio::path_handle null_path_handle;
+ FileHandleType h1 = llfio::construct<FileHandleType>{null_path_handle,
+ "tempfile",
+ llfio::file_handle::mode::write,
+ llfio::file_handle::creation::if_needed,
+ llfio::file_handle::caching::temporary,
+ llfio::file_handle::flag::none}()
+ .value(); // NOLINT
+ DirectoryHandleType h2 = llfio::construct<DirectoryHandleType>{null_path_handle,
+ "tempdir",
+ llfio::file_handle::mode::write,
+ llfio::file_handle::creation::if_needed,
+ llfio::file_handle::caching::all,
+ llfio::file_handle::flag::none}()
+ .value(); // NOLINT
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+ auto check = [](llfio::result<llfio::filesystem::path> res, const char *desc) -> llfio::filesystem::path {
+ BOOST_CHECK(res);
+ if(!res)
+ {
+ std::cerr << " Getting the win32 path of a " << desc << " FAILED due to " << res.error().message().c_str() << std::endl;
+ }
+ else if(res.value().empty())
+ {
+ BOOST_CHECK(!res.value().empty());
+ std::cerr << " Getting the win32 path of a " << desc << " FAILED due to the returned path being empty" << std::endl;
+ }
+ else
+ {
+ std::cout << " The win32 path of a " << desc << " is " << res.value() << std::endl;
+ return std::move(res).value();
+ }
+ return {};
+ };
+ std::cout << "\nwin32_path_namespace::any:\n";
+ auto h1path_any = check(to_win32_path(h1, llfio::win32_path_namespace::any), "file");
+ auto h2path_any = check(to_win32_path(h2, llfio::win32_path_namespace::any), "directory");
+ std::cout << "\nwin32_path_namespace::device:\n";
+ auto h1path_device = check(to_win32_path(h1, llfio::win32_path_namespace::device), "file");
+ auto h2path_device = check(to_win32_path(h2, llfio::win32_path_namespace::device), "directory");
+ std::cout << "\nwin32_path_namespace::dos:\n";
+ auto h1path_dos = check(to_win32_path(h1, llfio::win32_path_namespace::dos), "file");
+ auto h2path_dos = check(to_win32_path(h2, llfio::win32_path_namespace::dos), "directory");
+ std::cout << "\nwin32_path_namespace::guid_volume:\n";
+ auto h1path_guid_volume = check(to_win32_path(h1, llfio::win32_path_namespace::guid_volume), "file");
+ auto h2path_guid_volume = check(to_win32_path(h2, llfio::win32_path_namespace::guid_volume), "directory");
+ //std::cout << "\nwin32_path_namespace::guid_all:\n";
+ //auto h1path_guid_all = check(to_win32_path(h1, llfio::win32_path_namespace::guid_all), "file");
+ //auto h2path_guid_all = check(to_win32_path(h2, llfio::win32_path_namespace::guid_all), "directory");
+
+ for(auto &path : {
+ h1path_any,
+ h1path_device,
+ h1path_dos,
+ h1path_guid_volume,
+ //h1path_guid_all,
+ })
+ {
+ if(!path.empty())
+ {
+ std::cout << "\nChecking file " << path << " can be opened ...";
+ auto res = llfio::file_handle::file({}, path);
+ BOOST_CHECK(res);
+ if(res)
+ {
+ BOOST_CHECK(res.value().st_dev() == h1.st_dev());
+ BOOST_CHECK(res.value().st_ino() == h1.st_ino());
+ }
+ }
+ }
+ std::cout << "\n";
+ for(auto &path : {
+ h2path_any,
+ h2path_device,
+ h2path_dos,
+ h2path_guid_volume,
+ //h2path_guid_all,
+ })
+ {
+ if(!path.empty())
+ {
+ std::cout << "\nChecking directory " << path << " can be opened ...";
+ auto res = llfio::directory_handle::directory({}, path);
+ BOOST_CHECK(res);
+ if(res)
+ {
+ BOOST_CHECK(res.value().st_dev() == h2.st_dev());
+ BOOST_CHECK(res.value().st_ino() == h2.st_ino());
+ }
+ }
+ }
+ std::cout << std::endl;
+ h1.unlink().value();
+ h2.unlink().value();
+}
+
+KERNELTEST_TEST_KERNEL(integration, llfio, current_path, handle, "Tests that llfio::handle::current_path() works as expected",
+ TestHandleCurrentPath<LLFIO_V2_NAMESPACE::file_handle, LLFIO_V2_NAMESPACE::directory_handle>())
+KERNELTEST_TEST_KERNEL(integration, llfio, current_path, cached_parent_handle_adapter,
+ "Tests that llfio::cached_parent_handle_adapter::current_path() works as expected",
+ TestHandleCurrentPath<LLFIO_V2_NAMESPACE::algorithm::cached_parent_handle_adapter<LLFIO_V2_NAMESPACE::file_handle>,
+ LLFIO_V2_NAMESPACE::algorithm::cached_parent_handle_adapter<LLFIO_V2_NAMESPACE::directory_handle>>())
+KERNELTEST_TEST_KERNEL(integration, llfio, to_win32_path, handle, "Tests that llfio::to_win32_path() works as expected",
+ TestToWin32Path<LLFIO_V2_NAMESPACE::file_handle, LLFIO_V2_NAMESPACE::directory_handle>())