[Bps-public-commit] brackup branch, master, updated. 5445cb3c0d21c9555b579fd929eef3043e3c1418

Alex Vandiver alexmv at bestpractical.com
Tue Jul 13 12:11:03 EDT 2010


The branch, master has been updated
       via  5445cb3c0d21c9555b579fd929eef3043e3c1418 (commit)
       via  7ace239840d42d2dbeffc58637b6717c7823a918 (commit)
       via  22041bee9cf6de030e7142410079ed225620b86d (commit)
       via  3702e3fe92e6d4e27b072226b722bd2f897f6cc7 (commit)
       via  ea7fbbee27340493436bd062f3a7110be92bcf35 (commit)
      from  46ed50e51fe0ece61e30b79d68d11fa073388f10 (commit)

Summary of changes:
 Changes                |    3 ++
 brackup                |   20 +++++++++++++
 lib/Brackup/Backup.pm  |   56 +++++++++++++++++++++++++++++++++++-
 lib/Brackup/Config.pm  |   10 ++++++
 lib/Brackup/File.pm    |   19 ++++++++++++
 lib/Brackup/Restore.pm |   74 ++++++++++++++++++++++++++++++++++++++++++++++--
 6 files changed, 177 insertions(+), 5 deletions(-)

- Log -----------------------------------------------------------------
commit ea7fbbee27340493436bd062f3a7110be92bcf35
Author: gavin at openfusion.com.au <gavin at openfusion.com.au@c3152786-d43a-0410-8499-09eb43983aed>
Date:   Tue Jun 1 19:11:38 2010 +0000

    Add --list-sources and --list-targets options to brackup.
    
    git-svn-id: http://brackup.googlecode.com/svn/trunk@314 c3152786-d43a-0410-8499-09eb43983aed

diff --git a/brackup b/brackup
index 03501dc..45e0274 100755
--- a/brackup
+++ b/brackup
@@ -58,6 +58,14 @@ Produces output suitable for piping into C<zenity --progress> to get a
 pretty GUI progress bar while running a backup.  This option is
 incompatable with C<--verbose>, as both print to STDOUT.
 
+=item --list-sources
+
+List the names of the sources defined in your configuration file.
+
+=item --list-targets
+
+List the names of the targets defined in your configuration file.
+
 =back
 
 =head1 WARRANTY
@@ -104,6 +112,7 @@ my $opt_dryrun;
 my $opt_verbose;
 my $opt_du_stats;
 my $opt_zenityprogress;
+my ($opt_list_sources, $opt_list_targets);
 
 my $config_file = Brackup::Config->default_config_file_name;
 my $arguments = join(' ', @ARGV);
@@ -120,6 +129,8 @@ usage() unless
                'dry-run'   => \$opt_dryrun,
                'du-stats'  => \$opt_du_stats,
                'config=s'  => \$config_file,
+               'list-sources'   => \$opt_list_sources,
+               'list-targets'   => \$opt_list_targets,
                );
 usage() if @ARGV;
 
@@ -143,6 +154,15 @@ if ($opt_du_stats && $src_name) {
     exit 0;
 }
 
+if ($opt_list_sources) {
+    print join("\n", $config->list_sources), "\n";
+    exit 0;
+}
+if ($opt_list_targets) {
+    print join("\n", $config->list_targets), "\n";
+    exit 0;
+}
+
 usage() unless $src_name && $target_name;
 
 my $cwd = getcwd();
diff --git a/lib/Brackup/Config.pm b/lib/Brackup/Config.pm
index dc80f1f..d7486d8 100644
--- a/lib/Brackup/Config.pm
+++ b/lib/Brackup/Config.pm
@@ -164,6 +164,16 @@ sub load_root {
     return $root;
 }
 
