ID:               35326
 User updated by:  bugs dot php dot net at chsc dot dk
 Reported By:      bugs dot php dot net at chsc dot dk
-Status:           Feedback
+Status:           Open
 Bug Type:         Directory function related
 Operating System: Linux
 PHP Version:      5.0.5
 New Comment:

Yes, it also occurs with the CVS snapshot (this time I tried with the
CGI version).

AFAICS the problem is in php_plain_files_mkdir in
main/streams/plain_wrapper.c. If php_mkdir() or VCWD_MKDIR() returns
false, the method gives up instead of checking whether directory exists
anyway, i.e. if it was created by another thread.


Previous Comments:
------------------------------------------------------------------------

[2005-11-22 12:13:10] [EMAIL PROTECTED]

Please try using this CVS snapshot:

  http://snaps.php.net/php5-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5-win32-latest.zip



------------------------------------------------------------------------

[2005-11-22 11:32:49] bugs dot php dot net at chsc dot dk

Description:
------------
There appears to be a concurrency issue when mkdir is called on two
separate threads with the following parameters:

Thread 1:
mkdir('/tmp/foo/bar/1', 0777, true);

Thread 2:
mkdir('/tmp/foo/bar/2', 0777, true);

Sometimes one of the threads (e.g. thread 2) two fails with "Warning:
mkdir(): File exists" and the directory /tmp/foo/bar/2 does not exist
afterwards.

What I think is happening in thread 2 is is this:
PHP looks for /tmp/foo/bar/2 and sees that it does not exist. Neither
does /tmp/foo/bar and /tmp/foo. So it tries to create /tmp/foo, but
that directory was just created a millisecond second ago by another
thread, so mkdir gives instead of just moving on to create /tmp/foo/bar
and /tmp/foo/bar/2.

Reproduce code:
---------------
This code reproduces the problem in about every second attempt. It
consists of two files, index.php and iframe.php.


index.php:

<?php
$fire = time() + 2;
?>
<h1>Nr. 1</h1>
<iframe src="iframe.php?fire=<?= $fire ?>&amp;no=1"></iframe>
<h1>Nr. 2</h1>
<iframe src="iframe.php?fire=<?= $fire ?>&amp;no=2"></iframe>


iframe.php:

<?php
$fire = $_GET['fire'];
$no = $_GET['no'];
// synchronize the two threads
while ($fire > time());
$dir = '/tmp/' . $fire . '/foo/bar/foo/bar/' . $no;
//sleep($no);
var_dump(is_dir($dir));
echo "Making $dir ";
mkdir($dir, 0777, true);
var_dump(is_dir($dir));
?>


Expected result:
----------------
Thread 2 should output this:
bool(false) Making /tmp/1132653651/foo/bar/foo/bar/2 bool(true)


Actual result:
--------------
Thread 2 sometimes outputs this:
bool(false) Making /tmp/1132655181/foo/bar/foo/bar/2 Warning: mkdir():
File exists in /home/chsc/public_html/mkdir/iframe.php on line 10
bool(false) 

Notice that the directory does not exist afterwards.

If I uncomment the sleep() call above, there are no problems.


A workaround:
$ok = mkdir($dir, 0777, true);
if (!$ok && !is_dir($dir)) {
    sleep(1);
    mkdir($dir, 0777, true);
}


In other words, it works if I try again. I hope that mkdir() can be
changed so that it only returns false if the directory cannot be
created at all (e.g. because of lack of permissions or because it
already exists).



------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=35326&edit=1

Reply via email to