std::filesystem Implementation Corner Cases, part 2
[See also: std::filesystem Implementation Corner Cases, part 1]
create_directories [fs.op.create_directories]
Given a p
with:
auto p = fs::path("a/b/c/");
where there is none of the directories in that path existing in the current directory and we have enough rights to create directories we get:
Clang >9.0.1 (godbolt trunk) and MSVC 19.16/19.23:
FAILED:
CHECK( fs::create_directories(t.path() / "d/e/f/", ec) )
with expansion:
false
I made a godbolt example: https://godbolt.org/z/5883uY
#include <filesystem>
#include <iostream>
#include <system_error>
int main() {
std::error_code ec;
std::cout << std::boolalpha << std::filesystem::exists("a/b/c/") << "/";
std::cout << std::filesystem::create_directories("a/b/c/", ec) << "/";
std::cout << !!ec << "/" << std::filesystem::exists("a/b/c/");
}
GCC:
false/true/false/true
So 1) false
, as it doesn’t exists, 2) true
, as create_directories()
created it,
3) false
, as there is no error, and 4) true
, the path now exists.
Clang (trunk) (and MSVC as tested via Appveyor):
false/false/false/true
This is 1) false
, as it doesn’t exist, 2) false
, telling us it didn’t create a
directory, 3) false
, there was no error, and 4) true
, as the path now exists.
The directories are created but the function returns false, while not setting any error condition in ec.
The standard reads: “Returns: true if a new directory was created, otherwise false.
The signature with argument ec returns false
if an error occurs.”
Clearly there should have been either a return of true or an error in ec
. The
function did create three directory, but tells us it didn’t.
Analyzing the source of libc++ and MSVC (github) for this, it can be seen, that both create the series of directory creations (libc++ uses recursion, MSVC iteration):
"a"
"a/b"
"a/b/c"
"a/b/c/"
The returned bool is for both the result of the last directory creation, and
both return false
because the last call does nothing as the last two are
the same from the perspective of CreateDirectoryW
and ::mkdir
.
My tests on Travis using Clang 7, 8 and 9 didn’t show this behaviour, which irritates me a bit.