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:
Diffstat (limited to 'include/llfio/v2.0/detail/impl/posix/directory_handle.ipp')
-rw-r--r--include/llfio/v2.0/detail/impl/posix/directory_handle.ipp52
1 files changed, 49 insertions, 3 deletions
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 61169c8f..f1cca812 100644
--- a/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp
+++ b/include/llfio/v2.0/detail/impl/posix/directory_handle.ipp
@@ -67,7 +67,7 @@ result<directory_handle> directory_handle::directory(const path_handle &base, pa
_mode = mode::read;
}
// Also trying to truncate a directory returns EISDIR
- if(_creation == creation::truncate)
+ if(_creation == creation::truncate_existing)
{
return errc::is_a_directory;
}
@@ -85,9 +85,34 @@ result<directory_handle> directory_handle::directory(const path_handle &base, pa
path = ".";
}
path_view::c_str zpath(path);
+ auto rename_random_dir_over_existing_dir = [_mode, _caching, flags](const path_handle &base, path_view_type path) -> result<directory_handle> {
+ // Take a path handle to the directory containing the file
+ auto path_parent = path.parent_path();
+ path_handle dirh;
+ 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);
+ }
+ // Create a randomly named directory, and rename it over
+ OUTCOME_TRY(rfh, random_directory(dirh, _mode, _caching, flags));
+ auto r = rfh.relink(dirh, path.filename());
+ if(r)
+ {
+ return std::move(rfh);
+ }
+ // If failed to rename, remove
+ (void) rfh.unlink();
+ return r.error();
+ };
if(base.is_valid())
{
- if(_creation == creation::if_needed || _creation == creation::only_if_not_exist)
+ if(_creation == creation::if_needed || _creation == creation::only_if_not_exist || _creation == creation::always_new)
{
if(-1 == ::mkdirat(base.native_handle().fd, zpath.buffer, 0x1f8 /*770*/))
{
@@ -95,6 +120,16 @@ result<directory_handle> directory_handle::directory(const path_handle &base, pa
{
return posix_error();
}
+ if(_creation == creation::always_new)
+ {
+ auto r = rename_random_dir_over_existing_dir(base, path);
+ if(!r)
+ {
+ return r.error();
+ }
+ ret = std::move(r).value();
+ goto opened;
+ }
}
attribs &= ~(O_CREAT | O_EXCL);
}
@@ -102,7 +137,7 @@ result<directory_handle> directory_handle::directory(const path_handle &base, pa
}
else
{
- if(_creation == creation::if_needed || _creation == creation::only_if_not_exist)
+ if(_creation == creation::if_needed || _creation == creation::only_if_not_exist || _creation == creation::always_new)
{
if(-1 == ::mkdir(zpath.buffer, 0x1f8 /*770*/))
{
@@ -110,6 +145,16 @@ result<directory_handle> directory_handle::directory(const path_handle &base, pa
{
return posix_error();
}
+ if(_creation == creation::always_new)
+ {
+ auto r = rename_random_dir_over_existing_dir(base, path);
+ if(!r)
+ {
+ return r.error();
+ }
+ ret = std::move(r).value();
+ goto opened;
+ }
}
attribs &= ~(O_CREAT | O_EXCL);
}
@@ -119,6 +164,7 @@ result<directory_handle> directory_handle::directory(const path_handle &base, pa
{
return posix_error();
}
+opened:
if(!(flags & flag::disable_safety_unlinks))
{
if(!ret.value()._fetch_inode())