Make WordPress Core

Changeset 62636


Ignore:
Timestamp:
07/05/2026 12:46:16 AM (3 months ago)
Author:
westonruter
Message:

Filesystem: Fix subdirectory recursion in WP_Filesystem_Direct::chgrp() and ::chown().

This applies the equivalent fix which had previously been done to ::chmod(). Tests are added for all three methods.

Developed in subset of ​https://github.com/WordPress/wordpress-develop/pull/11593.
Follow-up to r12997.

Fixes #65584.
See #65409, #11261.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-filesystem-direct.php

    r61601 r62636  
    140140                $filelist = $this->dirlist( $file );
    141141
    142                 foreach ( $filelist as $filename ) {
    143                         $this->chgrp( $file . $filename, $group, $recursive );
     142                foreach ( $filelist as $file_listing ) {
     143                        $this->chgrp( $file . $file_listing['name'], $group, $recursive );
    144144                }
    145145
    … …  
    228228                $filelist = $this->dirlist( $file );
    229229
    230                 foreach ( $filelist as $filename ) {
    231                         $this->chown( $file . '/' . $filename, $owner, $recursive );
     230                foreach ( $filelist as $file_listing ) {
     231                        $this->chown( $file . '/' . $file_listing['name'], $owner, $recursive );
    232232                }
    233233
  • trunk/tests/phpunit/tests/filesystem/wpFilesystemDirect/base.php

    r61424 r62636  
    1818         * The file structure for tests.
    1919         *
    20          * @var array
     20         * @var array<string, array{type: string, path: string, contents?: string}>
    2121         */
    2222        protected static $file_structure = array();
  • trunk/tests/phpunit/tests/filesystem/wpFilesystemDirect/chgrp.php

    r57753 r62636  
    3030                $this->assertFalse( self::$filesystem->chgrp( self::$file_structure['test_dir']['path'] . $path, 0 ) );
    3131        }
     32
     33        /**
     34         * Tests that recursive {@see WP_Filesystem_Direct::chgrp()} descends into subdirectories.
     35         *
     36         * The resulting group cannot be asserted without elevated privileges, so recursion is
     37         * verified by recording the paths passed to {@see WP_Filesystem_Direct::chgrp()}. Changing each item to its current
     38         * group is a permitted no-op that avoids requiring root and its "Operation not permitted" warning.
     39         *
     40         * @ticket 65584
     41         */
     42        public function test_should_recurse_into_subdirectories(): void {
     43                $directory   = untrailingslashit( self::$file_structure['test_dir']['path'] );
     44                $nested_file = self::$file_structure['subfile']['path'];
     45
     46                $spy = new class( null ) extends WP_Filesystem_Direct {
     47                        /** @var string[] */
     48                        public array $visited = array();
     49
     50                        public function chgrp( $file, $group, $recursive = false ) {
     51                                $this->visited[] = $file;
     52                                return parent::chgrp( $file, $group, $recursive );
     53                        }
     54                };
     55
     56                $spy->chgrp( $directory, (int) filegroup( $directory ), true );
     57
     58                $this->assertContains(
     59                        $nested_file,
     60                        $spy->visited,
     61                        'chgrp() did not recurse into the nested subdirectory.'
     62                );
     63        }
    3264}
  • trunk/tests/phpunit/tests/filesystem/wpFilesystemDirect/chmod.php

    r57753 r62636  
    7575                );
    7676        }
     77
     78        /**
     79         * Tests that recursive {@see WP_Filesystem_Direct::chmod()} applies the mode to files in subdirectories.
     80         *
     81         * @ticket 65584
     82         */
     83        public function test_should_change_mode_recursively(): void {
     84                if ( self::is_windows() ) {
     85                        $this->markTestSkipped( 'chmod() does not support octal modes on Windows.' );
     86                }
     87
     88                $directory   = untrailingslashit( self::$file_structure['test_dir']['path'] );
     89                $nested_file = self::$file_structure['subfile']['path'];
     90
     91                $this->assertTrue(
     92                        self::$filesystem->chmod( $directory, 0640, true ),
     93                        'chmod() did not report success.'
     94                );
     95
     96                clearstatcache();
     97
     98                $this->assertSame(
     99                        '640',
     100                        self::$filesystem->getchmod( $nested_file ),
     101                        'The mode was not applied to a file in a nested subdirectory.'
     102                );
     103        }
    77104}
  • trunk/tests/phpunit/tests/filesystem/wpFilesystemDirect/chown.php

    r57753 r62636  
    3030                $this->assertFalse( self::$filesystem->chown( $path, fileowner( __FILE__ ) ) );
    3131        }
     32
     33        /**
     34         * Tests that recursive {@see WP_Filesystem_Direct::chown()} descends into subdirectories.
     35         *
     36         * The resulting owner cannot be asserted without elevated privileges, so recursion is
     37         * verified by recording the paths passed to {@see WP_Filesystem_Direct::chown()}. Changing each item to its current
     38         * owner is a permitted no-op that avoids requiring root and its "Operation not permitted" warning.
     39         *
     40         * @ticket 65584
     41         */
     42        public function test_should_recurse_into_subdirectories(): void {
     43                $directory   = untrailingslashit( self::$file_structure['test_dir']['path'] );
     44                $nested_file = self::$file_structure['subfile']['path'];
     45
     46                $spy = new class( null ) extends WP_Filesystem_Direct {
     47                        /** @var string[] */
     48                        public array $visited = array();
     49
     50                        public function chown( $file, $owner, $recursive = false ) {
     51                                $this->visited[] = $file;
     52                                return parent::chown( $file, $owner, $recursive );
     53                        }
     54                };
     55
     56                $spy->chown( $directory, (int) fileowner( $directory ), true );
     57
     58                $this->assertContains(
     59                        $nested_file,
     60                        $spy->visited,
     61                        'chown() did not recurse into the nested subdirectory.'
     62                );
     63        }
    3264}
Note: See TracChangeset for help on using the changeset viewer.