+ * @param string $dir Virtual URL (or storage path) of directory to clean
+ * @return Status
+ */
+ public function quickCleanDir( $dir ) {
+ $status = $this->newGood();
+ $status->merge( $this->backend->clean(
+ [ 'dir' => $this->resolveToStoragePath( $dir ) ] ) );
+
+ return $status;
+ }
+
+ /**
+ * Import a batch of files from the local file system into the repo.
+ * This does no locking nor journaling and overrides existing files.
+ * This function can be used to write to otherwise read-only foreign repos.
+ * This is intended for copying generated thumbnails into the repo.
+ *
+ * All path parameters may be a file system path, storage path, or virtual URL.
+ * When "headers" are given they are used as HTTP headers if supported.
+ *
+ * @param array $triples List of (source path or FSFile, destination path, disposition)
+ * @return Status
+ */
+ public function quickImportBatch( array $triples ) {
+ $status = $this->newGood();
+ $operations = [];
+ foreach ( $triples as $triple ) {
+ list( $src, $dst ) = $triple;
+ if ( $src instanceof FSFile ) {
+ $op = 'store';
+ } else {
+ $src = $this->resolveToStoragePath( $src );
+ $op = FileBackend::isStoragePath( $src ) ? 'copy' : 'store';
+ }
+ $dst = $this->resolveToStoragePath( $dst );
+
+ if ( !isset( $triple[2] ) ) {
+ $headers = [];
+ } elseif ( is_string( $triple[2] ) ) {
+ // back-compat
+ $headers = [ 'Content-Disposition' => $triple[2] ];
+ } elseif ( is_array( $triple[2] ) && isset( $triple[2]['headers'] ) ) {
+ $headers = $triple[2]['headers'];
+ } else {
+ $headers = [];
+ }
+
+ $operations[] = [
+ 'op' => $op,
+ 'src' => $src,
+ 'dst' => $dst,
+ 'headers' => $headers
+ ];
+ $status->merge( $this->initDirectory( dirname( $dst ) ) );
+ }
+ $status->merge( $this->backend->doQuickOperations( $operations ) );
+
+ return $status;
+ }
+
+ /**
+ * Purge a batch of files from the repo.
+ * This function can be used to write to otherwise read-only foreign repos.
+ * This does no locking nor journaling and is intended for purging thumbnails.
+ *
+ * @param array $paths List of virtual URLs or storage paths
+ * @return Status
+ */
+ public function quickPurgeBatch( array $paths ) {
+ $status = $this->newGood();
+ $operations = [];
+ foreach ( $paths as $path ) {
+ $operations[] = [
+ 'op' => 'delete',
+ 'src' => $this->resolveToStoragePath( $path ),
+ 'ignoreMissingSource' => true
+ ];
+ }
+ $status->merge( $this->backend->doQuickOperations( $operations ) );
+
+ return $status;
+ }
+
+ /**
+ * Pick a random name in the temp zone and store a file to it.
+ * Returns a Status object with the file Virtual URL in the value,
+ * file can later be disposed using FileRepo::freeTemp().
+ *
+ * @param string $originalName The base name of the file as specified
+ * by the user. The file extension will be maintained.
+ * @param string $srcPath The current location of the file.
+ * @return Status Object with the URL in the value.
+ */
+ public function storeTemp( $originalName, $srcPath ) {
+ $this->assertWritableRepo(); // fail out if read-only
+
+ $date = MWTimestamp::getInstance()->format( 'YmdHis' );
+ $hashPath = $this->getHashPath( $originalName );
+ $dstUrlRel = $hashPath . $date . '!' . rawurlencode( $originalName );
+ $virtualUrl = $this->getVirtualUrl( 'temp' ) . '/' . $dstUrlRel;
+
+ $result = $this->quickImport( $srcPath, $virtualUrl );
+ $result->value = $virtualUrl;
+
+ return $result;
+ }
+
+ /**
+ * Remove a temporary file or mark it for garbage collection
+ *
+ * @param string $virtualUrl The virtual URL returned by FileRepo::storeTemp()
+ * @return bool True on success, false on failure
+ */
+ public function freeTemp( $virtualUrl ) {
+ $this->assertWritableRepo(); // fail out if read-only
+
+ $temp = $this->getVirtualUrl( 'temp' );
+ if ( substr( $virtualUrl, 0, strlen( $temp ) ) != $temp ) {
+ wfDebug( __METHOD__ . ": Invalid temp virtual URL\n" );
+
+ return false;
+ }
+
+ return $this->quickPurge( $virtualUrl )->isOK();
+ }
+
+ /**
+ * Concatenate a list of temporary files into a target file location.
+ *
+ * @param array $srcPaths Ordered list of source virtual URLs/storage paths
+ * @param string $dstPath Target file system path
+ * @param int $flags Bitwise combination of the following flags:
+ * self::DELETE_SOURCE Delete the source files on success
+ * @return Status
+ */
+ public function concatenate( array $srcPaths, $dstPath, $flags = 0 ) {
+ $this->assertWritableRepo(); // fail out if read-only
+
+ $status = $this->newGood();
+
+ $sources = [];
+ foreach ( $srcPaths as $srcPath ) {
+ // Resolve source to a storage path if virtual
+ $source = $this->resolveToStoragePath( $srcPath );
+ $sources[] = $source; // chunk to merge
+ }
+
+ // Concatenate the chunks into one FS file
+ $params = [ 'srcs' => $sources, 'dst' => $dstPath ];
+ $status->merge( $this->backend->concatenate( $params ) );
+ if ( !$status->isOK() ) {
+ return $status;
+ }
+
+ // Delete the sources if required
+ if ( $flags & self::DELETE_SOURCE ) {
+ $status->merge( $this->quickPurgeBatch( $srcPaths ) );
+ }
+
+ // Make sure status is OK, despite any quickPurgeBatch() fatals
+ $status->setResult( true );
+
+ return $status;
+ }
+
+ /**
+ * Copy or move a file either from a storage path, virtual URL,
+ * or file system path, into this repository at the specified destination location.
+ *
+ * Returns a Status object. On success, the value contains "new" or