Bug #69473 [Opn]: bug in symlink() prevents relative symlinks on Windows
| From: | pajoye@php.net | Date: | Sat, 18 Apr 2015 03:22:27 +0000 |
| Subject: | Bug #69473 [Opn]: bug in symlink() prevents relative symlinks on Windows | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-192178@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=69473&edit=1
ID: 69473
Updated by: pajoye@php.net
Reported by: email at spikx dot net
Summary: bug in symlink() prevents relative symlinks on
Windows
Status: Open
Type: Bug
Package: Win32API related
Operating System: Windows 7
PHP Version: 5.6.8
Block user comment: N
Private report: N
New Comment:
Your cwd is not foo1, so it won't work
See https://msdn.microsoft.com/en-us/library/windows/desktop/aa363878%28v=vs.85%29.aspx
Previous Comments:
------------------------------------------------------------------------
[2015-04-17 16:13:34] email at spikx dot net
Sorry, I mixed up the foo1 and foo2 folders in this test (I created a symlink to ../foo1 within foo2
instead of a symlink to ../foo2 within foo1, like in the original example), but you get the idea,
doesn't matter anyway :)
------------------------------------------------------------------------
[2015-04-17 16:09:28] email at spikx dot net
No, the symlink, which is called "foo3" in this case is located in the folder foo2
($source is 'foo2/foo3') and points to '../foo1' ($target), i.e. the foo1 folder
in the root directory (which is the parent directory of foo2). Look at this console output from
Linux, where it works, I think it will get more clear then:
[...]/symlinktest # vi index.php (create the aformentioned script)
[...]/symlinktest # php index.php (execute script via php binary)
[...]/symlinktest # ls -la (list root directory)
4.0K Apr 17 18:02 .
4.0K Apr 17 18:01 ..
4.0K Apr 17 18:02 foo1
4.0K Apr 17 18:02 foo2
71 Apr 17 18:02 index.php
[...]/symlinktest # cd foo2
[...]/symlinktest/foo2 # ls -la
4.0K Apr 17 18:02 .
4.0K Apr 17 18:02 ..
7 Apr 17 18:02 foo3 -> ../foo1
Just to mention it again: relative symlinks work on Windows too. However, PHP's implementation
of the symlink function prevents relative symlinks, due to the GetFileAttributes call on the target
path.
------------------------------------------------------------------------
[2015-04-17 13:49:24] pajoye@php.net
Your script creates a link to a non existing directory (../foo2) instead of the one you created
(./foo2).
Or am I missing something?
------------------------------------------------------------------------
[2015-04-17 07:08:16] email at spikx dot net
The issue with the CWD is even more problematic than expected. Assume you have a local XAMPP
installation on your Windows system and the aforementioned script is under
C:\xampp\htdocs\symlinktest\index.php
Now, if you execute this script via Apache (e.g. by opening it via your Browser), the CWD (for the
Win32API functions) will actually be
C:\xampp (!)
At least it was in my case. If you execute the script via the command line directly within
C:\xampp\htdocs\symlinktest, then the CWD for the Win32API functions will also be
C:\xampp\htdocs\symlinktest as expected.
Calling chdir(â¦) before the symlink(â¦) call did not change the CWD for the Win32API
function as well.
In my opinion, the
if ((attr = GetFileAttributes(topath)) == INVALID_FILE_ATTRIBUTES) { ... }
should simply be removed - or only applied, if
topath is not a relative path. It's
then the responsibility of the user to make sure the relative path provided in $target
is valid/meaningful. As it is currently, PHP's symlink function only allows you to generate
invalid relative symlinks anyway.
------------------------------------------------------------------------
[2015-04-16 20:29:44] email at spikx dot net
Description:
------------
As far as I checked, the following applies to any PHP version since the symlink function was
introduced (in PHP 5.3).
Currently it is impossible under Windows to create relative symbolic links with PHP's symlink
function. It will always fail with the message "Could not fetch file information". The
reason is the following:
At line #169 ( https://github.com/php/php-src/blob/master/ext/standard/link_win32.c#L169
) the function checks, if the $target ("topath" in the C function) actually exists:
if ((attr = GetFileAttributes(topath)) == INVALID_FILE_ATTRIBUTES) { ... }
However, the Win32API function "GetFileAttributes" expects the path to be either absolute
or relative **to the CWD**! This means that this check will always fail, if you want to use a
relative symlink, since the relative path of the symlink is relative to the $source's
directory, not relative to the CWD.
Test script:
---------------
<?php
mkdir('foo1');
mkdir('foo2');
symlink( '../foo2', 'foo1/foo3' );
Expected result:
----------------
/foo1 should contain a directory symlink to ../foo2 (i.e. the /foo2 directory in the root folder)
Actual result:
--------------
Under Windows:
Warning: symlink(): Could not fetch file information(error 2) in index.php on line 6
Under Linux:
foo1 contains a directory symlink to ../foo2 (i.e. the foo2 directory in CWD)
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=69473&edit=1