X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=lib%2FCloudStore%2FAPI.pm;h=39a27cd5e9ac5c627d85bcf6e68431a53d8f5dbc;hb=03d21c8b5c3ce89af9fd2b4bb5730d7af995baf3;hp=9ac973a9339be265b9473b02f043156a07fe8e2c;hpb=d5f7e65abeed1a2dab636d91dc3c8c0d35d1f552;p=cloudstore.git diff --git a/lib/CloudStore/API.pm b/lib/CloudStore/API.pm index 9ac973a..39a27cd 100644 --- a/lib/CloudStore/API.pm +++ b/lib/CloudStore/API.pm @@ -9,29 +9,55 @@ use base qw(CloudStore::Gearman CloudStore::MD5sum); use File::Path qw(make_path remove_tree); use File::Find; use Data::Dump qw(dump); +use Carp qw(confess cluck); sub new { my ($class,$slice) = @_; - my ( undef, $dir, $port, undef ) = getgrnam($slice); - die "can't find group $slice: $!" unless $dir && $port; + cluck "DEPRICIATED $slice specified" if $slice; + my $self = { passwd => '/var/lib/extrausers/passwd', - PORT => $port, - SLICE => $dir, }; bless $self, $class; - $self->{md5} = $self->user_info('md5'); + $self->{md5} = $self->user_info("md5") || die "can't find user md5"; +=for removed + $self->{md5}->{dir} = "$dir/md5"; + if ( ! -e $self->{md5}->{dir} ) { + make_path $self->{md5}->{dir}, { uid => $self->{md5}->{uid}, gid => $self->{md5}->{gid} }; + warn "## CREATED md5pool $self->{md5}->{dir}\n"; + } +=cut return $self; } +sub slice_dir_port { + my ($self,$slice) = @_; + my ( undef, $dir, $port, undef ) = getgrnam($slice); + die "getgrnam $slice: $!" if $!; + warn "# slice_dir_port $slice = $dir $port\n"; + return ( $dir, $port ); +} + +sub dir2gearman { + my $self = shift; + my $dir = shift; + $dir =~ s/\W+/_/g; + $dir =~ s/^_+//; + $dir =~ s{_\d+$}{}; + return join('_', $dir, @_); +} + sub user_info { my ($self,$login) = @_; + confess "need login" unless $login; + my @n = qw/ login passwd uid gid quota comment gecos dir shell expire /; my @p = $login =~ m/^\d+$/ ? getpwuid $login : getpwnam $login; + die "user_info $login: $@" if $@; my $user; $user->{$_} = shift @p foreach @n; return $user; @@ -51,27 +77,36 @@ sub create_user { } close($fh); + my $slice = $ENV{SLICE} || 's1'; + $slice =~ s{/.+/(\w+)$}{$1}; + my ( $dir, $port ) = $self->slice_dir_port( $slice ); + + $dir ||= $ENV{SLICE}; + $port ||= 6501; + if ( ! $found ) { $max_uid++; - my $dir = "$self->{SLICE}/$max_uid"; - warn "# create_user $new_email $new_quota = $max_uid $dir"; + $dir .= "/$max_uid"; + warn "# create_user $slice $new_email $new_quota = $max_uid $dir"; open(my $fh, '>>', $self->{passwd}); - print $fh "u$max_uid:$new_passwd:$max_uid:$self->{PORT}:$new_email:$dir:/bin/true\n"; + print $fh "u$max_uid:$new_passwd:$max_uid:$port:$new_email:$dir:/bin/true\n"; close($fh); $found = $max_uid; mkdir $dir; - chown $max_uid, $self->{PORT}, $dir; + chown $max_uid, $port, $dir; - open($fh, '>', "$dir/.meta/secrets"); + my $path = "$dir/.meta/secrets"; + $self->mkbasepath($path); + open($fh, '>', $path); print $fh "u$max_uid:$new_passwd\n"; close $fh; } # FIXME update quota only on create? - $self->gearman_do( 'narada_s1_quota_set' => "$found $new_quota" ); + $self->gearman_do( $self->dir2gearman( $dir, 'quota', 'set' ) => "$found $new_quota" ); - return $found; + return 'u' . $found; } sub mkbasepath { @@ -99,7 +134,7 @@ sub user_dir { warn "# user_dir created $path\n"; } - warn "## user_dir $path"; + #warn "### user_dir $path"; return $path; } @@ -113,7 +148,9 @@ sub append_meta { my $log = shift @_; my $user = shift @_; my $path = $self->user_dir( $user => $log ); - my $line = join('#',@_); + my $delimiter = '#'; + $delimiter = ' ' if $log =~ m/md5sum$/; + my $line = join($delimiter,@_); open(my $fh, '>>', $path); print $fh "$line\n"; close $fh; @@ -133,7 +170,7 @@ sub usage { $sum->{_usage} += $v[1]; } my ( $usage, $quota ) = split(/ /, - $self->gearman_do( 'narada_s1_quota_get' => $user->{uid} ) + $self->gearman_do( $self->dir2gearman( $user->{dir}, 'quota', 'get' ) => $user->{uid} ) ); $sum->{_usage} += $usage; $sum->{_quota} = $quota; @@ -145,6 +182,7 @@ sub send_file { my ( $self, $f_uid,$f_path, $t_uid,$t_path ) = @_; my $f = $self->user_info($f_uid); + die "FIXME not on current slice" if $f->{dir} !~ m/^$ENV{SLICE}/; my $t = $self->user_info($t_uid); my $f_full = "$f->{dir}/$f_path"; @@ -164,15 +202,58 @@ sub send_file { $self->delete( $t, $t_path ) if -e $t_full; - link $f_full, $t_full; - $self->append( $t, 'recv', -s $t_full, $f->{uid}, $t_path ); + my $size = -s $f_full; + my $md5; + + my $ok; + { + no autodie qw(link); + $ok = link $f_full, $t_full + }; + if ( ! $ok || $! =~ m/cross-link/ ) { + $ok = symlink $f_full, $t_full; + } else { + $size = -s $t_full; + + if ( $f->{uid} == $self->{md5}->{uid} ) { + $md5 = $f_path; # we don't have local md5sum db for md5 user! + } else { + $md5 = $self->md5_get($f_full); + } + + } + + if ( $ok ) { + $self->append( $t, 'recv', $size, $f->{uid}, $t_path ); + $self->append_meta('md5sum', $t, $md5 => $t_path ) if $md5; # md5sum for received files! FIXME -- cross-slice md5 + $self->refresh_file_list( $t ); + } + + return $size; } sub rename_file { my ( $self, $user, $from, $to ) = @_; $user = $self->user_info($user) unless ref $user eq 'HASH'; - $self->append( $user, 'rename', $from, $to ); + my $f_full = "$user->{dir}/$from"; + my $t_full = "$user->{dir}/$to"; + + $self->mkbasepath( $t_full, { uid => $user->{uid}, gid => $user->{gid} } ); + my $ok = rename $f_full, $t_full; + + my $md5 = $self->md5_get($t_full); + if ( ! $md5 ) { + warn "ERROR: no md5sum for $from"; + return $ok; # XXX our internal error + } + + $self->append_meta('md5sum', $user, 'rename' => $from ); + $self->append_meta('md5sum', $user, $md5 => $from ); + + $self->refresh_file_list( $user ); + + return $ok; } @@ -205,10 +286,31 @@ sub delete { warn "delete $deleted_size bytes shared\n"; $self->append( $user, 'delete', -$deleted_size, $user->{uid}, $path ); + $self->append_meta('md5sum', $user, 'delete', $path ); + + $self->refresh_file_list( $user ); - $self->md5sum($user)->out( $path ); - return $full_path; } +sub file_size { + my ( $self, $user, $path ) = @_; + $user = $self->user_info($user) unless ref $user eq 'HASH'; + + my $full_path = "$user->{dir}/$path"; + return -s $full_path; +} + +sub refresh_file_list { + my ( $self, $user ) = @_; + $user = $self->user_info($user) unless ref $user eq 'HASH'; + my $full_path = "$user->{dir}/.meta/files"; + if ( -e $full_path ) { + warn "## refresh_file_list $full_path"; + unlink $full_path || warn "unlink $full_path: $!"; + } else { + warn "## refresh_file_list $full_path missing"; + } +} + 1;