1<?php 2 3namespace dokuwiki\plugin\sitebackup; 4 5use splitbrain\PHPArchive\Tar as UpstreamTar; 6 7/** 8 * Tar with the upstream mtime bug patched. 9 * 10 * DokuWiki 2025-05-14b "Librarian" ships an old version of 11 * splitbrain/php-archive whose Tar::writeRawFileHeader() contains: 12 * $size = self::numberEncode($size, 12); 13 * $mtime = self::numberEncode($size, 12); // <-- $size, not $mtime 14 * So every file's mtime field ends up holding its size, octal-encoded. GNU tar 15 * dutifully reads the value as a Unix timestamp and shows 1970-01-01 with a 16 * size-derived seconds offset. 17 * 18 * Fixed upstream in splitbrain/php-archive PR #38. This subclass copies the 19 * method verbatim and corrects the one line so existing DokuWiki installs 20 * don't have to wait for the vendored library to be bumped. 21 */ 22class PatchedTar extends UpstreamTar 23{ 24 /** 25 * @inheritdoc 26 */ 27 protected function writeRawFileHeader($name, $uid, $gid, $perm, $size, $mtime, $typeflag = '') 28 { 29 // handle filename length restrictions 30 $prefix = ''; 31 $namelen = strlen($name); 32 if ($namelen > 100) { 33 $file = basename($name); 34 $dir = dirname($name); 35 if (strlen($file) > 100 || strlen($dir) > 155) { 36 // we're still too large, let's use GNU longlink 37 $this->writeRawFileHeader('././@LongLink', 0, 0, 0, $namelen, 0, 'L'); 38 for ($s = 0; $s < $namelen; $s += 512) { 39 $this->writebytes(pack("a512", substr($name, $s, 512))); 40 } 41 $name = substr($name, 0, 100); // cut off name 42 } else { 43 // we're fine when splitting, use POSIX ustar 44 $prefix = $dir; 45 $name = $file; 46 } 47 } 48 49 // values are needed in octal 50 $uid = sprintf("%6s ", decoct($uid)); 51 $gid = sprintf("%6s ", decoct($gid)); 52 $perm = sprintf("%6s ", decoct($perm)); 53 $size = self::numberEncode($size, 12); 54 $mtime = self::numberEncode($mtime, 12); // patched: was numberEncode($size, 12) 55 56 $data_first = pack("a100a8a8a8a12A12", $name, $perm, $uid, $gid, $size, $mtime); 57 $data_last = pack("a1a100a6a2a32a32a8a8a155a12", $typeflag, '', 'ustar', '', '', '', '', '', $prefix, ""); 58 59 for ($i = 0, $chks = 0; $i < 148; $i++) { 60 $chks += ord($data_first[$i]); 61 } 62 63 for ($i = 156, $chks += 256, $j = 0; $i < 512; $i++, $j++) { 64 $chks += ord($data_last[$j]); 65 } 66 67 $this->writebytes($data_first); 68 69 $chks = pack("a8", sprintf("%6s ", decoct($chks))); 70 $this->writebytes($chks.$data_last); 71 } 72} 73