user23573
user23573

Reputation: 2579

boost::filesystem::relative() cannot access the file because it is being used by another process

When accessing some network drives, the functions relative(path, base_path) and canonical(path, base_path) throw an exception. The message is always:

The process cannot access the file because it is being used by another process

I've observed this behavior only on some shared network drives that were operated by our IT department and contain symbolic links. I was not able to provoke the same issue on local drives or on shared drives from an adjacent computer. Our suspicion is that the archive/backup solution used on the network drives is also a driver here. The known factors are these so far:

My questions are:

One possible workaround would be to re-implement the relative() function to use only path manipulation and does not access the filesystem. But I'd like to avoid the re-implementation.

An small sample program that may exhibit the problem if the tested path has the issue:

#include <vector>
#include <string>
#include <tuple>
#include <boost/filesystem.hpp>
#include <boost/system/error_code.hpp>

using namespace std;
using namespace boost::filesystem;
using boost::system::error_code;


int main()
{
    vector<string> testpaths = {
        "< path to a directory which is to test >",
    };

    for(auto & line : testpaths)
    {
        if(line.empty()) continue;   // skip empty lines

        cout << " path: " << line << "   ";

        path testpath(line.c_str());
        // simplified testing, use parent of parent
        path basepath = testpath.parent_path().parent_path();

        boost::system::error_code ec;
        path relpath = relative(testpath, basepath, ec);
        if(ec)  cout << "  ---> error: " << ec.message();
        else    cout << " ok, relative: " << relpath.string();
        cout << endl;
    }
}

Upvotes: 4

Views: 5801

Answers (3)

GWD
GWD

Reputation: 1464

As of Aug./Sept. 2020 this issue also appeared for RStdio 1.2.5033 and 1.3.1073 - created an issue with RStudio dev on gihtub. They expect their next boost update to fix this bug (again).
Putting this here although it is an RStudio topic - in case someone runs into this from the RStudio side.

Upvotes: 1

Evgen
Evgen

Reputation: 194

I was hitting this problem in a multi-process situation, so the lock solution by @RED SOFT ADAIR would not help. Until the Boost fix is released, I implemented this:

auto full_path = boost::filesystem::path(path_str).lexically_normal();
MY_ASSERT(boost::filesystem::exists(full_path), "Path normalization of '%s' resulted in non-existing path '%s'", 
            path_str.c_str(), full_path.string().c_str());

This worked out fine through the tests I created to expose this problem. lexically_normal operates on the path string, so it does not care about existence of the path. But it's prone to misinterpretations, when links are involved inside the path.

Upvotes: 1

RED SOFT ADAIR
RED SOFT ADAIR

Reputation: 12238

I had the same problem where the path only contains a directory using boost 1.65.1:

unexpected exception: boost::filesystem::weakly_canonical: The process cannot access the file because it is being used by another process; 

This also only happens on a network drive when the path contains a symbolic link.

It seems that this is a synchronization problem. Obviously using boost:filesystem the same symbolic link can not be accessed in parallel. I defined a custom function that encapsulates and synchronizes the access to weakly_canonical:

static boost::recursive_mutex   sgCanonicalMutex;

boost::filesystem::path CanonicalPath(const boost::filesystem::path inPath)
{        
        boost::recursive_mutex::scoped_lock lk(sgCanonicalMutex);
        return boost::filesystem::weakly_canonical(inPath);
}

After that change the problem did not occur anymore. There also is a note about the underlying system error code ERROR_SHARING_VIOLATION in the documentation of boost::filesystem::status. See https://www.boost.org/doc/libs/1_70_0/libs/filesystem/doc/reference.html

I think that the root cause is in the boost sources: boost\libs\filesystem\src\operations.cpp

The function read_symlink contains

handle_wrapper h(
      create_file_handle(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0));

The third parameter (value 0) is the dwShareMode passed to CreateFileW (see https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilew). This parameter possibly should be FILE_SHARE_READ. This is still left unchanged in the latest boost 1.70.

Upvotes: 2

Related Questions