Skip to content

Improper long path support for relative paths #10992

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

Closed
lunter2 opened this issue Apr 1, 2023 · 7 comments
Closed

Improper long path support for relative paths #10992

lunter2 opened this issue Apr 1, 2023 · 7 comments

Comments

@lunter2
Copy link

lunter2 commented Apr 1, 2023

Description

The following code:

<?php
 chdir('C:\\');print(getcwd()); // C:\ (ok)

 var_dump(mkdir('C:\\'.str_repeat('a',255))); // true (absolute path - directory name with 255 characters created)
 var_dump(mkdir(str_repeat('b',255))); // false (relative path - directory name with 255 characters NOT created - max 247 characters works)
?>

Resulted in this output:

C:\
bool(true)
bool(false)

But I expected this output instead:

C:\
bool(true)
bool(true)

PHP Version

PHP 8.2.4

Operating System

Windows 10 Pro 22H2 (10.0.19045.2788)

@iluuu1994
Copy link
Member

Are expected and actual result reversed here?

@lunter2
Copy link
Author

lunter2 commented Apr 3, 2023

I corrected it.

@nielsdos
Copy link
Member

nielsdos commented Apr 3, 2023

I tried to reproduce this on my Windows VM (Win10 22H2 so same as yours). I cannot reproduce this behaviour (I tried both with LongPathsEnabled 0 and 1).
Are you sure the reproduction code works on its own and is correct (*)? Can you also try this with extensions disabled (php -n)?. How long is the path of the current working directory, maybe that has some influence?

(*) I can't create a file/directory with 256 or more characters. But in that case the behaviour of mkdir and file_put_contents is the same.

@lunter2
Copy link
Author

lunter2 commented Apr 3, 2023

I change test script. Try again.

@lunter2 lunter2 changed the title mkdir() long paths problem mkdir() relative paths problem Apr 4, 2023
@lunter2
Copy link
Author

lunter2 commented Apr 4, 2023

New test script.

<?php
 chdir('C:\\');print(getcwd()); // C:\ (ok)

 var_dump(mkdir('C:\\'.str_repeat('a',255))); // true (absolute path - directory name with 255 characters created)
 var_dump(mkdir(str_repeat('b',255))); // false (relative path - directory name with 255 characters NOT created - max 247 characters works)
?>

I can confirm it on another computer.

c:\php>php -n mkdir.php
C:\bool(true)

Warning: mkdir(): No such file or directory in C:\php\mkdir.php on line 5
bool(false)

@nielsdos
Copy link
Member

nielsdos commented Apr 4, 2023

I can reproduce it, and I have found the root cause.
You'll be able to reproduce it on NTS builds, but not on ZTS builds. I was using ZTS which is the reason I couldn't reproduce it earlier.

What happens is that for long paths we rely on Windows's path canonicalization to prepend \\?\ to the path. The caveat here is that the path needs to be an absolute path for the \\?\ to work. In the 'b' example the path is not absolute, but relative, so the path lookup in Windows fails. On NTS when mkdir is called we directly call php_win32_ioutil_mkdir.

But why does it work on ZTS then? Well, on ZTS we do #define VIRTUAL_DIR (*). This makes sure that when we create a directory we call virtual_mkdir instead of php_win32_ioutil_mkdir. This first transforms the path to an absolute path by calling virtual_file_ex and only then calls php_win32_ioutil_mkdir. This indirectly makes the \\?\ style paths work because the paths that are sent to php_win32_ioutil_mkdir are always absolute in this case.

I suspect that most path-related functions suffer from this problem. I guess we should somehow make it absolute on NTS if we do a canonicalization transformation. (Side question: why is VIRTUAL_DIR ZTS-only?)

(*)

#ifdef ZTS
#define VIRTUAL_DIR
#endif

@lunter2
Copy link
Author

lunter2 commented Apr 4, 2023

Yes, I use NTS.

cmb69 added a commit to cmb69/php-src that referenced this issue Nov 3, 2024
Relative paths are passed to the ioutils APIs, these are not properly
converted to long paths.  If the path length already exceeds a given
threshold (usually 259 characters, but only 247 for `mkdir()`), the
long path prefix is prepended, resulting in an invalid path, since long
paths have to be absolute.  If the path length does not exceed that
threshold, no conversion to a long path is done, although that may be
necessary.

Thus we take the path length of the current working directory into
account when checking the threshold, and prepend it to the filename if
necessary.

Since this is only relevant for NTS builds, and using the current
working directory of the process would be erroneous for ZTS builds, we
skip the new code for ZTS builds.
@cmb69 cmb69 changed the title mkdir() relative paths problem Improper long path support for relative paths Nov 3, 2024
@cmb69 cmb69 self-assigned this Nov 3, 2024
@cmb69 cmb69 closed this as completed in 5c76ef7 Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants