Why doesn't std.file.exists follow symbolic links?

Jack Applegame japplegame at gmail.com
Fri Jul 2 14:11:22 UTC 2021

On Friday, 2 July 2021 at 12:32:21 UTC, jfondren wrote:
> On Friday, 2 July 2021 at 12:09:20 UTC, Jack Applegame wrote:
>> ```d
>> import std.stdio : writeln;
>> import std.file : exists, write, symlink, remove;
>> void main() {
>>     write("file.txt", "hello");
>>     symlink("file.txt", "link.txt");
>>     writeln(exists("link.txt")); // true
>>     remove("file.txt");
>>     writeln(exists("link.txt")); // true, why?
>> }
>> ```
>> In other languages (including C++) similar functions follow 
>> symbolic links.
> Some thoughts:
> 1. This is a dubious test anyway as the status of the file can 
> change
> immediately after the test. If at all possible the better way 
> to deal
> with a file system is to "ask for forgiveness" (gracefully 
> react to
> errors) rather than "ask for permission" (use tests like this 
> and then
> be surprised by an error that can still happen).

This is a completely different topic. The above code is just a 
demonstration that `std.file.exists` does not follow symbolic 
links, and not the real code.

> 2. Saying that a symlink "doesn't exist" when it clearly does 
> exist
> could also be confusing.

I do not think so. The symbolic link should be transparent by 

> 3. System software that's trying to make secure use of the 
> filesystem
> should really be using the openat() and other *at syscalls with
> dir fds. The kernel APIs have developed a lot in the past few 
> decades
> and one reason I prefer D over traditional 'scripting 
> languages' is
> that those languages have all refused to track these 
> developments, so
> e.g. D but not Perl can swap two files atomically (with 
> renameat2),
> without worrying about race conditions where a process might 
> notice
> that one of the files doesn't exist.

This is also a completely different topic.

> 4. Actually for the reasons above, if std.file.exists were 
> freshly
> made I think it would also be completely fine to change it if 
> indeed
> stat() is the more popular underlying call...
> 5. ... but it's been like this since 2015. So people who wanted 
> to know what the function actually did have already peeked into 
> the library, saw it was lstat() on POSIX, and are now relying 
> on that.
> I would resolving this in the direction of clearly documenting 
> the interaction with symlinks.

Maybe you're right. I don't know how to fix this correctly.

More information about the Digitalmars-d mailing list