Bug #81145 [PATCH]: copy() and stream_copy_to_stream() fail for +4GB files
| From: | cmb@php.net | Date: | Wed, 16 Jun 2021 11:19:10 +0000 |
| Subject: | Bug #81145 [PATCH]: copy() and stream_copy_to_stream() fail for +4GB files | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-234433@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=81145&edit=1
ID: 81145
Patch added by: cmb@php.net
Reported by: php at bitm dot sg
Summary: copy() and stream_copy_to_stream() fail for +4GB
files
Status: Analyzed
Type: Bug
Package: Filesystem function related
Operating System: Windows 10.0.19042.985 x64
PHP Version: 7.4
Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
The following pull request has been associated:
Patch Name: Fix #81145: copy() and stream_copy_to_stream() fail for +4GB files
On GitHub: https://github.com/php/php-src/pull/7158
Patch: https://github.com/php/php-src/pull/7158.patch
Previous Comments:
------------------------------------------------------------------------
[2021-06-16 11:04:34] cmb@php.net
Confirmed (affects PHP-7.4 on Windows as well).
Thanks for the helpful analysis on reddit[1].
[1] <https://www.reddit.com/r/PHP/comments/o0oqhg/problems_copying_large_files/h1y9a5t/>
------------------------------------------------------------------------
[2021-06-16 10:14:09] php at bitm dot sg
Fixed the Windows version because it was cut off.
------------------------------------------------------------------------
[2021-06-16 09:56:11] nikic@php.net
Seems to work fine on Linux.
------------------------------------------------------------------------
[2021-06-16 09:43:27] php at bitm dot sg
Description:
------------
Using copy() or stream_copy_to_stream() fails on Windows with files over 4GB, even if the underlying
volume (NTFS) supports it and Windows + PHP are 64 bit.
Test script:
---------------
<?php
//Both files must be on an NTFS volume. You may use the same volume.
$src='C:/temp/4G.src.bin';
$dst='C:/temp/4G.dst.bin';
define('SIZE_4G',0x100000000);
@unlink($src);
//Create file and append random content at the 4GB boundary
exec('fsutil file createnew ' . escapeshellarg($src) . ' ' . (SIZE_4G-0x100));
$fp=fopen($src,'ab');
fwrite($fp,random_bytes(0x200));
fclose($fp);
copy($src,$dst);
if(filesize($src)!==filesize($dst)){die('Files have different sizes!');}
$f1=fopen($src,'rb') or die('src open failed');
$f2=fopen($dst,'rb') or die('dst open failed');
//Seek to 4 GB boundary, as this is the location where the problem occurs
fseek($f1,SIZE_4G-0x100,SEEK_SET);
fseek($f2,SIZE_4G-0x100,SEEK_SET);
echo (fread($f1,0x200)===fread($f2,0x200)?'Identical':'Copy failed');
fclose($f1);
fclose($f2);
Expected result:
----------------
The functions should copy files and streams as-is and the script should print "Identical"
Actual result:
--------------
Script prints "Copy failed"
Only the first 4 GB of the source file are copied.
This is actually done repeatedly until the destination is as large as the source. So if the file is
13 GB, the destination will contain the first 4 GB of the source 3 times, followed by the first GB
again.
using "fwrite($b,fread($a,$buffer))" to manually copy files works.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=81145&edit=1