I have a root path represented by an std::filesystem::path
. I want to add some user provided filename to this path and make sure the resulting path is not out of the root directory.
For example:
std::filesystem::path root = "/foo/bar";
std::filesystem::path userFile = "ham/spam";
std::filesystem::path finalPath = root / userFile;
The final path is ok, it is inside /foo/bar
.
But if I give ../ham/spam
to the userFile
variable, this will result in a file outside the define rootPath
.
How can I check that the resulting file keeps inside its allowed boundaries ?
filesystem::is_directory Checks if the given file status or path corresponds to a directory. 1) Equivalent to s. type() == file_type::directory. 2) Equivalent to is_directory(status(p)) or is_directory(status(p, ec)), respectively.
boost::filesystem::path is the central class in Boost. Filesystem for representing and processing paths. Definitions can be found in the namespace boost::filesystem and in the header file boost/filesystem. hpp . Paths can be built by passing a string to the constructor of boost::filesystem::path (see Example 35.1).
We can call IsEmpty to check whether a given directory is empty. An empty directory is considered to have no files or other directories in it. IsEmpty returns true if the directory is empty; false otherwise. The following table lists the parameters expected by this method.
First, you need to normalize the final path. This removes all .
and ..
s in the path. Then, you need to check to see if it has any mismatches in its directory iterator range, relative to root
. And there's a standard library algorithm for that.
So overall, the code looks like this:
std::optional<fs::path> MakeAbsolute(const fs::path &root, const fs::path &userPath)
{
auto finalPath = (root / userPath).lexically_normal();
auto[rootEnd, nothing] = std::mismatch(root.begin(), root.end(), finalPath.begin());
if(rootEnd != root.end())
return std::nullopt;
return finalPath;
}
Note that this only works theoretically; the user may have used symlink shenanigans within the root directory to break out of your root directory. You would need to use canonical
rather than lexically_normal
to ensure that this doesn't happen. However, canonical
requires that the path exist, so if this is a path to a file/directory that needs to be created, it won't work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With