This commit changes behavior of directory_entry constructors and modifiers
that change the stored path in v4: the methods will now automatically query
the filesystem for the file status instead of leaving the cached data
default-initialized. This means that the paths passed to directory_entry
must be valid, otherwise an error will be returned. Filesystem querying
is implemented in the new directory_entry::refresh methods.
The constructors and modifiers that accepted file_status arguments are
now removed in v4. The cached file statuses are an implementation detail,
and eventually we may want to add more cached data, as we add more observers
to directory_entry.
Also added a few file type observers to directory_entry. These observers
allow to avoid querying the filesystem if the full file status is not cached
but the file type is (i.e. when permissions are not cached). This is the case
with readdir-based implementation of directory_iterator, if the underlying
C library supports dirent::d_type field.
recursive_directory_iterator has been updated to use the added file type
observers instead of querying the full status. This may improve performance
of directory iteration.
Closes https://github.com/boostorg/filesystem/issues/288.
This fixes hard compilation error when the passed type is not an iterator
at all. As a result, path constructors from iterators are no longer
selected by the compiler in overload resolution in users' code, when
the caller is passing an initializer list with a pair of non-iterator
elements. Added a test for this fix.
Also, use integral_constant to implement boolean type traits.
Fixes https://github.com/boostorg/filesystem/issues/287.
Path comparison operators that accept arbitrary path source types now require
the other argument to be exactly path. This prevents the compiler from picking
those operators when the other argument is convertible to path. This can happen
even when neither of the arguments are actually paths, e.g. when the
comparison operators are brought into the current scope by a using directive.
Fixes https://github.com/boostorg/filesystem/issues/285.
GetFileInformationByHandleEx with information classes that produce FILE_ID_128
fail with a special error code ERROR_INVALID_LEVEL when the filesystem is
SMBv1. Treat this error code the same as ERROR_INVALID_PARAMETER.
Fixes https://github.com/boostorg/filesystem/issues/284.
If the file handle for a directory in a SMBv1 share was opened with
FILE_READ_ATTRIBUTES access mode, GetFileInformationByHandleEx with
FileAttributeTagInfo returns FILE_ATTRIBUTE_NORMAL in the attributes, which
affected status, symlink_status and everything depending on those.
Work around this Windows bug by adding FILE_READ_EA everywhere where we need
attributes to be correct.
Also, use GENERIC_READ access mode when we call GetFileTime on the handle
afterwards. GetFileTime documentation explicitly mentions that GENERIC_READ
is required for it.
Fixes https://github.com/boostorg/filesystem/issues/282.
The previous strategy of force-inlining methods that are dependent
on the library version is not effective with MSVC in debug mode,
when linking the static library. The compiler does not inline
methods despite the markup, and during linking the static library
with the user's module the linker may or may not pick up user's
definitions of these methods.
When building the library, do not define path methods that depend
on the library version. Instead, explicitly call v4 internal methods
throughout the implementation. This way the compiled library does not
contain v4 versions of these methods, and therefore does not conflict
with user's definitions of these methods.
Fixes https://github.com/boostorg/filesystem/issues/279.
v4 remove_filename works similar to std::filesystem, i.e. preserves
the trailing directory separator after removing the filename.
v3 remove_filename works as before. Its behavior is also useful in
v4, so added a new method remove_filename_and_trailing_separators
with the same behavior.
Also added replace_filename that was previously missing.
remove_filename discrepancy from std::filesystem was reported in:
https://github.com/boostorg/filesystem/issues/271
This resolves build error if examples are compiled for multiple
target configurations. When building tutorial examples, only one
target is supposed to be used.
This causes ambiguities in users' code where the previously added conversion
from user-defined types that have a conversion to one of the path source
types:
struct my_class
{
operator std::string() const;
};
std::string to_string(std::string const&);
std::string to_string(boost::filesystem::path const&);
to_string(my_class());
The above call is ambiguous as the conversion operator in my_class and
a converting constructor in boost::filesystem::path from my_class are
both available and have equivalent ranks.
Removing the conversion constructors from boost::filesystem::path
means users will have to explicitly cast their types to one of the
path source types before constructing path.
In order to preserve backward compatibility with operator== and operator!=
for paths that also accepted source types (path::string_type,
const path::value_type*), we have to update path::compare and comparison
operators to accept types that are convertible to source types.
Fixes https://github.com/boostorg/filesystem/issues/273.
Deduplicated files are reparse points with IO_REPARSE_TAG_DEDUP tag. Such
files are created by a dedup service running in the background, so a regular
file may be converted to a dedup reparse point at any time and without user's
intervention. For all intents and purposes dedup files should look like
normal, regular files, so it makes sense to report them as such in
Boost.Filesystem methods like status(), symlink_status() and everything
based on those. This commit implements this.
Closes https://github.com/boostorg/filesystem/issues/262.
Added ERROR_CALL_NOT_IMPLEMENTED to the list of error codes that are used
to permanently downgrade directory querying method. This error code is
returned by Wine, which up until version 7.21 did not support
FileIdExtdDirectoryRestartInfo and FileFullDirectoryRestartInfo.
Further, use non-permanent downgrade on ERROR_INVALID_PARAMETER. Apparently,
some mounted filesystems don't implement even the older info classes,
such as FileFullDirectoryRestartInfo and FileIdBothDirectoryRestartInfo.
These info classes are otherwise supported by the system and work on other
filesystems.
Lastly, if querying FileIdBothDirectoryRestartInfo fails, fall back to
NtQueryDirectoryFile API.
Fixes https://github.com/boostorg/filesystem/issues/255.
Fixes https://github.com/boostorg/filesystem/issues/266.
Closes https://github.com/boostorg/filesystem/pull/267.
Path traits and relevant path members were reworked to better support
wider range of types that are compatible with path constructors, assignment
and appending members. Added support for C++17 std::string_view,
boost::string_view and boost::container::string as the possible string
types accepted by path members.
Also extended support for types convertible to one of the string types.
Previously, user's type had to be convertible to a string with a character
type that matches the native path character type. Now all supported character
types are acceptable.
Additionally, restricted members accepting a pair of iterators to only accept
iterators whose value types are one of the supported path character types.
Lastly, path::compare and comparison operators now only accept path arguments,
relying on path conversion constructors to do the job of supporting various
source types. Also removed noexcept from compare as it is using lex_compare
and iterators internally and those can throw.
Closes https://github.com/boostorg/filesystem/issues/208.
Users are advised to use string types and iterators instead of containers
to construct/assign/append to paths.
In v4, the support for containers is removed.
During its operation, weakly_canonical would call status() on the path
consisting only from the root name of the input path. This would fail
with ERROR_INVALID_FUNCTION if the root name starts with the "\\?\" prefix,
as the root name path is not absolute.
To fix this, we don't check the status of the root name path (which is
not the correct check anyways as it tests the current directory on the
corresponding drive for existence, which is not what we want). Additionally,
avoid calling status() on the paths containing dot and dot-dot elements
during the weakly_canonical execution for the same reason - the "\\?\"
prefix disables most of the path processing in Windows APIs, including
dot and dot-dot elements resolution.
Fixes https://github.com/boostorg/filesystem/issues/247.
This follows up the previous update for POSIX.
The new implementation of remove_all on Windows Vista and later uses
NtCreateFile internal function in order to open files relative to
a previously opened directory handle, similar to POSIX openat.
Furthermore, querying file status and removing the file is now also
done through file handles to avoid performing path resolutions.
Closes https://github.com/boostorg/filesystem/issues/224.
The previous implementation could still allow for following symlinks
while remove_all is running if a directory was replaced with a symlink
higher in the tree than remove_all is currently processing. This was
reported here:
https://github.com/boostorg/filesystem/issues/224#issuecomment-1183738097
The solution is to use POSIX.1-2008 *at APIs to prevent symlink resolution
higher in the directory tree while iterating over the subtree in remove_all.
This required updating the directory iterator construction interface so that
it is possible to pass the base directory fd and return fd of the directory
used by the iterator. This is done via platform-specific params that are
currently defined only for POSIX. Additionally, status, symlink_status and
remove were extended to accept the base directory fd as well.
Other systems, including Windows, remain vulnerable.
Related to https://github.com/boostorg/filesystem/issues/224.
The copy_file_range implementation of copy_file used to set incorrect sendfile
fallback if copy_file_range failed with ENOSYS. The fallback would skip
checking the filesystem type for whether it is supported by sendfile.
Also, wrapped sendfile and copy_file_range implementations in structs to
silence clang warnings about using C++11 feature in C++03 mode: the functions
are in an anonymous namespace and therefore have internal linkage, and
pointers to such functions are not allowed to be used in non-type template
parameters in C++03.
Reproduce the workaround for GetFileInformationByHandleEx returning
ERROR_INVALID_PARAMETER when querying FILE_ATTRIBUTE_TAG_INFO on FAT/exFAT
filesystems in directory iterator construction.
Fixes https://github.com/boostorg/filesystem/issues/237.
Apparently, GetFileInformationByHandleEx(FileAttributeTagInfo) fails
with ERROR_INVALID_PARAMETER on FAT/exFAT filesystems, which used to
be interpreted as "file not found" result in (symlink_)status(). The
file is clearly present since it was successfully opened before,
and the error is presumably because the filesystem does not support
reparse points and cannot return a ReparseTag.
Check that error code and also ERROR_NOT_SUPPORTED for good measure
and fall back to the legacy code path that works for FAT/exFAT.
Fixes https://github.com/boostorg/filesystem/issues/236.
For some system files and folders like "System Volume Information"
CreateFileW fails with ERROR_ACCESS_DENIED while GetFileAttributesW
succeeds. GetFileAttributesW doesn't allow to discover whether the
file is a symlink or some other kind of a reparse point, so this
fallback will only work for files that are not reparse points,
symlinks or not. For reparse points continue to report error.
Closes https://github.com/boostorg/filesystem/issues/234.
Even though the syscall number is defined in kernel headers, the syscall
is blacklisted by seccomp in runtime.
Note that Android 11 also introduces the libc wrapper for statx, so
effectively the library will always use the libc wrapper on Android.
Reported in https://github.com/boostorg/filesystem/issues/229.
Windows 10 1709 and later support POSIX semantics for removing files,
which means the file name is removed from the filesystem namespace as
soon as the file is marked for deletion. This makes opening the file
afterwards impossible, and allows creating a new file with the same
name, even if the deleted file is still open and in use.
The implementation uses runtime detection of the feature in the OS.
We are also using two more implementations for file removal: one that
employs the more recent FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE
flag (available since Windows 10 1809), and FILE_DISPOSITION_INFO
structure (supported since Windows Vista). The former allows to optimize
removal of read-only files, and the latter allows to make file deletion
atomic (i.e. not prone to failure if the file is replaced on the filesystem
while the operation is executing). The implementation is chosen in
runtime, depending on which one succeeds removing a file.
Also, added support for deleting read-only directories, in addition
to non-directory files, and simplified code a little.
Closes https://github.com/boostorg/filesystem/issues/216.
We have changed v4 path::extension() to not return the filename if
it starts with a dot, but we have not made path::replace_extension
version-dependent, which made v3 behave like v4. Fixing this,
and optimizing v4 path::replace_extension in the process.
directory_iterator implementation now explicitly opens a directory
handle and relies on GetFileInformationByHandleEx or NtQueryDirectoryFile
to query information of the files in the directory. With
GetFileInformationByHandleEx, there are at least three ways to request
the information, each supported on different Windows versions and
different filesystems and providing different sets of information.
We support all three (FILE_ID_BOTH_DIR_INFO, FILE_FULL_DIR_INFO and
FILE_ID_EXTD_DIR_INFO), and we fall back to older ones if the newer
ones are not supported. GetFileInformationByHandleEx is available
since Windows Vista.
NtQueryDirectoryFile is an NT API that provides similar information to
GetFileInformationByHandleEx, but exists since at least Windows XP,
but some sources state it has existed since NT 4.0. This API is now
used when GetFileInformationByHandleEx is not available and it replaces
FindFirstFileW/FindNextFileW/FindClose based implementation (which
supposedly uses NtQueryDirectoryFile internally). Being an NT API,
we have to handle NTSTATUS error codes returned from it, so we had to
refactor unique path code that also used NTSTATUS previously.
Opening a directory handle explicitly allows to support O_NOFOLLOW
semantics on Windows, as we are able to prevent CreateFile from
following to the reparse point target. This is needed for remove_all
implementation to fix CVE-2022-21658. Similar to POSIX, remove_all_impl
on Windows now requests the directory iterator to not follow symlinks
when it is used to dive into a directory.
FindFirstFileW/FindNextFileW/FindClose based implementation is still
preserved for now for Windows CE, as it is unlikely to support neither
GetFileInformationByHandleEx nor NtQueryDirectoryFile. Given that
Windows CE has been untested for many years and is probably broken
anyway, its support is now declared deprecated. The related code,
including Find*-based directory iterator, will be removed in a
future release.
Closes https://github.com/boostorg/filesystem/issues/224.
And a couple cleanup changes:
- Since we now may use GetFileInformationByHandleEx, we are now using
it to query FILE_ATTRIBUTE_TAG_INFO for testing whether a reparse
point is a symlink.
- In resize_file_impl, we now specify all sharing flags to allow the
operation to succeed if the file is already opened by someone.
Turns out string_file.hpp was tested in operations_unit_test, though not
included directly. Since string_file.hpp contents are disabled when the
test is compiled (as any other deprecated functionality), the test failed
to compile.
Moved the string_file.hpp test to deprecated_test, which explicitly enables
deprecated functionality. Also, include string_file.hpp in filesystem.hpp
if explicitly requested by defining BOOST_FILESYSTEM_DEPRECATED.
Another process could replace the directory being processed by remove_all
with a symlink after remove_all called symlink_status but before
it creates a directory iterator. As a result, remove_all would remove
the linked directory contents instead of removing the symlink.
On POSIX systems that support fdopendir and O_NOFOLLOW flag for open(2),
this can be prevented by opening the directory with O_NOFOLLOW before
iterating. This will fail if the directory was replaced with a symlink.
No protection on other systems.
Reported in https://github.com/boostorg/filesystem/issues/224.
MSVC and possibly some other compilers that don't support __attribute__((used))
may remove the global p_init_path_globals pointer in a special data section
because it is not referenced anywhere. Add a dummy global object that
references the pointer in its constructor as a workaround.
Fixes https://github.com/boostorg/filesystem/issues/217.
Reworked remove() operation to separate POSIX and Windows implementations.
On Windows, if the file to be removed is read-only, try to reset the read-only
attribute before deleting the file. If deleting fails (other than because the
file is already deleted), try to restore the read-only attribute.
As a side effect, we were able to remove an implementation detail value from
the file_type enum that was used by the old remove() implementation.
Added a test for remove() on a read-only file on Windows. Also added tests
for remove_all(), including for cases with symlinks, hardlinks and read-only
files.
Also, corrected mklink /J argument in tests. The command accepts /j (lowercase)
to the same effect, but the formal help lists /J (uppercase) to create junctions.
Reported in https://github.com/boostorg/filesystem/issues/216.
In v4 path::lexically_normal, don't generate a trailing dot element if the
original path ends with a directory separator or dot. Also omit the trailing
directory separator the normalized path ends with a dot-dot element.
Additionally, convert directory separators to preferred separators in
root name on Windows (in v3 and v4). This may be significant for UNC paths.
If the source path ends with a non-empty filename, and the appended path
is empty, C++17 std::filesystem requires to add a trailing directory
separator.
Because of the changed semantics of appending operations in v4, path
composition in absolute() would produce incorrect results because at some
point it would append root directory and therefore discard root name
that was potentially added before. The updated implementation fixes that,
and also fixes the case when the input path is already absolute and
starts with a root directory, and the base path has a root name.
Previously, the returned path would contain the root name from the
base path, while the correct thing to do is to return the input path
as is.