serenity
serenity copied to clipboard
Symlink: linking to a non-existing file results in unexpected behaviour
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.
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.
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
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