Changeset 65
- Timestamp:
- 10/08/06 01:04:31 (2 years ago)
- Files:
-
- trunk/Changes (modified) (1 diff)
- trunk/lib/Brackup/Backup.pm (modified) (1 diff)
- trunk/lib/Brackup/Chunk.pm (modified) (5 diffs)
- trunk/lib/Brackup/Root.pm (modified) (2 diffs)
- trunk/lib/Brackup/Target/Filesystem.pm (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/Changes
r63 r65 1 - support putting .meta files besides .chunk files on the Target 2 to enable reconstructing the digest database in the future, should 3 it get lost. also start to flesh out per-chunk digests, which 4 would enable backing up large databases (say, InnoDB tablespaces) where 5 large chunks of the file never change. 6 1 7 - new --du-stats to command to act like the du(1) command, but 2 8 based on a root in brackup.conf, and skipping ignored directories. trunk/lib/Brackup/Backup.pm
r62 r65 77 77 # store the metafile, encrypted, on the target 78 78 if (my $rcpt = $self->{root}->gpg_rcpt) { 79 my $encfile .=".enc";79 my $encfile = $backup_file . ".enc"; 80 80 system($self->{root}->gpg_path, $self->{root}->gpg_args, 81 81 "--trust-model=always", trunk/lib/Brackup/Chunk.pm
r62 r65 5 5 use Carp qw(croak); 6 6 use Digest::SHA1 qw(sha1_hex); 7 use File::Temp qw(tempfile);8 7 9 8 # fields … … 14 13 # sometimes: 15 14 # digest if calculated "type:hex" 15 # _rawdigest "type:hex" of not encrypted, not compressed. 16 16 # _chunkref if calculated, scalarref 17 17 # backlength if calculated … … 63 63 } 64 64 65 sub chunkref { 66 my $self = shift; 67 return $self->{_chunkref} if $self->{_chunkref}; 65 # returns true if encrypted, false otherwise 66 sub encrypted { 67 my $self = shift; 68 return $self->root->gpg_rcpt ? 1 : 0; 69 } 70 71 sub raw_digest { 72 my $self = shift; 73 return $self->{_rawdigest} if $self->{_rawdigest}; 74 my $rchunk = $self->raw_chunkref; 75 return $self->{_rawdigest} = "sha1:" . sha1_hex($$rchunk); 76 } 77 78 sub raw_chunkref { 79 my $self = shift; 80 return $self->{_raw_chunkref} if $self->{_raw_chunkref}; 68 81 69 82 my $data; 70 my $dataref_with_learning = sub {71 # record the encrypted/72 $self->_learn_lengthdigest_from_data(\$data);73 return $self->{_chunkref} = \$data;74 };75 76 my $root = $self->root;77 my $gpg_rcpt = $root->gpg_rcpt;78 79 83 my $fullpath = $self->{file}->fullpath; 80 84 open(my $fh, $fullpath) or die "Failed to open $fullpath: $!\n"; 81 85 seek($fh, $self->{offset}, 0) or die "Couldn't seek: $!\n"; 82 read($fh, $data, $self->{length}) or die "Failed to read: $!\n"; 86 my $rv = read($fh, $data, $self->{length}) 87 or die "Failed to read: $!\n"; 88 unless ($rv == $self->{length}) { 89 Carp::confess("Read $rv bytes, not $self->{length}"); 90 } 91 92 return $self->{_raw_chunkref} = \$data; 93 } 94 95 sub chunkref { 96 my $self = shift; 97 return $self->{_chunkref} if $self->{_chunkref}; 98 99 my $dataref_and_cache_it = sub { 100 my $ref = shift; 101 $self->_learn_lengthdigest_from_data($ref); 102 return $self->{_chunkref} = $ref; 103 }; 83 104 84 105 # non-encrypting case 85 return $dataref_with_learning->() unless $gpg_rcpt; 86 87 # FIXME: let users control where their temp files go? 88 my ($tmpfh, $tmpfn) = tempfile(); 89 print $tmpfh $data or die "failed to print: $!"; 90 close $tmpfh or die "failed to close: $!\n"; 91 die "size not right" unless -s $tmpfn == $self->{length}; 92 93 my ($etmpfh, $etmpfn) = tempfile(); 94 95 system($self->root->gpg_path, $self->root->gpg_args, 96 "--recipient", $gpg_rcpt, 97 "--trust-model=always", 98 "--batch", 99 "--encrypt", 100 "--output=$etmpfn", 101 "--yes", $tmpfn) 102 and die "Failed to run gpg: $!\n"; 103 open (my $enc_fh, $etmpfn) or die "Failed to open $etmpfn: $!\n"; 104 $data = do { local $/; <$enc_fh>; }; 105 106 return $dataref_with_learning->(); 106 unless ($self->encrypted) { 107 return $dataref_and_cache_it->($self->raw_chunkref); 108 } 109 110 # encrypting case. 111 my $enc = $self->root->encrypt($self->raw_chunkref); 112 return $dataref_and_cache_it->(\$enc); 107 113 } 108 114 … … 111 117 my $self = shift; 112 118 delete $self->{_chunkref}; 119 delete $self->{_raw_chunkref}; 113 120 } 114 121 … … 207 214 } 208 215 216 sub compressed { 217 my $self = shift; 218 return 0; # FUTURE: support compressed chunks 219 } 220 221 sub meta_contents { 222 my $self = shift; 223 my $meta = ""; 224 my $addmeta = sub { 225 my ($k, $v) = @_; 226 $meta .= "$k: $v\n"; 227 }; 228 229 if ($self->encrypted) { 230 $addmeta->("chunkcachekey", $self->cachekey); 231 } 232 233 if ($self->compressed) { 234 #FUTURE: 235 #$addmeta->("compression", "gz"); 236 } 237 238 if ($self->encrypted || $self->compressed) { 239 $addmeta->("raw_digest", $self->raw_digest); 240 } 241 242 if ($self->encrypted) { 243 $meta = $self->root->encrypt($meta); 244 } 245 246 return $meta; 247 248 } 249 209 250 1; trunk/lib/Brackup/Root.pm
r64 r65 5 5 use File::Find; 6 6 use Brackup::DigestDatabase; 7 use File::Temp qw(tempfile); 7 8 8 9 sub new { … … 165 166 166 167 $pop_dir->() while @dir_stack; 167 168 168 } 169 170 # given data (scalar or scalarref), returns encrypted data 171 sub encrypt { 172 my ($self, $data) = @_; 173 my $gpg_rcpt = $self->gpg_rcpt 174 or Carp::confess("Encryption not setup for this root"); 175 176 $data = \$data unless ref $data; 177 178 # FIXME: let users control where their temp files go? 179 my ($tmpfh, $tmpfn) = tempfile(); 180 print $tmpfh $$data 181 or die "failed to print: $!"; 182 close $tmpfh 183 or die "failed to close: $!\n"; 184 Carp::confess("size not right") 185 unless -s $tmpfn == length $$data; 186 187 my ($etmpfh, $etmpfn) = tempfile(); 188 189 system($self->gpg_path, $self->gpg_args, 190 "--recipient", $gpg_rcpt, 191 "--trust-model=always", 192 "--batch", 193 "--encrypt", 194 "--output=$etmpfn", 195 "--yes", $tmpfn) 196 and die "Failed to run gpg: $!\n"; 197 open (my $enc_fh, $etmpfn) or die "Failed to open $etmpfn: $!\n"; 198 return do { local $/; <$enc_fh>; }; 169 199 } 170 200 trunk/lib/Brackup/Target/Filesystem.pm
r41 r65 30 30 } 31 31 32 sub chunkpath {33 my ($self, $dig ) = @_;32 sub _diskpath { 33 my ($self, $dig, $ext) = @_; 34 34 my @parts; 35 35 my $fulldig = $dig; … … 39 39 push @parts, $1; 40 40 } 41 return $self->{path} . "/" . join("/", @parts) . "/$fulldig.chunk"; 41 return $self->{path} . "/" . join("/", @parts) . "/$fulldig.$ext"; 42 } 43 44 sub chunkpath { 45 my ($self, $dig) = @_; 46 return $self->_diskpath($dig, "chunk"); 47 } 48 49 sub metapath { 50 my ($self, $dig) = @_; 51 return $self->_diskpath($dig, "meta"); 42 52 } 43 53 … … 80 90 } 81 91 92 if (my $mstr = $chunk->meta_contents) { 93 my $mpath = $self->metapath($dig); 94 open (my $fh, ">$mpath") or die "Failed to open $path for writing: $!\n"; 95 print $fh $mstr; 96 close($fh) or die "Failed to close $mpath\n"; 97 } 98 82 99 return 1; 83 100 }
