49 $oldLayout = $this->
getOption(
'oldlayout' );
50 if ( !in_array( $oldLayout, [
'name',
'sha1' ] ) ) {
53 $newLayout = $this->
getOption(
'newlayout' );
54 if ( !in_array( $newLayout, [
'name',
'sha1' ] ) ) {
61 $be = $repo->getBackend();
64 $be = $be->getInternalBackend();
67 $dbw = $repo->getPrimaryDB();
69 $origBase = $be->getContainerStoragePath(
"{$repo->getName()}-original" );
75 $conds[] = $dbw->expr(
'img_timestamp',
'>=', $dbw->timestamp( $since ) );
82 $res = $dbw->newSelectQueryBuilder()
83 ->select( [
'img_name',
'img_sha1' ] )
85 ->where( $dbw->expr(
'img_name',
'>', $lastName ) )
87 ->orderBy(
'img_name' )
89 ->caller( __METHOD__ )->fetchResultSet();
91 foreach ( $res as $row ) {
92 $lastName = $row->img_name;
94 $file = $repo->newFile( $row->img_name );
96 $sha1 = $row->img_sha1 !==
'' ? $row->img_sha1 : $file->getSha1();
99 $this->
error(
"Image SHA-1 not known for {$row->img_name}." );
101 if ( $oldLayout ===
'sha1' ) {
102 $spath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
104 $spath = $file->getPath();
107 if ( $newLayout ===
'sha1' ) {
108 $dpath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
110 $dpath = $file->getPath();
113 $status = $be->prepare( [
114 'dir' => dirname( $dpath ),
'bypassReadOnly' =>
true ] );
115 if ( !$status->isOK() ) {
116 $this->
error( $status );
119 $batch[] = [
'op' =>
'copy',
'overwrite' =>
true,
120 'src' => $spath,
'dst' => $dpath,
'img' => $row->img_name ];
123 foreach ( $file->getHistory() as $ofile ) {
124 $sha1 = $ofile->getSha1();
125 if ( $sha1 ===
'' ) {
126 $this->
error(
"Image SHA-1 not set for {$ofile->getArchiveName()}." );
130 if ( $oldLayout ===
'sha1' ) {
131 $spath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
132 } elseif ( $ofile->isDeleted( File::DELETED_FILE ) ) {
133 $spath = $be->getContainerStoragePath(
"{$repo->getName()}-deleted" ) .
134 '/' . $repo->getDeletedHashPath( $sha1 ) .
135 $sha1 .
'.' . $ofile->getExtension();
137 $spath = $ofile->getPath();
140 if ( $newLayout ===
'sha1' ) {
141 $dpath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
143 $dpath = $ofile->getPath();
146 $status = $be->prepare( [
147 'dir' => dirname( $dpath ),
'bypassReadOnly' =>
true ] );
148 if ( !$status->isOK() ) {
149 $this->
error( $status );
151 $batch[] = [
'op' =>
'copy',
'overwrite' =>
true,
152 'src' => $spath,
'dst' => $dpath,
'img' => $ofile->getArchiveName() ];
155 if ( count( $batch ) >= $batchSize ) {
160 }
while ( $res->numRows() );
162 if ( count( $batch ) ) {
169 $conds[] = $dbw->expr(
'fa_deleted_timestamp',
'>=', $dbw->timestamp( $since ) );
175 $res = $dbw->newSelectQueryBuilder()
176 ->select( [
'fa_storage_key',
'fa_id',
'fa_name' ] )
177 ->from(
'filearchive' )
178 ->where( $dbw->expr(
'fa_id',
'>', $lastId ) )
181 ->limit( $batchSize )
182 ->caller( __METHOD__ )->fetchResultSet();
184 foreach ( $res as $row ) {
185 $lastId = $row->fa_id;
186 $sha1Key = $row->fa_storage_key;
187 if ( $sha1Key ===
'' ) {
188 $this->
error(
"Image SHA-1 not set for file #{$row->fa_id} (deleted)." );
191 $sha1 = substr( $sha1Key, 0, strpos( $sha1Key,
'.' ) );
193 if ( $oldLayout ===
'sha1' ) {
194 $spath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
196 $spath = $be->getContainerStoragePath(
"{$repo->getName()}-deleted" ) .
197 '/' . $repo->getDeletedHashPath( $sha1Key ) . $sha1Key;
200 if ( $newLayout ===
'sha1' ) {
201 $dpath =
"{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}";
203 $dpath = $be->getContainerStoragePath(
"{$repo->getName()}-deleted" ) .
204 '/' . $repo->getDeletedHashPath( $sha1Key ) . $sha1Key;
207 $status = $be->prepare( [
208 'dir' => dirname( $dpath ),
'bypassReadOnly' =>
true ] );
209 if ( !$status->isOK() ) {
210 $this->
error( $status );
213 $batch[] = [
'op' =>
'copy',
'src' => $spath,
'dst' => $dpath,
214 'overwriteSame' =>
true,
'img' =>
"(ID {$row->fa_id}) {$row->fa_name}" ];
216 if ( count( $batch ) >= $batchSize ) {
221 }
while ( $res->numRows() );
223 if ( count( $batch ) ) {
227 $this->
output(
"Done (started $startTime)\n" );