php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81259 Long execution causes unlink function to give wrong result
Submitted: 2021-07-14 22:45 UTC Modified: 2021-07-21 16:29 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: raincomplain at outlook dot com Assigned: cmb (profile)
Status: Wont fix Package: Filesystem function related
PHP Version: 8.0 OS: Windows
Private report: No CVE-ID: None
 [2021-07-14 22:45 UTC] raincomplain at outlook dot com
Description:
------------
As you know on Windows as of PHP 7.3 it is possible to unlink() files with handles in use (no need to close the handle). To do that it seems to me that PHP trys to (delay) unlinking until program execution ends(which is the problem). Unlinking files in the past when a file handle is open was not possible at all, however as of 7.3 unlink() returns `true` even though the file is not deleted yet.

The test script shows that we can do things (creating data2.txt) even when the program is not correct yet (data.txt has to wait 10 seconds to be removed).

Test script:
---------------
$fp= fopen('data.txt', 'r');

if (unlink('data.txt')) {
	fopen('data2.txt', 'w');
}
sleep(10);

Expected result:
----------------
.
..
data2.txt

Actual result:
--------------
.
..
data.txt
data2.txt ( for 10 seconds)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-07-15 11:42 UTC] raincomplain at outlook dot com
-PHP Version: 7.3.29 +PHP Version: 7.3
 [2021-07-15 11:42 UTC] raincomplain at outlook dot com
Version 7.3
 [2021-07-15 11:45 UTC] rtrtrtrtrt at dfdfdfdf dot dfd
https://www.php.net/supported-versions.php
 [2021-07-15 11:55 UTC] raincomplain at outlook dot com
This bug started at 7.3 and is reproducible in version 8
 [2021-07-15 11:57 UTC] raincomplain at outlook dot com
-PHP Version: 7.3 +PHP Version: 8
 [2021-07-15 11:57 UTC] raincomplain at outlook dot com
Tested on 7.3 and 8
 [2021-07-15 12:42 UTC] raincomplain at outlook dot com
8.0
 [2021-07-15 13:18 UTC] cmb@php.net
-Assigned To: +Assigned To: cmb
 [2021-07-15 13:18 UTC] cmb@php.net
The respective changes in PHP 7.3 are an attempt to more closely
match POSIX semantics regarding unlinking of files.  On Windows,
unlinking is not possible if there are open file handles, so
putting the file in a delete-pending state is the closest
equivalent, and that means that the file will be deleted after the
last handle to it has been closed, and it is no longer possible to
access the file in any way (permission denied).  It seems to me
that under this semantics having unkink() returning true is
actually correct – this still allows to check whether the file was
put in delete-pending state or not.

However, files in delete-pending state behave pretty inconsistently
wrt. other file functions; while file_exist() and friends return
false, scandir() and friends still report the file to be there.  If
we were putting the file in delete-on-close state, the results of
these functions would be consistent (file_exist() and friends would
return true), but even if it is possible to implement that, the
file will eventually move to the delete-pending state, and the
inconsistency would show up again.

I'm not sure what to do here.  unlink()ing by putting the file in
the delete-pending state appears generally more useful than just
letting the unlink() attempt fail, so we likely will not revert
this (besides that it is a bit late; PHP 7.3.0 was released more
than 30 months ago).  Fixing the inconsistencies between
file_exists() and scandir() is likely not possible (or worth the
trouble).  So it might be best to clearly document the exact
behavior.

Still, it seems to me there is no (clean) way to detect whether a
file is in delete-pending state, and at least that appears to be
an unfortunate omission.  If such a function was available,
userland code could do something like

    if (unlink('data.txt') && !file_is_delete_pending('data.txt)) {
        fopen('data2.txt', 'w');
    }

From what I can tell, writing such a function in C should be
possible and not too hard.

Further reading: <https://go.microsoft.com/fwlink/?LinkId=140636>
(particularly chapter 4, File deletion semantics).
 [2021-07-16 03:31 UTC] raincomplain at outlook dot com
From Windows OS point of view it makes sense when a process wants to delete a file to put that file in a delete-pending state if it's opened by another process. However, it doesn't make sense for PHP to still keeps a handle open if the file in question is to be deleted. I think the handle should be closed by PHP on behalf of the programmer right before unlinking since the only process that owns the file is PHP itself. We then should worry only about other things like Windows indexing service or antiviruses that might have a hold on that file at that particular moment of time which if you ask me I don't think it's something to be worried about.
 [2021-07-21 16:29 UTC] cmb@php.net
-Status: Assigned +Status: Wont fix
 [2021-07-21 16:29 UTC] cmb@php.net
> I think the handle should be closed by PHP on behalf of the
> programmer right before unlinking since the only process that owns
> the file is PHP itself.

Besides that that's hard to accomplish (we would need to keep a
map of file names to open file handles per process/thread), the
semantics would be even more unexpected.  It seems to be way
easier to keep track of that in the application, if even needed.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 05 23:01:30 2024 UTC