Symlink Target – Is Symlink’s Target Relative to the Destination’s Parent Directory?

symlink

I've got the following file structure:

build/
client/
  –> index.js

And when I try to create a symbolic link named "client" inside the build directory that refers to the client directory in the cwd like so

// Fails
$ pwd
/home/user/
$ ln -s client build/client 
$ stat build/client/index.js
stat: build/client/index.js: stat: Too many levels of symbolic links

I get the ELOOP error displayed above. When I change the target path to be relative to the destination path, all is good:

// Works
$ pwd
/home/user/
$ ln -s ../client build/client 
$ stat build/client/index.js
stat: <outputs file stats>

Is this the intended behavior and please explain why…

Best Answer

For the one that doesn't work, if we look at the ls -l result, we get the following:

[sparticvs@sparta test]$ ls -l build/
total 0
lrwxrwxrwx. 1 sparticvs sparticvs 6 Dec 17 16:08 client -> client

Now to understand what is going on here. Let's look at the command you called:

ln -s client build/client

According to the Man Page, there are two possible matches for this format

SYNOPSIS
       ln [OPTION]... [-T] TARGET LINK_NAME   (1st form)
       ln [OPTION]... TARGET... DIRECTORY     (3rd form)

It will match on the first form (since its first). Now, the "target name" or client in your case, can be (according to the complete ln manual) arbitrary strings. They don't have to resolve to anything right now, but can resolve to something in the future. What you are creating with your invocation is a "dangling symlink" and the system does not keep you from creating these.

Now your second invocation ln -s ../client build/client is what is called a "relative symlink" (as you noted in your own post). There is a second type and that is an "absolute symlink" which would be called by doing ln -s /home/user/client build/client.

This is not a bug. According to the manual it states:

When creating a relative symlink in a different location than the current directory, the resolution of the symlink will be different than the resolution of the same string from the current directory. Therefore, many users prefer to first change directories to the location where the relative symlink will be created, so that tab-completion or other file resolution will find the same target as what will be placed in the symlink.

-- from info coreutils 'ln invocation'

That said, you MUST use either the relative or absolute path to the target.

Related Question