Brackup
view release on metacpan or search on metacpan
1.10 (2010-10-31)
- permit 0 as a filename. https://rt.cpan.org/Ticket/Display.html?id=62004
- add Riak target, allowing backups to a riak cluster (Gavin Carr)
- add uid/gid info to metafile, and use in restores (where possible)
(Gavin Carr)
- allow multiple gpg recipients to be specified, any can restore (Alex
Vandiver)
- if IO::Compress::Gzip is available, write a compressed brackup metafile in
unencrypted mode, and handle properly for reads and restores (Gavin Carr)
- remove orphaned chunks from inventory as part of garbage collection
(Gavin Carr)
lib/Brackup/Backup.pm view on Meta::CPAN
$self->{root} = delete $opts{root}; # Brackup::Root
$self->{target} = delete $opts{target}; # Brackup::Target
$self->{dryrun} = delete $opts{dryrun}; # bool
$self->{verbose} = delete $opts{verbose}; # bool
$self->{inventory} = delete $opts{inventory}; # bool
$self->{savefiles} = delete $opts{savefiles}; # bool
$self->{zenityprogress} = delete $opts{zenityprogress}; # bool
$self->{modecounts} = {}; # type -> mode(octal) -> count
$self->{idcounts} = {}; # type -> uid/gid -> count
$self->{_uid_map} = {}; # uid -> username
$self->{_gid_map} = {}; # gid -> group
$self->{saved_files} = []; # list of Brackup::File objects backed up
$self->{unflushed_files} = []; # list of Brackup::File objects not in backup_file
croak("Unknown options: " . join(', ', keys %opts)) if %opts;
return $self;
}
# returns true (a Brackup::BackupStats object) on success, or dies with error
lib/Brackup/Backup.pm view on Meta::CPAN
my ($self, $type) = @_;
my $map = $self->{modecounts}{$type} || {};
return (sort { $map->{$b} <=> $map->{$a} } keys %$map)[0];
}
sub default_uid {
my $self = shift;
return $self->{_def_uid} ||= $self->_default_id('u');
}
sub default_gid {
my $self = shift;
return $self->{_def_gid} ||= $self->_default_id('g');
}
sub _default_id {
my ($self, $type) = @_;
my $map = $self->{idcounts}{$type} || {};
return (sort { $map->{$b} <=> $map->{$a} } keys %$map)[0];
}
# space-separated list of local uid:username mappings
sub uid_map {
lib/Brackup/Backup.pm view on Meta::CPAN
my @map;
my $uidcounts = $self->{idcounts}{u};
for my $uid (sort { $a <=> $b } keys %$uidcounts) {
if (my $name = getpwuid($uid)) {
push @map, "$uid:$name";
}
}
return join(' ', @map);
}
# space-separated list of local gid:group mappings
sub gid_map {
my $self = shift;
my @map;
my $gidcounts = $self->{idcounts}{g};
for my $gid (sort { $a <=> $b } keys %$gidcounts) {
if (my $name = getgrgid($gid)) {
push @map, "$gid:$name";
}
}
return join(' ', @map);
}
sub backup_time {
my $self = shift;
return $self->{backup_time} ||= time();
}
lib/Brackup/Backup.pm view on Meta::CPAN
die "Bogus header value from driver" if $val =~ /[\r\n]/;
$ret .= "Driver-$k: $val\n";
}
}
$ret .= "RootName: " . $self->{root}->name . "\n";
$ret .= "RootPath: " . $self->{root}->path . "\n";
$ret .= "TargetName: " . $self->{target}->name . "\n";
$ret .= "DefaultFileMode: " . $self->default_file_mode . "\n";
$ret .= "DefaultDirMode: " . $self->default_directory_mode . "\n";
$ret .= "DefaultUID: " . $self->default_uid . "\n";
$ret .= "DefaultGID: " . $self->default_gid . "\n";
$ret .= "UIDMap: " . $self->uid_map . "\n";
$ret .= "GIDMap: " . $self->gid_map . "\n";
$ret .= "GPG-Recipient: $_\n" for $self->{root}->gpg_rcpts;
$ret .= "\n";
return $ret;
}
sub record_mode_ids {
my ($self, $file) = @_;
$self->{modecounts}{$file->type}{$file->mode}++;
$self->{idcounts}{u}{$file->uid}++;
$self->{idcounts}{g}{$file->gid}++;
}
sub add_unflushed_file {
my ($self, $file, $handlelist) = @_;
push @{ $self->{unflushed_files} }, [ $file, $handlelist ];
}
sub flush_files {
my ($self, $fh) = @_;
while (my $rec = shift @{ $self->{unflushed_files} }) {
lib/Brackup/File.pm view on Meta::CPAN
sub mode {
my $self = shift;
return sprintf('%#o', $self->stat->mode & 0777);
}
sub uid {
my $self = shift;
return $self->stat->uid;
}
sub gid {
my $self = shift;
return $self->stat->gid;
}
sub as_rfc822 {
my ($self, $schunk_list, $backup) = @_;
my $ret = "";
my $set = sub {
my ($key, $val) = @_;
return unless length $val;
$ret .= "$key: $val\n";
};
lib/Brackup/File.pm view on Meta::CPAN
unless (($type eq "d" && $mode eq $backup->default_directory_mode) ||
($type eq "f" && $mode eq $backup->default_file_mode)) {
$set->("Mode", $mode);
}
}
my $uid = $self->uid;
unless ($uid eq $backup->default_uid) {
$set->("UID", $uid);
}
my $gid = $self->gid;
unless ($gid eq $backup->default_gid) {
$set->("GID", $gid);
}
return $ret . "\n";
}
1;
lib/Brackup/Mount.pm view on Meta::CPAN
my ($path) = @_;
my $record = $meta->{$path};
return -ENOENT unless $record;
return (
0, # device number (?)
0, # inode
$record->{mode},
0, # nlink
$<, # uid
0, # gid
0, # rdev
$record->{size},
$record->{atime},
$record->{mtime},
$record->{mtime}, # ctime
1024, # blocksize
1, # blocks
);
},
lib/Brackup/Restore.pm view on Meta::CPAN
my ($class, %opts) = @_;
my $self = bless {}, $class;
$self->{to} = delete $opts{to}; # directory we're restoring to
$self->{prefix} = delete $opts{prefix}; # directory/file filename prefix, or "" for all
$self->{filename}= delete $opts{file}; # filename we're restoring from
$self->{config} = delete $opts{config}; # brackup config (if available)
$self->{verbose} = delete $opts{verbose};
$self->{_local_uid_map} = {}; # remote/metafile uid -> local uid
$self->{_local_gid_map} = {}; # remote/metafile gid -> local gid
$self->{prefix} =~ s/\/$// if $self->{prefix};
$self->{_stats_to_run} = []; # stack (push/pop) of subrefs to reset stat info on
die "Destination directory doesn't exist" unless $self->{to} && -d $self->{to};
croak("Unknown options: " . join(', ', keys %opts)) if %opts;
$self->{metafile} = Brackup::DecryptedFile->new(filename => $self->{filename});
lib/Brackup/Restore.pm view on Meta::CPAN
if (my $remote_user = $self->{_remote_user_map}->{$remote_uid}) {
my $local_uid = getpwnam($remote_user);
return $self->{_local_uid_map}->{$remote_uid} = $local_uid
if defined $local_uid;
}
# if remote username missing locally, fallback to $remote_uid
return $self->{_local_uid_map}->{$remote_uid} = $remote_uid;
}
sub _lookup_remote_gid {
my ($self, $remote_gid, $meta) = @_;
return $self->{_local_gid_map}->{$remote_gid}
if defined $self->{_local_gid_map}->{$remote_gid};
# meta remote group map - remote_gid => remote group
$self->{_remote_group_map} ||= { map { split /:/, $_, 2 } split /\s+/, $meta->{GIDMap} };
# try and lookup local gid using remote group
if (my $remote_group = $self->{_remote_group_map}->{$remote_gid}) {
my $local_gid = getgrnam($remote_group);
return $self->{_local_gid_map}->{$remote_gid} = $local_gid
if defined $local_gid;
}
# if remote group missing locally, fallback to $remote_gid
return $self->{_local_gid_map}->{$remote_gid} = $remote_gid;
}
sub _chown {
my ($self, $full, $it, $type, $meta) = @_;
my $uid = $self->_lookup_remote_uid($it->{UID}, $meta) if $it->{UID};
my $gid = $self->_lookup_remote_gid($it->{GID}, $meta) if $it->{GID};
if ($type eq 'l') {
if (! defined $self->{_lchown}) {
no strict 'subs';
$self->{_lchown} = eval { require Lchown } && Lchown::LCHOWN_AVAILABLE;
}
if ($self->{_lchown}) {
Lchown::lchown($uid, -1, $full) if defined $uid;
Lchown::lchown(-1, $gid, $full) if defined $gid;
}
} else {
# ignore errors, but change uid and gid separately to sidestep unprivileged failures
chown $uid, -1, $full if defined $uid;
chown -1, $gid, $full if defined $gid;
}
}
sub _update_statinfo {
my ($self, $full, $it) = @_;
push @{ $self->{_stats_to_run} }, sub {
if (defined $it->{Mode}) {
chmod(oct $it->{Mode}, $full) or
die "Failed to change mode of $full: $!";
( run in 2.534 seconds using v1.01-cache-2.11-cpan-97f6503c9c8 )