-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
gh-81793: always call linkat() from os.link(), if available #24997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The issue with link() is that POSIX does not define its behavior regarding symbolic links: "If path1 names a symbolic link, it is implementation-defined whether link() follows the symbolic link, or creates a new link to the symbolic link itself." And it is indeed implemented differently on Linux and NetBSD.
This PR is stale because it has been open for 30 days with no activity. |
if (follow_symlinks) { | ||
PyErr_SetString(PyExc_NotImplementedError, | ||
"link: follow_symlinks=True unavailable on this platform"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
follow_symlinks
is true by default, so os.link()
will always fail if linkat
is not available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's desirable? follow_symlinks
is documented as true by default, so if that's unlikely to work, it seems better to error out than to ignore it.
linkat
has been in Linux since 2006 and FreeBSD since 2009, so hopefully this isn't a case that many people will run into.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it is not desirable. Otherwise we would just not implement os.link()
without linkat
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, you could still pass follow_symlinks=False
if you're happy with that behaviour, so it's more useful than the function not existing at all. What alternative are you suggesting?
- Should
os.link()
implement a symlink-following fallback with 2 system calls? Is there a race condition there? - Should the
follow_symlinks
default be documented as platform dependent? That would be accurate but surprising, since most functions with that parameter default toTrue
, and it makes it easy to write code that does something slightly different on Mac & Linux.
But is there any relevant platform or configuration where linkat()
is not available? It looks like this has been ubiquitous for well over a decade, so maybe the fallback is kind of academic anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am working on this issue now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #81793.
The following commit authors need to sign the Contributor License Agreement: |
Fixed by #132517. |
This is a continuation of PR GH-14843 (closes GH-14843), adding a test. I've pasted the original description below.
I had to rework the change a bit; I find the Apple specific stuff confusing, so I hope I've got it right. 😕
The issue with link() is, that POSIX does not define its behavior regarding symbolic links:
"If path1 names a symbolic link, it is implementation-defined whether link() follows the symbolic link, or creates a new link to the symbolic link itself."
And it is indeed implemented differently on e.g. Linux and NetBSD. So, it makes no sense to call link(), where linkat() is available.
https://bugs.python.org/issue37612
https://bugs.python.org/issue37612