From: Aaron Schulz Date: Thu, 12 Jan 2012 22:01:02 +0000 (+0000) Subject: * Collapse multiple directory separators in FileBackend::normalizeStoragePath().... X-Git-Tag: 1.31.0-rc.0~25322 X-Git-Url: http://git.cyclocoop.org/url?a=commitdiff_plain;h=9956408b550115a8719350e7e6371598b81903f4;p=lhc%2Fweb%2Fwiklou.git * Collapse multiple directory separators in FileBackend::normalizeStoragePath(). Also renamed the function to normalizeContainerPath() to be less confusing. * Made SwiftFileBackend respect the 'latest' parameter of various functions via "X-Newest: true" header. Added to TODO in the doGetFileStat() function, as cloudfiles needs upstream changes for that. * Fixed SwiftFileIterator to return paths relative to the given directory. * Clean up for FSFileBackend trailing slash handling. --- diff --git a/includes/filerepo/backend/FSFileBackend.php b/includes/filerepo/backend/FSFileBackend.php index ccbfe481b0..4654070e6f 100644 --- a/includes/filerepo/backend/FSFileBackend.php +++ b/includes/filerepo/backend/FSFileBackend.php @@ -514,7 +514,8 @@ class FSFileIterator implements Iterator { * @param $dir string */ public function __construct( $dir ) { - $this->suffixStart = strlen( realpath( $dir ) ) + 1; // size of "path/to/dir/" + $dir = realpath( $dir ); // normalize + $this->suffixStart = strlen( $dir ) + 1; // size of "path/to/dir/" try { $flags = FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS; $this->iter = new RecursiveIteratorIterator( diff --git a/includes/filerepo/backend/FileBackend.php b/includes/filerepo/backend/FileBackend.php index d9710989cf..76025c8b75 100644 --- a/includes/filerepo/backend/FileBackend.php +++ b/includes/filerepo/backend/FileBackend.php @@ -1226,12 +1226,14 @@ abstract class FileBackend extends FileBackendBase { * Null is returned if the path involves directory traversal. * Traversal is insecure for FS backends and broken for others. * - * @param $path string + * @param $path string Storage path relative to a container * @return string|null */ - final protected static function normalizeStoragePath( $path ) { + final protected static function normalizeContainerPath( $path ) { // Normalize directory separators $path = strtr( $path, '\\', '/' ); + // Collapse consecutive directory separators + $path = preg_replace( '![/]{2,}!', '/', $path ); // Use the same traversal protection as Title::secureAndSplit() if ( strpos( $path, '.' ) !== false ) { if ( @@ -1264,7 +1266,7 @@ abstract class FileBackend extends FileBackendBase { final protected function resolveStoragePath( $storagePath ) { list( $backend, $container, $relPath ) = self::splitStoragePath( $storagePath ); if ( $backend === $this->name ) { // must be for this backend - $relPath = self::normalizeStoragePath( $relPath ); + $relPath = self::normalizeContainerPath( $relPath ); if ( $relPath !== null ) { // Get shard for the normalized path if this container is sharded $cShard = $this->getContainerShard( $container, $relPath ); diff --git a/includes/filerepo/backend/SwiftFileBackend.php b/includes/filerepo/backend/SwiftFileBackend.php index e9bbb4ecc7..c630011701 100644 --- a/includes/filerepo/backend/SwiftFileBackend.php +++ b/includes/filerepo/backend/SwiftFileBackend.php @@ -15,8 +15,6 @@ * which is available at https://github.com/rackspace/php-cloudfiles. * All of the library classes must be registed in $wgAutoloadClasses. * - * @TODO: handle 'latest' param as "X-Newest: true". - * * @ingroup FileBackend */ class SwiftFileBackend extends FileBackend { @@ -378,7 +376,7 @@ class SwiftFileBackend extends FileBackend { protected function doSecureInternal( $fullCont, $dir, array $params ) { $status = Status::newGood(); // @TODO: restrict container from $this->swiftProxyUser - return $status; // badgers? We don't need no steenking badgers! + return $status; } /** @@ -398,6 +396,7 @@ class SwiftFileBackend extends FileBackend { $stat = false; try { $container = $conn->get_container( $srcCont ); + // @TODO: handle 'latest' param as "X-Newest: true" $obj = $container->get_object( $srcRel ); // Convert "Tue, 03 Jan 2012 22:01:04 GMT" to TS_MW $date = DateTime::createFromFormat( 'D, d F Y G:i:s e', $obj->last_modified ); @@ -440,7 +439,7 @@ class SwiftFileBackend extends FileBackend { try { $container = $conn->get_container( $srcCont ); $obj = $container->get_object( $srcRel ); - $data = $obj->read(); + $data = $obj->read( $this->headersFromParams( $params ) ); } catch ( NoSuchContainerException $e ) { } catch ( NoSuchObjectException $e ) { } catch ( InvalidResponseException $e ) { @@ -462,7 +461,7 @@ class SwiftFileBackend extends FileBackend { * Do not call this function outside of SwiftFileIterator * * @param $fullCont string Resolved container name - * @param $dir string Resolved storage directory + * @param $dir string Resolved storage directory with no trailing slash * @param $after string Storage path of file to list items after * @param $limit integer Max number of items to list * @return Array @@ -476,7 +475,7 @@ class SwiftFileBackend extends FileBackend { $files = array(); try { $container = $conn->get_container( $fullCont ); - $files = $container->list_objects( $limit, $after, $dir ); + $files = $container->list_objects( $limit, $after, "{$dir}/" ); } catch ( NoSuchContainerException $e ) { } catch ( NoSuchObjectException $e ) { } catch ( InvalidResponseException $e ) { @@ -534,8 +533,8 @@ class SwiftFileBackend extends FileBackend { } try { - $output = fopen("php://output", "w"); - $obj->stream( $output ); + $output = fopen( "php://output", "w" ); + $obj->stream( $output, $this->headersFromParams( $params ) ); } catch ( InvalidResponseException $e ) { $status->fatal( 'backend-fail-connect', $this->name ); } catch ( Exception $e ) { // some other exception? @@ -571,13 +570,17 @@ class SwiftFileBackend extends FileBackend { try { $cont = $conn->get_container( $srcCont ); $obj = $cont->get_object( $srcRel ); - $obj->save_to_filename( $tmpFile->getPath() ); + $handle = fopen( $tmpFile->getPath(), 'w' ); + if ( $handle ) { + $obj->stream( $handle, $this->headersFromParams( $params ) ); + fclose( $handle ); + } else { + $tmpFile = null; // couldn't open temp file + } } catch ( NoSuchContainerException $e ) { $tmpFile = null; } catch ( NoSuchObjectException $e ) { $tmpFile = null; - } catch ( IOException $e ) { - $tmpFile = null; } catch ( InvalidResponseException $e ) { $tmpFile = null; } catch ( Exception $e ) { // some other exception? @@ -588,6 +591,22 @@ class SwiftFileBackend extends FileBackend { return $tmpFile; } + /** + * Get headers to send to Swift when reading a file based + * on a FileBackend params array, e.g. that of getLocalCopy(). + * $params is currently only checked for a 'latest' flag. + * + * @param $params Array + * @return Array + */ + protected function headersFromParams( array $params ) { + $hdrs = array(); + if ( !empty( $params['latest'] ) ) { + $hdrs[] = 'X-Newest: true'; + } + return $hdrs; + } + /** * Get a connection to the swift proxy * @@ -644,6 +663,7 @@ class SwiftFileIterator implements Iterator { protected $backend; protected $container; // protected $dir; // string storage directory + protected $suffixStart; // integer const PAGE_SIZE = 5000; // file listing buffer size @@ -652,16 +672,20 @@ class SwiftFileIterator implements Iterator { * * @param $backend SwiftFileBackend * @param $fullCont string Resolved container name - * @param $dir string Resolved relateive path + * @param $dir string Resolved relative directory */ public function __construct( SwiftFileBackend $backend, $fullCont, $dir ) { + $this->backend = $backend; $this->container = $fullCont; $this->dir = $dir; - $this->backend = $backend; + if ( substr( $this->dir, -1 ) === '/' ) { + $this->dir = substr( $this->dir, 0, -1 ); // remove trailing slash + } + $this->suffixStart = strlen( $dir ) + 1; // size of "path/to/dir/" } public function current() { - return current( $this->bufferIter ); + return substr( current( $this->bufferIter ), $this->suffixStart ); } public function key() {