dpkg-source.pl 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660
  1. #! /usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Dpkg;
  5. use Dpkg::Gettext;
  6. use Dpkg::ErrorHandling qw(warning warnerror error failure unknown
  7. internerr syserr subprocerr usageerr
  8. $warnable_error $quiet_warnings);
  9. my @filesinarchive;
  10. my %dirincluded;
  11. my %notfileobject;
  12. my $fn;
  13. my $ur;
  14. my $varlistfile;
  15. my $controlfile;
  16. my $changelogfile;
  17. my $changelogformat;
  18. our $diff_ignore_regexp = '';
  19. my $diff_ignore_default_regexp = '
  20. # Ignore general backup files
  21. (?:^|/).*~$|
  22. # Ignore emacs recovery files
  23. (?:^|/)\.#.*$|
  24. # Ignore vi swap files
  25. (?:^|/)\..*\.swp$|
  26. # Ignore baz-style junk files or directories
  27. (?:^|/),,.*(?:$|/.*$)|
  28. # File-names that should be ignored (never directories)
  29. (?:^|/)(?:DEADJOE|\.cvsignore|\.arch-inventory|\.bzrignore|\.gitignore)$|
  30. # File or directory names that should be ignored
  31. (?:^|/)(?:CVS|RCS|\.deps|\{arch\}|\.arch-ids|\.svn|\.hg|_darcs|\.git|
  32. \.shelf|_MTN|\.bzr(?:\.backup|tags)?)(?:$|/.*$)
  33. ';
  34. no warnings 'qw';
  35. my @tar_ignore_default_pattern = qw(
  36. *.a
  37. *.la
  38. *.o
  39. *.so
  40. *.swp
  41. *~
  42. ,,*
  43. .[#~]*
  44. .arch-ids
  45. .arch-inventory
  46. .bzr
  47. .bzr.backup
  48. .bzr.tags
  49. .bzrignore
  50. .cvsignore
  51. .deps
  52. .git
  53. .gitignore
  54. .hg
  55. .shelf
  56. .svn
  57. CVS
  58. DEADJOE
  59. RCS
  60. _MTN
  61. _darcs
  62. {arch}
  63. );
  64. # Take out comments and newlines
  65. $diff_ignore_default_regexp =~ s/^#.*$//mg;
  66. $diff_ignore_default_regexp =~ s/\n//sg;
  67. my $sourcestyle = 'X';
  68. my $min_dscformat = 1;
  69. my $max_dscformat = 3;
  70. my $def_dscformat = "1.0"; # default format for -b
  71. my $expectprefix;
  72. # Compression
  73. my @comp_supported = qw(gzip bzip2 lzma);
  74. my %comp_supported = map { $_ => 1 } @comp_supported;
  75. my %comp_ext = ( gzip => 'gz', bzip2 => 'bz2', lzma => 'lzma' );
  76. my $comp_regex = '(?:gz|bz2|lzma)';
  77. my $compression = 'gzip';
  78. my $comp_level = '9';
  79. my $comp_ext = $comp_ext{$compression};
  80. # Packages
  81. my %remove;
  82. my %override;
  83. # Files
  84. my %md5sum;
  85. my %size;
  86. my %type; # used by checktype
  87. my %filepatched; # used by checkdiff
  88. my %dirtocreate; # used by checkdiff
  89. my @tar_ignore;
  90. use POSIX;
  91. use Fcntl qw (:mode);
  92. use English;
  93. use File::Temp qw (tempfile);
  94. use Cwd;
  95. push (@INC, $dpkglibdir);
  96. require 'controllib.pl';
  97. our (%f, %fi);
  98. our $sourcepackage;
  99. our %substvar;
  100. our @src_dep_fields;
  101. textdomain("dpkg-dev");
  102. my @dsc_fields = (qw(Format Source Binary Architecture Version Origin
  103. Maintainer Uploaders Homepage Standards-Version
  104. Vcs-Browser Vcs-Arch Vcs-Bzr Vcs-Cvs Vcs-Darcs
  105. Vcs-Git Vcs-Hg Vcs-Mtn Vcs-Svn),
  106. @src_dep_fields);
  107. # Make sure patch doesn't get any funny ideas
  108. delete $ENV{'POSIXLY_CORRECT'};
  109. my @exit_handlers = ();
  110. sub exit_handler {
  111. &$_ foreach ( reverse @exit_handlers );
  112. exit(127);
  113. }
  114. $SIG{'INT'} = \&exit_handler;
  115. $SIG{'HUP'} = \&exit_handler;
  116. $SIG{'QUIT'} = \&exit_handler;
  117. sub version {
  118. printf _g("Debian %s version %s.\n"), $progname, $version;
  119. print _g("
  120. Copyright (C) 1996 Ian Jackson and Klee Dienes.");
  121. print _g("
  122. This is free software; see the GNU General Public Licence version 2 or
  123. later for copying conditions. There is NO warranty.
  124. ");
  125. }
  126. sub usage {
  127. printf _g(
  128. "Usage: %s [<option> ...] <command>
  129. Commands:
  130. -x <filename>.dsc [<output-dir>]
  131. extract source package.
  132. -b <dir> [<orig-dir>|<orig-targz>|\'\']
  133. build source package.
  134. Build options:
  135. -c<controlfile> get control info from this file.
  136. -l<changelogfile> get per-version info from this file.
  137. -F<changelogformat> force change log format.
  138. -V<name>=<value> set a substitution variable.
  139. -T<varlistfile> read variables here, not debian/substvars.
  140. -D<field>=<value> override or add a .dsc field and value.
  141. -U<field> remove a field.
  142. -E turn certain warnings into errors.
  143. -W when -E is enabled, -W disables it.
  144. -q quiet operation, do not print warnings.
  145. -i[<regexp>] filter out files to ignore diffs of
  146. (defaults to: '%s').
  147. -I[<pattern>] filter out files when building tarballs
  148. (defaults to: %s).
  149. -sa auto select orig source (-sA is default).
  150. -sk use packed orig source (unpack & keep).
  151. -sp use packed orig source (unpack & remove).
  152. -su use unpacked orig source (pack & keep).
  153. -sr use unpacked orig source (pack & remove).
  154. -ss trust packed & unpacked orig src are same.
  155. -sn there is no diff, do main tarfile only.
  156. -sA,-sK,-sP,-sU,-sR like -sa,-sk,-sp,-su,-sr but may overwrite.
  157. -Z<compression> select compression to use (defaults to 'gzip',
  158. supported are: %s).
  159. -z<level> compression level to use (defaults to '9',
  160. supported are: '1'-'9', 'best', 'fast')
  161. Extract options:
  162. -sp (default) leave orig source packed in current dir.
  163. -sn do not copy original source to current dir.
  164. -su unpack original source tree too.
  165. General options:
  166. -h, --help show this help message.
  167. --version show the version.
  168. "), $progname,
  169. $diff_ignore_default_regexp,
  170. join('', map { " -I$_" } @tar_ignore_default_pattern),
  171. "@comp_supported" ;
  172. }
  173. sub handleformat {
  174. my $fmt = shift;
  175. return unless $fmt =~ /^(\d+)/; # only check major version
  176. return $1 >= $min_dscformat && $1 <= $max_dscformat;
  177. }
  178. sub loadvcs {
  179. my $vcs = shift;
  180. my $mod = "Dpkg::Source::VCS::$vcs";
  181. eval qq{require $mod};
  182. return $@ || import $mod;
  183. }
  184. my $opmode;
  185. my $tar_ignore_default_pattern_done;
  186. while (@ARGV && $ARGV[0] =~ m/^-/) {
  187. $_=shift(@ARGV);
  188. if (m/^-b$/) {
  189. &setopmode('build');
  190. } elsif (m/^-x$/) {
  191. &setopmode('extract');
  192. } elsif (m/^-Z/) {
  193. $compression = $POSTMATCH;
  194. $comp_ext = $comp_ext{$compression};
  195. usageerr(sprintf(_g("%s is not a supported compression"), $compression))
  196. unless $comp_supported{$compression};
  197. } elsif (m/^-z/) {
  198. $comp_level = $POSTMATCH;
  199. usageerr(sprintf(_g("%s is not a compression level"), $comp_level))
  200. unless $comp_level =~ /^([1-9]|fast|best)$/;
  201. } elsif (m/^-s([akpursnAKPUR])$/) {
  202. warning(sprintf(_g("-s%s option overrides earlier -s%s option"), $1, $sourcestyle))
  203. if $sourcestyle ne 'X';
  204. $sourcestyle= $1;
  205. } elsif (m/^-c/) {
  206. $controlfile= $POSTMATCH;
  207. } elsif (m/^-l/) {
  208. $changelogfile= $POSTMATCH;
  209. } elsif (m/^-F([0-9a-z]+)$/) {
  210. $changelogformat=$1;
  211. } elsif (m/^-D([^\=:]+)[=:]/) {
  212. $override{$1}= $POSTMATCH;
  213. } elsif (m/^-U([^\=:]+)$/) {
  214. $remove{$1}= 1;
  215. } elsif (m/^-i(.*)$/) {
  216. $diff_ignore_regexp = $1 ? $1 : $diff_ignore_default_regexp;
  217. } elsif (m/^-I(.+)$/) {
  218. push @tar_ignore, "--exclude=$1";
  219. } elsif (m/^-I$/) {
  220. unless ($tar_ignore_default_pattern_done) {
  221. push @tar_ignore,
  222. map { "--exclude=$_" } @tar_ignore_default_pattern;
  223. # Prevent adding multiple times
  224. $tar_ignore_default_pattern_done = 1;
  225. }
  226. } elsif (m/^-V(\w[-:0-9A-Za-z]*)[=:]/) {
  227. $substvar{$1}= $POSTMATCH;
  228. } elsif (m/^-T/) {
  229. $varlistfile= $POSTMATCH;
  230. } elsif (m/^-(h|-help)$/) {
  231. &usage; exit(0);
  232. } elsif (m/^--version$/) {
  233. &version; exit(0);
  234. } elsif (m/^-W$/) {
  235. $warnable_error= 1;
  236. } elsif (m/^-E$/) {
  237. $warnable_error= 0;
  238. } elsif (m/^-q$/) {
  239. $quiet_warnings = 1;
  240. } elsif (m/^--$/) {
  241. last;
  242. } else {
  243. &usageerr(sprintf(_g("unknown option \`%s'"), $_));
  244. }
  245. }
  246. defined($opmode) || &usageerr(_g("need -x or -b"));
  247. $SIG{'PIPE'} = 'DEFAULT';
  248. if ($opmode eq 'build') {
  249. @ARGV || &usageerr(_g("-b needs a directory"));
  250. @ARGV<=2 || &usageerr(_g("-b takes at most a directory and an orig source argument"));
  251. my $dir = shift(@ARGV);
  252. $dir= "./$dir" unless $dir =~ m:^/:; $dir =~ s,/*$,,;
  253. stat($dir) || &error(sprintf(_g("cannot stat directory %s: %s"), $dir, $!));
  254. -d $dir || &error(sprintf(_g("directory argument %s is not a directory"), $dir));
  255. $changelogfile= "$dir/debian/changelog" unless defined($changelogfile);
  256. $controlfile= "$dir/debian/control" unless defined($controlfile);
  257. parsechangelog($changelogfile, $changelogformat);
  258. parsecontrolfile($controlfile);
  259. $f{"Format"}= $compression eq 'gzip' ? $def_dscformat : '2.0';
  260. &init_substvars;
  261. my @sourcearch;
  262. my %archadded;
  263. my $archspecific = 0; # XXX: Not used?!
  264. my %packageadded;
  265. my @binarypackages;
  266. for $_ (keys %fi) {
  267. my $v = $fi{$_};
  268. if (s/^C //) {
  269. if (m/^Source$/i) {
  270. setsourcepackage($v);
  271. } elsif (m/^(Format|Standards-Version|Origin|Maintainer|Homepage)$/i ||
  272. m/^Vcs-(Browser|Arch|Bzr|Cvs|Darcs|Git|Hg|Mtn|Svn)$/i) {
  273. $f{$_}= $v;
  274. }
  275. elsif (m/^Uploaders$/i) { ($f{$_}= $v) =~ s/[\r\n]//g; }
  276. elsif (m/^Build-(Depends|Conflicts)(-Indep)?$/i) {
  277. my $dep = parsedep($v, 1);
  278. &error(sprintf(_g("error occurred while parsing %s"), $_)) unless defined $dep;
  279. $f{$_}= showdep($dep, 1);
  280. }
  281. elsif (s/^X[BC]*S[BC]*-//i) { $f{$_}= $v; }
  282. elsif (m/^(Section|Priority|Files|Bugs)$/i || m/^X[BC]+-/i) { }
  283. else { &unknown(_g('general section of control info file')); }
  284. } elsif (s/^C(\d+) //) {
  285. my $i = $1;
  286. my $p = $fi{"C$i Package"};
  287. push(@binarypackages,$p) unless $packageadded{$p}++;
  288. if (m/^Architecture$/) {
  289. if (debarch_eq($v, 'any')) {
  290. @sourcearch= ('any');
  291. } elsif (debarch_eq($v, 'all')) {
  292. if (!@sourcearch || $sourcearch[0] eq 'all') {
  293. @sourcearch= ('all');
  294. } else {
  295. @sourcearch= ('any');
  296. }
  297. } else {
  298. if (@sourcearch && grep($sourcearch[0] eq $_, 'any', 'all')) {
  299. @sourcearch= ('any');
  300. } else {
  301. for my $a (split(/\s+/, $v)) {
  302. &error(sprintf(_g("`%s' is not a legal architecture string"), $a))
  303. unless $a =~ /^[\w-]+$/;
  304. &error(sprintf(_g("architecture %s only allowed on its own".
  305. " (list for package %s is `%s')"), $a, $p, $a))
  306. if grep($a eq $_, 'any','all');
  307. push(@sourcearch,$a) unless $archadded{$a}++;
  308. }
  309. }
  310. }
  311. $f{'Architecture'}= join(' ',@sourcearch);
  312. } elsif (s/^X[BC]*S[BC]*-//i) {
  313. $f{$_}= $v;
  314. } elsif (m/^(Package|Essential|Pre-Depends|Depends|Provides)$/i ||
  315. m/^(Recommends|Suggests|Conflicts|Replaces)$/i ||
  316. m/^(Breaks|Enhances|Description|Tag|Section|Priority)$/i ||
  317. m/^X[BC]+-/i) {
  318. } else {
  319. &unknown(_g("package's section of control info file"));
  320. }
  321. } elsif (s/^L //) {
  322. if (m/^Source$/) {
  323. setsourcepackage($v);
  324. } elsif (m/^Version$/) {
  325. checkversion( $v );
  326. $f{$_}= $v;
  327. } elsif (s/^X[BS]*C[BS]*-//i) {
  328. $f{$_}= $v;
  329. } elsif (m/^(Maintainer|Changes|Urgency|Distribution|Date|Closes)$/i ||
  330. m/^X[BS]+-/i) {
  331. } else {
  332. &unknown(_g("parsed version of changelog"));
  333. }
  334. } elsif (m/^o:.*/) {
  335. } else {
  336. &internerr(sprintf(_g("value from nowhere, with key >%s< and value >%s<"), $_, $v));
  337. }
  338. }
  339. my $vcs;
  340. if ($f{Format} =~ /^\s*(\d+\.\d+)\s*$/) {
  341. if ($1 >= 3.0) {
  342. error(sprintf(_g("don't know how to generate %s format source package (missing vcs specifier in Format field?)"), $1));
  343. }
  344. if ($1 > 1.0) {
  345. error(sprintf(_g("don't know how to generate %s format source package"), $1));
  346. }
  347. }
  348. elsif ($f{Format} =~ /^\s*(\d+(?:\.\d+)?)\s+\((\w+)\)\s*$/) {
  349. $f{Format}=$1;
  350. if ($1 < 3.0) {
  351. error(sprintf(_g("control info file 'Format' field for version %s does not support vcs specifier \"%s\""), $1, $2));
  352. }
  353. if ($1 >= 4) {
  354. error(sprintf(_g("unsupported control info file 'Format' value \"%s\""), $1));
  355. }
  356. $vcs=$2;
  357. loadvcs($2)
  358. || error(sprintf(_g("unsupported vcs \"%s\" in control info file 'Format' field"), $2));
  359. if ($sourcestyle =~ /[akpursKPUR]/) {
  360. warning(sprintf(_g("source handling style -s%s not supported when generating %s format source package"), $sourcestyle, $vcs));
  361. }
  362. $sourcestyle='v';
  363. }
  364. $sourcestyle =~ y/X/A/;
  365. $sourcestyle =~ m/[akpursnAKPURv]/ ||
  366. &usageerr(sprintf(_g("source handling style -s%s not allowed with -b"), $sourcestyle));
  367. $f{'Binary'}= join(', ',@binarypackages);
  368. for my $f (keys %override) {
  369. $f{capit($f)} = $override{$f};
  370. }
  371. for my $f (qw(Version)) {
  372. defined($f{$f}) || &error(sprintf(_g("missing information for critical output field %s"), $f));
  373. }
  374. for my $f (qw(Maintainer Architecture Standards-Version)) {
  375. defined($f{$f}) ||
  376. warning(sprintf(_g("missing information for output field %s"), $f));
  377. }
  378. defined($sourcepackage) || &error(_g("unable to determine source package name !"));
  379. $f{'Source'}= $sourcepackage;
  380. for my $f (keys %remove) {
  381. delete $f{capit($f)};
  382. }
  383. my $version = $f{'Version'};
  384. $version =~ s/^\d+://;
  385. my $upstreamversion = $version;
  386. $upstreamversion =~ s/-[^-]*$//;
  387. my $basenamerev = $sourcepackage.'_'.$version;
  388. my $basename = $sourcepackage.'_'.$upstreamversion;
  389. my $basedirname = $basename;
  390. $basedirname =~ s/_/-/;
  391. my $origdir = "$dir.orig";
  392. my $origtargz;
  393. if (@ARGV) {
  394. my $origarg = shift(@ARGV);
  395. if (length($origarg)) {
  396. stat($origarg) || &error(sprintf(_g("cannot stat orig argument %s: %s"), $origarg, $!));
  397. if (-d _) {
  398. $origdir= $origarg;
  399. $origdir= "./$origdir" unless $origdir =~ m,^/,; $origdir =~ s,/*$,,;
  400. $sourcestyle =~ y/aA/rR/;
  401. $sourcestyle =~ m/[ursURS]/ ||
  402. &error(sprintf(_g("orig argument is unpacked but source handling style".
  403. " -s%s calls for packed (.orig.tar.<ext>)"), $sourcestyle));
  404. } elsif (-f _) {
  405. $origtargz= $origarg;
  406. $sourcestyle =~ y/aA/pP/;
  407. $sourcestyle =~ m/[kpsKPS]/ ||
  408. &error(sprintf(_g("orig argument is packed but source handling style".
  409. " -s%s calls for unpacked (.orig/)"), $sourcestyle));
  410. } else {
  411. &error("orig argument $origarg is not a plain file or directory");
  412. }
  413. } else {
  414. $sourcestyle =~ y/aA/nn/;
  415. $sourcestyle =~ m/n/ ||
  416. &error(sprintf(_g("orig argument is empty (means no orig, no diff)".
  417. " but source handling style -s%s wants something"), $sourcestyle));
  418. }
  419. } elsif ($sourcestyle =~ m/[aA]/) {
  420. my @origtargz = map { "$basename.orig.tar.$comp_ext{$_}" } ($compression, @comp_supported);
  421. foreach my $origtar (@origtargz) {
  422. if (stat($origtar)) {
  423. -f _ || &error(sprintf(_g("packed orig `%s' exists but is not a plain file"), $origtar));
  424. $sourcestyle =~ y/aA/pP/;
  425. $origtargz = $origtar;
  426. last;
  427. } elsif ($! != ENOENT) {
  428. &syserr(sprintf(_g("unable to stat putative packed orig `%s'"), $origtar));
  429. }
  430. }
  431. if (!$origtargz) {
  432. if (stat($origdir)) {
  433. -d _ || &error(sprintf(_g("unpacked orig `%s' exists but is not a directory"), $origdir));
  434. $sourcestyle =~ y/aA/rR/;
  435. } elsif ($! != ENOENT) {
  436. &syserr(sprintf(_g("unable to stat putative unpacked orig `%s'"), $origdir));
  437. } else {
  438. $sourcestyle =~ y/aA/nn/;
  439. }
  440. }
  441. }
  442. my $dirbase = $dir;
  443. $dirbase =~ s,/?$,,;
  444. $dirbase =~ s,[^/]+$,,;
  445. my $dirname = $&;
  446. $dirname eq $basedirname ||
  447. warning(sprintf(_g("source directory '%s' is not <sourcepackage>" .
  448. "-<upstreamversion> '%s'"), $dir, $basedirname));
  449. my $tarname;
  450. my $tardirname;
  451. my $tardirbase;
  452. my $origdirname;
  453. if ($sourcestyle eq 'v') {
  454. $tarname="$basenamerev.$vcs.tar.gz";
  455. $tardirbase= $dirbase; $tardirname= "$dirbase/$tarname.tmp";
  456. eval qq{Dpkg::Source::VCS::${vcs}::prep_tar(\$dir, \$tardirname)};
  457. if ($@) {
  458. &syserr($@);
  459. }
  460. push @exit_handlers, sub { erasedir($tardirname) };
  461. }
  462. elsif ($sourcestyle ne 'n') {
  463. my $origdirbase = $origdir;
  464. $origdirbase =~ s,/?$,,;
  465. $origdirbase =~ s,[^/]+$,,; $origdirname= $&;
  466. $origdirname eq "$basedirname.orig" ||
  467. warning(sprintf(_g(".orig directory name %s is not <package>" .
  468. "-<upstreamversion> (wanted %s)"),
  469. $origdirname, "$basedirname.orig"));
  470. $tardirbase= $origdirbase; $tardirname= $origdirname;
  471. $tarname= $origtargz || "$basename.orig.tar.$comp_ext";
  472. $tarname =~ /$basename.orig.tar.($comp_regex)/ ||
  473. warning(sprintf(_g(".orig.tar name %s is not <package>_<upstreamversion>" .
  474. ".orig.tar (wanted %s)"), $tarname, "$basename.orig.tar.$comp_regex"));
  475. if (($1 ne 'gz') && ($f{'Format'} < 2)) { $f{'Format'} = '2.0' };
  476. } else {
  477. $tardirbase= $dirbase; $tardirname= $dirname;
  478. $tarname= "$basenamerev.tar.$comp_ext";
  479. }
  480. if ($sourcestyle =~ m/[nurURv]/) {
  481. if (stat($tarname)) {
  482. $sourcestyle =~ m/[nURv]/ ||
  483. &error(sprintf(_g("tarfile `%s' already exists, not overwriting,".
  484. " giving up; use -sU or -sR to override"), $tarname));
  485. } elsif ($! != ENOENT) {
  486. &syserr(sprintf(_g("unable to check for existence of `%s'"), $tarname));
  487. }
  488. printf(_g("%s: building %s in %s")."\n",
  489. $progname, $sourcepackage, $tarname)
  490. || &syserr(_g("write building tar message"));
  491. my ($ntfh, $newtar) = tempfile( "$tarname.new.XXXXXX",
  492. DIR => &getcwd, UNLINK => 0 );
  493. &forkgzipwrite($newtar);
  494. defined(my $c2 = fork) || syserr(_g("fork for tar"));
  495. if (!$c2) {
  496. chdir($tardirbase) || &syserr(sprintf(_g("chdir to above (orig) source %s"), $tardirbase));
  497. open(STDOUT,">&GZIP") || &syserr(_g("reopen gzip for tar"));
  498. # FIXME: put `--' argument back when tar is fixed
  499. exec('tar',@tar_ignore,'-cf','-',$tardirname) or &syserr(_g("exec tar"));
  500. }
  501. close(GZIP);
  502. &reapgzip;
  503. $c2 == waitpid($c2,0) || &syserr(_g("wait for tar"));
  504. $? && !(WIFSIGNALED($c2) && WTERMSIG($c2) == SIGPIPE) && subprocerr("tar");
  505. rename($newtar,$tarname) ||
  506. &syserr(sprintf(_g("unable to rename `%s' (newly created) to `%s'"), $newtar, $tarname));
  507. chmod(0666 &~ umask(), $tarname) ||
  508. &syserr(sprintf(_g("unable to change permission of `%s'"), $tarname));
  509. } else {
  510. printf(_g("%s: building %s using existing %s")."\n",
  511. $progname, $sourcepackage, $tarname)
  512. || &syserr(_g("write using existing tar message"));
  513. }
  514. addfile("$tarname");
  515. if ($sourcestyle =~ m/[kpKP]/) {
  516. if (stat($origdir)) {
  517. $sourcestyle =~ m/[KP]/ ||
  518. &error(sprintf(_g("orig dir `%s' already exists, not overwriting,".
  519. " giving up; use -sA, -sK or -sP to override"), $origdir));
  520. push @exit_handlers, sub { erasedir($origdir) };
  521. erasedir($origdir);
  522. pop @exit_handlers;
  523. } elsif ($! != ENOENT) {
  524. &syserr(sprintf(_g("unable to check for existence of orig dir `%s'"), $origdir));
  525. }
  526. $expectprefix= $origdir; $expectprefix =~ s,^\./,,;
  527. my $expectprefix_dirname = $origdirname;
  528. # tar checking is disabled, there are too many broken tar archives out there
  529. # which we can still handle anyway.
  530. # checktarsane($origtargz,$expectprefix);
  531. mkdir("$origtargz.tmp-nest",0755) ||
  532. &syserr(sprintf(_g("unable to create `%s'"), "$origtargz.tmp-nest"));
  533. push @exit_handlers, sub { erasedir("$origtargz.tmp-nest") };
  534. extracttar($origtargz,"$origtargz.tmp-nest",$expectprefix_dirname);
  535. rename("$origtargz.tmp-nest/$expectprefix_dirname",$expectprefix) ||
  536. &syserr(sprintf(_g("unable to rename `%s' to `%s'"),
  537. "$origtargz.tmp-nest/$expectprefix_dirname",
  538. $expectprefix));
  539. rmdir("$origtargz.tmp-nest") ||
  540. &syserr(sprintf(_g("unable to remove `%s'"), "$origtargz.tmp-nest"));
  541. pop @exit_handlers;
  542. }
  543. if ($sourcestyle eq 'v') {
  544. erasedir($tardirname)
  545. }
  546. if ($sourcestyle =~ m/[kpursKPUR]/) {
  547. my $diffname = "$basenamerev.diff.$comp_ext";
  548. printf(_g("%s: building %s in %s")."\n",
  549. $progname, $sourcepackage, $diffname)
  550. || &syserr(_g("write building diff message"));
  551. my ($ndfh, $newdiffgz) = tempfile( "$diffname.new.XXXXXX",
  552. DIR => &getcwd, UNLINK => 0 );
  553. &forkgzipwrite($newdiffgz);
  554. defined(my $c2 = open(FIND, "-|")) || syserr(_g("fork for find"));
  555. if (!$c2) {
  556. chdir($dir) || &syserr(sprintf(_g("chdir to %s for find"), $dir));
  557. exec('find','.','-print0') or &syserr(_g("exec find"));
  558. }
  559. $/= "\0";
  560. file:
  561. while (defined($fn= <FIND>)) {
  562. $fn =~ s/\0$//;
  563. next file if $fn =~ m/$diff_ignore_regexp/o;
  564. $fn =~ s,^\./,,;
  565. lstat("$dir/$fn") || &syserr(sprintf(_g("cannot stat file %s"), "$dir/$fn"));
  566. my $mode = S_IMODE((lstat(_))[2]);
  567. my $size = (lstat(_))[7];
  568. if (-l _) {
  569. $type{$fn}= 'symlink';
  570. checktype($origdir, $fn, '-l') || next;
  571. defined(my $n = readlink("$dir/$fn")) ||
  572. &syserr(sprintf(_g("cannot read link %s"), "$dir/$fn"));
  573. defined(my $n2 = readlink("$origdir/$fn")) ||
  574. &syserr(sprintf(_g("cannot read orig link %s"), "$origdir/$fn"));
  575. $n eq $n2 || &unrepdiff2(sprintf(_g("symlink to %s"), $n2),
  576. sprintf(_g("symlink to %s"), $n));
  577. } elsif (-f _) {
  578. my $ofnread;
  579. $type{$fn}= 'plain file';
  580. if (!lstat("$origdir/$fn")) {
  581. $! == ENOENT || &syserr(sprintf(_g("cannot stat orig file %s"), "$origdir/$fn"));
  582. $ofnread= '/dev/null';
  583. if( !$size ) {
  584. warning(sprintf(_g("newly created empty file '%s' will not be represented in diff"), $fn));
  585. } else {
  586. if( $mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) {
  587. warning(sprintf(_g("executable mode %04o of '%s' will not be represented in diff"), $mode, $fn))
  588. unless $fn eq 'debian/rules';
  589. }
  590. if( $mode & ( S_ISUID | S_ISGID | S_ISVTX ) ) {
  591. warning(sprintf(_g("special mode %04o of '%s' will not be represented in diff"), $mode, $fn));
  592. }
  593. }
  594. } elsif (-f _) {
  595. $ofnread= "$origdir/$fn";
  596. } else {
  597. &unrepdiff2(_g("something else"),
  598. _g("plain file"));
  599. next;
  600. }
  601. defined(my $c3 = open(DIFFGEN, "-|")) || syserr(_g("fork for diff"));
  602. if (!$c3) {
  603. $ENV{'LC_ALL'}= 'C';
  604. $ENV{'LANG'}= 'C';
  605. $ENV{'TZ'}= 'UTC0';
  606. my $tab = ("$basedirname/$fn" =~ / /) ? "\t" : '';
  607. exec('diff','-u',
  608. '-L',"$basedirname.orig/$fn$tab",
  609. '-L',"$basedirname/$fn$tab",
  610. '--',"$ofnread","$dir/$fn") or &syserr(_g("exec diff"));
  611. }
  612. my $difflinefound = 0;
  613. $/= "\n";
  614. while (<DIFFGEN>) {
  615. if (m/^binary/i) {
  616. close(DIFFGEN); $/= "\0";
  617. &unrepdiff(_g("binary file contents changed"));
  618. next file;
  619. } elsif (m/^[-+\@ ]/) {
  620. $difflinefound=1;
  621. } elsif (m/^\\ No newline at end of file$/) {
  622. warning(sprintf(_g("file %s has no final newline " .
  623. "(either original or modified version)"), $fn));
  624. } else {
  625. s/\n$//;
  626. &internerr(sprintf(_g("unknown line from diff -u on %s: `%s'"), $fn, $_));
  627. }
  628. print(GZIP $_) || &syserr(_g("failed to write to compression pipe"));
  629. }
  630. close(DIFFGEN); $/= "\0";
  631. my $es;
  632. if (WIFEXITED($?) && (($es=WEXITSTATUS($?))==0 || $es==1)) {
  633. if ($es==1 && !$difflinefound) {
  634. &unrepdiff(_g("diff gave 1 but no diff lines found"));
  635. }
  636. } else {
  637. subprocerr(sprintf(_g("diff on %s"), "$dir/$fn"));
  638. }
  639. } elsif (-p _) {
  640. $type{$fn}= 'pipe';
  641. checktype($origdir, $fn, '-p');
  642. } elsif (-b _ || -c _ || -S _) {
  643. &unrepdiff(_g("device or socket is not allowed"));
  644. } elsif (-d _) {
  645. $type{$fn}= 'directory';
  646. if (!lstat("$origdir/$fn")) {
  647. $! == ENOENT
  648. || &syserr(sprintf(_g("cannot stat orig file %s"), "$origdir/$fn"));
  649. } elsif (! -d _) {
  650. &unrepdiff2(_g('not a directory'),
  651. _g('directory'));
  652. }
  653. } else {
  654. &unrepdiff(sprintf(_g("unknown file type (%s)"), $!));
  655. }
  656. }
  657. close(FIND); $? && subprocerr("find on $dir");
  658. close(GZIP) || &syserr(_g("finish write to compression pipe"));
  659. &reapgzip;
  660. rename($newdiffgz, $diffname) ||
  661. &syserr(sprintf(_g("unable to rename `%s' (newly created) to `%s'"), $newdiffgz, $diffname));
  662. chmod(0666 &~ umask(), $diffname) ||
  663. &syserr(sprintf(_g("unable to change permission of `%s'"), $diffname));
  664. defined($c2= open(FIND,"-|")) || &syserr(_g("fork for 2nd find"));
  665. if (!$c2) {
  666. chdir($origdir) || &syserr(sprintf(_g("chdir to %s for 2nd find"), $origdir));
  667. exec('find','.','-print0') or &syserr(_g("exec 2nd find"));
  668. }
  669. $/= "\0";
  670. while (defined($fn= <FIND>)) {
  671. $fn =~ s/\0$//;
  672. next if $fn =~ m/$diff_ignore_regexp/o;
  673. $fn =~ s,^\./,,;
  674. next if defined($type{$fn});
  675. lstat("$origdir/$fn") || &syserr(sprintf(_g("cannot check orig file %s"), "$origdir/$fn"));
  676. if (-f _) {
  677. warning(sprintf(_g("ignoring deletion of file %s"), $fn));
  678. } elsif (-d _) {
  679. warning(sprintf(_g("ignoring deletion of directory %s"), $fn));
  680. } elsif (-l _) {
  681. warning(sprintf(_g("ignoring deletion of symlink %s"), $fn));
  682. } else {
  683. &unrepdiff2(_g('not a file, directory or link'),
  684. _g('nonexistent'));
  685. }
  686. }
  687. close(FIND); $? && subprocerr("find on $dirname");
  688. &addfile($diffname);
  689. }
  690. if ($sourcestyle =~ m/[prPR]/) {
  691. erasedir($origdir);
  692. }
  693. printf(_g("%s: building %s in %s")."\n",
  694. $progname, $sourcepackage, "$basenamerev.dsc")
  695. || &syserr(_g("write building message"));
  696. open(STDOUT,"> $basenamerev.dsc") || &syserr(sprintf(_g("create %s"), "$basenamerev.dsc"));
  697. set_field_importance(@dsc_fields);
  698. outputclose($varlistfile);
  699. if ($ur) {
  700. printf(STDERR _g("%s: unrepresentable changes to source")."\n",
  701. $progname)
  702. || &syserr(sprintf(_g("write error msg: %s"), $!));
  703. exit(1);
  704. }
  705. exit(0);
  706. } else { # -> opmode ne 'build'
  707. $sourcestyle =~ y/X/p/;
  708. $sourcestyle =~ m/[pun]/ ||
  709. &usageerr(sprintf(_g("source handling style -s%s not allowed with -x"), $sourcestyle));
  710. @ARGV>=1 || &usageerr(_g("-x needs at least one argument, the .dsc"));
  711. @ARGV<=2 || &usageerr(_g("-x takes no more than two arguments"));
  712. my $dsc = shift(@ARGV);
  713. $dsc= "./$dsc" unless $dsc =~ m:^/:;
  714. ! -d $dsc
  715. || &usageerr(_g("-x needs the .dsc file as first argument, not a directory"));
  716. my $dscdir = $dsc;
  717. $dscdir = "./$dscdir" unless $dsc =~ m,^/|^\./,;
  718. $dscdir =~ s,/[^/]+$,,;
  719. my $newdirectory;
  720. if (@ARGV) {
  721. $newdirectory= shift(@ARGV);
  722. ! -e $newdirectory || &error(sprintf(_g("unpack target exists: %s"), $newdirectory));
  723. }
  724. my $is_signed = 0;
  725. open(DSC,"< $dsc") || &error(sprintf(_g("cannot open .dsc file %s: %s"), $dsc, $!));
  726. while (<DSC>) {
  727. next if /^\s*$/o;
  728. $is_signed = 1 if /^-----BEGIN PGP SIGNED MESSAGE-----$/o;
  729. last;
  730. }
  731. close(DSC);
  732. if ($is_signed) {
  733. if (-x '/usr/bin/gpg') {
  734. my $gpg_command = 'gpg -q --verify ';
  735. if (-r '/usr/share/keyrings/debian-keyring.gpg') {
  736. $gpg_command = $gpg_command.'--keyring /usr/share/keyrings/debian-keyring.gpg ';
  737. }
  738. $gpg_command = $gpg_command.quotemeta($dsc).' 2>&1';
  739. my @gpg_output = `$gpg_command`;
  740. my $gpg_status = $? >> 8;
  741. if ($gpg_status) {
  742. print STDERR join("",@gpg_output);
  743. &error(sprintf(_g("failed to verify signature on %s"), $dsc))
  744. if ($gpg_status == 1);
  745. }
  746. } else {
  747. warning(sprintf(_g("could not verify signature on %s since gpg isn't installed"), $dsc));
  748. }
  749. } else {
  750. warning(sprintf(_g("extracting unsigned source package (%s)"), $dsc));
  751. }
  752. open(CDATA,"< $dsc") || &error(sprintf(_g("cannot open .dsc file %s: %s"), $dsc, $!));
  753. parsecdata(\*CDATA, 'S', -1, sprintf(_g("source control file %s"), $dsc));
  754. close(CDATA);
  755. for my $f (qw(Source Version Files)) {
  756. defined($fi{"S $f"}) ||
  757. &error(sprintf(_g("missing critical source control field %s"), $f));
  758. }
  759. my $dscformat = $def_dscformat;
  760. if (defined $fi{'S Format'}) {
  761. if (not handleformat($fi{'S Format'})) {
  762. &error(sprintf(_g("Unsupported format of .dsc file (%s)"), $fi{'S Format'}));
  763. }
  764. $dscformat=$fi{'S Format'};
  765. }
  766. $sourcepackage = $fi{'S Source'}; # XXX: should use setsourcepackage??
  767. checkpackagename( $sourcepackage );
  768. my $version = $fi{'S Version'};
  769. my $baseversion;
  770. my $revision;
  771. checkversion( $version );
  772. $version =~ s/^\d+://;
  773. if ($version =~ m/-([^-]+)$/) {
  774. $baseversion= $`; $revision= $1;
  775. } else {
  776. $baseversion= $version; $revision= '';
  777. }
  778. my $files = $fi{'S Files'};
  779. my @tarfiles;
  780. my $difffile;
  781. my $debianfile;
  782. my %vcsfiles;
  783. my %seen;
  784. for my $file (split(/\n /, $files)) {
  785. next if $file eq '';
  786. $file =~ m/^([0-9a-f]{32})[ \t]+(\d+)[ \t]+([0-9a-zA-Z][-+:.,=0-9a-zA-Z_~]+)$/
  787. || &error(sprintf(_g("Files field contains bad line `%s'"), $file));
  788. ($md5sum{$3},$size{$3},$file) = ($1,$2,$3);
  789. local $_ = $file;
  790. &error(sprintf(_g("Files field contains invalid filename `%s'"), $file))
  791. unless s/^\Q$sourcepackage\E_\Q$baseversion\E(?=[.-])// and
  792. s/\.$comp_regex$//;
  793. s/^-\Q$revision\E(?=\.)// if length $revision;
  794. &error(sprintf(_g("repeated file type - files `%s' and `%s'"), $seen{$_}, $file)) if $seen{$_};
  795. $seen{$_} = $file;
  796. checkstats($dscdir, $file);
  797. if (/^\.(?:orig(-\w+)?\.)?tar$/) {
  798. if ($1) { push @tarfiles, $file; } # push orig-foo.tar.gz to the end
  799. else { unshift @tarfiles, $file; }
  800. } elsif (/^\.debian\.tar$/) {
  801. $debianfile = $file;
  802. } elsif (/^\.(\w+)\.tar$/) {
  803. my $vcs=$1;
  804. # TODO try to load vcs module
  805. push @tarfiles, $file;
  806. $vcsfiles{$file}=$vcs;
  807. } elsif (/^\.diff$/) {
  808. $difffile = $file;
  809. } else {
  810. &error(sprintf(_g("unrecognised file type - `%s'"), $file));
  811. }
  812. }
  813. &error(_g("no tarfile in Files field")) unless @tarfiles;
  814. my $native = !($difffile || $debianfile);
  815. if ($native) {
  816. warning(_g("multiple tarfiles in native package")) if @tarfiles > 1;
  817. warning(_g("native package with .orig.tar"))
  818. unless $seen{'.tar'} or $seen{"-$revision.tar"} or %vcsfiles;
  819. } else {
  820. warning(_g("no upstream tarfile in Files field")) unless $seen{'.orig.tar'} or %vcsfiles;
  821. if ($dscformat =~ /^1\./) {
  822. warning(sprintf(_g("multiple upstream tarballs in %s format dsc"), $dscformat)) if @tarfiles > 1;
  823. warning(sprintf(_g("debian.tar in %s format dsc"), $dscformat)) if $debianfile;
  824. }
  825. }
  826. if (%vcsfiles && $dscformat !~ /^3\./) {
  827. warning(sprintf(_g("<rc>.tar file in %s format dsc"), $dscformat));
  828. }
  829. $newdirectory = $sourcepackage.'-'.$baseversion unless defined($newdirectory);
  830. $expectprefix = $newdirectory;
  831. $expectprefix .= '.orig' if $difffile || $debianfile;
  832. checkdiff("$dscdir/$difffile") if $difffile;
  833. printf(_g("%s: extracting %s in %s")."\n",
  834. $progname, $sourcepackage, $newdirectory)
  835. || &syserr(_g("write extracting message"));
  836. &erasedir($newdirectory);
  837. ! -e "$expectprefix"
  838. || rename("$expectprefix","$newdirectory.tmp-keep")
  839. || &syserr(sprintf(_g("unable to rename `%s' to `%s'"), $expectprefix, "$newdirectory.tmp-keep"));
  840. push @tarfiles, $debianfile if $debianfile;
  841. for my $tarfile (@tarfiles)
  842. {
  843. my $target;
  844. if ($tarfile =~ /\.orig-(\w+)\.tar/) {
  845. my $sub = $1;
  846. $sub =~ s/\d+$// if $sub =~ /\D/;
  847. $target = "$expectprefix/$sub";
  848. } elsif ($tarfile =~ /\.debian\.tar/) {
  849. $target = "$expectprefix/debian";
  850. } else {
  851. $target = $expectprefix;
  852. }
  853. my $tmp = "$target.tmp-nest";
  854. (my $t = $target) =~ s!.*/!!;
  855. mkdir($tmp,0700) || &syserr(sprintf(_g("unable to create `%s'"), $tmp));
  856. printf(_g("%s: unpacking %s")."\n", $progname, $tarfile);
  857. extracttar("$dscdir/$tarfile",$tmp,$t);
  858. rename("$tmp/$t",$target)
  859. || &syserr(sprintf(_g("unable to rename `%s' to `%s'"), "$tmp/$t", $target));
  860. rmdir($tmp)
  861. || &syserr(sprintf(_g("unable to remove `%s'"), $tmp));
  862. # for the first tar file:
  863. if ($tarfile eq $tarfiles[0] and !$native)
  864. {
  865. # -sp: copy the .orig.tar.gz if required
  866. if ($sourcestyle =~ /p/) {
  867. stat("$dscdir/$tarfile") ||
  868. &syserr(sprintf(_g("failed to stat `%s' to see if need to copy"), "$dscdir/$tarfile"));
  869. my ($dsctardev, $dsctarino) = stat _;
  870. my $copy_required;
  871. if (stat($tarfile)) {
  872. my ($dumptardev, $dumptarino) = stat _;
  873. $copy_required = ($dumptardev != $dsctardev ||
  874. $dumptarino != $dsctarino);
  875. } else {
  876. $! == ENOENT ||
  877. syserr(sprintf(_g("failed to check destination `%s'".
  878. " to see if need to copy"), $tarfile));
  879. $copy_required = 1;
  880. }
  881. if ($copy_required) {
  882. system('cp','--',"$dscdir/$tarfile", $tarfile);
  883. $? && subprocerr("cp $dscdir/$tarfile to $tarfile");
  884. }
  885. }
  886. # -su: keep .orig directory unpacked
  887. elsif ($sourcestyle =~ /u/ and $expectprefix ne $newdirectory) {
  888. ! -e "$newdirectory.tmp-keep"
  889. || &error(_g("unable to keep orig directory (already exists)"));
  890. system('cp','-ar','--',$expectprefix,"$newdirectory.tmp-keep");
  891. $? && subprocerr("cp $expectprefix to $newdirectory.tmp-keep");
  892. }
  893. }
  894. if (exists $vcsfiles{$tarfile}) {
  895. printf(_g("%s: extracting source from %s repository")."\n", $progname, $vcsfiles{$tarfile});
  896. loadvcs($vcsfiles{$tarfile})
  897. || error(sprintf(_g("unsupported vcs \"%s\""), $vcsfiles{$tarfile}));
  898. eval qq{Dpkg::Source::VCS::$vcsfiles{$tarfile}::post_unpack_tar(\$target)};
  899. if ($@) {
  900. &syserr($@);
  901. }
  902. }
  903. }
  904. my @patches;
  905. push @patches, "$dscdir/$difffile" if $difffile;
  906. if ($debianfile and -d (my $pd = "$expectprefix/debian/patches"))
  907. {
  908. my @p;
  909. opendir D, $pd;
  910. while (defined ($_ = readdir D))
  911. {
  912. # patches match same rules as run-parts
  913. next unless /^[\w-]+$/ and -f "$pd/$_";
  914. my $p = $_;
  915. checkdiff("$pd/$p");
  916. push @p, $p;
  917. }
  918. closedir D;
  919. push @patches, map "$newdirectory/debian/patches/$_", sort @p;
  920. }
  921. for my $dircreate (keys %dirtocreate) {
  922. my $dircreatem = "";
  923. for my $dircreatep (split("/", $dircreate)) {
  924. $dircreatem .= $dircreatep . "/";
  925. if (!lstat($dircreatem)) {
  926. $! == ENOENT || &syserr(sprintf(_g("cannot stat %s"), $dircreatem));
  927. mkdir($dircreatem,0777)
  928. || &syserr(sprintf(_g("failed to create %s subdirectory"), $dircreatem));
  929. }
  930. else {
  931. -d _ || &error(sprintf(_g("diff patches file in directory `%s',"
  932. ." but %s isn't a directory !"), $dircreate, $dircreatem));
  933. }
  934. }
  935. }
  936. if ($newdirectory ne $expectprefix)
  937. {
  938. rename($expectprefix,$newdirectory) ||
  939. &syserr(sprintf(_g("failed to rename newly-extracted %s to %s"), $expectprefix, $newdirectory));
  940. # rename the copied .orig directory
  941. ! -e "$newdirectory.tmp-keep"
  942. || rename("$newdirectory.tmp-keep",$expectprefix)
  943. || &syserr(sprintf(_g("failed to rename saved %s to %s"), "$newdirectory.tmp-keep", $expectprefix));
  944. }
  945. for my $patch (@patches) {
  946. printf(_g("%s: applying %s")."\n", $progname, $patch);
  947. if ($patch =~ /\.$comp_regex$/) {
  948. &forkgzipread($patch);
  949. *DIFF = *GZIP;
  950. } else {
  951. open DIFF, $patch or &error(sprintf(_g("can't open diff `%s'"), $patch));
  952. }
  953. defined(my $c2 = fork) || syserr(_g("fork for patch"));
  954. if (!$c2) {
  955. open(STDIN,"<&DIFF") || &syserr(_g("reopen gzip for patch"));
  956. chdir($newdirectory) || &syserr(sprintf(_g("chdir to %s for patch"), $newdirectory));
  957. $ENV{'LC_ALL'}= 'C';
  958. $ENV{'LANG'}= 'C';
  959. exec('patch','-s','-t','-F','0','-N','-p1','-u',
  960. '-V','never','-g0','-b','-z','.dpkg-orig') or &syserr(_g("exec patch"));
  961. }
  962. close(DIFF);
  963. $c2 == waitpid($c2,0) || &syserr(_g("wait for patch"));
  964. $? && subprocerr("patch");
  965. &reapgzip if $patch =~ /\.$comp_regex$/;
  966. }
  967. my $now = time;
  968. for $fn (keys %filepatched) {
  969. my $ftr = "$newdirectory/" . substr($fn, length($expectprefix) + 1);
  970. utime($now, $now, $ftr) || &syserr(sprintf(_g("cannot change timestamp for %s"), $ftr));
  971. $ftr.= ".dpkg-orig";
  972. unlink($ftr) || &syserr(sprintf(_g("remove patch backup file %s"), $ftr));
  973. }
  974. if (!(my @s = lstat("$newdirectory/debian/rules"))) {
  975. $! == ENOENT || &syserr(sprintf(_g("cannot stat %s"), "$newdirectory/debian/rules"));
  976. warning(sprintf(_g("%s does not exist"), "$newdirectory/debian/rules"));
  977. } elsif (-f _) {
  978. chmod($s[2] | 0111, "$newdirectory/debian/rules") ||
  979. &syserr(sprintf(_g("cannot make %s executable"), "$newdirectory/debian/rules"));
  980. } else {
  981. warning(sprintf(_g("%s is not a plain file"), "$newdirectory/debian/rules"));
  982. }
  983. my $execmode = 0777 & ~umask;
  984. (my @s = stat('.')) || syserr(_g("cannot stat `.'"));
  985. my $dirmode = $execmode | ($s[2] & 02000);
  986. my $plainmode = $execmode & ~0111;
  987. my $fifomode = ($plainmode & 0222) | (($plainmode & 0222) << 1);
  988. for $fn (@filesinarchive) {
  989. $fn=~ s,^$expectprefix,$newdirectory,;
  990. (my @s = lstat($fn)) || syserr(sprintf(_g("cannot stat extracted object `%s'"), $fn));
  991. my $mode = $s[2];
  992. my $newmode;
  993. if (-d _) {
  994. $newmode= $dirmode;
  995. } elsif (-f _) {
  996. $newmode= ($mode & 0111) ? $execmode : $plainmode;
  997. } elsif (-p _) {
  998. $newmode= $fifomode;
  999. } elsif (!-l _) {
  1000. &internerr(sprintf(_g("unknown object `%s' after extract (mode 0%o)"), $fn, $mode));
  1001. } else { next; }
  1002. next if ($mode & 07777) == $newmode;
  1003. chmod($newmode,$fn) ||
  1004. &syserr(sprintf(_g("cannot change mode of `%s' to 0%o from 0%o"),
  1005. $fn,$newmode,$mode));
  1006. }
  1007. exit(0);
  1008. }
  1009. sub checkstats {
  1010. my $dscdir = shift;
  1011. my ($f) = @_;
  1012. my @s;
  1013. my $m;
  1014. open(STDIN,"< $dscdir/$f") || &syserr(sprintf(_g("cannot read %s"), "$dscdir/$f"));
  1015. (@s= stat(STDIN)) || &syserr(sprintf(_g("cannot fstat %s"), "$dscdir/$f"));
  1016. $s[7] == $size{$f} || &error(sprintf(_g("file %s has size %s instead of expected %s"), $f, $s[7], $size{$f}));
  1017. $m= `md5sum`; $? && subprocerr("md5sum $f"); $m =~ s/\n$//;
  1018. $m = readmd5sum( $m );
  1019. $m eq $md5sum{$f} || &error(sprintf(_g("file %s has md5sum %s instead of expected %s"), $f, $m, $md5sum{$f}));
  1020. open(STDIN,"</dev/null") || &syserr(_g("reopen stdin from /dev/null"));
  1021. }
  1022. sub erasedir {
  1023. my ($dir) = @_;
  1024. if (!lstat($dir)) {
  1025. $! == ENOENT && return;
  1026. &syserr(sprintf(_g("cannot stat directory %s (before removal)"), $dir));
  1027. }
  1028. system 'rm','-rf','--',$dir;
  1029. $? && subprocerr("rm -rf $dir");
  1030. if (!stat($dir)) {
  1031. $! == ENOENT && return;
  1032. &syserr(sprintf(_g("unable to check for removal of dir `%s'"), $dir));
  1033. }
  1034. &failure(sprintf(_g("rm -rf failed to remove `%s'"), $dir));
  1035. }
  1036. sub checktarcpio {
  1037. my ($tarfileread, $wpfx) = @_;
  1038. my ($tarprefix, $c2);
  1039. @filesinarchive = ();
  1040. # make <CPIO> read from the uncompressed archive file
  1041. &forkgzipread ("$tarfileread");
  1042. if (! defined ($c2 = open (CPIO,"-|"))) { &syserr (_g("fork for cpio")); }
  1043. if (!$c2) {
  1044. $ENV{'LC_ALL'}= 'C';
  1045. $ENV{'LANG'}= 'C';
  1046. open (STDIN,"<&GZIP") || &syserr (_g("reopen gzip for cpio"));
  1047. &cpiostderr;
  1048. exec ('cpio','-0t') or &syserr (_g("exec cpio"));
  1049. }
  1050. close (GZIP);
  1051. $/ = "\0";
  1052. while (defined ($fn = <CPIO>)) {
  1053. $fn =~ s/\0$//;
  1054. # store printable name of file for error messages
  1055. my $pname = $fn;
  1056. $pname =~ y/ -~/?/c;
  1057. if ($fn =~ m/\n/) {
  1058. &error (sprintf(_g("tarfile `%s' contains object with".
  1059. " newline in its name (%s)"), $tarfileread, $pname));
  1060. }
  1061. next if ($fn eq '././@LongLink');
  1062. if (! $tarprefix) {
  1063. if ($fn =~ m/\n/) {
  1064. &error(sprintf(_g("first output from cpio -0t (from `%s') ".
  1065. "contains newline - you probably have an out of ".
  1066. "date version of cpio. GNU cpio 2.4.2-2 is known to work"), $tarfileread));
  1067. }
  1068. $tarprefix = ($fn =~ m,((\./)*[^/]*)[/],)[0];
  1069. # need to check for multiple dots on some operating systems
  1070. # empty tarprefix (due to regex failer) will match emptry string
  1071. if ($tarprefix =~ /^[.]*$/) {
  1072. &error(sprintf(_g("tarfile `%s' does not extract into a ".
  1073. "directory off the current directory (%s from %s)"),
  1074. $tarfileread, $tarprefix, $pname));
  1075. }
  1076. }
  1077. my $fprefix = substr ($fn, 0, length ($tarprefix));
  1078. my $slash = substr ($fn, length ($tarprefix), 1);
  1079. if ((($slash ne '/') && ($slash ne '')) || ($fprefix ne $tarprefix)) {
  1080. &error (sprintf(_g("tarfile `%s' contains object (%s) ".
  1081. "not in expected directory (%s)"),
  1082. $tarfileread, $pname, $tarprefix));
  1083. }
  1084. # need to check for multiple dots on some operating systems
  1085. if ($fn =~ m/[.]{2,}/) {
  1086. &error (sprintf(_g("tarfile `%s' contains object with".
  1087. " /../ in its name (%s)"),
  1088. $tarfileread, $pname));
  1089. }
  1090. push (@filesinarchive, $fn);
  1091. }
  1092. close (CPIO);
  1093. $? && subprocerr ("cpio");
  1094. &reapgzip;
  1095. $/= "\n";
  1096. my $tarsubst = quotemeta ($tarprefix);
  1097. return $tarprefix;
  1098. }
  1099. sub checktarsane {
  1100. my ($tarfileread, $wpfx) = @_;
  1101. my ($c2);
  1102. %dirincluded = ();
  1103. %notfileobject = ();
  1104. my $tarprefix = &checktarcpio ($tarfileread, $wpfx);
  1105. # make <TAR> read from the uncompressed archive file
  1106. &forkgzipread ("$tarfileread");
  1107. if (! defined ($c2 = open (TAR,"-|"))) { &syserr (_g("fork for tar -t")); }
  1108. if (! $c2) {
  1109. $ENV{'LC_ALL'}= 'C';
  1110. $ENV{'LANG'}= 'C';
  1111. open (STDIN, "<&GZIP") || &syserr (_g("reopen gzip for tar -t"));
  1112. exec ('tar', '-vvtf', '-') or &syserr (_g("exec tar -vvtf -"));
  1113. }
  1114. close (GZIP);
  1115. my $efix= 0;
  1116. while (<TAR>) {
  1117. chomp;
  1118. if (! m,^(\S{10})\s,) {
  1119. &error(sprintf(_g("tarfile `%s' contains unknown object ".
  1120. "listed by tar as `%s'"),
  1121. $tarfileread, $_));
  1122. }
  1123. my $mode = $1;
  1124. $mode =~ s/^([-dpsl])// ||
  1125. &error(sprintf(_g("tarfile `%s' contains object `%s' with ".
  1126. "unknown or forbidden type `%s'"),
  1127. $tarfileread, $fn, substr($_,0,1)));
  1128. my $type = $&;
  1129. if ($mode =~ /^l/) { $_ =~ s/ -> .*//; }
  1130. s/ link to .+//;
  1131. my @tarfields = split(' ', $_, 6);
  1132. if (@tarfields < 6) {
  1133. &error (sprintf(_g("tarfile `%s' contains incomplete entry `%s'"), $tarfileread, $_)."\n");
  1134. }
  1135. my $tarfn = deoctify ($tarfields[5]);
  1136. # store printable name of file for error messages
  1137. my $pname = $tarfn;
  1138. $pname =~ y/ -~/?/c;
  1139. # fetch name of file as given by cpio
  1140. $fn = $filesinarchive[$efix++];
  1141. my $l = length($fn);
  1142. if (substr ($tarfn, 0, $l + 4) eq "$fn -> ") {
  1143. # This is a symlink, as listed by tar. cpio doesn't
  1144. # give us the targets of the symlinks, so we ignore this.
  1145. $tarfn = substr($tarfn, 0, $l);
  1146. }
  1147. if ($tarfn ne $fn) {
  1148. if ((length ($fn) == 99) && (length ($tarfn) >= 99)
  1149. && (substr ($fn, 0, 99) eq substr ($tarfn, 0, 99))) {
  1150. # this file doesn't match because cpio truncated the name
  1151. # to the first 100 characters. let it slide for now.
  1152. warning(sprintf(_g("filename '%s' was truncated by cpio;" .
  1153. " unable to check full pathname"), $pname));
  1154. # Since it didn't match, later checks will not be able
  1155. # to stat this file, so we replace it with the filename
  1156. # fetched from tar.
  1157. $filesinarchive[$efix-1] = $tarfn;
  1158. } else {
  1159. &error (sprintf(_g("tarfile `%s' contains unexpected object".
  1160. " listed by tar as `%s'; expected `%s'"), $tarfileread, $_, $pname));
  1161. }
  1162. }
  1163. # if cpio truncated the name above,
  1164. # we still can't allow files to expand into /../
  1165. # need to check for multiple dots on some operating systems
  1166. if ($tarfn =~ m/[.]{2,}/) {
  1167. &error (sprintf(_g("tarfile `%s' contains object with".
  1168. "/../ in its name (%s)"), $tarfileread, $pname));
  1169. }
  1170. if ($tarfn =~ /\.dpkg-orig$/) {
  1171. &error (sprintf(_g("tarfile `%s' contains file with name ending in .dpkg-orig"), $tarfileread));
  1172. }
  1173. if ($mode =~ /[sStT]/ && $type ne 'd') {
  1174. &error (sprintf(_g("tarfile `%s' contains setuid, setgid".
  1175. " or sticky object `%s'"), $tarfileread, $pname));
  1176. }
  1177. if ($tarfn eq "$tarprefix/debian" && $type ne 'd') {
  1178. &error (sprintf(_g("tarfile `%s' contains object `debian'".
  1179. " that isn't a directory"), $tarfileread));
  1180. }
  1181. if ($type eq 'd') { $tarfn =~ s,/$,,; }
  1182. $tarfn =~ s,(\./)*,,;
  1183. my $dirname = $tarfn;
  1184. if (($dirname =~ s,/[^/]+$,,) && (! defined ($dirincluded{$dirname}))) {
  1185. &warnerror (sprintf(_g("tarfile `%s' contains object `%s' but its containing ".
  1186. "directory `%s' does not precede it"), $tarfileread, $pname, $dirname));
  1187. $dirincluded{$dirname} = 1;
  1188. }
  1189. if ($type eq 'd') { $dirincluded{$tarfn} = 1; }
  1190. if ($type ne '-') { $notfileobject{$tarfn} = 1; }
  1191. }
  1192. close (TAR);
  1193. $? && subprocerr ("tar -vvtf");
  1194. &reapgzip;
  1195. my $tarsubst = quotemeta ($tarprefix);
  1196. @filesinarchive = map { s/^$tarsubst/$wpfx/; $_ } @filesinarchive;
  1197. %dirincluded = map { s/^$tarsubst/$wpfx/; $_=>1 } (keys %dirincluded);
  1198. %notfileobject = map { s/^$tarsubst/$wpfx/; $_=>1 } (keys %notfileobject);
  1199. }
  1200. # check diff for sanity, find directories to create as a side effect
  1201. sub checkdiff
  1202. {
  1203. my $diff = shift;
  1204. if ($diff =~ /\.$comp_regex$/) {
  1205. &forkgzipread($diff);
  1206. *DIFF = *GZIP;
  1207. } else {
  1208. open DIFF, $diff or &error(sprintf(_g("can't open diff `%s'"), $diff));
  1209. }
  1210. $/="\n";
  1211. $_ = <DIFF>;
  1212. HUNK:
  1213. while (defined($_) || !eof(DIFF)) {
  1214. # skip cruft leading up to patch (if any)
  1215. until (/^--- /) {
  1216. last HUNK unless defined ($_ = <DIFF>);
  1217. }
  1218. # read file header (---/+++ pair)
  1219. s/\n$// or &error(sprintf(_g("diff `%s' is missing trailing newline"), $diff));
  1220. s/^--- // or &error(sprintf(_g("expected ^--- in line %d of diff `%s'"), $., $diff));
  1221. s/\t.*//;
  1222. $_ eq '/dev/null' or s!^(\./)?[^/]+/!$expectprefix/! or
  1223. &error(sprintf(_g("diff `%s' patches file with no subdirectory"), $diff));
  1224. /\.dpkg-orig$/ and
  1225. &error(sprintf(_g("diff `%s' patches file with name ending .dpkg-orig"), $diff));
  1226. $fn = $_;
  1227. (defined($_= <DIFF>) and s/\n$//) or
  1228. &error(sprintf(_g("diff `%s' finishes in middle of ---/+++ (line %d)"), $diff, $.));
  1229. s/\t.*//;
  1230. (s/^\+\+\+ // and s!^(\./)?[^/]+/!!)
  1231. or &error(sprintf(_g("line after --- isn't as expected in diff `%s' (line %d)"), $diff, $.));
  1232. if ($fn eq '/dev/null') {
  1233. $fn = "$expectprefix/$_";
  1234. } else {
  1235. $_ eq substr($fn, length($expectprefix)+1)
  1236. or &error(sprintf(_g("line after --- isn't as expected in diff `%s' (line %d)"), $diff, $.));
  1237. }
  1238. my $dirname = $fn;
  1239. if ($dirname =~ s,/[^/]+$,, && !defined($dirincluded{$dirname})) {
  1240. $dirtocreate{$dirname} = 1;
  1241. }
  1242. defined($notfileobject{$fn}) &&
  1243. &error(sprintf(_g("diff `%s' patches something which is not a plain file"), $diff));
  1244. defined($filepatched{$fn}) &&
  1245. $filepatched{$fn} eq $diff &&
  1246. error(sprintf(_g("diff patches file %s twice"), $fn));
  1247. $filepatched{$fn} = $diff;
  1248. # read hunks
  1249. my $hunk = 0;
  1250. while (defined($_ = <DIFF>) && !(/^--- / or /^Index:/)) {
  1251. # read hunk header (@@)
  1252. s/\n$// or &error(sprintf(_g("diff `%s' is missing trailing newline"), $diff));
  1253. next if /^\\ No newline/;
  1254. /^@@ -\d+(,(\d+))? \+\d+(,(\d+))? @\@( .*)?$/ or
  1255. &error(sprintf(_g("Expected ^\@\@ in line %d of diff `%s'"), $., $diff));
  1256. my ($olines, $nlines) = ($1 ? $2 : 1, $3 ? $4 : 1);
  1257. ++$hunk;
  1258. # read hunk
  1259. while ($olines || $nlines) {
  1260. defined($_ = <DIFF>) or &error(sprintf(_g("unexpected end of diff `%s'"), $diff));
  1261. s/\n$// or &error(sprintf(_g("diff `%s' is missing trailing newline"), $diff));
  1262. next if /^\\ No newline/;
  1263. if (/^ /) { --$olines; --$nlines; }
  1264. elsif (/^-/) { --$olines; }
  1265. elsif (/^\+/) { --$nlines; }
  1266. else { &error(sprintf(_g("expected [ +-] at start of line %d of diff `%s'"), $., $diff)); }
  1267. }
  1268. }
  1269. $hunk or &error(sprintf(_g("expected ^\@\@ at line %d of diff `%s'"), $., $diff));
  1270. }
  1271. close(DIFF);
  1272. &reapgzip if $diff =~ /\.$comp_regex$/;
  1273. }
  1274. sub extracttar {
  1275. my ($tarfileread,$dirchdir,$newtopdir) = @_;
  1276. my ($mode, $modes_set, $i, $j);
  1277. &forkgzipread("$tarfileread");
  1278. defined(my $c2 = fork) || syserr(_g("fork for tar -xkf -"));
  1279. if (!$c2) {
  1280. open(STDIN,"<&GZIP") || &syserr(_g("reopen gzip for tar -xkf -"));
  1281. &cpiostderr;
  1282. chdir($dirchdir) || &syserr(sprintf(_g("cannot chdir to `%s' for tar extract"), $dirchdir));
  1283. exec('tar','--no-same-owner','--no-same-permissions',
  1284. '-xkf','-') or &syserr(_g("exec tar -xkf -"));
  1285. }
  1286. close(GZIP);
  1287. $c2 == waitpid($c2,0) || &syserr(_g("wait for tar -xkf -"));
  1288. $? && subprocerr("tar -xkf -");
  1289. &reapgzip;
  1290. # Unfortunately tar insists on applying our umask _to the original
  1291. # permissions_ rather than mostly-ignoring the original
  1292. # permissions. We fix it up with chmod -R (which saves us some
  1293. # work) but we have to construct a u+/- string which is a bit
  1294. # of a palaver. (Numeric doesn't work because we need [ugo]+X
  1295. # and [ugo]=<stuff> doesn't work because that unsets sgid on dirs.)
  1296. #
  1297. # We still need --no-same-permissions because otherwise tar might
  1298. # extract directory setgid (which we want inherited, not
  1299. # extracted); we need --no-same-owner because putting the owner
  1300. # back is tedious - in particular, correct group ownership would
  1301. # have to be calculated using mount options and other madness.
  1302. #
  1303. # It would be nice if tar could do it right, or if pax could cope
  1304. # with GNU format tarfiles with long filenames.
  1305. #
  1306. $mode= 0777 & ~umask;
  1307. for ($i=0; $i<9; $i+=3) {
  1308. $modes_set.= ',' if $i;
  1309. $modes_set.= qw(u g o)[$i/3];
  1310. for ($j=0; $j<3; $j++) {
  1311. $modes_set.= $mode & (0400 >> ($i+$j)) ? '+' : '-';
  1312. $modes_set.= qw(r w X)[$j];
  1313. }
  1314. }
  1315. system 'chmod','-R',$modes_set,'--',$dirchdir;
  1316. $? && subprocerr("chmod -R $modes_set $dirchdir");
  1317. opendir(D,"$dirchdir") || &syserr(sprintf(_g("Unable to open dir %s"), $dirchdir));
  1318. my @dirchdirfiles = grep($_ ne "." && $_ ne "..", readdir(D));
  1319. closedir(D) || &syserr(sprintf(_g("Unable to close dir %s"), $dirchdir));
  1320. if (@dirchdirfiles==1 && -d "$dirchdir/$dirchdirfiles[0]") {
  1321. rename("$dirchdir/$dirchdirfiles[0]", "$dirchdir/$newtopdir") ||
  1322. &syserr(sprintf(_g("Unable to rename %s to %s"),
  1323. "$dirchdir/$dirchdirfiles[0]",
  1324. "$dirchdir/$newtopdir"));
  1325. } else {
  1326. mkdir("$dirchdir/$newtopdir.tmp", 0777) or
  1327. &syserr(sprintf(_g("Unable to mkdir %s"),
  1328. "$dirchdir/$newtopdir.tmp"));
  1329. for (@dirchdirfiles) {
  1330. rename("$dirchdir/$_", "$dirchdir/$newtopdir.tmp/$_") or
  1331. &syserr(sprintf(_g("Unable to rename %s to %s"),
  1332. "$dirchdir/$_",
  1333. "$dirchdir/$newtopdir.tmp/$_"));
  1334. }
  1335. rename("$dirchdir/$newtopdir.tmp", "$dirchdir/$newtopdir") or
  1336. &syserr(sprintf(_g("Unable to rename %s to %s"),
  1337. "$dirchdir/$newtopdir.tmp",
  1338. "$dirchdir/$newtopdir"));
  1339. }
  1340. }
  1341. sub cpiostderr {
  1342. open(STDERR,"| grep -E -v '^[0-9]+ blocks\$' >&2") ||
  1343. &syserr(_g("reopen stderr for tar to grep out blocks message"));
  1344. }
  1345. sub checktype {
  1346. my ($dir, $fn, $type) = @_;
  1347. if (!lstat("$dir/$fn")) {
  1348. &unrepdiff2(_g("nonexistent"),$type{$fn});
  1349. } else {
  1350. my $v = eval("$type _ ? 2 : 1");
  1351. $v || internerr(sprintf(_g("checktype %s (%s)"), "$@", $type));
  1352. return 1 if $v == 2;
  1353. &unrepdiff2(_g("something else"),$type{$fn});
  1354. }
  1355. return 0;
  1356. }
  1357. sub setopmode {
  1358. defined($opmode) && &usageerr(_g("only one of -x or -b allowed, and only once"));
  1359. $opmode= $_[0];
  1360. }
  1361. sub unrepdiff {
  1362. printf(STDERR _g("%s: cannot represent change to %s: %s")."\n",
  1363. $progname, $fn, $_[0])
  1364. || &syserr(_g("write syserr unrep"));
  1365. $ur++;
  1366. }
  1367. sub unrepdiff2 {
  1368. printf(STDERR _g("%s: cannot represent change to %s:\n".
  1369. "%s: new version is %s\n".
  1370. "%s: old version is %s\n"),
  1371. $progname, $fn, $progname, $_[1], $progname, $_[0])
  1372. || &syserr(_g("write syserr unrep"));
  1373. $ur++;
  1374. }
  1375. # FIXME: Local to *gzip* funcs
  1376. my $cgz;
  1377. my $gzipsigpipeok;
  1378. sub forkgzipwrite {
  1379. my @prog;
  1380. if ($_[0] =~ /\.gz\.new\..{6}$/) {
  1381. @prog = qw(gzip);
  1382. } elsif ($_[0] =~ /\.bz2\.new\..{6}$/) {
  1383. @prog = qw(bzip2);
  1384. } elsif ($_[0] =~ /\.lzma\.new\..{6}$/) {
  1385. @prog = qw(lzma);
  1386. } else {
  1387. &error(sprintf(_g("unknown compression type on file %s"), $_[0]));
  1388. }
  1389. my $level = "-$comp_level";
  1390. $level = "--$comp_level"
  1391. if $comp_level =~ /best|fast/;
  1392. push @prog, $level;
  1393. open(GZIPFILE,">", $_[0]) || &syserr(sprintf(_g("create file %s"), $_[0]));
  1394. pipe(GZIPREAD,GZIP) || &syserr(_g("pipe for gzip"));
  1395. defined($cgz= fork) || &syserr(_g("fork for gzip"));
  1396. if (!$cgz) {
  1397. open(STDIN,"<&",\*GZIPREAD) || &syserr(_g("reopen gzip pipe"));
  1398. close(GZIPREAD); close(GZIP);
  1399. open(STDOUT,">&",\*GZIPFILE) || &syserr(_g("reopen tar"));
  1400. exec({ $prog[0] } @prog) or &syserr(_g("exec gzip"));
  1401. }
  1402. close(GZIPREAD);
  1403. $gzipsigpipeok= 0;
  1404. }
  1405. sub forkgzipread {
  1406. local $SIG{PIPE} = 'DEFAULT';
  1407. my $prog;
  1408. if ($_[0] =~ /\.gz$/) {
  1409. $prog = 'gunzip';
  1410. } elsif ($_[0] =~ /\.bz2$/) {
  1411. $prog = 'bunzip2';
  1412. } elsif ($_[0] =~ /\.lzma$/) {
  1413. $prog = 'unlzma';
  1414. } else {
  1415. &error(sprintf(_g("unknown compression type on file %s"), $_[0]));
  1416. }
  1417. open(GZIPFILE,"<", $_[0]) || &syserr(sprintf(_g("read file %s"), $_[0]));
  1418. pipe(GZIP,GZIPWRITE) || &syserr(sprintf(_g("pipe for %s"), $prog));
  1419. defined($cgz= fork) || &syserr(sprintf(_g("fork for %s"), $prog));
  1420. if (!$cgz) {
  1421. open(STDOUT,">&",\*GZIPWRITE) || &syserr(sprintf(_g("reopen %s pipe"), $prog));
  1422. close(GZIPWRITE); close(GZIP);
  1423. open(STDIN,"<&",\*GZIPFILE) || &syserr(_g("reopen input file"));
  1424. exec({ $prog } $prog) or &syserr(sprintf(_g("exec %s"), $prog));
  1425. }
  1426. close(GZIPWRITE);
  1427. $gzipsigpipeok= 1;
  1428. }
  1429. sub reapgzip {
  1430. $cgz == waitpid($cgz,0) || &syserr(_g("wait for gzip"));
  1431. !$? || ($gzipsigpipeok && WIFSIGNALED($?) && WTERMSIG($?)==SIGPIPE) ||
  1432. subprocerr("gzip");
  1433. close(GZIPFILE);
  1434. }
  1435. my %added_files;
  1436. sub addfile {
  1437. my ($filename)= @_;
  1438. $added_files{$filename}++ &&
  1439. &internerr( sprintf(_g("tried to add file `%s' twice"), $filename));
  1440. stat($filename) || &syserr(sprintf(_g("could not stat output file `%s'"), $filename));
  1441. my $size = (stat _)[7];
  1442. my $md5sum= `md5sum <$filename`;
  1443. $? && &subprocerr("md5sum $filename");
  1444. $md5sum = readmd5sum( $md5sum );
  1445. $f{'Files'}.= "\n $md5sum $size $filename";
  1446. }
  1447. # replace \ddd with their corresponding character, refuse \ddd > \377
  1448. # modifies $_ (hs)
  1449. {
  1450. my $backslash;
  1451. sub deoctify {
  1452. my $fn= $_[0];
  1453. $backslash= sprintf("\\%03o", unpack("C", "\\")) if !$backslash;
  1454. s/\\{2}/$backslash/g;
  1455. @_= split(/\\/, $fn);
  1456. foreach (@_) {
  1457. /^(\d{3})/ or next;
  1458. &failure(sprintf(_g("bogus character `\\%s' in `%s'"), $1, $fn)."\n")
  1459. if oct($1) > 255;
  1460. $_= pack("c", oct($1)) . $POSTMATCH;
  1461. }
  1462. return join("", @_);
  1463. } }