- /**
- * @see FileBackend::doConcatenateInternal()
- */
- protected function doConcatenateInternal( array $params ) {
- $status = Status::newGood();
-
- list( $c, $dest ) = $this->resolveStoragePath( $params['dst'] );
- if ( $dest === null ) {
- $status->fatal( 'backend-fail-invalidpath', $params['dst'] );
- return $status;
- }
-
- // Check if the destination file exists and we can't handle that
- $destExists = file_exists( $dest );
- if ( $destExists && empty( $params['overwriteDest'] ) ) {
- $status->fatal( 'backend-fail-alreadyexists', $params['dst'] );
- return $status;
- }
-
- // Create a new temporary file...
- wfSuppressWarnings();
- $tmpPath = tempnam( wfTempDir(), 'concatenate' );
- wfRestoreWarnings();
- if ( $tmpPath === false ) {
- $status->fatal( 'backend-fail-createtemp' );
- return $status;
- }
-
- // Build up that file using the source chunks (in order)...
- wfSuppressWarnings();
- $tmpHandle = fopen( $tmpPath, 'a' );
- wfRestoreWarnings();
- if ( $tmpHandle === false ) {
- $status->fatal( 'backend-fail-opentemp', $tmpPath );
- return $status;
- }
- foreach ( $params['srcs'] as $virtualSource ) {
- list( $c, $source ) = $this->resolveStoragePath( $virtualSource );
- if ( $source === null ) {
- fclose( $tmpHandle );
- $status->fatal( 'backend-fail-invalidpath', $virtualSource );
- return $status;
- }
- // Load chunk into memory (it should be a small file)
- $sourceHandle = fopen( $source, 'r' );
- if ( $sourceHandle === false ) {
- fclose( $tmpHandle );
- $status->fatal( 'backend-fail-read', $virtualSource );
- return $status;
- }
- // Append chunk to file (pass chunk size to avoid magic quotes)
- if ( !stream_copy_to_stream( $sourceHandle, $tmpHandle ) ) {
- fclose( $sourceHandle );
- fclose( $tmpHandle );
- $status->fatal( 'backend-fail-writetemp', $tmpPath );
- return $status;
- }
- fclose( $sourceHandle );
- }
- wfSuppressWarnings();
- if ( !fclose( $tmpHandle ) ) {
- $status->fatal( 'backend-fail-closetemp', $tmpPath );
- return $status;
- }
- wfRestoreWarnings();
-
- // Handle overwrite behavior of file destination if applicable.
- // Note that we already checked if no overwrite params were set above.
- if ( $destExists ) {
- // Windows does not support moving over existing files
- if ( wfIsWindows() ) {
- wfSuppressWarnings();
- $ok = unlink( $dest );
- wfRestoreWarnings();
- if ( !$ok ) {
- $status->fatal( 'backend-fail-delete', $params['dst'] );
- return $status;
- }
- }
- } else {
- // Make sure destination directory exists
- if ( !wfMkdirParents( dirname( $dest ) ) ) {
- $status->fatal( 'directorycreateerror', $params['dst'] );
- return $status;
- }
- }
-
- // Rename the temporary file to the destination path
- wfSuppressWarnings();
- $ok = rename( $tmpPath, $dest );
- wfRestoreWarnings();
- if ( !$ok ) {
- $status->fatal( 'backend-fail-move', $tmpPath, $params['dst'] );
- return $status;
- }
-
- $this->chmod( $dest );
-
- return $status;
- }
-