wfMkdirParents: recover from mkdir race condition
authorElliott Eggleston <ejegg@ejegg.com>
Thu, 12 Sep 2013 22:55:45 +0000 (18:55 -0400)
committerParent5446 <tylerromeo@gmail.com>
Thu, 12 Sep 2013 23:43:45 +0000 (23:43 +0000)
If mkdir fails, check again to see if dir has been created
since our initial check, and return true if so.

Also, in initial check, only return true if $dir is really
a directory, not a file.

Bug: 49391
Change-Id: I2b331669fae70948ce79ba1477c05968a3095c3d

includes/GlobalFunctions.php
tests/phpunit/includes/GlobalFunctions/GlobalTest.php

index bed2c44..f43393a 100644 (file)
@@ -2521,7 +2521,7 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
                wfDebug( "$caller: called wfMkdirParents($dir)\n" );
        }
 
-       if ( strval( $dir ) === '' || file_exists( $dir ) ) {
+       if ( strval( $dir ) === '' || ( file_exists( $dir ) && is_dir( $dir ) ) ) {
                return true;
        }
 
@@ -2537,6 +2537,11 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
        wfRestoreWarnings();
 
        if ( !$ok ) {
+               //directory may have been created on another request since we last checked
+               if ( is_dir( $dir ) ) {
+                       return true;
+               }
+
                // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis.
                wfLogWarning( sprintf( "failed to mkdir \"%s\" mode 0%o", $dir, $mode ) );
        }
index 6a2a0df..244b100 100644 (file)
@@ -630,6 +630,15 @@ class GlobalTest extends MediaWikiTestCase {
                return $a;
        }
 
+       function testWfMkdirParents() {
+               // Should not return true if file exists instead of directory
+               $fname = $this->getNewTempFile();
+               wfSuppressWarnings();
+               $ok = wfMkdirParents( $fname );
+               wfRestoreWarnings();
+               $this->assertFalse( $ok );
+       }
+
        /**
         * @dataProvider provideWfShellMaintenanceCmdList
         */