+sub list_sources {
+    my ($self) = @_;
+    return sort map { s/^SOURCE://; $_ } grep(/^SOURCE:/, keys %$self);
+}
+
+sub list_targets {
+    my ($self) = @_;
+    return sort map { s/^TARGET://; $_ } grep(/^TARGET:/, keys %$self);
+}
+
 sub load_target {
     my ($self, $name) = @_;
     my $confsec = $self->{"TARGET:$name"} or

commit 3702e3fe92e6d4e27b072226b722bd2f897f6cc7
Author: gavin at openfusion.com.au <gavin at openfusion.com.au@c3152786-d43a-0410-8499-09eb43983aed>
Date:   Fri Jun 4 16:03:25 2010 +0000

    Update Brackup::Backup and Brackup::File to capture user/group info in metafile.
    
    git-svn-id: http://brackup.googlecode.com/svn/trunk@315 c3152786-d43a-0410-8499-09eb43983aed

diff --git a/lib/Brackup/Backup.pm b/lib/Brackup/Backup.pm
index f6c78a8..3f8fe22 100644
--- a/lib/Brackup/Backup.pm
+++ b/lib/Brackup/Backup.pm
@@ -22,6 +22,10 @@ sub new {
     $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
@@ -60,7 +64,7 @@ sub backup {
     $root->foreach_file(sub {
         my ($file) = @_;  # a Brackup::File
         push @files, $file;
-        $self->record_mode($file);
+        $self->record_mode_ids($file);
         $n_files++;
         $n_kb += $file->size / 1024;
     });
@@ -342,6 +346,48 @@ sub _default_mode {
     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 {
+    my $self = shift;
+    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();
@@ -367,14 +413,20 @@ sub backup_header {
     $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 {
+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 {
diff --git a/lib/Brackup/File.pm b/lib/Brackup/File.pm
index 196a2c8..a6ad2de 100644
--- a/lib/Brackup/File.pm
+++ b/lib/Brackup/File.pm
@@ -188,6 +188,16 @@ sub mode {
     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 = "";
@@ -223,6 +233,15 @@ sub as_rfc822 {
         }
     }
 
+    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";
 }
 

commit 22041bee9cf6de030e7142410079ed225620b86d
Author: gavin at openfusion.com.au <gavin at openfusion.com.au@c3152786-d43a-0410-8499-09eb43983aed>
Date:   Fri Jun 4 16:06:22 2010 +0000

    Update Brackup::Restore to chown restored files using metafile user/group info.
    
    git-svn-id: http://brackup.googlecode.com/svn/trunk@316 c3152786-d43a-0410-8499-09eb43983aed

diff --git a/lib/Brackup/Restore.pm b/lib/Brackup/Restore.pm
index c51cbdc..3b8ab48 100644
--- a/lib/Brackup/Restore.pm
+++ b/lib/Brackup/Restore.pm
@@ -19,6 +19,9 @@ sub new {
     $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
@@ -120,15 +123,18 @@ sub restore {
         my $full = $self->{to} . "/" . $path;
         my $full_escaped = $self->{to} . "/" . $path_escaped_stripped;
 
-        # restore default modes from header
-        $it->{Mode} ||= $meta->{DefaultFileMode} if $type eq "f";
-        $it->{Mode} ||= $meta->{DefaultDirMode}  if $type eq "d";
+        # restore default modes/user/group from header
+        $it->{Mode} ||= ($type eq 'd' ? $meta->{DefaultDirMode} : $meta->{DefaultFileMode});
+        $it->{UID}  ||= $meta->{DefaultUID};
+        $it->{GID}  ||= $meta->{DefaultGID};
 
         warn " * restoring $path_escaped to $full_escaped\n" if $self->{verbose};
         $self->_restore_link     ($full, $it) if $type eq "l";
         $self->_restore_directory($full, $it) if $type eq "d";
         $self->_restore_fifo     ($full, $it) if $type eq "p";
         $self->_restore_file     ($full, $it) if $type eq "f";
+
+        $self->_chown($full, $it, $type, $meta) if $it->{UID} || $it->{GID};
     }
 
     # clear chunk cached by _restore_file
@@ -146,6 +152,68 @@ sub restore {
     }
 }
 
+sub _lookup_remote_uid {
+    my ($self, $remote_uid, $meta) = @_;
+
+    return $self->{_local_uid_map}->{$remote_uid} 
+        if defined $self->{_local_uid_map}->{$remote_uid};
+
+    # meta remote user map - remote_uid => remote username
+    $self->{_remote_user_map} ||= { map { split /:/, $_, 2 } split /\s+/, $meta->{UIDMap} };
+
+    # try and lookup local uid using remote username
+    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) = @_;
 

commit 7ace239840d42d2dbeffc58637b6717c7823a918
Author: gavin at openfusion.com.au <gavin at openfusion.com.au@c3152786-d43a-0410-8499-09eb43983aed>
Date:   Fri Jun 4 16:08:09 2010 +0000

    Add ownership entry to Changes.
    
    git-svn-id: http://brackup.googlecode.com/svn/trunk@317 c3152786-d43a-0410-8499-09eb43983aed

diff --git a/Changes b/Changes
index 1b49102..33df2f3 100644
--- a/Changes
+++ b/Changes
@@ -1,3 +1,6 @@
+  - 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)
 

commit 5445cb3c0d21c9555b579fd929eef3043e3c1418
Merge: 46ed50e 7ace239
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Tue Jul 13 12:04:29 2010 -0400

    Merge remote branch 'trunk'


-----------------------------------------------------------------------



More information about the Bps-public-commit mailing list