Check if an std::filesystem::path is inside a directory
Asked Answered
I

1

8

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 ?

Igraine answered 9/4, 2020 at 14:34 Comment(3)
Does this help? en.cppreference.com/w/cpp/experimental/fs/canonicalLucan
If only the std::filesystem library contained some function that computed a new absolute path, wouldn't it be useful?Watkins
@SamVarshavchik: No, it wouldn't, because absolute (and canonical for that matter) both require the path to exist. Which it may not.Rattlebrain
R
12

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.

Rattlebrain answered 9/4, 2020 at 16:2 Comment(1)
use std::filesystem::weakly_canonical() to avoid requirement of existance in canonicalFedora

© 2022 - 2024 — McMap. All rights reserved.