46 $oldLayout = $this->
getOption(
'oldlayout' );
47 if ( !in_array( $oldLayout, [
'name',
'sha1' ] ) ) {
50 $newLayout = $this->
getOption(
'newlayout' );
51 if ( !in_array( $newLayout, [
'name',
'sha1' ] ) ) {
58 $be = $repo->getBackend();
61 $be = $be->getInternalBackend();
64 $dbw = $repo->getPrimaryDB();
66 $origBase = $be->getContainerStoragePath(
"{$repo->getName()}-original" );
72 $conds[] = $dbw->expr(
'img_timestamp',
'>=', $dbw->timestamp( $since ) );
79 $res = $dbw->newSelectQueryBuilder()
80 ->select( [
'img_name',
'img_sha1' ] )
82 ->where( $dbw->expr(
'img_name',
'>', $lastName ) )
84 ->orderBy(
'img_name' )
86 ->caller( __METHOD__ )->fetchResultSet();
88 foreach ( $res as $row ) {
89 $lastName = $row->img_name;
91 $file = $repo->newFile( $row->img_name );
93 $sha1 = strlen( $row->img_sha1 ) ? $row->img_sha1 : $file->getSha1();
95 if ( !strlen( $sha1 ) ) {
96 $this->
error(
"Image SHA-1 not known for {$row->img_name}." );
98 if ( $oldLayout ===
'sha1' ) {
99 $spath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
101 $spath = $file->getPath();
104 if ( $newLayout ===
'sha1' ) {
105 $dpath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
107 $dpath = $file->getPath();
110 $status = $be->prepare( [
111 'dir' => dirname( $dpath ),
'bypassReadOnly' =>
true ] );
112 if ( !$status->isOK() ) {
113 $this->
error( $status );
116 $batch[] = [
'op' =>
'copy',
'overwrite' =>
true,
117 'src' => $spath,
'dst' => $dpath,
'img' => $row->img_name ];
120 foreach ( $file->getHistory() as $ofile ) {
121 $sha1 = $ofile->getSha1();
122 if ( !strlen( $sha1 ) ) {
123 $this->
error(
"Image SHA-1 not set for {$ofile->getArchiveName()}." );
127 if ( $oldLayout ===
'sha1' ) {
128 $spath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
129 } elseif ( $ofile->isDeleted( File::DELETED_FILE ) ) {
130 $spath = $be->getContainerStoragePath(
"{$repo->getName()}-deleted" ) .
131 '/' . $repo->getDeletedHashPath( $sha1 ) .
132 $sha1 .
'.' . $ofile->getExtension();
134 $spath = $ofile->getPath();
137 if ( $newLayout ===
'sha1' ) {
138 $dpath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
140 $dpath = $ofile->getPath();
143 $status = $be->prepare( [
144 'dir' => dirname( $dpath ),
'bypassReadOnly' =>
true ] );
145 if ( !$status->isOK() ) {
146 $this->
error( $status );
148 $batch[] = [
'op' =>
'copy',
'overwrite' =>
true,
149 'src' => $spath,
'dst' => $dpath,
'img' => $ofile->getArchiveName() ];
152 if ( count( $batch ) >= $batchSize ) {
157 }
while ( $res->numRows() );
159 if ( count( $batch ) ) {
166 $conds[] = $dbw->expr(
'fa_deleted_timestamp',
'>=', $dbw->timestamp( $since ) );
172 $res = $dbw->newSelectQueryBuilder()
173 ->select( [
'fa_storage_key',
'fa_id',
'fa_name' ] )
174 ->from(
'filearchive' )
175 ->where( $dbw->expr(
'fa_id',
'>', $lastId ) )
178 ->limit( $batchSize )
179 ->caller( __METHOD__ )->fetchResultSet();
181 foreach ( $res as $row ) {
182 $lastId = $row->fa_id;
183 $sha1Key = $row->fa_storage_key;
184 if ( !strlen( $sha1Key ) ) {
185 $this->
error(
"Image SHA-1 not set for file #{$row->fa_id} (deleted)." );
188 $sha1 = substr( $sha1Key, 0, strpos( $sha1Key,
'.' ) );
190 if ( $oldLayout ===
'sha1' ) {
191 $spath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
193 $spath = $be->getContainerStoragePath(
"{$repo->getName()}-deleted" ) .
194 '/' . $repo->getDeletedHashPath( $sha1Key ) . $sha1Key;
197 if ( $newLayout ===
'sha1' ) {
198 $dpath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
200 $dpath = $be->getContainerStoragePath(
"{$repo->getName()}-deleted" ) .
201 '/' . $repo->getDeletedHashPath( $sha1Key ) . $sha1Key;
204 $status = $be->prepare( [
205 'dir' => dirname( $dpath ),
'bypassReadOnly' =>
true ] );
206 if ( !$status->isOK() ) {
207 $this->
error( $status );
210 $batch[] = [
'op' =>
'copy',
'src' => $spath,
'dst' => $dpath,
211 'overwriteSame' =>
true,
'img' =>
"(ID {$row->fa_id}) {$row->fa_name}" ];
213 if ( count( $batch ) >= $batchSize ) {
218 }
while ( $res->numRows() );
220 if ( count( $batch ) ) {
224 $this->
output(
"Done (started $startTime)\n" );