1 package CloudStore::Store;
7 use File::Path qw(make_path);
9 use Digest::MD5 qw(md5_base64);
10 use Data::Dump qw(dump);
23 $self->{db} = tie %md5, 'BerkeleyDB::Hash', -Filename => '/tmp/md5.db', -Flags => DB_CREATE;
26 warn "# new ",dump $self if $ENV{DEBUG};
32 my ( $self,$data ) = @_;
36 my ( $self,$data ) = @_;
40 my ( $self,$data ) = @_;
42 # if ( my $old = $self->file_get( $data ) ) {
43 # $self->usage_decr( $data );
46 $self->new_file($data);
50 my ( $self,$data ) = @_;
51 # $self->file_set($data);
52 # $self->usage_incr($data);
56 my ( $self, $data ) = @_;
57 # $self->usage_decr( $data );
61 my ( $self, $data ) = @_;
66 my ( $self, $data ) = @_;
68 warn "# new_link ",dump $data;
70 if ( $data->{file} =~ m{^(.*/?)\.send/([^/]+)/(.+)$} ) {
71 my ( $dir, $to, $name ) = ( $1, $2, $3 );
72 my $path = "users/$data->{login}/blob/" . $data->{file};
73 my $link_to = readlink $path;
75 if ( $link_to =~ s{^\Q/rsyncd-munged/\E}{/} ) {
78 $s =~ s{/[^/]+$}{}; # strip filename
79 while ( $link_to =~ s{/../}{/} ) {
80 $s =~ s{/[^/]+$}{} || die "can't strip $s";
81 warn "## simplify $s $link_to\n";
85 my $d = "users/$to/blob";
87 warn "ERROR: no to user $to in $d";
92 # $name can contain directories so we must create them
94 $to_dir =~ s{/[^/]+$}{};
95 make_path $to_dir if ! -e $to_dir;
98 warn "ERROR: can't find source $s";
101 warn "link $s -> $d\n";
104 my ($l,$f) = ($1,$2) if $s =~ m{users/([^/]+)/blob/(.+)};
106 # my $origin = $self->file_get({
110 # $self->new_file($origin);
111 warn "INFO: sent file ",dump($l,$f);
112 my $md5 = $self->{md5}->{$s} || die "no md5 for $s";
113 $self->{md5}->{$d} = $md5;
118 warn "ERROR: can't SEND To:$to Name:$name Link:$link_to";
124 my ( $self,$data ) = @_;
126 my $blob = "users/$data->{login}/blob";
127 my $path = "$blob/$data->{file}";
129 if ( $data->{itemize} =~ m/^[c>]([fdL])/ ) { # received change/create
132 if ( $type eq 'f' ) {
133 $self->modify_file( $data );
134 $self->dedup( $data, $path );
135 } elsif ( $type eq 'd' ) {
136 $self->make_dir( $data );
137 } elsif ( $type eq 'L' ) {
138 $self->new_link( $data );
140 die "unknown type $type ", dump $data;
142 } elsif ( $data->{itemize} =~ m/\*deleting/ ) {
143 $self->remove_file($data);
149 my ( $self, $path, $md5 ) = @_;
151 my $pool = 'md5'; # FIXME sharding?
152 mkdir $pool unless -e $pool;
154 if ( -e "$pool/$md5" ) {
155 warn "dedup hit $md5 $path\n";
156 my $dedup = $path . '.dedup';
157 rename $path, $dedup;
158 link "$pool/$md5", $path;
162 link $path, "$pool/$md5";
165 $self->{md5}->{$path} = $md5;
166 warn "++ $md5 $path\n";
169 my $empty_md5 = " " x 32;
172 my ( $self, $data, $path ) = @_;
174 if ( $data->{file} =~ /^(.+\/)?md5sum$/ ) {
177 warn "IMPORT ", $data->{file}, "\n";
178 open(my $md5sum, '<', $path);
181 my ( $md5, $file ) = split(/\s+/,$_,2);
182 if ( ! -e "md5/$md5" ) {
183 warn "MISSING $md5 $file\n";
186 my $new = "users/$data->{login}/blob/$dir$file";
188 # create path from md5sum file
189 my $only_dir = $1 if $new =~ m{^(.+)/[^/]+$};
190 make_path $only_dir unless -d $only_dir;
191 $imported += link "md5/$md5", $new;
193 login => $data->{login},
194 host => $data->{host},
195 file => $dir . $file,
199 $self->new_file($fake);
200 warn "import from $path ",dump($fake);
202 $self->md5pool( $new => $md5 );
205 print "INFO imported $imported files from ",dump($data);
208 if ( $data->{md5} ne $empty_md5 ) {
209 $self->md5pool( $path => $data->{md5} );
211 warn "empty md5", dump $data;