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-14 22:05:04 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2018-08-14 22:05:04 +0300
commit83b7ad9bfda9af36414d8d6acac454288cb90a3a (patch)
tree6257bfa05626926de3c45a32bfad48cc6c068157 /include
parente2434aa9d42d50651ed9685b5125f58262366081 (diff)
symlink_handle is finished and fully working on POSIX.
Also fixed a number of vptr slicing bugs across the handle implementations, mainly caused by missing operator=() implementations. Fixed path_handle::clone() not working on POSIX.
Diffstat (limited to 'include')
-rw-r--r--include/llfio/revision.hpp6
-rw-r--r--include/llfio/v2.0/algorithm/cached_parent_handle_adapter.hpp7
-rw-r--r--include/llfio/v2.0/detail/impl/posix/handle.ipp33
-rw-r--r--include/llfio/v2.0/detail/impl/posix/map_handle.ipp3
-rw-r--r--include/llfio/v2.0/detail/impl/posix/symlink_handle.ipp152
-rw-r--r--include/llfio/v2.0/detail/impl/windows/handle.ipp8
-rw-r--r--include/llfio/v2.0/detail/impl/windows/map_handle.ipp7
-rw-r--r--include/llfio/v2.0/file_handle.hpp7
-rw-r--r--include/llfio/v2.0/map_handle.hpp11
-rw-r--r--include/llfio/v2.0/mapped.hpp8
-rw-r--r--include/llfio/v2.0/native_handle_type.hpp4
-rw-r--r--include/llfio/v2.0/path_handle.hpp35
-rw-r--r--include/llfio/v2.0/symlink_handle.hpp34
13 files changed, 252 insertions, 63 deletions
diff --git a/include/llfio/revision.hpp b/include/llfio/revision.hpp
index 244d4668..99cdfd0a 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 964d174c1c44d4810789b198bbf07271cebbe8c8
-#define LLFIO_PREVIOUS_COMMIT_DATE "2018-07-24 19:29:25 +00:00"
-#define LLFIO_PREVIOUS_COMMIT_UNIQUE 964d174c
+#define LLFIO_PREVIOUS_COMMIT_REF e2434aa9d42d50651ed9685b5125f58262366081
+#define LLFIO_PREVIOUS_COMMIT_DATE "2018-08-01 08:52:22 +00:00"
+#define LLFIO_PREVIOUS_COMMIT_UNIQUE e2434aa9
diff --git a/include/llfio/v2.0/algorithm/cached_parent_handle_adapter.hpp b/include/llfio/v2.0/algorithm/cached_parent_handle_adapter.hpp
index 4f5d6ba5..308d8451 100644
--- a/include/llfio/v2.0/algorithm/cached_parent_handle_adapter.hpp
+++ b/include/llfio/v2.0/algorithm/cached_parent_handle_adapter.hpp
@@ -91,7 +91,12 @@ namespace algorithm
cached_parent_handle_adapter(const cached_parent_handle_adapter &) = default;
cached_parent_handle_adapter(cached_parent_handle_adapter &&) = default; // NOLINT
cached_parent_handle_adapter &operator=(const cached_parent_handle_adapter &) = default;
- cached_parent_handle_adapter &operator=(cached_parent_handle_adapter &&) = default; // NOLINT
+ cached_parent_handle_adapter &operator=(cached_parent_handle_adapter &&o) noexcept
+ {
+ this->~cached_parent_handle_adapter();
+ new(this) cached_parent_handle_adapter(std::move(o));
+ return *this;
+ }
cached_parent_handle_adapter(adapted_handle_type &&o, const path_handle &base, path_view path)
: adapted_handle_type(std::move(o))
{
diff --git a/include/llfio/v2.0/detail/impl/posix/handle.ipp b/include/llfio/v2.0/detail/impl/posix/handle.ipp
index 03459064..37884e0b 100644
--- a/include/llfio/v2.0/detail/impl/posix/handle.ipp
+++ b/include/llfio/v2.0/detail/impl/posix/handle.ipp
@@ -134,6 +134,14 @@ result<void> handle::close() noexcept
LLFIO_LOG_FUNCTION_CALL(this);
if(_v)
{
+#ifndef NDEBUG
+ // Trap when refined handle implementations don't set their vptr properly (this took a while to debug!)
+ if((static_cast<unsigned>(_v.behaviour) & 0xff00) != 0 && !(_v.behaviour & native_handle_type::disposition::_child_close_executed))
+ {
+ LLFIO_LOG_FATAL(this, "handle::close() called on a derived handle implementation, this suggests vptr is incorrect");
+ abort();
+ }
+#endif
if(are_safety_fsyncs_issued() && is_writable())
{
if(-1 == fsync(_v.fd))
@@ -155,10 +163,31 @@ result<handle> handle::clone() const noexcept
LLFIO_LOG_FUNCTION_CALL(this);
result<handle> ret(handle(native_handle_type(), _caching, _flags));
ret.value()._v.behaviour = _v.behaviour;
- ret.value()._v.fd = ::fcntl(_v.fd, F_DUPFD_CLOEXEC);
+ ret.value()._v.fd = ::fcntl(_v.fd, F_DUPFD_CLOEXEC, 0);
if(-1 == ret.value()._v.fd)
{
- return posix_error();
+ int e = errno;
+ if(e == EBADF)
+ {
+ // Fall back onto F_DUPFD
+ ret.value()._v.fd = ::fcntl(_v.fd, F_DUPFD, 0);
+ if(-1 != ret.value()._v.fd)
+ {
+ // Set close on exec
+ int attribs = ::fcntl(_v.fd, F_GETFL);
+ if(-1 == attribs)
+ {
+ return posix_error();
+ }
+ attribs |= FD_CLOEXEC;
+ if(-1 == ::fcntl(_v.fd, F_SETFL, attribs))
+ {
+ return posix_error();
+ }
+ return ret;
+ }
+ }
+ return posix_error(e);
}
return ret;
}
diff --git a/include/llfio/v2.0/detail/impl/posix/map_handle.ipp b/include/llfio/v2.0/detail/impl/posix/map_handle.ipp
index 60e4ec14..1c174f03 100644
--- a/include/llfio/v2.0/detail/impl/posix/map_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/posix/map_handle.ipp
@@ -305,8 +305,9 @@ static inline result<void *> do_mmap(native_handle_type &nativeh, void *ataddr,
return addr;
}
-result<map_handle> map_handle::map(size_type bytes, section_handle::flag _flag) noexcept
+result<map_handle> map_handle::map(size_type bytes, bool /*unused*/, section_handle::flag _flag) noexcept
{
+ // TODO: Keep a cache of MADV_FREE pages deallocated
if(bytes == 0u)
{
return errc::argument_out_of_domain;
diff --git a/include/llfio/v2.0/detail/impl/posix/symlink_handle.ipp b/include/llfio/v2.0/detail/impl/posix/symlink_handle.ipp
index a0d4e7cd..2233ec33 100644
--- a/include/llfio/v2.0/detail/impl/posix/symlink_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/posix/symlink_handle.ipp
@@ -33,6 +33,8 @@ namespace detail
LLFIO_HEADERS_ONLY_FUNC_SPEC result<void> stat_from_symlink(struct stat &s, const handle &_h) noexcept
{
#if !LLFIO_SYMLINK_HANDLE_IS_FAKED
+ (void) s;
+ (void) _h;
return posix_error(EBADF);
#else
const auto &h = static_cast<const symlink_handle &>(_h);
@@ -45,7 +47,7 @@ namespace detail
}
}
-result<void> symlink_handle::_create_symlink(path_view target, deadline d, bool atomic_replace) noexcept
+result<void> symlink_handle::_create_symlink(const path_handle &dirh, const handle::path_type &filename, path_view target, deadline d, bool atomic_replace) noexcept
{
std::chrono::steady_clock::time_point began_steady;
std::chrono::system_clock::time_point end_utc;
@@ -63,17 +65,6 @@ result<void> symlink_handle::_create_symlink(path_view target, deadline d, bool
path_view::c_str zpath(target);
try
{
-#if !LLFIO_SYMLINK_HANDLE_IS_FAKED
- if(_devid == 0 && _inode == 0)
- {
- OUTCOME_TRY(_fetch_inode());
- }
- path_type filename;
- OUTCOME_TRY(dirh, detail::containing_directory(std::ref(filename), *this, *this, d));
-#else
- const path_handle &dirh = _dirh;
- const path_type &filename = _leafname;
-#endif
if(atomic_replace)
{
// symlinkat() won't replace an existing symlink, so we need to create it
@@ -82,7 +73,8 @@ result<void> symlink_handle::_create_symlink(path_view target, deadline d, bool
{
auto randomname = utils::random_string(32);
randomname.append(".random");
- if(-1 == ::symlinkat(zpath.buffer, dirh.native_handle().fd, randomname.c_str()))
+ // std::cerr << "symlinkat " << zpath.buffer << " " << dirh.native_handle().fd << " " << randomname << std::endl;
+ if(-1 == ::symlinkat(zpath.buffer, dirh.is_valid() ? dirh.native_handle().fd : AT_FDCWD, randomname.c_str()))
{
if(EEXIST == errno)
{
@@ -108,7 +100,8 @@ result<void> symlink_handle::_create_symlink(path_view target, deadline d, bool
}
return posix_error();
}
- if(-1 == ::renameat(dirh.native_handle().fd, randomname.c_str(), dirh.native_handle().fd, filename.c_str()))
+ // std::cerr << "renameat " << dirh.native_handle().fd << " " << randomname << " " << filename << std::endl;
+ if(-1 == ::renameat(dirh.is_valid() ? dirh.native_handle().fd : AT_FDCWD, randomname.c_str(), dirh.is_valid() ? dirh.native_handle().fd : AT_FDCWD, filename.c_str()))
{
return posix_error();
}
@@ -117,7 +110,8 @@ result<void> symlink_handle::_create_symlink(path_view target, deadline d, bool
}
else
{
- if(-1 == ::symlinkat(zpath.buffer, dirh.native_handle().fd, filename.c_str()))
+ // std::cerr << "symlinkat " << zpath.buffer << " " << dirh.native_handle().fd << " " << filename << std::endl;
+ if(-1 == ::symlinkat(zpath.buffer, dirh.is_valid() ? dirh.native_handle().fd : AT_FDCWD, filename.c_str()))
{
return posix_error();
}
@@ -221,6 +215,11 @@ result<symlink_handle::path_type> symlink_handle::current_path() const noexcept
LLFIO_LOG_FUNCTION_CALL(this);
try
{
+ // Deleted?
+ if(!_dirh.is_valid() && _leafname.empty())
+ {
+ return _leafname;
+ }
for(;;)
{
// Sanity check that we still exist
@@ -243,6 +242,42 @@ result<symlink_handle::path_type> symlink_handle::current_path() const noexcept
return error_from_exception();
}
}
+
+result<void> symlink_handle::relink(const path_handle &base, path_view_type path, bool atomic_replace, deadline d) noexcept
+{
+ LLFIO_LOG_FUNCTION_CALL(this);
+ OUTCOME_TRY(fs_handle::relink(base, path, atomic_replace, d));
+ try
+ {
+ // Take a path handle to the directory containing the symlink
+ auto path_parent = path.parent_path();
+ _leafname = path.filename().path();
+ if(base.is_valid() && path_parent.empty())
+ {
+ OUTCOME_TRY(dh, base.clone());
+ _dirh = std::move(dh);
+ }
+ else if(!path_parent.empty())
+ {
+ OUTCOME_TRY(dh, path_handle::path(base, path_parent));
+ _dirh = std::move(dh);
+ }
+ }
+ catch(...)
+ {
+ return error_from_exception();
+ }
+ return success();
+}
+
+result<void> symlink_handle::unlink(deadline d) noexcept
+{
+ LLFIO_LOG_FUNCTION_CALL(this);
+ OUTCOME_TRY(fs_handle::unlink(d));
+ _dirh = {};
+ _leafname = path_type();
+ return success();
+}
#endif
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
@@ -258,37 +293,37 @@ LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<symlink_handle> symlink_handle::symlink(c
OUTCOME_TRY(attribs, attribs_from_handle_mode_caching_and_flags(nativeh, _mode, _creation, caching::all, flags));
nativeh.behaviour &= ~native_handle_type::disposition::seekable; // not seekable
#if !LLFIO_SYMLINK_HANDLE_IS_FAKED
- // Linux can open symbolic links directly like this
- attribs |= O_PATH | O_NOFOLLOW;
- path_view::c_str zpath(path);
- if(base.is_valid())
- {
- nativeh.fd = ::openat(base.native_handle().fd, zpath.buffer, attribs, 0x1b0 /*660*/);
- }
- else
- {
- nativeh.fd = ::open(zpath.buffer, attribs, 0x1b0 /*660*/);
- }
- if(-1 == nativeh.fd)
- {
- return posix_error();
- }
+ path_handle dirh;
+ path_type leafname;
#else
(void) attribs;
+ path_handle &dirh = ret.value()._dirh;
+ path_type &leafname = ret.value()._leafname;
+#endif
+ int dirhfd = AT_FDCWD;
try
{
// Take a path handle to the directory containing the symlink
auto path_parent = path.parent_path();
- ret.value()._leafname = path.filename().path();
- if(base.is_valid() && !path_parent.empty())
+ leafname = path.filename().path();
+ if(base.is_valid() && path_parent.empty())
{
+#if !LLFIO_SYMLINK_HANDLE_IS_FAKED
+ dirhfd = base.native_handle().fd;
+#else
OUTCOME_TRY(dh, base.clone());
- ret.value()._dirh = std::move(dh);
+ dirh = std::move(dh);
+ dirhfd = dirh.native_handle().fd;
+#endif
}
else
+#if !LLFIO_SYMLINK_HANDLE_IS_FAKED // always take a dirh if faking the handle for race safety
+ if(!path_parent.empty())
+#endif
{
OUTCOME_TRY(dh, path_handle::path(base, path_parent.empty() ? "." : path_parent));
- ret.value()._dirh = std::move(dh);
+ dirh = std::move(dh);
+ dirhfd = dirh.native_handle().fd;
}
}
catch(...)
@@ -301,7 +336,7 @@ LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<symlink_handle> symlink_handle::symlink(c
{
// Complain if it doesn't exist
struct stat s;
- if(-1 == ::fstatat(ret.value()._dirh.native_handle().fd, ret.value()._leafname.c_str(), &s, AT_SYMLINK_NOFOLLOW))
+ if(-1 == ::fstatat(dirhfd, leafname.c_str(), &s, AT_SYMLINK_NOFOLLOW))
{
return posix_error();
}
@@ -312,13 +347,13 @@ LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<symlink_handle> symlink_handle::symlink(c
case creation::truncate:
{
// Create an empty symlink, ignoring any file exists errors, unless only_if_not_exist
- auto r = ret.value()._create_symlink(
+ auto r = ret.value()._create_symlink(dirh, leafname,
#ifdef __linux__
- ".", // Linux is not POSIX conforming here, and refuses to create empty symlinks
+ ".", // Linux is not POSIX conforming here, and refuses to create empty symlinks
#else
- "",
+ "",
#endif
- std::chrono::seconds(10), false);
+ std::chrono::seconds(10), false);
if(!r)
{
if(_creation == creation::only_if_not_exist || r.error() != errc::file_exists)
@@ -327,6 +362,14 @@ LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<symlink_handle> symlink_handle::symlink(c
break;
}
}
+#if !LLFIO_SYMLINK_HANDLE_IS_FAKED
+ // Linux can open symbolic links directly like this
+ attribs |= O_PATH | O_NOFOLLOW;
+ nativeh.fd = ::openat(dirhfd, leafname.c_str(), attribs, 0x1b0 /*660*/);
+ if(-1 == nativeh.fd)
+ {
+ return posix_error();
+ }
#endif
return ret;
}
@@ -389,7 +432,36 @@ 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 d) noexcept
{
LLFIO_LOG_FUNCTION_CALL(this);
- OUTCOME_TRY(_create_symlink(req.buffers.path(), d, true));
+#if !LLFIO_SYMLINK_HANDLE_IS_FAKED
+ if(_devid == 0 && _inode == 0)
+ {
+ OUTCOME_TRY(_fetch_inode());
+ }
+ path_type filename;
+ OUTCOME_TRY(dirh, detail::containing_directory(std::ref(filename), *this, *this, d));
+#else
+ const path_handle &dirh = _dirh;
+ const path_type &filename = _leafname;
+#endif
+ OUTCOME_TRY(_create_symlink(dirh, filename, req.buffers.path(), d, true));
+#if !LLFIO_SYMLINK_HANDLE_IS_FAKED
+ {
+ // Current fd now points at the symlink we just atomically replaced, so need to reopen
+ // it onto the new symlink
+ auto newthis = symlink(dirh, filename, is_writable() ? mode::write : mode::read, creation::open_existing, _flags);
+ // Prevent unlink on first close if set
+ _flags &= ~flag::unlink_on_first_close;
+ // Close myself
+ OUTCOME_TRY(close());
+ // If reopen failed, report that now
+ if(!newthis)
+ {
+ return newthis.error();
+ }
+ // Swap myself with the new this
+ swap(newthis.value());
+ }
+#endif
return success(std::move(req.buffers));
}
diff --git a/include/llfio/v2.0/detail/impl/windows/handle.ipp b/include/llfio/v2.0/detail/impl/windows/handle.ipp
index cebc354f..e3d0e851 100644
--- a/include/llfio/v2.0/detail/impl/windows/handle.ipp
+++ b/include/llfio/v2.0/detail/impl/windows/handle.ipp
@@ -75,6 +75,14 @@ result<void> handle::close() noexcept
LLFIO_LOG_FUNCTION_CALL(this);
if(_v)
{
+#ifndef NDEBUG
+ // Trap when refined handle implementations don't set their vptr properly (this took a while to debug!)
+ if((static_cast<unsigned>(_v.behaviour) & 0xff00) != 0 && !(_v.behaviour & native_handle_type::disposition::_child_close_executed))
+ {
+ LLFIO_LOG_FATAL(this, "handle::close() called on a derived handle implementation, this suggests vptr is incorrect");
+ abort();
+ }
+#endif
if(are_safety_fsyncs_issued() && is_writable())
{
if(FlushFileBuffers(_v.h) == 0)
diff --git a/include/llfio/v2.0/detail/impl/windows/map_handle.ipp b/include/llfio/v2.0/detail/impl/windows/map_handle.ipp
index ca54e008..e1661072 100644
--- a/include/llfio/v2.0/detail/impl/windows/map_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/windows/map_handle.ipp
@@ -59,6 +59,10 @@ result<void> section_handle::close() noexcept
LLFIO_LOG_FUNCTION_CALL(this);
if(_v)
{
+#ifndef NDEBUG
+ // Tell handle::close() that we have correctly executed
+ _v.behaviour |= native_handle_type::disposition::_child_close_executed;
+#endif
OUTCOME_TRYV(handle::close());
OUTCOME_TRYV(_anonymous.close());
_flag = flag::none;
@@ -477,8 +481,9 @@ map_handle::io_result<map_handle::const_buffers_type> map_handle::barrier(map_ha
}
-result<map_handle> map_handle::map(size_type bytes, section_handle::flag _flag) noexcept
+result<map_handle> map_handle::map(size_type bytes, bool /*unused*/, section_handle::flag _flag) noexcept
{
+ // TODO: Keep a cache of DiscardVirtualMemory()/MEM_RESET pages deallocated
bytes = win32_round_up_to_allocation_size(bytes);
result<map_handle> ret(map_handle(nullptr));
native_handle_type &nativeh = ret.value()._v;
diff --git a/include/llfio/v2.0/file_handle.hpp b/include/llfio/v2.0/file_handle.hpp
index c41ac559..de8386f0 100644
--- a/include/llfio/v2.0/file_handle.hpp
+++ b/include/llfio/v2.0/file_handle.hpp
@@ -208,6 +208,13 @@ public:
}
}
}
+#ifndef NDEBUG
+ if(_v)
+ {
+ // Tell handle::close() that we have correctly executed
+ _v.behaviour |= native_handle_type::disposition::_child_close_executed;
+ }
+#endif
return io_handle::close();
}
diff --git a/include/llfio/v2.0/map_handle.hpp b/include/llfio/v2.0/map_handle.hpp
index 60deb440..d84df116 100644
--- a/include/llfio/v2.0/map_handle.hpp
+++ b/include/llfio/v2.0/map_handle.hpp
@@ -377,8 +377,9 @@ public:
return ret;
}
- /*! Create new memory and map it into view.
- \param bytes How many bytes to create and map. Typically will be rounded up to a multiple of the page size (see `utils::page_sizes()`) on POSIX, 64Kb on Windows.
+ /*! Map unused memory into view, creating new memory if insufficient unused memory is available. Note that the memory mapped by this call may contain non-zero bits (recycled memory) unless `zeroed` is true.
+ \param bytes How many bytes to map. Typically will be rounded up to a multiple of the page size (see `utils::page_sizes()`) on POSIX, 64Kb on Windows.
+ \param zeroed Set to true if only all bits zeroed memory is wanted.
\param _flag The permissions with which to map the view. `flag::none` can be useful for reserving virtual address space without committing system resources, use commit() to later change availability of memory.
\note On Microsoft Windows this constructor uses the faster VirtualAlloc() which creates less versatile page backed memory. If you want anonymous memory
@@ -389,7 +390,7 @@ public:
\errors Any of the values POSIX mmap() or VirtualAlloc() can return.
*/
LLFIO_MAKE_FREE_FUNCTION
- static LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<map_handle> map(size_type bytes, section_handle::flag _flag = section_handle::flag::readwrite) noexcept;
+ static LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<map_handle> map(size_type bytes, bool zeroed = false, section_handle::flag _flag = section_handle::flag::readwrite) noexcept;
/*! Create a memory mapped view of a backing storage, optionally reserving additional address space for later growth.
\param section A memory section handle specifying the backing storage to use.
@@ -646,9 +647,9 @@ VirtualAlloc() memory cannot do.
\errors Any of the values POSIX mmap() or VirtualAlloc() can return.
*/
-inline result<map_handle> map(map_handle::size_type bytes, section_handle::flag _flag = section_handle::flag::readwrite) noexcept
+inline result<map_handle> map(map_handle::size_type bytes, bool zeroed = false, section_handle::flag _flag = section_handle::flag::readwrite) noexcept
{
- return map_handle::map(std::forward<decltype(bytes)>(bytes), std::forward<decltype(_flag)>(_flag));
+ return map_handle::map(std::forward<decltype(bytes)>(bytes), zeroed, std::forward<decltype(_flag)>(_flag));
}
/*! Create a memory mapped view of a backing storage, optionally reserving additional address space for later growth.
\param section A memory section handle specifying the backing storage to use.
diff --git a/include/llfio/v2.0/mapped.hpp b/include/llfio/v2.0/mapped.hpp
index e0385254..e723ca75 100644
--- a/include/llfio/v2.0/mapped.hpp
+++ b/include/llfio/v2.0/mapped.hpp
@@ -81,13 +81,15 @@ public:
//! Returns a reference to the internal map handle
const map_handle &map() const noexcept { return _maph; }
- /*! Create a view of new memory.
+ /*! Create a view of newly allocated unused memory, creating new memory if insufficient unused memory is available.
+ Note that the memory mapped by this call may contain non-zero bits (recycled memory) unless `zeroed` is true.
\param length The number of items to map.
+ \param zeroed Whether to ensure that the viewed memory returned is all bits zero or not.
\param _flag The flags to pass to `map_handle::map()`.
*/
- explicit mapped(size_type length, section_handle::flag _flag = section_handle::flag::readwrite)
- : _maph(map_handle::map(length * sizeof(T), _flag).value())
+ explicit mapped(size_type length, bool zeroed = false, section_handle::flag _flag = section_handle::flag::readwrite)
+ : _maph(map_handle::map(length * sizeof(T), zeroed, _flag).value())
{
byte *addr = _maph.address();
static_cast<span<T> &>(*this) = span<T>(reinterpret_cast<T *>(addr), length); // NOLINT
diff --git a/include/llfio/v2.0/native_handle_type.hpp b/include/llfio/v2.0/native_handle_type.hpp
index 0961db83..c4784f94 100644
--- a/include/llfio/v2.0/native_handle_type.hpp
+++ b/include/llfio/v2.0/native_handle_type.hpp
@@ -58,7 +58,9 @@ struct native_handle_type // NOLINT
symlink = 1U << 10U, //!< Is a symlink
multiplexer = 1U << 11U, //!< Is a kqueue/epoll/iocp
process = 1U << 12U, //!< Is a child process
- section = 1U << 13U //!< Is a memory section
+ section = 1U << 13U, //!< Is a memory section
+
+ _child_close_executed = 1U << 28U // used to trap when vptr has become corrupted
}
QUICKCPPLIB_BITFIELD_END(disposition)
disposition behaviour; //! The behaviour of the handle
diff --git a/include/llfio/v2.0/path_handle.hpp b/include/llfio/v2.0/path_handle.hpp
index 87798c04..1e308ca7 100644
--- a/include/llfio/v2.0/path_handle.hpp
+++ b/include/llfio/v2.0/path_handle.hpp
@@ -64,7 +64,6 @@ public:
//! Default constructor
constexpr path_handle() {} // NOLINT
- ~path_handle() = default;
//! Construct a handle from a supplied native handle
explicit constexpr path_handle(native_handle_type h, caching caching = caching::all, flag flags = flag::none)
: handle(h, caching, flags)
@@ -77,9 +76,22 @@ public:
//! No copy construction (use `clone()`)
path_handle(const path_handle &) = delete;
//! Move assignment permitted
- path_handle &operator=(path_handle &&) = default;
+ path_handle &operator=(path_handle &&o) noexcept
+ {
+ this->~path_handle();
+ new(this) path_handle(std::move(o));
+ return *this;
+ }
//! No copy assignment
path_handle &operator=(const path_handle &) = delete;
+ //! Swap with another instance
+ LLFIO_MAKE_FREE_FUNCTION
+ void swap(path_handle &o) noexcept
+ {
+ path_handle temp(std::move(*this));
+ *this = std::move(o);
+ o = std::move(temp);
+ }
/*! Create a path handle opening access to some location on the filing system.
Some operating systems provide a particularly lightweight method of doing this
@@ -94,6 +106,25 @@ public:
LLFIO_MAKE_FREE_FUNCTION
static LLFIO_HEADERS_ONLY_MEMFUNC_SPEC result<path_handle> path(path_view_type _path) noexcept { return path(path_handle(), _path); }
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC ~path_handle() override
+ {
+ if(_v)
+ {
+ (void) path_handle::close();
+ }
+ }
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<void> close() noexcept override
+ {
+ LLFIO_LOG_FUNCTION_CALL(this);
+#ifndef NDEBUG
+ if(_v)
+ {
+ // Tell handle::close() that we have correctly executed
+ _v.behaviour |= native_handle_type::disposition::_child_close_executed;
+ }
+#endif
+ return handle::close();
+ }
/*! Clone this handle (copy constructor is disabled to avoid accidental copying).
*/
result<path_handle> clone() const noexcept
diff --git a/include/llfio/v2.0/symlink_handle.hpp b/include/llfio/v2.0/symlink_handle.hpp
index 266f4d79..844afe51 100644
--- a/include/llfio/v2.0/symlink_handle.hpp
+++ b/include/llfio/v2.0/symlink_handle.hpp
@@ -31,7 +31,7 @@ Distributed under the Boost Software License, Version 1.0.
//! \file symlink_handle.hpp Provides a handle to a symbolic link.
#ifndef LLFIO_SYMLINK_HANDLE_IS_FAKED
-#if defined(_WIN32) //|| defined(__linux__)
+#if defined(_WIN32) || defined(__linux__)
#define LLFIO_SYMLINK_HANDLE_IS_FAKED 0
#else
#define LLFIO_SYMLINK_HANDLE_IS_FAKED 1
@@ -84,8 +84,8 @@ class LLFIO_DECL symlink_handle : public handle, public fs_handle
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC const handle &_get_handle() const noexcept final { return *this; }
#ifndef _WIN32
- friend LLFIO_HEADERS_ONLY_FUNC_SPEC result<void> detail::stat_from_symlink(struct stat &s, const handle &h) noexcept;
- result<void> _create_symlink(path_view target, deadline d, bool atomic_replace) noexcept;
+ friend result<void> detail::stat_from_symlink(struct stat &s, const handle &h) noexcept;
+ result<void> _create_symlink(const path_handle &dirh, const handle::path_type &filename, path_view target, deadline d, bool atomic_replace) noexcept;
#endif
public:
@@ -311,9 +311,22 @@ public:
//! No copy construction (use `clone()`)
symlink_handle(const symlink_handle &) = delete;
//! Move assignment permitted
- symlink_handle &operator=(symlink_handle &&) = default;
+ symlink_handle &operator=(symlink_handle &&o) noexcept
+ {
+ this->~symlink_handle();
+ new(this) symlink_handle(std::move(o));
+ return *this;
+ }
//! No copy assignment
symlink_handle &operator=(const symlink_handle &) = delete;
+ //! Swap with another instance
+ LLFIO_MAKE_FREE_FUNCTION
+ void swap(symlink_handle &o) noexcept
+ {
+ symlink_handle temp(std::move(*this));
+ *this = std::move(o);
+ o = std::move(temp);
+ }
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC ~symlink_handle() override
{
@@ -338,6 +351,13 @@ public:
}
}
#if !LLFIO_SYMLINK_HANDLE_IS_FAKED
+#ifndef NDEBUG
+ if(_v)
+ {
+ // Tell handle::close() that we have correctly executed
+ _v.behaviour |= native_handle_type::disposition::_child_close_executed;
+ }
+#endif
return handle::close();
#else
_dirh = {};
@@ -362,6 +382,12 @@ public:
#if LLFIO_SYMLINK_HANDLE_IS_FAKED
LLFIO_HEADERS_ONLY_VIRTUAL_SPEC result<path_type> current_path() const noexcept override;
+ LLFIO_MAKE_FREE_FUNCTION
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC
+ result<void> relink(const path_handle &base, path_view_type path, bool atomic_replace = true, deadline d = std::chrono::seconds(30)) noexcept override;
+ LLFIO_MAKE_FREE_FUNCTION
+ LLFIO_HEADERS_ONLY_VIRTUAL_SPEC
+ result<void> unlink(deadline d = std::chrono::seconds(30)) noexcept override;
#endif
/*! Create a symlink handle opening access to a symbolic link.