Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(216)

Side by Side Diff: third_party/dpkg-dev/scripts/Dpkg/Source/Patch.pm

Issue 2411423002: Linux build: Use sysroot when calculating dependencies (Closed)
Patch Set: Update expected_deps Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright © 2008 Raphaël Hertzog <hertzog@debian.org>
2 #
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
16 package Dpkg::Source::Patch;
17
18 use strict;
19 use warnings;
20
21 our $VERSION = '0.01';
22
23 use Dpkg;
24 use Dpkg::Gettext;
25 use Dpkg::IPC;
26 use Dpkg::ErrorHandling;
27 use Dpkg::Source::Functions qw(fs_time);
28
29 use POSIX qw(:errno_h :sys_wait_h);
30 use File::Find;
31 use File::Basename;
32 use File::Spec;
33 use File::Path;
34 use File::Compare;
35 use Fcntl ':mode';
36 #XXX: Needed for sub-second timestamps, require recent perl
37 #use Time::HiRes qw(stat);
38
39 use parent qw(Dpkg::Compression::FileHandle);
40
41 sub create {
42 my ($self, %opts) = @_;
43 $self->ensure_open('w'); # Creates the file
44 *$self->{errors} = 0;
45 *$self->{empty} = 1;
46 if ($opts{old} and $opts{new}) {
47 $opts{old} = '/dev/null' unless -e $opts{old};
48 $opts{new} = '/dev/null' unless -e $opts{new};
49 if (-d $opts{old} and -d $opts{new}) {
50 $self->add_diff_directory($opts{old}, $opts{new}, %opts);
51 } elsif (-f $opts{old} and -f $opts{new}) {
52 $self->add_diff_file($opts{old}, $opts{new}, %opts);
53 } else {
54 $self->_fail_not_same_type($opts{old}, $opts{new});
55 }
56 $self->finish() unless $opts{nofinish};
57 }
58 }
59
60 sub set_header {
61 my ($self, $header) = @_;
62 *$self->{header} = $header;
63 }
64
65 sub add_diff_file {
66 my ($self, $old, $new, %opts) = @_;
67 $opts{include_timestamp} = 0 unless exists $opts{include_timestamp};
68 my $handle_binary = $opts{handle_binary_func} || sub {
69 my ($self, $old, $new) = @_;
70 $self->_fail_with_msg($new, _g('binary file contents changed'));
71 };
72 # Optimization to avoid forking diff if unnecessary
73 return 1 if compare($old, $new, 4096) == 0;
74 # Default diff options
75 my @options;
76 if ($opts{options}) {
77 push @options, @{$opts{options}};
78 } else {
79 push @options, '-p';
80 }
81 # Add labels
82 if ($opts{label_old} and $opts{label_new}) {
83 if ($opts{include_timestamp}) {
84 my $ts = (stat($old))[9];
85 my $t = POSIX::strftime('%Y-%m-%d %H:%M:%S', gmtime($ts));
86 $opts{label_old} .= sprintf("\t%s.%09d +0000", $t,
87 ($ts - int($ts)) * 1_000_000_000);
88 $ts = (stat($new))[9];
89 $t = POSIX::strftime('%Y-%m-%d %H:%M:%S', gmtime($ts));
90 $opts{label_new} .= sprintf("\t%s.%09d +0000", $t,
91 ($ts - int($ts)) * 1_000_000_000);
92 } else {
93 # Space in filenames need special treatment
94 $opts{label_old} .= "\t" if $opts{label_old} =~ / /;
95 $opts{label_new} .= "\t" if $opts{label_new} =~ / /;
96 }
97 push @options, '-L', $opts{label_old},
98 '-L', $opts{label_new};
99 }
100 # Generate diff
101 my $diffgen;
102 my $diff_pid = spawn(
103 exec => [ 'diff', '-u', @options, '--', $old, $new ],
104 env => { LC_ALL => 'C', LANG => 'C', TZ => 'UTC0' },
105 to_pipe => \$diffgen,
106 );
107 # Check diff and write it in patch file
108 my $difflinefound = 0;
109 my $binary = 0;
110 while (<$diffgen>) {
111 if (m/^(?:binary|[^-+\@ ].*\bdiffer\b)/i) {
112 $binary = 1;
113 &$handle_binary($self, $old, $new);
114 last;
115 } elsif (m/^[-+\@ ]/) {
116 $difflinefound++;
117 } elsif (m/^\\ /) {
118 warning(_g('file %s has no final newline (either ' .
119 'original or modified version)'), $new);
120 } else {
121 chomp;
122 error(_g("unknown line from diff -u on %s: `%s'"), $new, $_);
123 }
124 if (*$self->{empty} and defined(*$self->{header})) {
125 $self->print(*$self->{header}) or syserr(_g('failed to write'));
126 *$self->{empty} = 0;
127 }
128 print { $self } $_ or syserr(_g('failed to write'));
129 }
130 close($diffgen) or syserr('close on diff pipe');
131 wait_child($diff_pid, nocheck => 1,
132 cmdline => "diff -u @options -- $old $new");
133 # Verify diff process ended successfully
134 # Exit code of diff: 0 => no difference, 1 => diff ok, 2 => error
135 # Ignore error if binary content detected
136 my $exit = WEXITSTATUS($?);
137 unless (WIFEXITED($?) && ($exit == 0 || $exit == 1 || $binary)) {
138 subprocerr(_g('diff on %s'), $new);
139 }
140 return ($exit == 0 || $exit == 1);
141 }
142
143 sub add_diff_directory {
144 my ($self, $old, $new, %opts) = @_;
145 # TODO: make this function more configurable
146 # - offer to disable some checks
147 my $basedir = $opts{basedirname} || basename($new);
148 my $inc_removal = $opts{include_removal} || 0;
149 my $diff_ignore;
150 if ($opts{diff_ignore_func}) {
151 $diff_ignore = $opts{diff_ignore_func};
152 } elsif ($opts{diff_ignore_regex}) {
153 $diff_ignore = sub { return $_[0] =~ /$opts{diff_ignore_regex}/o };
154 } else {
155 $diff_ignore = sub { return 0 };
156 }
157
158 my @diff_files;
159 my %files_in_new;
160 my $scan_new = sub {
161 my $fn = (length > length($new)) ? substr($_, length($new) + 1) : '.';
162 return if &$diff_ignore($fn);
163 $files_in_new{$fn} = 1;
164 lstat("$new/$fn") or syserr(_g('cannot stat file %s'), "$new/$fn");
165 my $mode = S_IMODE((lstat(_))[2]);
166 my $size = (lstat(_))[7];
167 if (-l _) {
168 unless (-l "$old/$fn") {
169 $self->_fail_not_same_type("$old/$fn", "$new/$fn");
170 return;
171 }
172 my $n = readlink("$new/$fn");
173 unless (defined $n) {
174 syserr(_g('cannot read link %s'), "$new/$fn");
175 }
176 my $n2 = readlink("$old/$fn");
177 unless (defined $n2) {
178 syserr(_g('cannot read link %s'), "$old/$fn");
179 }
180 unless ($n eq $n2) {
181 $self->_fail_not_same_type("$old/$fn", "$new/$fn");
182 }
183 } elsif (-f _) {
184 my $old_file = "$old/$fn";
185 if (not lstat("$old/$fn")) {
186 if ($! != ENOENT) {
187 syserr(_g('cannot stat file %s'), "$old/$fn");
188 }
189 $old_file = '/dev/null';
190 } elsif (not -f _) {
191 $self->_fail_not_same_type("$old/$fn", "$new/$fn");
192 return;
193 }
194
195 my $label_old = "$basedir.orig/$fn";
196 if ($opts{use_dev_null}) {
197 $label_old = $old_file if $old_file eq '/dev/null';
198 }
199 push @diff_files, [$fn, $mode, $size, $old_file, "$new/$fn",
200 $label_old, "$basedir/$fn"];
201 } elsif (-p _) {
202 unless (-p "$old/$fn") {
203 $self->_fail_not_same_type("$old/$fn", "$new/$fn");
204 }
205 } elsif (-b _ || -c _ || -S _) {
206 $self->_fail_with_msg("$new/$fn",
207 _g('device or socket is not allowed'));
208 } elsif (-d _) {
209 if (not lstat("$old/$fn")) {
210 if ($! != ENOENT) {
211 syserr(_g('cannot stat file %s'), "$old/$fn");
212 }
213 } elsif (not -d _) {
214 $self->_fail_not_same_type("$old/$fn", "$new/$fn");
215 }
216 } else {
217 $self->_fail_with_msg("$new/$fn", _g('unknown file type'));
218 }
219 };
220 my $scan_old = sub {
221 my $fn = (length > length($old)) ? substr($_, length($old) + 1) : '.';
222 return if &$diff_ignore($fn);
223 return if $files_in_new{$fn};
224 lstat("$old/$fn") or syserr(_g('cannot stat file %s'), "$old/$fn");
225 if (-f _) {
226 if ($inc_removal) {
227 push @diff_files, [$fn, 0, 0, "$old/$fn", '/dev/null',
228 "$basedir.orig/$fn", '/dev/null'];
229 } else {
230 warning(_g('ignoring deletion of file %s'), $fn);
231 }
232 } elsif (-d _) {
233 warning(_g('ignoring deletion of directory %s'), $fn);
234 } elsif (-l _) {
235 warning(_g('ignoring deletion of symlink %s'), $fn);
236 } else {
237 $self->_fail_not_same_type("$old/$fn", "$new/$fn");
238 }
239 };
240
241 find({ wanted => $scan_new, no_chdir => 1 }, $new);
242 find({ wanted => $scan_old, no_chdir => 1 }, $old);
243
244 if ($opts{order_from} and -e $opts{order_from}) {
245 my $order_from = Dpkg::Source::Patch->new(
246 filename => $opts{order_from});
247 my $analysis = $order_from->analyze($basedir, verbose => 0);
248 my %patchorder;
249 my $i = 0;
250 foreach my $fn (@{$analysis->{patchorder}}) {
251 $fn =~ s{^[^/]+/}{};
252 $patchorder{$fn} = $i++;
253 }
254 # 'quilt refresh' sorts files as follows:
255 # - Any files in the existing patch come first, in the order in
256 # which they appear in the existing patch.
257 # - New files follow, sorted lexicographically.
258 # This seems a reasonable policy to follow, and avoids autopatches
259 # being shuffled when they are regenerated.
260 foreach my $diff_file (sort { $a->[0] cmp $b->[0] } @diff_files) {
261 my $fn = $diff_file->[0];
262 $patchorder{$fn} = $i++ unless exists $patchorder{$fn};
263 }
264 @diff_files = sort { $patchorder{$a->[0]} <=> $patchorder{$b->[0]} }
265 @diff_files;
266 } else {
267 @diff_files = sort { $a->[0] cmp $b->[0] } @diff_files;
268 }
269
270 foreach my $diff_file (@diff_files) {
271 my ($fn, $mode, $size,
272 $old_file, $new_file, $label_old, $label_new) = @$diff_file;
273 my $success = $self->add_diff_file($old_file, $new_file,
274 label_old => $label_old,
275 label_new => $label_new, %opts);
276 if ($success and
277 $old_file eq '/dev/null' and $new_file ne '/dev/null') {
278 if (not $size) {
279 warning(_g("newly created empty file '%s' will not " .
280 'be represented in diff'), $fn);
281 } else {
282 if ($mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
283 warning(_g("executable mode %04o of '%s' will " .
284 'not be represented in diff'), $mode, $fn)
285 unless $fn eq 'debian/rules';
286 }
287 if ($mode & (S_ISUID | S_ISGID | S_ISVTX)) {
288 warning(_g("special mode %04o of '%s' will not " .
289 'be represented in diff'), $mode, $fn);
290 }
291 }
292 }
293 }
294 }
295
296 sub finish {
297 my ($self) = @_;
298 close($self) or syserr(_g('cannot close %s'), $self->get_filename());
299 return not *$self->{errors};
300 }
301
302 sub register_error {
303 my ($self) = @_;
304 *$self->{errors}++;
305 }
306 sub _fail_with_msg {
307 my ($self, $file, $msg) = @_;
308 errormsg(_g('cannot represent change to %s: %s'), $file, $msg);
309 $self->register_error();
310 }
311 sub _fail_not_same_type {
312 my ($self, $old, $new) = @_;
313 my $old_type = get_type($old);
314 my $new_type = get_type($new);
315 errormsg(_g('cannot represent change to %s:'), $new);
316 errormsg(_g(' new version is %s'), $new_type);
317 errormsg(_g(' old version is %s'), $old_type);
318 $self->register_error();
319 }
320
321 sub _getline {
322 my $handle = shift;
323
324 my $line = <$handle>;
325 if (defined $line) {
326 # Strip end-of-line chars
327 chomp($line);
328 $line =~ s/\r$//;
329 }
330 return $line;
331 }
332
333 sub _intuit_file_patched {
334 my ($old, $new) = @_;
335
336 return $new unless defined $old;
337 return $old unless defined $new;
338 return $new if -e $new and not -e $old;
339 return $old if -e $old and not -e $new;
340
341 # We don't consider the case where both files are non-existent and
342 # where patch picks the one with the fewest directories to create
343 # since dpkg-source will pre-create the required directories
344
345 # Precalculate metrics used by patch
346 my ($tmp_o, $tmp_n) = ($old, $new);
347 my ($len_o, $len_n) = (length($old), length($new));
348 $tmp_o =~ s{[/\\]+}{/}g;
349 $tmp_n =~ s{[/\\]+}{/}g;
350 my $nb_comp_o = ($tmp_o =~ tr{/}{/});
351 my $nb_comp_n = ($tmp_n =~ tr{/}{/});
352 $tmp_o =~ s{^.*/}{};
353 $tmp_n =~ s{^.*/}{};
354 my ($blen_o, $blen_n) = (length($tmp_o), length($tmp_n));
355
356 # Decide like patch would
357 if ($nb_comp_o != $nb_comp_n) {
358 return ($nb_comp_o < $nb_comp_n) ? $old : $new;
359 } elsif ($blen_o != $blen_n) {
360 return ($blen_o < $blen_n) ? $old : $new;
361 } elsif ($len_o != $len_n) {
362 return ($len_o < $len_n) ? $old : $new;
363 }
364 return $old;
365 }
366
367 # Fetch the header filename ignoring the optional timestamp
368 sub _fetch_filename {
369 my ($diff, $header) = @_;
370
371 # Strip any leading spaces.
372 $header =~ s/^\s+//;
373
374 # Is it a C-style string?
375 if ($header =~ m/^"/) {
376 error(_g('diff %s patches file with C-style encoded filename'), $diff);
377 } else {
378 # Tab is the official separator, it's always used when
379 # filename contain spaces. Try it first, otherwise strip on space
380 # if there's no tab
381 $header =~ s/\s.*// unless $header =~ s/\t.*//;
382 }
383
384 return $header;
385 }
386
387 # check diff for sanity, find directories to create as a side effect
388 sub analyze {
389 my ($self, $destdir, %opts) = @_;
390
391 $opts{verbose} //= 1;
392 my $diff = $self->get_filename();
393 my %filepatched;
394 my %dirtocreate;
395 my @patchorder;
396 my $patch_header = '';
397 my $diff_count = 0;
398
399 $_ = _getline($self);
400
401 HUNK:
402 while (defined($_) or not eof($self)) {
403 my (%path, %fn);
404 # skip comments leading up to patch (if any)
405 while (1) {
406 if (/^(?:--- |\+\+\+ |@@ -)/) {
407 last;
408 } else {
409 $patch_header .= "$_\n";
410 }
411 last HUNK if not defined($_ = _getline($self));
412 }
413 $diff_count++;
414 # read file header (---/+++ pair)
415 unless(s/^--- //) {
416 error(_g("expected ^--- in line %d of diff `%s'"), $., $diff);
417 }
418 $path{old} = $_ = _fetch_filename($diff, $_);
419 $fn{old} = $_ if $_ ne '/dev/null' and s{^[^/]*/+}{$destdir/};
420 if (/\.dpkg-orig$/) {
421 error(_g("diff `%s' patches file with name ending .dpkg-orig"), $dif f);
422 }
423
424 unless (defined($_ = _getline($self))) {
425 error(_g("diff `%s' finishes in middle of ---/+++ (line %d)"), $diff , $.);
426 }
427 unless (s/^\+\+\+ //) {
428 error(_g("line after --- isn't as expected in diff `%s' (line %d)"), $diff, $.);
429 }
430 $path{new} = $_ = _fetch_filename($diff, $_);
431 $fn{new} = $_ if $_ ne '/dev/null' and s{^[^/]*/+}{$destdir/};
432
433 unless (defined $fn{old} or defined $fn{new}) {
434 error(_g("none of the filenames in ---/+++ are valid in diff '%s' (l ine %d)"),
435 $diff, $.);
436 }
437
438 # Safety checks on both filenames that patch could use
439 foreach my $key ('old', 'new') {
440 next unless defined $fn{$key};
441 if ($path{$key} =~ m{/\.\./}) {
442 error(_g('%s contains an insecure path: %s'), $diff, $path{$key} );
443 }
444 my $path = $fn{$key};
445 while (1) {
446 if (-l $path) {
447 error(_g('diff %s modifies file %s through a symlink: %s'),
448 $diff, $fn{$key}, $path);
449 }
450 last unless $path =~ s{/+[^/]*$}{};
451 last if length($path) <= length($destdir); # $destdir is assumed safe
452 }
453 }
454
455 if ($path{old} eq '/dev/null' and $path{new} eq '/dev/null') {
456 error(_g("original and modified files are /dev/null in diff `%s' (li ne %d)"),
457 $diff, $.);
458 } elsif ($path{new} eq '/dev/null') {
459 error(_g("file removal without proper filename in diff `%s' (line %d )"),
460 $diff, $. - 1) unless defined $fn{old};
461 if ($opts{verbose}) {
462 warning(_g('diff %s removes a non-existing file %s (line %d)'),
463 $diff, $fn{old}, $.) unless -e $fn{old};
464 }
465 }
466 my $fn = _intuit_file_patched($fn{old}, $fn{new});
467
468 my $dirname = $fn;
469 if ($dirname =~ s{/[^/]+$}{} and not -d $dirname) {
470 $dirtocreate{$dirname} = 1;
471 }
472
473 if (-e $fn and not -f _) {
474 error(_g("diff `%s' patches something which is not a plain file"), $ diff);
475 }
476
477 if ($filepatched{$fn}) {
478 warning(_g("diff `%s' patches file %s twice"), $diff, $fn)
479 if $opts{verbose};
480 } else {
481 $filepatched{$fn} = 1;
482 push @patchorder, $fn;
483 }
484
485 # read hunks
486 my $hunk = 0;
487 while (defined($_ = _getline($self))) {
488 # read hunk header (@@)
489 next if /^\\ /;
490 last unless (/^@@ -\d+(,(\d+))? \+\d+(,(\d+))? @\@( .*)?$/);
491 my ($olines, $nlines) = ($1 ? $2 : 1, $3 ? $4 : 1);
492 # read hunk
493 while ($olines || $nlines) {
494 unless (defined($_ = _getline($self))) {
495 if (($olines == $nlines) and ($olines < 3)) {
496 warning(_g("unexpected end of diff `%s'"), $diff)
497 if $opts{verbose};
498 last;
499 } else {
500 error(_g("unexpected end of diff `%s'"), $diff);
501 }
502 }
503 next if /^\\ /;
504 # Check stats
505 if (/^ / || /^$/) { --$olines; --$nlines; }
506 elsif (/^-/) { --$olines; }
507 elsif (/^\+/) { --$nlines; }
508 else {
509 error(_g("expected [ +-] at start of line %d of diff `%s'"),
510 $., $diff);
511 }
512 }
513 $hunk++;
514 }
515 unless($hunk) {
516 error(_g("expected ^\@\@ at line %d of diff `%s'"), $., $diff);
517 }
518 }
519 close($self);
520 unless ($diff_count) {
521 warning(_g("diff `%s' doesn't contain any patch"), $diff)
522 if $opts{verbose};
523 }
524 *$self->{analysis}{$destdir}{dirtocreate} = \%dirtocreate;
525 *$self->{analysis}{$destdir}{filepatched} = \%filepatched;
526 *$self->{analysis}{$destdir}{patchorder} = \@patchorder;
527 *$self->{analysis}{$destdir}{patchheader} = $patch_header;
528 return *$self->{analysis}{$destdir};
529 }
530
531 sub prepare_apply {
532 my ($self, $analysis, %opts) = @_;
533 if ($opts{create_dirs}) {
534 foreach my $dir (keys %{$analysis->{dirtocreate}}) {
535 eval { mkpath($dir, 0, 0777); };
536 syserr(_g('cannot create directory %s'), $dir) if $@;
537 }
538 }
539 }
540
541 sub apply {
542 my ($self, $destdir, %opts) = @_;
543 # Set default values to options
544 $opts{force_timestamp} = 1 unless exists $opts{force_timestamp};
545 $opts{remove_backup} = 1 unless exists $opts{remove_backup};
546 $opts{create_dirs} = 1 unless exists $opts{create_dirs};
547 $opts{options} ||= [ '-t', '-F', '0', '-N', '-p1', '-u',
548 '-V', 'never', '-g0', '-b', '-z', '.dpkg-orig'];
549 $opts{add_options} ||= [];
550 push @{$opts{options}}, @{$opts{add_options}};
551 # Check the diff and create missing directories
552 my $analysis = $self->analyze($destdir, %opts);
553 $self->prepare_apply($analysis, %opts);
554 # Apply the patch
555 $self->ensure_open('r');
556 my ($stdout, $stderr) = ('', '');
557 spawn(
558 exec => [ 'patch', @{$opts{options}} ],
559 chdir => $destdir,
560 env => { LC_ALL => 'C', LANG => 'C' },
561 delete_env => [ 'POSIXLY_CORRECT' ], # ensure expected patch behaviour
562 wait_child => 1,
563 nocheck => 1,
564 from_handle => $self->get_filehandle(),
565 to_string => \$stdout,
566 error_to_string => \$stderr,
567 );
568 if ($?) {
569 print { *STDOUT } $stdout;
570 print { *STDERR } $stderr;
571 subprocerr('LC_ALL=C patch ' . join(' ', @{$opts{options}}) .
572 ' < ' . $self->get_filename());
573 }
574 $self->close();
575 # Reset the timestamp of all the patched files
576 # and remove .dpkg-orig files
577 my @files = keys %{$analysis->{filepatched}};
578 my $now = $opts{timestamp};
579 $now ||= fs_time($files[0]) if $opts{force_timestamp} && scalar @files;
580 foreach my $fn (@files) {
581 if ($opts{force_timestamp}) {
582 utime($now, $now, $fn) or $! == ENOENT
583 or syserr(_g('cannot change timestamp for %s'), $fn);
584 }
585 if ($opts{remove_backup}) {
586 $fn .= '.dpkg-orig';
587 unlink($fn) or syserr(_g('remove patch backup file %s'), $fn);
588 }
589 }
590 return $analysis;
591 }
592
593 # Verify if check will work...
594 sub check_apply {
595 my ($self, $destdir, %opts) = @_;
596 # Set default values to options
597 $opts{create_dirs} = 1 unless exists $opts{create_dirs};
598 $opts{options} ||= [ '--dry-run', '-s', '-t', '-F', '0', '-N', '-p1', '-u',
599 '-V', 'never', '-g0', '-b', '-z', '.dpkg-orig'];
600 $opts{add_options} ||= [];
601 push @{$opts{options}}, @{$opts{add_options}};
602 # Check the diff and create missing directories
603 my $analysis = $self->analyze($destdir, %opts);
604 $self->prepare_apply($analysis, %opts);
605 # Apply the patch
606 $self->ensure_open('r');
607 my $patch_pid = spawn(
608 exec => [ 'patch', @{$opts{options}} ],
609 chdir => $destdir,
610 env => { LC_ALL => 'C', LANG => 'C' },
611 delete_env => [ 'POSIXLY_CORRECT' ], # ensure expected patch behaviour
612 from_handle => $self->get_filehandle(),
613 to_file => '/dev/null',
614 error_to_file => '/dev/null',
615 );
616 wait_child($patch_pid, nocheck => 1);
617 my $exit = WEXITSTATUS($?);
618 subprocerr('patch --dry-run') unless WIFEXITED($?);
619 $self->close();
620 return ($exit == 0);
621 }
622
623 # Helper functions
624 sub get_type {
625 my $file = shift;
626 if (not lstat($file)) {
627 return _g('nonexistent') if $! == ENOENT;
628 syserr(_g('cannot stat %s'), $file);
629 } else {
630 -f _ && return _g('plain file');
631 -d _ && return _g('directory');
632 -l _ && return sprintf(_g('symlink to %s'), readlink($file));
633 -b _ && return _g('block device');
634 -c _ && return _g('character device');
635 -p _ && return _g('named pipe');
636 -S _ && return _g('named socket');
637 }
638 }
639
640 1;
OLDNEW
« no previous file with comments | « third_party/dpkg-dev/scripts/Dpkg/Source/Package/V3/Quilt.pm ('k') | third_party/dpkg-dev/scripts/Dpkg/Source/Quilt.pm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698