PHP's copy() fails to copy files within the /home mount on Azure Web App w/PHP 8.2 Linux stack
When both the source and destination is in the /home mount, copy() always fails:
copy( "/home/site/wwwroot/sourcefile.txt", "/home/site/wwwroot/destfile.txt" );
// copy() returns $false and an empty destination file is created.
// PHP does not produce any error output.
Workarounds for copying the same files by other means succeeds:
file_put_contents( "destfile.txt", file_get_contents( "sourcefile.txt" ) );
exec("cp sourcefile.txt destfile.txt");
This is a newly created Azure Web App with Linux OS and PHP 8.2 stack. No special configuration. A bit weird that an Azure Web App with PHP cannot use copy() within the wwwroot directory, especially when it is needed by Wordpress to do installations and upgrades of Wordpress, themes and plugins.
/home is a cifs mount with file_mode=0777.
I tried to run a strace on php, and I discovered that it tries to copy the file using copy_file_range()
with a max size length argument, and that it fails with an I/O error:
copy_file_range(5, NULL, 6, NULL, 9223372036854775807, 0) = -1 EIO (Input/output error)
While an oversized length value works for other filesystems, it results in EIO (A low-level I/O error occurred while copying) on cifs mounts.
Looking at PHP's source at php-8.2.2/main/streams/streams.c lines 1576,1577,1584, it always try to use the max value for the length if copy_file_range() is available (only on Linux systems):
/* clamp to INT_MAX to avoid EOVERFLOW */
const size_t cfr_max = MIN(maxlen, (size_t)SSIZE_MAX);
ssize_t result = copy_file_range(src_fd, NULL, dest_fd, NULL, cfr_max, 0);
Patching PHP to specify the source file size as the length argument as in the example on https://man7.org/linux/man-pages/man2/copy_file_range.2.html would solve the problem. Configuring PHP without copy_file_range()
would also solve it, but also discard the benefits of copy_file_range()
. Hopefully it will be fixed in an upcoming PHP version, but I think Microsoft should provide an default or an easy to apply workaround before that happens.
Any other solutions, suggestions or insights would be welcome!
# php -v
PHP 8.2.0 (cli) (built: Dec 27 2022 20:38:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.0, Copyright (c) Zend Technologies
with Zend OPcache v8.2.0, Copyright (c), by Zend Technologies
# egrep '(Version|Features)' /proc/fs/cifs/DebugData
/proc/fs/cifs/DebugData:CIFS Version 2.10
/proc/fs/cifs/DebugData:Features: DFS,FSCACHE,STATS,DEBUG,ALLOW_INSECURE_LEGACY,WEAK_PW_HASH,CIFS_POSIX,UPCALL(SPNEGO),XATTR,ACL
# mount | grep home # (some values replaced with ... for privacy)
//10.0.0.1/volume-...-default/... on /home type cifs (rw,relatime,vers=default,cache=strict,username=dummyadmin_...,domain=,uid=0,noforceuid,gid=0,noforcegid,addr=10.0.0.1,file_mode=0777,dir_mode=0777,soft,nounix,mapposix,mfsymlinks,noperm,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
# uname -a
Linux 3f6c4cc7fa2c 4.15.0-191-generic #202-Ubuntu SMP Thu Aug 4 01:49:29 UTC 2022 x86_64 GNU/Linux
# cat /etc/debian_version
11.6
# cat /etc/motd
_____
/ _ \ __________ _________ ____
/ /_\ \\___ / | \_ __ \_/ __ \
/ | \/ /| | /| | \/\ ___/
\____|__ /_____ \____/ |__| \___ >
\/ \/ \/
A P P S E R V I C E O N L I N U X
Documentation: http://aka.ms/webapp-linux
PHP quickstart: https://aka.ms/php-qs
PHP version : 8.2.0
Note: Any data outside '/home' is not persisted
PHP 8.2.0 (cli) (built: Dec 27 2022 20:38:32) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.0, Copyright (c) Zend Technologies
with Zend OPcache v8.2.0, Copyright (c), by Zend Technologies