serenity icon indicating copy to clipboard operation
serenity copied to clipboard

Symlink: linking to a non-existing file results in unexpected behaviour

Open cees-elzinga opened this issue 3 years ago • 3 comments

Creating a symlink to a non-existing file results in unexpected behaviour.

$ ln -s /tmp/a-non-existing-file /home/anon/symlink
$ ls -al /home/anon
symlink -> /tmp/a-non-existing-file
$ echo 123 > /home/anon/symlink
$ ls /tmp/
/tmp/symlink

Observed behaviour

The file /tmp/symlink is created

Expected behaviour

The file /tmp/a-non-existing-file is created.

This is what happens in linux/macos.

cees-elzinga avatar Jan 05 '22 19:01 cees-elzinga

Bug is here:

https://github.com/SerenityOS/serenity/blob/589ebbc24eb3acc86f50043f896414fe190a5229/Kernel/FileSystem/VirtualFileSystem.cpp#L321-L325

parent_custody is the path to the parent directory of the resolved symlink, while path still points to original /home/anon/symlink entry. When concatenation happens it produce the bogus path.

The problem is probably originating from the caller site:

https://github.com/SerenityOS/serenity/blob/589ebbc24eb3acc86f50043f896414fe190a5229/Kernel/FileSystem/VirtualFileSystem.cpp#L213-L218

were resolve_path should also return the new path.

It seems the problem is pathological. Tying to do a realpath on symlink is result in an error, instead of showing the destination path.

mhermier avatar Jan 18 '22 23:01 mhermier

Problem his deeper than expected, it is possible to create files with any name in the target link path:

$ ln -s /tmp/a-non-existing-file /home/anon/symlink
$ echo 123 > /home/anon/symlink/foo
$ ls /tmp/
/tmp/foo

mhermier avatar Jan 19 '22 08:01 mhermier

There is also something off with moving symlinks that point to a directory. It should rename the symlink. But it copies the directory.

$ cd /tmp/
$ mkdir dir
$ touch dir/file
$ ln -s dir symlink
$ ls -al
drwxr-xr-x dir
lrw-r--r-- symlink -> dir
$ mv symlink symlink2
$ ls -al
drwxr-xr-x dir
drwxr-xr-x symlink2 <-- its a directory now!

It does work correctly for symlinks pointing to a file.

For cross-device symlinks it can't even unlink the original file:

$ cd /home/anon/
$ ln -s /tmp/dir symlink
$ ls -al
lrw-r--r-- symlink -> /tmp/dir
$ mv symlink symlink2
mv: unlink 'symlink/': Is a directory
$ ls -al
lrw-r--r-- symlink -> /tmp/dir
drwxr-xr-x symlink2

cees-elzinga avatar Oct 25 '22 15:10 cees-elzinga