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>2018-08-24 11:59:28 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2018-08-24 11:59:28 +0300
commit5f82c897584065164c593ea0ca3a602ac651198c (patch)
tree4e1a880af2902e11561aa4608af1d1d1c77f35d6 /include/llfio
parent0b0eae81e199476a1f5246c68011bd00d8653363 (diff)
Reworked directory_handle to use same io_request and read() pattern as all the other handles.
Diffstat (limited to 'include/llfio')
-rw-r--r--include/llfio/revision.hpp6
-rw-r--r--include/llfio/v2.0/detail/impl/posix/directory_handle.ipp112
-rw-r--r--include/llfio/v2.0/detail/impl/storage_profile.ipp6
-rw-r--r--include/llfio/v2.0/detail/impl/windows/directory_handle.ipp50
-rw-r--r--include/llfio/v2.0/directory_handle.hpp92
-rw-r--r--include/llfio/v2.0/symlink_handle.hpp2
6 files changed, 142 insertions, 126 deletions
diff --git a/include/llfio/revision.hpp b/include/llfio/revision.hpp
index c430e71f..b37644b9 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 517fce968606853d24bae19176a7c224aaed97dc
-#define LLFIO_PREVIOUS_COMMIT_DATE "2018-08-22 19:56:24 +00:00"
-#define LLFIO_PREVIOUS_COMMIT_UNIQUE 517fce96
+#define LLFIO_PREVIOUS_COMMIT_REF 0b0eae81e199476a1f5246c68011bd00d8653363
+#define LLFIO_PREVIOUS_COMMIT_DATE "2018-08-23 08:43:35 +00:00"
+#define LLFIO_PREVIOUS_COMMIT_UNIQUE 0b0eae81
diff --git a/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp b/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp
index 247f030b..69bf45cf 100644
--- a/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp
@@ -209,16 +209,16 @@ LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<path_handle> directory_handle::clone_to_p
return ret;
}
-result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_type &&tofill, path_view_type glob, filter /*unused*/, span<char> kernelbuffer) const noexcept
+result<directory_handle::buffers_type> directory_handle::read(io_request<buffers_type> req) const noexcept
{
LLFIO_LOG_FUNCTION_CALL(this);
- if(tofill.empty())
+ if(req.buffers.empty())
{
- return enumerate_info{std::move(tofill), stat_t::want::none, false};
+ return std::move(req.buffers);
}
// Is glob a single entry match? If so, this is really a stat call
- path_view_type::c_str zglob(glob);
- if(!glob.empty() && !glob.contains_glob())
+ path_view_type::c_str zglob(req.glob);
+ if(!req.glob.empty() && !req.glob.contains_glob())
{
struct stat s
{
@@ -227,46 +227,46 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
{
return posix_error();
}
- tofill[0].stat.st_dev = s.st_dev;
- tofill[0].stat.st_ino = s.st_ino;
- tofill[0].stat.st_type = to_st_type(s.st_mode);
- tofill[0].stat.st_perms = s.st_mode & 0xfff;
- tofill[0].stat.st_nlink = s.st_nlink;
- tofill[0].stat.st_uid = s.st_uid;
- tofill[0].stat.st_gid = s.st_gid;
- tofill[0].stat.st_rdev = s.st_rdev;
+ req.buffers[0].stat.st_dev = s.st_dev;
+ req.buffers[0].stat.st_ino = s.st_ino;
+ req.buffers[0].stat.st_type = to_st_type(s.st_mode);
+ req.buffers[0].stat.st_perms = s.st_mode & 0xfff;
+ req.buffers[0].stat.st_nlink = s.st_nlink;
+ req.buffers[0].stat.st_uid = s.st_uid;
+ req.buffers[0].stat.st_gid = s.st_gid;
+ req.buffers[0].stat.st_rdev = s.st_rdev;
#ifdef __ANDROID__
- tofill[0].stat.st_atim = to_timepoint(*((struct timespec *) &s.st_atime));
- tofill[0].stat.st_mtim = to_timepoint(*((struct timespec *) &s.st_mtime));
- tofill[0].stat.st_ctim = to_timepoint(*((struct timespec *) &s.st_ctime));
+ req.buffers[0].stat.st_atim = to_timepoint(*((struct timespec *) &s.st_atime));
+ req.buffers[0].stat.st_mtim = to_timepoint(*((struct timespec *) &s.st_mtime));
+ req.buffers[0].stat.st_ctim = to_timepoint(*((struct timespec *) &s.st_ctime));
#elif defined(__APPLE__)
- tofill[0].stat.st_atim = to_timepoint(s.st_atimespec);
- tofill[0].stat.st_mtim = to_timepoint(s.st_mtimespec);
- tofill[0].stat.st_ctim = to_timepoint(s.st_ctimespec);
+ req.buffers[0].stat.st_atim = to_timepoint(s.st_atimespec);
+ req.buffers[0].stat.st_mtim = to_timepoint(s.st_mtimespec);
+ req.buffers[0].stat.st_ctim = to_timepoint(s.st_ctimespec);
#else // Linux and BSD
- tofill[0].stat.st_atim = to_timepoint(s.st_atim);
- tofill[0].stat.st_mtim = to_timepoint(s.st_mtim);
- tofill[0].stat.st_ctim = to_timepoint(s.st_ctim);
+ req.buffers[0].stat.st_atim = to_timepoint(s.st_atim);
+ req.buffers[0].stat.st_mtim = to_timepoint(s.st_mtim);
+ req.buffers[0].stat.st_ctim = to_timepoint(s.st_ctim);
#endif
- tofill[0].stat.st_size = s.st_size;
- tofill[0].stat.st_allocated = static_cast<handle::extent_type>(s.st_blocks) * 512;
- tofill[0].stat.st_blocks = s.st_blocks;
- tofill[0].stat.st_blksize = s.st_blksize;
+ req.buffers[0].stat.st_size = s.st_size;
+ req.buffers[0].stat.st_allocated = static_cast<handle::extent_type>(s.st_blocks) * 512;
+ req.buffers[0].stat.st_blocks = s.st_blocks;
+ req.buffers[0].stat.st_blksize = s.st_blksize;
#ifdef HAVE_STAT_FLAGS
- tofill[0].stat.st_flags = s.st_flags;
+ req.buffers[0].stat.st_flags = s.st_flags;
#endif
#ifdef HAVE_STAT_GEN
- tofill[0].stat.st_gen = s.st_gen;
+ req.buffers[0].stat.st_gen = s.st_gen;
#endif
#ifdef HAVE_BIRTHTIMESPEC
#if defined(__APPLE__)
- tofill[0].stat.st_birthtim = to_timepoint(s.st_birthtimespec);
+ req.buffers[0].stat.st_birthtim = to_timepoint(s.st_birthtimespec);
#else
- tofill[0].stat.st_birthtim = to_timepoint(s.st_birthtim);
+ req.buffers[0].stat.st_birthtim = to_timepoint(s.st_birthtim);
#endif
#endif
- tofill[0].stat.st_sparse = static_cast<unsigned int>((static_cast<handle::extent_type>(s.st_blocks) * 512) < static_cast<handle::extent_type>(s.st_size));
- tofill._resize(1);
+ req.buffers[0].stat.st_sparse = static_cast<unsigned int>((static_cast<handle::extent_type>(s.st_blocks) * 512) < static_cast<handle::extent_type>(s.st_size));
+ req.buffers._resize(1);
static constexpr stat_t::want default_stat_contents = stat_t::want::dev | stat_t::want::ino | stat_t::want::type | stat_t::want::perms | stat_t::want::nlink | stat_t::want::uid | stat_t::want::gid | stat_t::want::rdev | stat_t::want::atim | stat_t::want::mtim | stat_t::want::ctim | stat_t::want::size |
stat_t::want::allocated | stat_t::want::blocks | stat_t::want::blksize
#ifdef HAVE_STAT_FLAGS
@@ -279,7 +279,9 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
| stat_t::want::birthtim
#endif
| stat_t::want::sparse;
- return enumerate_info{std::move(tofill), default_stat_contents, true};
+ req.buffers._metadata = default_stat_contents;
+ req.buffers._done = true;
+ return std::move(req.buffers);
}
#ifdef __linux__
// Unlike FreeBSD, Linux doesn't define a getdents() function, so we'll do that here.
@@ -295,17 +297,17 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
return syscall(SYS_getdirentries64, fd, buf, count, &foo);
});
#endif
- if(!tofill._kernel_buffer && kernelbuffer.empty())
+ if(!req.buffers._kernel_buffer && req.kernelbuffer.empty())
{
// Let's assume the average leafname will be 64 characters long.
- size_t toallocate = (sizeof(dirent) + 64) * tofill.size();
+ size_t toallocate = (sizeof(dirent) + 64) * req.buffers.size();
auto *mem = new(std::nothrow) char[toallocate];
if(mem == nullptr)
{
return errc::not_enough_memory;
}
- tofill._kernel_buffer = std::unique_ptr<char[]>(mem);
- tofill._kernel_buffer_size = toallocate;
+ req.buffers._kernel_buffer = std::unique_ptr<char[]>(mem);
+ req.buffers._kernel_buffer_size = toallocate;
}
stat_t::want default_stat_contents = stat_t::want::ino | stat_t::want::type;
dirent *buffer;
@@ -314,8 +316,8 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
bool done = false;
do
{
- buffer = kernelbuffer.empty() ? reinterpret_cast<dirent *>(tofill._kernel_buffer.get()) : reinterpret_cast<dirent *>(kernelbuffer.data());
- bytesavailable = kernelbuffer.empty() ? tofill._kernel_buffer_size : kernelbuffer.size();
+ buffer = req.kernelbuffer.empty() ? reinterpret_cast<dirent *>(req.buffers._kernel_buffer.get()) : reinterpret_cast<dirent *>(req.kernelbuffer.data());
+ bytesavailable = req.kernelbuffer.empty() ? req.buffers._kernel_buffer_size : req.kernelbuffer.size();
// Seek to start
#ifdef __linux__
if(-1 == ::lseek64(_v.fd, 0, SEEK_SET))
@@ -327,17 +329,17 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
return posix_error();
#endif
bytes = getdents(_v.fd, reinterpret_cast<char *>(buffer), bytesavailable);
- if(kernelbuffer.empty() && bytes == -1 && EINVAL == errno)
+ if(req.kernelbuffer.empty() && bytes == -1 && EINVAL == errno)
{
- tofill._kernel_buffer.reset();
- size_t toallocate = tofill._kernel_buffer_size * 2;
+ req.buffers._kernel_buffer.reset();
+ size_t toallocate = req.buffers._kernel_buffer_size * 2;
auto *mem = new(std::nothrow) char[toallocate];
if(mem == nullptr)
{
return errc::not_enough_memory;
}
- tofill._kernel_buffer = std::unique_ptr<char[]>(mem);
- tofill._kernel_buffer_size = toallocate;
+ req.buffers._kernel_buffer = std::unique_ptr<char[]>(mem);
+ req.buffers._kernel_buffer_size = toallocate;
}
else
{
@@ -350,8 +352,10 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
} while(!done);
if(bytes == 0)
{
- tofill._resize(0);
- return enumerate_info{std::move(tofill), default_stat_contents, true};
+ req.buffers._resize(0);
+ req.buffers._metadata = default_stat_contents;
+ req.buffers._done = true;
+ return std::move(req.buffers);
}
LLFIO_VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(buffer, bytes); // NOLINT
size_t n = 0;
@@ -367,11 +371,11 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
goto cont;
}
}
- if(!glob.empty() && fnmatch(zglob.buffer, dent->d_name, 0) != 0)
+ if(!req.glob.empty() && fnmatch(zglob.buffer, dent->d_name, 0) != 0)
{
goto cont;
}
- directory_entry &item = tofill[n];
+ directory_entry &item = req.buffers[n];
item.leafname = path_view(dent->d_name, length);
item.stat = stat_t(nullptr);
item.stat.st_ino = dent->d_ino;
@@ -410,13 +414,17 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
if((bytes -= dent->d_reclen) <= 0)
{
// Fill is complete
- tofill._resize(n);
- return enumerate_info{std::move(tofill), default_stat_contents, true};
+ req.buffers._resize(n);
+ req.buffers._metadata = default_stat_contents;
+ req.buffers._done = true;
+ return std::move(req.buffers);
}
- if(n >= tofill.size())
+ if(n >= req.buffers.size())
{
// Fill is incomplete
- return enumerate_info{std::move(tofill), default_stat_contents, false};
+ req.buffers._metadata = default_stat_contents;
+ req.buffers._done = false;
+ return std::move(req.buffers);
}
}
}
diff --git a/include/llfio/v2.0/detail/impl/storage_profile.ipp b/include/llfio/v2.0/detail/impl/storage_profile.ipp
index be8d4e5c..338dfcbc 100644
--- a/include/llfio/v2.0/detail/impl/storage_profile.ipp
+++ b/include/llfio/v2.0/detail/impl/storage_profile.ipp
@@ -1239,9 +1239,9 @@ namespace storage_profile
std::vector<directory_entry> entries(no);
begin = std::chrono::high_resolution_clock::now();
- directory_handle::enumerate_info ei(dirh.enumerate(entries).value());
- assert(ei.done == true);
- assert(ei.filled.size() == no);
+ directory_handle::buffers_type ei(dirh.read(directory_handle::buffers_type(entries)).value());
+ assert(ei.done() == true);
+ assert(ei.size() == no);
end = std::chrono::high_resolution_clock::now();
s.enumerate = static_cast<unsigned long long>(static_cast<double>(std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count()) / no);
if(cold_cache)
diff --git a/include/llfio/v2.0/detail/impl/windows/directory_handle.ipp b/include/llfio/v2.0/detail/impl/windows/directory_handle.ipp
index 158bbc7f..f8afcfb6 100644
--- a/include/llfio/v2.0/detail/impl/windows/directory_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/windows/directory_handle.ipp
@@ -208,61 +208,61 @@ result<void> directory_handle::unlink(deadline d) noexcept
return h.unlink(d);
}
-result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_type &&tofill, path_view_type glob, filter filtering, span<char> kernelbuffer) const noexcept
+result<directory_handle::buffers_type> directory_handle::read(io_request<buffers_type> req) const noexcept
{
static constexpr stat_t::want default_stat_contents = stat_t::want::ino | stat_t::want::type | stat_t::want::atim | stat_t::want::mtim | stat_t::want::ctim | stat_t::want::size | stat_t::want::allocated | stat_t::want::birthtim | stat_t::want::sparse | stat_t::want::compressed | stat_t::want::reparse_point;
windows_nt_kernel::init();
using namespace windows_nt_kernel;
LLFIO_LOG_FUNCTION_CALL(this);
- if(tofill.empty())
+ if(req.buffers.empty())
{
- return enumerate_info{std::move(tofill), stat_t::want::none, false};
+ return std::move(req.buffers);
}
UNICODE_STRING _glob{};
memset(&_glob, 0, sizeof(_glob));
- path_view_type::c_str zglob(glob, true);
- if(!glob.empty())
+ path_view_type::c_str zglob(req.glob, true);
+ if(!req.glob.empty())
{
_glob.Buffer = const_cast<wchar_t *>(zglob.buffer);
_glob.Length = zglob.length * sizeof(wchar_t);
_glob.MaximumLength = _glob.Length + sizeof(wchar_t);
}
- if(!tofill._kernel_buffer && kernelbuffer.empty())
+ if(!req.buffers._kernel_buffer && req.kernelbuffer.empty())
{
// Let's assume the average leafname will be 64 characters long.
- size_t toallocate = (sizeof(FILE_ID_FULL_DIR_INFORMATION) + 64 * sizeof(wchar_t)) * tofill.size();
+ size_t toallocate = (sizeof(FILE_ID_FULL_DIR_INFORMATION) + 64 * sizeof(wchar_t)) * req.buffers.size();
auto *mem = new(std::nothrow) char[toallocate];
if(mem == nullptr)
{
return errc::not_enough_memory;
}
- tofill._kernel_buffer = std::unique_ptr<char[]>(mem);
- tofill._kernel_buffer_size = toallocate;
+ req.buffers._kernel_buffer = std::unique_ptr<char[]>(mem);
+ req.buffers._kernel_buffer_size = toallocate;
}
FILE_ID_FULL_DIR_INFORMATION *buffer;
ULONG bytes;
bool done = false;
do
{
- buffer = kernelbuffer.empty() ? reinterpret_cast<FILE_ID_FULL_DIR_INFORMATION *>(tofill._kernel_buffer.get()) : reinterpret_cast<FILE_ID_FULL_DIR_INFORMATION *>(kernelbuffer.data());
- bytes = kernelbuffer.empty() ? static_cast<ULONG>(tofill._kernel_buffer_size) : static_cast<ULONG>(kernelbuffer.size());
+ buffer = req.kernelbuffer.empty() ? reinterpret_cast<FILE_ID_FULL_DIR_INFORMATION *>(req.buffers._kernel_buffer.get()) : reinterpret_cast<FILE_ID_FULL_DIR_INFORMATION *>(req.kernelbuffer.data());
+ bytes = req.kernelbuffer.empty() ? static_cast<ULONG>(req.buffers._kernel_buffer_size) : static_cast<ULONG>(req.kernelbuffer.size());
IO_STATUS_BLOCK isb = make_iostatus();
- NTSTATUS ntstat = NtQueryDirectoryFile(_v.h, nullptr, nullptr, nullptr, &isb, buffer, bytes, FileIdFullDirectoryInformation, FALSE, glob.empty() ? nullptr : &_glob, TRUE);
+ NTSTATUS ntstat = NtQueryDirectoryFile(_v.h, nullptr, nullptr, nullptr, &isb, buffer, bytes, FileIdFullDirectoryInformation, FALSE, req.glob.empty() ? nullptr : &_glob, TRUE);
if(STATUS_PENDING == ntstat)
{
ntstat = ntwait(_v.h, isb, deadline());
}
- if(kernelbuffer.empty() && STATUS_BUFFER_OVERFLOW == ntstat)
+ if(req.kernelbuffer.empty() && STATUS_BUFFER_OVERFLOW == ntstat)
{
- tofill._kernel_buffer.reset();
- size_t toallocate = tofill._kernel_buffer_size * 2;
+ req.buffers._kernel_buffer.reset();
+ size_t toallocate = req.buffers._kernel_buffer_size * 2;
auto *mem = new(std::nothrow) char[toallocate];
if(mem == nullptr)
{
return errc::not_enough_memory;
}
- tofill._kernel_buffer = std::unique_ptr<char[]>(mem);
- tofill._kernel_buffer_size = toallocate;
+ req.buffers._kernel_buffer = std::unique_ptr<char[]>(mem);
+ req.buffers._kernel_buffer_size = toallocate;
}
else
{
@@ -289,9 +289,9 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
{
ffdi->FileName[length] = 0;
}
- directory_entry &item = tofill[n];
+ directory_entry &item = req.buffers[n];
item.leafname = path_view(wstring_view(ffdi->FileName, length));
- if(filtering == filter::fastdeleted && item.leafname.is_llfio_deleted())
+ if(req.filtering == filter::fastdeleted && item.leafname.is_llfio_deleted())
{
continue;
}
@@ -311,13 +311,17 @@ result<directory_handle::enumerate_info> directory_handle::enumerate(buffers_typ
if(ffdi->NextEntryOffset == 0u)
{
// Fill is complete
- tofill._resize(n);
- return enumerate_info{std::move(tofill), default_stat_contents, true};
+ req.buffers._resize(n);
+ req.buffers._metadata = default_stat_contents;
+ req.buffers._done = true;
+ return std::move(req.buffers);
}
- if(n >= tofill.size())
+ if(n >= req.buffers.size())
{
// Fill is incomplete
- return enumerate_info{std::move(tofill), default_stat_contents, false};
+ req.buffers._metadata = default_stat_contents;
+ req.buffers._done = false;
+ return std::move(req.buffers);
}
}
}
diff --git a/include/llfio/v2.0/directory_handle.hpp b/include/llfio/v2.0/directory_handle.hpp
index 8c5aa09d..9dbafd20 100644
--- a/include/llfio/v2.0/directory_handle.hpp
+++ b/include/llfio/v2.0/directory_handle.hpp
@@ -79,6 +79,8 @@ public:
//! The buffer type used by this handle, which is a `directory_entry`
using buffer_type = directory_entry;
+ //! The const buffer type used by this handle, which is a `directory_entry`
+ using const_buffer_type = directory_entry;
/*! The buffers type used by this handle, which is a contiguous sequence of `directory_entry`.
\warning Unless you supply your own kernel buffer, you need to keep this around as long as you
@@ -87,6 +89,14 @@ public:
*/
struct buffers_type : public span<buffer_type>
{
+ /*! The list of stat metadata retrieved. Sometimes, due to kernel API design,
+ enumerating a directory retrieves more than the metadata requested in the read
+ request. This indidicates what stat metadata is in the buffers filled.
+ */
+ stat_t::want metadata() const noexcept { return _metadata; }
+ //! Whether the directory was entirely read or not into any buffers supplied.
+ bool done() const noexcept { return _done; }
+
using span<buffer_type>::span;
//! Implicit construction from a span
/* constexpr */ buffers_type(span<buffer_type> v) // NOLINT TODO FIXME Make this constexpr when span becomes constexpr. SAME for move constructor below
@@ -95,7 +105,7 @@ public:
}
~buffers_type() = default;
//! Move constructor
- /* constexpr */ buffers_type(buffers_type &&o) noexcept : span<buffer_type>(std::move(o)), _kernel_buffer(std::move(o._kernel_buffer)), _kernel_buffer_size(o._kernel_buffer_size)
+ /* constexpr */ buffers_type(buffers_type &&o) noexcept : span<buffer_type>(std::move(o)), _kernel_buffer(std::move(o._kernel_buffer)), _kernel_buffer_size(o._kernel_buffer_size), _metadata(o._metadata), _done(o._done)
{
static_cast<span<buffer_type> &>(o) = {};
o._kernel_buffer_size = 0;
@@ -117,15 +127,42 @@ public:
std::unique_ptr<char[]> _kernel_buffer;
size_t _kernel_buffer_size{0};
void _resize(size_t l) { *static_cast<span<buffer_type> *>(this) = this->subspan(0, l); }
+ stat_t::want _metadata{stat_t::want::none};
+ bool _done{false};
};
-
//! How to do deleted file elimination on Windows
enum class filter
{
none, //!< Do no filtering at all
- fastdeleted //!< Filter out LLFIO deleted files based on their filename (fast and fairly reliable)
+ fastdeleted //!< For Windows without POSIX delete semantics, filter out LLFIO deleted files based on their filename (fast and fairly reliable)
+ };
+ //! The i/o request type used by this handle.
+ template <class /* unused */> struct io_request
+ {
+ buffers_type buffers{};
+ path_view_type glob{};
+ filter filtering{filter::fastdeleted};
+ span<char> kernelbuffer{};
+
+ /*! Construct a request to enumerate a directory with optionally specified kernel buffer.
+
+ \param _buffers The buffers to fill with enumerated directory entries.
+ \param _glob An optional shell glob by which to filter the items filled. Done kernel side on Windows, user side on POSIX.
+ \param _filtering Whether to filter out fake-deleted files on Windows or not.
+ \param _kernelbuffer A buffer to use for the kernel to fill. If left defaulted, a kernel buffer
+ is allocated internally and returned in the buffers returned which needs to not be destructed until one
+ is no longer using any items within (leafnames are views onto the original kernel data).
+ */
+ constexpr io_request(buffers_type _buffers, path_view_type _glob = {}, filter _filtering = filter::fastdeleted, span<char> _kernelbuffer = {})
+ : buffers(std::move(_buffers))
+ , glob(_glob)
+ , filtering(_filtering)
+ , kernelbuffer(_kernelbuffer)
+ {
+ }
};
+
public:
//! Default constructor
constexpr directory_handle() {} // NOLINT
@@ -259,32 +296,17 @@ public:
result<void> unlink(deadline d = std::chrono::seconds(30)) noexcept override;
#endif
- //! Completion information for `enumerate()`
- struct enumerate_info
- {
- //! The buffers filled.
- buffers_type filled;
- //! The list of stat metadata retrieved by `enumerate()` this call per `buffer_type`.
- stat_t::want metadata;
- //! Whether the directory was entirely read or not.
- bool done;
- };
- /*! Fill the buffers type with as many directory entries as will fit.
+ /*! Fill the buffers type with as many directory entries as will fit into any optionally supplied buffer.
\return Returns the buffers filled, what metadata was filled in and whether the entire directory
- was read into `tofill`.
- \param tofill The buffers to fill, returned to you on exit.
- \param glob An optional shell glob by which to filter the items filled. Done kernel side on Windows, user side on POSIX.
- \param filtering Whether to filter out fake-deleted files on Windows or not.
- \param kernelbuffer A buffer to use for the kernel to fill. If left defaulted, a kernel buffer
- is allocated internally and stored into `tofill` which needs to not be destructed until one
- is no longer using any items within (leafnames are views onto the original kernel data).
+ was read or not.
+ \param req A buffer fill (directory enumeration) request.
\errors todo
- \mallocs If the `kernelbuffer` parameter is set on entry, no memory allocations.
+ \mallocs If the `kernelbuffer` parameter is set in the request, no memory allocations.
If unset, at least one memory allocation, possibly more is performed.
*/
LLFIO_MAKE_FREE_FUNCTION
- LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<enumerate_info> enumerate(buffers_type &&tofill, path_view_type glob = path_view_type(), filter filtering = filter::fastdeleted, span<char> kernelbuffer = span<char>()) const noexcept;
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<buffers_type> read(io_request<buffers_type> req) const noexcept;
};
inline std::ostream &operator<<(std::ostream &s, const directory_handle::filter &v)
{
@@ -295,9 +317,9 @@ inline std::ostream &operator<<(std::ostream &s, const directory_handle::filter
}
return s << "llfio::directory_handle::filter::" << values[static_cast<size_t>(v)];
}
-inline std::ostream &operator<<(std::ostream &s, const directory_handle::enumerate_info & /*unused*/)
+inline std::ostream &operator<<(std::ostream &s, const directory_handle::buffers_type & /*unused*/)
{
- return s << "llfio::directory_handle::enumerate_info";
+ return s << "llfio::directory_handle::buffers_type";
}
//! \brief Constructor for `directory_handle`
@@ -350,26 +372,6 @@ inline result<directory_handle> temp_directory(directory_handle::path_view_type
{
return directory_handle::temp_directory(std::forward<decltype(name)>(name), std::forward<decltype(_mode)>(_mode), std::forward<decltype(_creation)>(_creation), std::forward<decltype(_caching)>(_caching), std::forward<decltype(flags)>(flags));
}
-/*! Fill the buffers type with as many directory entries as will fit.
-
-\return Returns the buffers filled, what metadata was filled in and whether the entire directory
-was read into `tofill`.
-\param self The object whose member function to call.
-\param tofill The buffers to fill, returned to you on exit.
-\param glob An optional shell glob by which to filter the items filled. Done kernel side on Windows, user side on POSIX.
-\param filtering Whether to filter out fake-deleted files on Windows or not.
-\param kernelbuffer A buffer to use for the kernel to fill. If left defaulted, a kernel buffer
-is allocated internally and stored into `tofill` which needs to not be destructed until one
-is no longer using any items within (leafnames are views onto the original kernel data).
-\errors todo
-\mallocs If the `kernelbuffer` parameter is set on entry, no memory allocations.
-If unset, at least one memory allocation, possibly more is performed.
-*/
-inline result<directory_handle::enumerate_info> enumerate(const directory_handle &self, directory_handle::buffers_type &&tofill, directory_handle::path_view_type glob = directory_handle::path_view_type(), directory_handle::filter filtering = directory_handle::filter::fastdeleted,
- span<char> kernelbuffer = span<char>()) noexcept
-{
- return self.enumerate(std::forward<decltype(tofill)>(tofill), std::forward<decltype(glob)>(glob), std::forward<decltype(filtering)>(filtering), std::forward<decltype(kernelbuffer)>(kernelbuffer));
-}
// END make_free_functions.py
LLFIO_V2_NAMESPACE_END
diff --git a/include/llfio/v2.0/symlink_handle.hpp b/include/llfio/v2.0/symlink_handle.hpp
index 844afe51..8b0f15ce 100644
--- a/include/llfio/v2.0/symlink_handle.hpp
+++ b/include/llfio/v2.0/symlink_handle.hpp
@@ -112,6 +112,8 @@ public:
//! The buffer type used by this handle, which is a `path_view`
using buffer_type = path_view;
+ //! The const buffer type used by this handle, which is a `path_view`
+ using const_buffer_type = path_view;
/*! The buffers type used by this handle for reads, which is a single item sequence of `path_view`.
\warning Unless you supply your own kernel buffer, you need to keep this around as long as you