Dpkg
view release on metacpan or search on metacpan
lib/Dpkg/Source/Archive.pm view on Meta::CPAN
'--no-same-permissions',
'--no-same-owner',
@{$opts{options}},
];
spawn(%spawn_opts);
$self->close();
# Fix permissions on extracted files because tar insists on applying
# our umask _to the original permissions_ rather than mostly-ignoring
# the original permissions.
# We still need --no-same-permissions because otherwise tar might
# extract directory setgid (which we want inherited, not
# extracted); we need --no-same-owner because putting the owner
# back is tedious - in particular, correct group ownership would
# have to be calculated using mount options and other madness.
fixperms($tmpdir) unless $opts{no_fixperms};
# If we are extracting "in-place" do not remove the destination directory.
if ($opts{in_place}) {
my $canon_basedir = Cwd::realpath($dest);
# On Solaris /dev/null points to /devices/pseudo/mm@0:null.
my $canon_devnull = Cwd::realpath('/dev/null');
my $check_symlink = sub {
my $pathname = shift;
my $canon_pathname = Cwd::realpath($pathname);
if (not defined $canon_pathname) {
return if $! == ENOENT;
syserr(g_("pathname '%s' cannot be canonicalized"), $pathname);
}
return if $canon_pathname eq $canon_devnull;
return if $canon_pathname eq $canon_basedir;
return if $canon_pathname =~ m{^\Q$canon_basedir/\E};
warning(g_("pathname '%s' points outside source root (to '%s')"),
$pathname, $canon_pathname);
};
my $move_in_place = sub {
my $relpath = File::Spec->abs2rel($File::Find::name, $tmpdir);
my $destpath = File::Spec->catfile($dest, $relpath);
my ($mode, $atime, $mtime);
lstat $File::Find::name
or syserr(g_('cannot get source pathname %s metadata'), $File::Find::name);
((undef) x 2, $mode, (undef) x 5, $atime, $mtime) = lstat _;
my $src_is_dir = -d _;
my $dest_exists = 1;
if (not lstat $destpath) {
if ($! == ENOENT) {
$dest_exists = 0;
} else {
syserr(g_('cannot get target pathname %s metadata'), $destpath);
}
}
my $dest_is_dir = -d _;
if ($dest_exists) {
if ($dest_is_dir && $src_is_dir) {
# Refresh the destination directory attributes with the
# ones from the tarball.
chmod $mode, $destpath
or syserr(g_('cannot change directory %s mode'), $File::Find::name);
utime $atime, $mtime, $destpath
or syserr(g_('cannot change directory %s times'), $File::Find::name);
# We should do nothing, and just walk further tree.
return;
} elsif ($dest_is_dir) {
rmdir $destpath
or syserr(g_('cannot remove destination directory %s'), $destpath);
} else {
$check_symlink->($destpath);
unlink $destpath
or syserr(g_('cannot remove destination file %s'), $destpath);
}
}
# If we are moving a directory, we do not need to walk it.
if ($src_is_dir) {
$File::Find::prune = 1;
}
rename $File::Find::name, $destpath
or syserr(g_('cannot move %s to %s'), $File::Find::name, $destpath);
};
my $scan_move_in_place = {
wanted => $move_in_place,
no_chdir => 1,
dangling_symlinks => 0,
};
find($scan_move_in_place, $tmpdir);
} else {
# Rename extracted directory.
opendir my $dir_dh, $tmpdir
or syserr(g_('cannot opendir %s'), $tmpdir);
my @entries = grep { $_ ne '.' && $_ ne '..' } readdir($dir_dh);
closedir($dir_dh);
erasedir($dest);
if (scalar(@entries) == 1 && ! -l "$tmpdir/$entries[0]" && -d _) {
rename "$tmpdir/$entries[0]", $dest
or syserr(g_('unable to rename %s to %s'),
"$tmpdir/$entries[0]", $dest);
} else {
rename $tmpdir, $dest
or syserr(g_('unable to rename %s to %s'), $tmpdir, $dest);
}
}
erasedir($tmpdir);
}
=head1 CHANGES
=head2 Version 0.xx
This is a private module.
=cut
1;
( run in 0.886 second using v1.01-cache-2.11-cpan-39bf76dae61 )