summaryrefslogtreecommitdiff
path: root/includes/filebackend/FileOp.php
diff options
context:
space:
mode:
authorLuke Shumaker <LukeShu@sbcglobal.net>2014-01-28 09:50:25 -0500
committerLuke Shumaker <LukeShu@sbcglobal.net>2014-01-28 09:50:25 -0500
commit5744df39e15f85c6cc8a9faf8924d77e76d2b216 (patch)
treea8c8dd40a94d1fa0d5377566aa5548ae55a163da /includes/filebackend/FileOp.php
parent4bb2aeca1d198391ca856aa16c40b8559c68daec (diff)
parent224b22a051051f6c2e494c3a2fb4adb42898e2d1 (diff)
Merge branch 'archwiki'
Conflicts: extensions/FluxBBAuthPlugin.php extensions/SyntaxHighlight_GeSHi/README extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.i18n.php extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.php extensions/SyntaxHighlight_GeSHi/geshi/docs/CHANGES extensions/SyntaxHighlight_GeSHi/geshi/docs/THANKS extensions/SyntaxHighlight_GeSHi/geshi/docs/TODO extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractClass.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractClass_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractMethod.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateClass.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateClass_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateMethod.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Class.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Class_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Constant.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Constructor.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Destructor.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Function.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Global.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/I.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Index.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Interface.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Interface_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/L.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Lminus.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Lplus.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Method.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Page.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Page_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateClass.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateClass_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateMethod.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateVariable.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/StaticMethod.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/StaticVariable.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/T.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Tminus.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Tplus.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Variable.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/blank.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/class_folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/file.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/function_folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/next_button.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/next_button_disabled.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/package.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/package_folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/previous_button.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/previous_button_disabled.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/private_class_logo.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/tutorial.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/tutorial_folder.png extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/up_button.png extensions/SyntaxHighlight_GeSHi/geshi/docs/geshi-doc.html extensions/SyntaxHighlight_GeSHi/geshi/docs/geshi-doc.txt extensions/SyntaxHighlight_GeSHi/geshi/geshi.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/4cs.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502acme.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502kickass.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502tasm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/68000devpac.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/abap.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/actionscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/actionscript3.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ada.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/algol68.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/apache.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/applescript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/apt_sources.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/asm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/asp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/autoconf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/autohotkey.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/autoit.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/avisynth.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/awk.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bascomavr.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bash.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/basic4gl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bibtex.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/blitzbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/bnf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/boo.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/c.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/c_loadrunner.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/c_mac.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/caddcl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cadlisp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cfdg.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cfm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/chaiscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cil.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/clojure.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cmake.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cobol.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/coffeescript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cpp-qt.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cpp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/csharp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/css.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/cuesheet.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/d.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/dcs.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/delphi.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/diff.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/div.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/dos.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/dot.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/e.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ecmascript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/eiffel.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/email.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/epc.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/erlang.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/euphoria.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/f1.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/falcon.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/fo.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/fortran.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/freebasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/fsharp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gambas.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gdb.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/genero.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/genie.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gettext.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/glsl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gnuplot.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/go.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/groovy.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/gwbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/haskell.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/hicest.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/hq9plus.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/html4strict.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/html5.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/icon.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/idl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ini.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/inno.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/intercal.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/io.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/j.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/java.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/java5.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/javascript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/jquery.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/kixtart.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/klonec.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/klonecpp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/latex.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lb.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lisp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/llvm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/locobasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/logtalk.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lolcode.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lotusformulas.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lotusscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lsl2.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/lua.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/m68k.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/magiksf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/make.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mapbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/matlab.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mirc.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mmix.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/modula2.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/modula3.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mpasm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mxml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/mysql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/newlisp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/nsis.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oberon2.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/objc.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/objeck.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ocaml-brief.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ocaml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oobas.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oracle11.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oracle8.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oxygene.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/oz.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pascal.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pcre.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/per.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/perl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/perl6.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/php-brief.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/php.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pic16.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pike.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pixelbender.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pli.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/plsql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/postgresql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/povray.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/powerbuilder.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/powershell.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/proftpd.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/progress.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/prolog.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/properties.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/providex.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/purebasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/pycon.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/python.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/q.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/qbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/rails.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/rebol.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/reg.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/robots.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/rpmspec.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/rsplus.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/ruby.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/sas.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/scala.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/scheme.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/scilab.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/sdlbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/smalltalk.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/smarty.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/sql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/systemverilog.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/tcl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/teraterm.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/text.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/thinbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/tsql.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/typoscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/unicon.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/uscript.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vala.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vb.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vbnet.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/verilog.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vhdl.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/vim.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/visualfoxpro.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/visualprolog.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/whitespace.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/whois.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/winbatch.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/xbasic.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/xml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/xorg_conf.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/xpp.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/yaml.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/z80.php extensions/SyntaxHighlight_GeSHi/geshi/geshi/zxbasic.php
Diffstat (limited to 'includes/filebackend/FileOp.php')
-rw-r--r--includes/filebackend/FileOp.php453
1 files changed, 244 insertions, 209 deletions
diff --git a/includes/filebackend/FileOp.php b/includes/filebackend/FileOp.php
index 7c43c489..fe833084 100644
--- a/includes/filebackend/FileOp.php
+++ b/includes/filebackend/FileOp.php
@@ -42,11 +42,12 @@ abstract class FileOp {
protected $state = self::STATE_NEW; // integer
protected $failed = false; // boolean
protected $async = false; // boolean
- protected $useLatest = true; // boolean
protected $batchId; // string
+ protected $doOperation = true; // boolean; operation is not a no-op
protected $sourceSha1; // string
- protected $destSameAsSource; // boolean
+ protected $overwriteSameCase; // boolean
+ protected $destExists; // boolean
/* Object life-cycle */
const STATE_NEW = 1;
@@ -54,54 +55,81 @@ abstract class FileOp {
const STATE_ATTEMPTED = 3;
/**
- * Build a new file operation transaction
+ * Build a new batch file operation transaction
*
- * @param $backend FileBackendStore
- * @param $params Array
+ * @param FileBackendStore $backend
+ * @param Array $params
* @throws MWException
*/
final public function __construct( FileBackendStore $backend, array $params ) {
$this->backend = $backend;
list( $required, $optional ) = $this->allowedParams();
+ // @todo normalizeAnyStoragePaths() calls are overzealous, use a parameter list
foreach ( $required as $name ) {
if ( isset( $params[$name] ) ) {
- $this->params[$name] = $params[$name];
+ // Normalize paths so the paths to the same file have the same string
+ $this->params[$name] = self::normalizeAnyStoragePaths( $params[$name] );
} else {
throw new MWException( "File operation missing parameter '$name'." );
}
}
foreach ( $optional as $name ) {
if ( isset( $params[$name] ) ) {
- $this->params[$name] = $params[$name];
+ // Normalize paths so the paths to the same file have the same string
+ $this->params[$name] = self::normalizeAnyStoragePaths( $params[$name] );
}
}
$this->params = $params;
}
/**
- * Set the batch UUID this operation belongs to
+ * Normalize $item or anything in $item that is a valid storage path
*
- * @param $batchId string
- * @return void
+ * @param string $item|array
+ * @return string|Array
+ */
+ protected function normalizeAnyStoragePaths( $item ) {
+ if ( is_array( $item ) ) {
+ $res = array();
+ foreach ( $item as $k => $v ) {
+ $k = self::normalizeIfValidStoragePath( $k );
+ $v = self::normalizeIfValidStoragePath( $v );
+ $res[$k] = $v;
+ }
+ return $res;
+ } else {
+ return self::normalizeIfValidStoragePath( $item );
+ }
+ }
+
+ /**
+ * Normalize a string if it is a valid storage path
+ *
+ * @param string $path
+ * @return string
*/
- final public function setBatchId( $batchId ) {
- $this->batchId = $batchId;
+ protected static function normalizeIfValidStoragePath( $path ) {
+ if ( FileBackend::isStoragePath( $path ) ) {
+ $res = FileBackend::normalizeStoragePath( $path );
+ return ( $res !== null ) ? $res : $path;
+ }
+ return $path;
}
/**
- * Whether to allow stale data for file reads and stat checks
+ * Set the batch UUID this operation belongs to
*
- * @param $allowStale bool
+ * @param string $batchId
* @return void
*/
- final public function allowStaleReads( $allowStale ) {
- $this->useLatest = !$allowStale;
+ final public function setBatchId( $batchId ) {
+ $this->batchId = $batchId;
}
/**
* Get the value of the parameter with the given name
*
- * @param $name string
+ * @param string $name
* @return mixed Returns null if the parameter is not set
*/
final public function getParam( $name ) {
@@ -138,11 +166,11 @@ abstract class FileOp {
/**
* Update a dependency tracking array to account for this operation
*
- * @param $deps Array Prior path reads/writes; format of FileOp::newPredicates()
+ * @param array $deps Prior path reads/writes; format of FileOp::newPredicates()
* @return Array
*/
final public function applyDependencies( array $deps ) {
- $deps['read'] += array_fill_keys( $this->storagePathsRead(), 1 );
+ $deps['read'] += array_fill_keys( $this->storagePathsRead(), 1 );
$deps['write'] += array_fill_keys( $this->storagePathsChanged(), 1 );
return $deps;
}
@@ -150,7 +178,7 @@ abstract class FileOp {
/**
* Check if this operation changes files listed in $paths
*
- * @param $paths Array Prior path reads/writes; format of FileOp::newPredicates()
+ * @param array $paths Prior path reads/writes; format of FileOp::newPredicates()
* @return boolean
*/
final public function dependsOn( array $deps ) {
@@ -170,33 +198,36 @@ abstract class FileOp {
/**
* Get the file journal entries for this file operation
*
- * @param $oPredicates Array Pre-op info about files (format of FileOp::newPredicates)
- * @param $nPredicates Array Post-op info about files (format of FileOp::newPredicates)
+ * @param array $oPredicates Pre-op info about files (format of FileOp::newPredicates)
+ * @param array $nPredicates Post-op info about files (format of FileOp::newPredicates)
* @return Array
*/
final public function getJournalEntries( array $oPredicates, array $nPredicates ) {
+ if ( !$this->doOperation ) {
+ return array(); // this is a no-op
+ }
$nullEntries = array();
$updateEntries = array();
$deleteEntries = array();
$pathsUsed = array_merge( $this->storagePathsRead(), $this->storagePathsChanged() );
- foreach ( $pathsUsed as $path ) {
+ foreach ( array_unique( $pathsUsed ) as $path ) {
$nullEntries[] = array( // assertion for recovery
- 'op' => 'null',
- 'path' => $path,
+ 'op' => 'null',
+ 'path' => $path,
'newSha1' => $this->fileSha1( $path, $oPredicates )
);
}
foreach ( $this->storagePathsChanged() as $path ) {
if ( $nPredicates['sha1'][$path] === false ) { // deleted
$deleteEntries[] = array(
- 'op' => 'delete',
- 'path' => $path,
+ 'op' => 'delete',
+ 'path' => $path,
'newSha1' => ''
);
} else { // created/updated
$updateEntries[] = array(
- 'op' => $this->fileExists( $path, $oPredicates ) ? 'update' : 'create',
- 'path' => $path,
+ 'op' => $this->fileExists( $path, $oPredicates ) ? 'update' : 'create',
+ 'path' => $path,
'newSha1' => $nPredicates['sha1'][$path]
);
}
@@ -205,9 +236,11 @@ abstract class FileOp {
}
/**
- * Check preconditions of the operation without writing anything
+ * Check preconditions of the operation without writing anything.
+ * This must update $predicates for each path that the op can change
+ * except when a failing status object is returned.
*
- * @param $predicates Array
+ * @param Array $predicates
* @return Status
*/
final public function precheck( array &$predicates ) {
@@ -241,10 +274,14 @@ abstract class FileOp {
return Status::newFatal( 'fileop-fail-attempt-precheck' );
}
$this->state = self::STATE_ATTEMPTED;
- $status = $this->doAttempt();
- if ( !$status->isOK() ) {
- $this->failed = true;
- $this->logFailure( 'attempt' );
+ if ( $this->doOperation ) {
+ $status = $this->doAttempt();
+ if ( !$status->isOK() ) {
+ $this->failed = true;
+ $this->logFailure( 'attempt' );
+ }
+ } else { // no-op
+ $status = Status::newGood();
}
return $status;
}
@@ -280,7 +317,7 @@ abstract class FileOp {
/**
* Adjust params to FileBackendStore internal file calls
*
- * @param $params Array
+ * @param Array $params
* @return Array (required params list, optional params list)
*/
protected function setFlags( array $params ) {
@@ -292,15 +329,7 @@ abstract class FileOp {
*
* @return Array
*/
- final public function storagePathsRead() {
- return array_map( 'FileBackend::normalizeStoragePath', $this->doStoragePathsRead() );
- }
-
- /**
- * @see FileOp::storagePathsRead()
- * @return Array
- */
- protected function doStoragePathsRead() {
+ public function storagePathsRead() {
return array();
}
@@ -309,24 +338,16 @@ abstract class FileOp {
*
* @return Array
*/
- final public function storagePathsChanged() {
- return array_map( 'FileBackend::normalizeStoragePath', $this->doStoragePathsChanged() );
- }
-
- /**
- * @see FileOp::storagePathsChanged()
- * @return Array
- */
- protected function doStoragePathsChanged() {
+ public function storagePathsChanged() {
return array();
}
/**
* Check for errors with regards to the destination file already existing.
- * This also updates the destSameAsSource and sourceSha1 member variables.
+ * Also set the destExists, overwriteSameCase and sourceSha1 member variables.
* A bad status will be returned if there is no chance it can be overwritten.
*
- * @param $predicates Array
+ * @param Array $predicates
* @return Status
*/
protected function precheckDestExistence( array $predicates ) {
@@ -336,8 +357,9 @@ abstract class FileOp {
if ( $this->sourceSha1 === null ) { // file in storage?
$this->sourceSha1 = $this->fileSha1( $this->params['src'], $predicates );
}
- $this->destSameAsSource = false;
- if ( $this->fileExists( $this->params['dst'], $predicates ) ) {
+ $this->overwriteSameCase = false;
+ $this->destExists = $this->fileExists( $this->params['dst'], $predicates );
+ if ( $this->destExists ) {
if ( $this->getParam( 'overwrite' ) ) {
return $status; // OK
} elseif ( $this->getParam( 'overwriteSame' ) ) {
@@ -349,7 +371,7 @@ abstract class FileOp {
// Give an error if the files are not identical
$status->fatal( 'backend-fail-notsame', $this->params['dst'] );
} else {
- $this->destSameAsSource = true; // OK
+ $this->overwriteSameCase = true; // OK
}
return $status; // do nothing; either OK or bad status
} else {
@@ -362,7 +384,7 @@ abstract class FileOp {
/**
* precheckDestExistence() helper function to get the source file SHA-1.
- * Subclasses should overwride this iff the source is not in storage.
+ * Subclasses should overwride this if the source is not in storage.
*
* @return string|bool Returns false on failure
*/
@@ -373,15 +395,15 @@ abstract class FileOp {
/**
* Check if a file will exist in storage when this operation is attempted
*
- * @param $source string Storage path
- * @param $predicates Array
+ * @param string $source Storage path
+ * @param Array $predicates
* @return bool
*/
final protected function fileExists( $source, array $predicates ) {
if ( isset( $predicates['exists'][$source] ) ) {
return $predicates['exists'][$source]; // previous op assures this
} else {
- $params = array( 'src' => $source, 'latest' => $this->useLatest );
+ $params = array( 'src' => $source, 'latest' => true );
return $this->backend->fileExists( $params );
}
}
@@ -389,15 +411,17 @@ abstract class FileOp {
/**
* Get the SHA-1 of a file in storage when this operation is attempted
*
- * @param $source string Storage path
- * @param $predicates Array
+ * @param string $source Storage path
+ * @param Array $predicates
* @return string|bool False on failure
*/
final protected function fileSha1( $source, array $predicates ) {
if ( isset( $predicates['sha1'][$source] ) ) {
return $predicates['sha1'][$source]; // previous op assures this
+ } elseif ( isset( $predicates['exists'][$source] ) && !$predicates['exists'][$source] ) {
+ return false; // previous op assures this
} else {
- $params = array( 'src' => $source, 'latest' => $this->useLatest );
+ $params = array( 'src' => $source, 'latest' => true );
return $this->backend->getFileSha1Base36( $params );
}
}
@@ -414,7 +438,7 @@ abstract class FileOp {
/**
* Log a file operation failure and preserve any temp files
*
- * @param $action string
+ * @param string $action
* @return void
*/
final public function logFailure( $action ) {
@@ -430,42 +454,32 @@ abstract class FileOp {
}
/**
- * Store a file into the backend from a file on the file system.
+ * Create a file in the backend with the given content.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
-class StoreFileOp extends FileOp {
- /**
- * @return array
- */
+class CreateFileOp extends FileOp {
protected function allowedParams() {
- return array( array( 'src', 'dst' ),
- array( 'overwrite', 'overwriteSame', 'disposition' ) );
+ return array( array( 'content', 'dst' ),
+ array( 'overwrite', 'overwriteSame', 'headers' ) );
}
- /**
- * @param $predicates array
- * @return Status
- */
protected function doPrecheck( array &$predicates ) {
$status = Status::newGood();
- // Check if the source file exists on the file system
- if ( !is_file( $this->params['src'] ) ) {
- $status->fatal( 'backend-fail-notexists', $this->params['src'] );
- return $status;
- // Check if the source file is too big
- } elseif ( filesize( $this->params['src'] ) > $this->backend->maxFileSizeInternal() ) {
+ // Check if the source data is too big
+ if ( strlen( $this->getParam( 'content' ) ) > $this->backend->maxFileSizeInternal() ) {
$status->fatal( 'backend-fail-maxsize',
$this->params['dst'], $this->backend->maxFileSizeInternal() );
- $status->fatal( 'backend-fail-store', $this->params['src'], $this->params['dst'] );
+ $status->fatal( 'backend-fail-create', $this->params['dst'] );
return $status;
- // Check if a file can be placed at the destination
+ // Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
- $status->fatal( 'backend-fail-store', $this->params['src'], $this->params['dst'] );
+ $status->fatal( 'backend-fail-create', $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
+ $this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
@@ -474,61 +488,54 @@ class StoreFileOp extends FileOp {
return $status; // safe to call attempt()
}
- /**
- * @return Status
- */
protected function doAttempt() {
- // Store the file at the destination
- if ( !$this->destSameAsSource ) {
- return $this->backend->storeInternal( $this->setFlags( $this->params ) );
+ if ( !$this->overwriteSameCase ) {
+ // Create the file at the destination
+ return $this->backend->createInternal( $this->setFlags( $this->params ) );
}
return Status::newGood();
}
- /**
- * @return bool|string
- */
protected function getSourceSha1Base36() {
- wfSuppressWarnings();
- $hash = sha1_file( $this->params['src'] );
- wfRestoreWarnings();
- if ( $hash !== false ) {
- $hash = wfBaseConvert( $hash, 16, 36, 31 );
- }
- return $hash;
+ return wfBaseConvert( sha1( $this->params['content'] ), 16, 36, 31 );
}
- protected function doStoragePathsChanged() {
+ public function storagePathsChanged() {
return array( $this->params['dst'] );
}
}
/**
- * Create a file in the backend with the given content.
+ * Store a file into the backend from a file on the file system.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
-class CreateFileOp extends FileOp {
+class StoreFileOp extends FileOp {
protected function allowedParams() {
- return array( array( 'content', 'dst' ),
- array( 'overwrite', 'overwriteSame', 'disposition' ) );
+ return array( array( 'src', 'dst' ),
+ array( 'overwrite', 'overwriteSame', 'headers' ) );
}
protected function doPrecheck( array &$predicates ) {
$status = Status::newGood();
- // Check if the source data is too big
- if ( strlen( $this->getParam( 'content' ) ) > $this->backend->maxFileSizeInternal() ) {
+ // Check if the source file exists on the file system
+ if ( !is_file( $this->params['src'] ) ) {
+ $status->fatal( 'backend-fail-notexists', $this->params['src'] );
+ return $status;
+ // Check if the source file is too big
+ } elseif ( filesize( $this->params['src'] ) > $this->backend->maxFileSizeInternal() ) {
$status->fatal( 'backend-fail-maxsize',
$this->params['dst'], $this->backend->maxFileSizeInternal() );
- $status->fatal( 'backend-fail-create', $this->params['dst'] );
+ $status->fatal( 'backend-fail-store', $this->params['src'], $this->params['dst'] );
return $status;
- // Check if a file can be placed at the destination
+ // Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
- $status->fatal( 'backend-fail-create', $this->params['dst'] );
+ $status->fatal( 'backend-fail-store', $this->params['src'], $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
+ $this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
@@ -537,28 +544,25 @@ class CreateFileOp extends FileOp {
return $status; // safe to call attempt()
}
- /**
- * @return Status
- */
protected function doAttempt() {
- if ( !$this->destSameAsSource ) {
- // Create the file at the destination
- return $this->backend->createInternal( $this->setFlags( $this->params ) );
+ if ( !$this->overwriteSameCase ) {
+ // Store the file at the destination
+ return $this->backend->storeInternal( $this->setFlags( $this->params ) );
}
return Status::newGood();
}
- /**
- * @return bool|String
- */
protected function getSourceSha1Base36() {
- return wfBaseConvert( sha1( $this->params['content'] ), 16, 36, 31 );
+ wfSuppressWarnings();
+ $hash = sha1_file( $this->params['src'] );
+ wfRestoreWarnings();
+ if ( $hash !== false ) {
+ $hash = wfBaseConvert( $hash, 16, 36, 31 );
+ }
+ return $hash;
}
- /**
- * @return array
- */
- protected function doStoragePathsChanged() {
+ public function storagePathsChanged() {
return array( $this->params['dst'] );
}
}
@@ -568,25 +572,26 @@ class CreateFileOp extends FileOp {
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class CopyFileOp extends FileOp {
- /**
- * @return array
- */
protected function allowedParams() {
return array( array( 'src', 'dst' ),
- array( 'overwrite', 'overwriteSame', 'disposition' ) );
+ array( 'overwrite', 'overwriteSame', 'ignoreMissingSource', 'headers' ) );
}
- /**
- * @param $predicates array
- * @return Status
- */
protected function doPrecheck( array &$predicates ) {
$status = Status::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
- $status->fatal( 'backend-fail-notexists', $this->params['src'] );
- return $status;
- // Check if a file can be placed at the destination
+ if ( $this->getParam( 'ignoreMissingSource' ) ) {
+ $this->doOperation = false; // no-op
+ // Update file existence predicates (cache 404s)
+ $predicates['exists'][$this->params['src']] = false;
+ $predicates['sha1'][$this->params['src']] = false;
+ return $status; // nothing to do
+ } else {
+ $status->fatal( 'backend-fail-notexists', $this->params['src'] );
+ return $status;
+ }
+ // Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-copy', $this->params['src'], $this->params['dst'] );
@@ -594,6 +599,7 @@ class CopyFileOp extends FileOp {
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
+ $this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
@@ -602,31 +608,27 @@ class CopyFileOp extends FileOp {
return $status; // safe to call attempt()
}
- /**
- * @return Status
- */
protected function doAttempt() {
- // Do nothing if the src/dst paths are the same
- if ( $this->params['src'] !== $this->params['dst'] ) {
- // Copy the file into the destination
- if ( !$this->destSameAsSource ) {
- return $this->backend->copyInternal( $this->setFlags( $this->params ) );
- }
+ if ( $this->overwriteSameCase ) {
+ $status = Status::newGood(); // nothing to do
+ } elseif ( $this->params['src'] === $this->params['dst'] ) {
+ // Just update the destination file headers
+ $headers = $this->getParam( 'headers' ) ?: array();
+ $status = $this->backend->describeInternal( $this->setFlags( array(
+ 'src' => $this->params['dst'], 'headers' => $headers
+ ) ) );
+ } else {
+ // Copy the file to the destination
+ $status = $this->backend->copyInternal( $this->setFlags( $this->params ) );
}
- return Status::newGood();
+ return $status;
}
- /**
- * @return array
- */
- protected function doStoragePathsRead() {
+ public function storagePathsRead() {
return array( $this->params['src'] );
}
- /**
- * @return array
- */
- protected function doStoragePathsChanged() {
+ public function storagePathsChanged() {
return array( $this->params['dst'] );
}
}
@@ -636,25 +638,26 @@ class CopyFileOp extends FileOp {
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class MoveFileOp extends FileOp {
- /**
- * @return array
- */
protected function allowedParams() {
return array( array( 'src', 'dst' ),
- array( 'overwrite', 'overwriteSame', 'disposition' ) );
+ array( 'overwrite', 'overwriteSame', 'ignoreMissingSource', 'headers' ) );
}
- /**
- * @param $predicates array
- * @return Status
- */
protected function doPrecheck( array &$predicates ) {
$status = Status::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
- $status->fatal( 'backend-fail-notexists', $this->params['src'] );
- return $status;
- // Check if a file can be placed at the destination
+ if ( $this->getParam( 'ignoreMissingSource' ) ) {
+ $this->doOperation = false; // no-op
+ // Update file existence predicates (cache 404s)
+ $predicates['exists'][$this->params['src']] = false;
+ $predicates['sha1'][$this->params['src']] = false;
+ return $status; // nothing to do
+ } else {
+ $status->fatal( 'backend-fail-notexists', $this->params['src'] );
+ return $status;
+ }
+ // Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-move', $this->params['src'], $this->params['dst'] );
@@ -662,6 +665,7 @@ class MoveFileOp extends FileOp {
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
+ $this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['src']] = false;
@@ -672,35 +676,35 @@ class MoveFileOp extends FileOp {
return $status; // safe to call attempt()
}
- /**
- * @return Status
- */
protected function doAttempt() {
- // Do nothing if the src/dst paths are the same
- if ( $this->params['src'] !== $this->params['dst'] ) {
- if ( !$this->destSameAsSource ) {
- // Move the file into the destination
- return $this->backend->moveInternal( $this->setFlags( $this->params ) );
+ if ( $this->overwriteSameCase ) {
+ if ( $this->params['src'] === $this->params['dst'] ) {
+ // Do nothing to the destination (which is also the source)
+ $status = Status::newGood();
} else {
- // Just delete source as the destination needs no changes
- $params = array( 'src' => $this->params['src'] );
- return $this->backend->deleteInternal( $this->setFlags( $params ) );
+ // Just delete the source as the destination file needs no changes
+ $status = $this->backend->deleteInternal( $this->setFlags(
+ array( 'src' => $this->params['src'] )
+ ) );
}
+ } elseif ( $this->params['src'] === $this->params['dst'] ) {
+ // Just update the destination file headers
+ $headers = $this->getParam( 'headers' ) ?: array();
+ $status = $this->backend->describeInternal( $this->setFlags(
+ array( 'src' => $this->params['dst'], 'headers' => $headers )
+ ) );
+ } else {
+ // Move the file to the destination
+ $status = $this->backend->moveInternal( $this->setFlags( $this->params ) );
}
- return Status::newGood();
+ return $status;
}
- /**
- * @return array
- */
- protected function doStoragePathsRead() {
+ public function storagePathsRead() {
return array( $this->params['src'] );
}
- /**
- * @return array
- */
- protected function doStoragePathsChanged() {
+ public function storagePathsChanged() {
return array( $this->params['src'], $this->params['dst'] );
}
}
@@ -710,28 +714,29 @@ class MoveFileOp extends FileOp {
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class DeleteFileOp extends FileOp {
- /**
- * @return array
- */
protected function allowedParams() {
return array( array( 'src' ), array( 'ignoreMissingSource' ) );
}
- protected $needsDelete = true;
-
- /**
- * @param array $predicates
- * @return Status
- */
protected function doPrecheck( array &$predicates ) {
$status = Status::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
- if ( !$this->getParam( 'ignoreMissingSource' ) ) {
+ if ( $this->getParam( 'ignoreMissingSource' ) ) {
+ $this->doOperation = false; // no-op
+ // Update file existence predicates (cache 404s)
+ $predicates['exists'][$this->params['src']] = false;
+ $predicates['sha1'][$this->params['src']] = false;
+ return $status; // nothing to do
+ } else {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
}
- $this->needsDelete = false;
+ // Check if a file can be placed/changed at the source
+ } elseif ( !$this->backend->isPathUsableInternal( $this->params['src'] ) ) {
+ $status->fatal( 'backend-fail-usable', $this->params['src'] );
+ $status->fatal( 'backend-fail-delete', $this->params['src'] );
+ return $status;
}
// Update file existence predicates
$predicates['exists'][$this->params['src']] = false;
@@ -739,21 +744,51 @@ class DeleteFileOp extends FileOp {
return $status; // safe to call attempt()
}
- /**
- * @return Status
- */
protected function doAttempt() {
- if ( $this->needsDelete ) {
- // Delete the source file
- return $this->backend->deleteInternal( $this->setFlags( $this->params ) );
+ // Delete the source file
+ return $this->backend->deleteInternal( $this->setFlags( $this->params ) );
+ }
+
+ public function storagePathsChanged() {
+ return array( $this->params['src'] );
+ }
+}
+
+/**
+ * Change metadata for a file at the given storage path in the backend.
+ * Parameters for this operation are outlined in FileBackend::doOperations().
+ */
+class DescribeFileOp extends FileOp {
+ protected function allowedParams() {
+ return array( array( 'src' ), array( 'headers' ) );
+ }
+
+ protected function doPrecheck( array &$predicates ) {
+ $status = Status::newGood();
+ // Check if the source file exists
+ if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
+ $status->fatal( 'backend-fail-notexists', $this->params['src'] );
+ return $status;
+ // Check if a file can be placed/changed at the source
+ } elseif ( !$this->backend->isPathUsableInternal( $this->params['src'] ) ) {
+ $status->fatal( 'backend-fail-usable', $this->params['src'] );
+ $status->fatal( 'backend-fail-describe', $this->params['src'] );
+ return $status;
}
- return Status::newGood();
+ // Update file existence predicates
+ $predicates['exists'][$this->params['src']] =
+ $this->fileExists( $this->params['src'], $predicates );
+ $predicates['sha1'][$this->params['src']] =
+ $this->fileSha1( $this->params['src'], $predicates );
+ return $status; // safe to call attempt()
}
- /**
- * @return array
- */
- protected function doStoragePathsChanged() {
+ protected function doAttempt() {
+ // Update the source file's metadata
+ return $this->backend->describeInternal( $this->setFlags( $this->params ) );
+ }
+
+ public function storagePathsChanged() {
return array( $this->params['src'] );
}
}