Search code examples
c++linuxsymlinkstd-filesystem

Setting std::filesystem::current_path() to a symlink without resolving link?


I'm trying to use std::filesystem::current_path() to change the working directory to something that might be a symlink. If the target is a symlink, the link is getting resolved and the working directory becomes the target of the link rather than the path I specified. My main issue with this is it makes relative paths incorrect.

As an example:

#include <filesystem>
#include <iostream>

using namespace std;
using namespace std::filesystem;

auto main(int, char **) -> int {
  // create absolute directory then symlink to it
  create_directory("/tmp/tgt");
  create_directory_symlink("/tmp/tgt", "/tmp/dir");

  cout << "cwd0: " << current_path() << '\n';
  current_path("/tmp/dir");
  cout << "cwd1: " << current_path() << '\n';

  remove("/tmp/tgt");
  remove("/tmp/dir");
  return 0;
}

Running this from within the /tmp directory, the output is.

cwd0: "/tmp"
cwd1: "/tmp/tgt"

but what I want is for cwd1 to show /tmp/dir

Is there a portable mechanism to change the working directory to a symlink?


Solution

  • Your working directory has to be a directory. A symlink is not a directory. So no, this feature does not exist.

    On the other hand, shells often emulate such behavior. For instance, in bash, if you do

    cd /tmp
    ln -s /some/other/dir foo
    cd foo
    cd ..
    

    you end up back in /tmp, not in /some/other. The explanation is that cd .. doesn't actually do chdir("..") (which would put you in /some/other for exactly the reason you stated). Instead, the shell uses an internal variable to keep track of the "logical" current directory, based on the sequence of previous cd commands, and compute what the new working directory should be on that basis.

    So if you want behavior like that, you'll have to emulate it yourself, just as shells do. It's not something the OS provides for you.