-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Treat relative symlink target paths on Windows like on Linux #1243
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
@pierrejoye The email address in the header of ext/standard/link_win32.c should be changed to pajoye@. |
Hm, but I don't think this really is a BC break? With the old code, you were simply unable to create relative symlinks under Windows when using PHP's |
Thanks for the patch! Ok for 7, big no for 5.x, BC why do you want to change then email? They are aliases and work just fine. |
It is incorrect to to say that relative links are impossible. See the doc, it is even documented how they work: relative to the current cwd. Now, to break it to make code more portable is fine, just not in 5.x |
@pierrejoye which documentation are you referring to? I didn't mean that relative symlinks are impossible in general, just that they cannot be created with PHP's |
@pierrejoye I wasn't aware that there are email aliases. Sorry for the noise. @fritzmg It is currently possible to create working symlinks on Windows when giving a relative path, at least when the symlink is in the same folder as its target:
Not sure if anybody uses that, but you never know. |
@cmb69 actually, the target would have to be in the CWD, otherwise your example won't work currently (on Windows) - and the source too, otherwise the symlink will be invalid. Oh and something else: even if the target and the source are in the CWD of PHP, it might still not work, depending on how the PHP process is started. The CWD of the Win32API function |
@cmb69 the msdn doc for createlink, it specifically refers that a relative
|
@pierrejoye but it does not say that: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363878%28v=vs.85%29.aspx You can create a relative symlink in 4 different ways:
|
Maybe we should un-skip some of those tests? Changing code behavior without having test to verify (or explain) what is the intended one looks wrong to me. |
We run them, and there is a good reason for this check. I will test the PR with all systems and post the results. DFS, shares and
|
It appears that the MSDN man page on CreateSymbolicLink is not particularly clear on how relative links will be interpreted. Looking at the 4 items, however, it becomes clear that relative paths are resolved relative to the symlink, unless a special syntax ( Changing the behavior for PHP 7 to be more inline with the way it works on other architectures seems to be appropriate, though. Consider a most basic test. This works under POSIX (tested with Cygwin), and on Windows with this PR but not without it. It's probably good to add a respective PHPT. With regard to the skipped PHPTs on Windows: there are some which have Win only counterparts (e.g. 001.phpt) and some which would have to be modified because they're using hard-coded /tmp/ paths (e.g. bug39367.phpt). In any way care must be taken to check for SeCreateSymbolicLinkPrivilege (which is not necessarily granted even for admin accounts) as it's done for e.g. bug47767.phpt. |
Yes, we do some trickery to do it and avoid to get false positive reports. But again, I am ok for 7, given that it does create more troubles than what
|
It only works, if the working directory of the parent process (or the process that invoked the running process) under which the PHP binary is executed happens to be the same as the working directory of the PHP script, due to the issues with the working directory I mentioned. Assume you are running XAMPP on Windows and you have the following script under <?php
mkdir('foo1');
mkdir('foo2');
file_put_contents('foo2/bar.txt', '42');
var_dump(getcwd());
symlink('C:foo2/bar.txt', 'foo1/foo3.txt');
var_dump(file_get_contents('foo1/foo3.txt')); It will still result in
if you:
Though I have not tested if the Win32API working directory is different, when PHP is running via CGI instead of an Apache module. |
IMHO it is not as simple as it is done. Also with the regard to the thread safety. Maybe an algo like this could be more reliable:
Maybe one could also memorize the _getcwd right at the start of the symlink() call so the _chdir() is not suddenly changed, that were another solution respecting thread safety. Would probably require locking, that would be probably the best. Thanks. |
@fritzmg Apache does chdir() to it's root directory, so it's not htdocs. That's probably a topic for another ticket, if you'd be a spot to create it. We could see whether we can chdir() to the correct htdocs from the PHP module. Thanks. |
@fritzmg it is critical to continue this discussion that you understand the limitations and caveats of symbolic on Windows. They are not, by many meaning, fully compatible with POSIX (if that even means anything anymore) or more specifically linux. I implemented this part, @weltling and other spent days to debug and fix edge cases in common scenarios like using symlinks on DFS, cross devices and all these scenarios we can see on sharing hosters or Cloud. Taking one simple example as a go to remove this check is not a good move. As I said earlier, we need to valid for every scenario we have in our infrastructures. If everything passes, we can apply, if not, we need to find another solution, if any. |
@fritzmg also the CWD in a TS SAPI is playing a role here, totally unrelated to this discussion but this is something different from what you may have in NTS. Read: there is no such thing than CWD but php does its own machinery to get CWD based on the current request. Just for the record :) |
Yes, I understand that in general symlinks are not fully compatible between POSIX and Windows and actual symlinks cannot be copied between these systems. However, the syntax and semantics of creating relative symlinks are compatible. A relative symlink created with the same parameters in their respective functions on both systems create the same result. e.g.
on Linux and
on Windows. PHP frameworks like Symfony currently work around this issue by creating absolute symbolic links, if the creation of the relative symbolic link fails. |
And this fallback must remain. No matter if this change will happen or
|
@pierrejoye I fully agree that the PR has to be carefully checked for more complex scenarios than simple local FS. I can't be of much help there, unfortunately, due to missing infrastructure. @weltling I understand that there may be threading issues wrt. symlink(). However, it seems to me that the code currently is in error wrt. the comment "The target is relative to the link itself, not to the CWD.". That is true, but a few lines above the target (topath) is checked relative to the CWD. Am I missing something? |
I was checking the flow more carefully yet. The target and link paths are always expanded using the CWDG, so no dependency on the CRT. Still CreateSymbolicLink() regarding relative paths depends on the current working dir in CRT. This together means - disregarding whether the target is expanded to the full path or not, the link being relative is an issue. In the current state where relative links are blocked, there is no issue. When enabling relative links, TS mode needs to ensure that the current working dir in the CRT is the same as in PHP. Your patch shows (and should be OK) no regression with CLI (despite needs more extensive testing) while enabling relative symlinks, however it will cause weird things with a real TS SAPI. You can check what I'm saying creating a simple snippet with some threaded program using _chdir() and CreateSymbolicLink(), there are templates on MSDN. Also, you can test basic network things creating network shares on the local machine. Thanks. |
@weltling Thanks for the information. I'll try to have a look at the issues within the next days. |
Since this did not land in php7, what would be the earliest version where this fix could be introduced? |
Hm, that's a shame, that this fix did not make it into PHP 7 - they didn't want to include it in PHP 5 due to BC. |
I wouldn't say the patch should be applied as is, it would enable any weird errors with relative paths for symlinks. Symlink can only be created by using system APIs, and those are not thread safe. Note also that it's not Windows only issue. Thanks. |
Since our windows people have rejected this as it is, and since it has merge conflicts, and since the author seems to have abandoned working on it, I'm closing this PR. Please take this action as encouragement to open a clean PR, that resolves the issues raised here, also get Anatol involved in the conversation again if you do so. |
@krakjoe where or why was it rejected? |
On Windows relative target paths refer to the CWD, while on Linux they refer to the link itself. This PR is supposed to adapt the Windows behavior to that of Linux, i.e. it fixes #69473.
I think this should be done for PHP 7; I'm not sure about PHP 5.5 and 5.6, as this constitutes a BC break.
Currently, no tests are included, because it seems that many tests using symlink() are skipped on Windows anyway.