--- fuse-comp.pl 2007/07/08 13:46:33 4 +++ fuse-comp.pl 2007/07/08 15:04:35 5 @@ -11,6 +11,7 @@ use PerlIO::gzip; use File::Path; use Data::Dump qw/dump/; +use Carp qw/confess/; my $mount = { from => '/tmp/comp', @@ -22,6 +23,9 @@ my $skip_extensions_regex = qr/\.(?:sw[a-z]|gif|png|jpeg|jpg|avi|rar|zip|bz2|gz|tgz|avi|mpeg|mpg|tmp|temp)$/i; +# don't compress files smaller than this +my $min_compress_size = 256; + foreach my $dir ( keys %$mount ) { if ( ! -e $mount->{$dir} ) { warn "created $mount->{$dir}\n"; @@ -65,6 +69,27 @@ return unpack("L", $buff); } +sub unlink_all { + my $file = shift; + foreach my $dir ( keys %$mount ) { + my $path = $mount->{$dir} . '/' . $file; + + map { + my $path = $_; + if ( -e $path ) { + if ( unlink $path ) { + warn "## unlink $path\n" if $debug; + } else { + warn "can't unlink $path: $!\n"; + return 0; + } + } + } [ $path, $path . '.gz' ]; + } + delete( $pending->{$file} ); + return 1; +} + sub x_getattr { my ($file) = fixup(shift); my (@list) = lstat($file); @@ -86,27 +111,33 @@ sub file_copy { my ( $s_opt, $s_path, $d_opt, $d_path ) = @_; warn "## file_copy( $s_opt $s_path $d_opt $d_path )\n"; - open(my $s, $s_opt, $s_path ) || die "can't open $s_path: $!"; - open(my $d, $d_opt, $d_path ) || die "can't open $d_path: $!"; + open(my $s, $s_opt, $s_path ) || confess "can't open $s_path: $!\npending = ", dump( $pending ); + open(my $d, $d_opt, $d_path ) || confess "can't open $d_path: $!"; my $buff; while( read( $s, $buff, 65535 ) ) { - print $d $buff || die "can't write into $d_path: $!"; + print $d $buff || confess "can't write into $d_path: $!"; warn ">> ", length($buff), " bytes, offset ", tell($s), " -> ", tell($d), "\n" if $debug; } close($d) || warn "can't close $d_path: $!"; close($s) || warn "can't close $s_path: $!"; - warn "-- $s_path [", -s $s_path, "]\n >>> $d_path [", -s $d_path, "]\n" if $debug; + warn "-- $s_path [", -s $s_path, "] >>> $d_path [", -s $d_path, "]\n" if $debug; + my ($mode,$uid,$gid,$atime,$mtime) = (stat $s_path)[2,4,5,8,9]; + + chmod $mode, $d_path || warn "chmod( $mode $d_path ) failed: $!\n"; + chown $uid,$gid,$d_path || warn "chown( $uid $gid $d_path ) failed: $!\n"; + utime $atime,$mtime,$d_path || warn "utime( $atime $mtime $d_path ) failed: $!\n"; } sub x_open { my ($file) = shift; my ($mode) = shift; $pending->{$file}->{open}++; + warn "# open( $file, $mode ) pending: ", $pending->{$file}->{open}, "\n"; my $fh; if ( $pending->{$file}->{open} == 1 ) { - warn "# open( $file, $mode )\n"; my $path = fixup($file); my $tmp = $mount->{tmp} . '/' . $file; + warn ">>> open abs path: $path\n"; if ( -e $tmp ) { $path = $tmp; } elsif ( $path =~ m/\.gz$/ ) { @@ -120,8 +151,8 @@ $pending->{$file}->{fh} = $fh; $pending->{$file}->{path} = $path; } elsif ( ! defined( $pending->{$file}->{fh} ) ) { - die "can't find fh for $file ", dump($pending); - } + confess "can't find fh for $file ", dump($pending); + }; return 0; } @@ -131,7 +162,7 @@ my $path = fixup( $file ); return -ENOENT() unless -e $path; my ($fsize) = -s $path; - my $fh = $pending->{$file}->{fh} || die "no fh? ", dump( $pending ); + my $fh = $pending->{$file}->{fh} || confess "no fh? ", dump( $pending ); if(seek($fh,$off,SEEK_SET)) { read($fh,$rv,$bufsize); } @@ -157,7 +188,7 @@ sub err { return (-shift || -$!) } sub x_readlink { return readlink(fixup(shift)); } -sub x_unlink { return unlink(fixup(shift)) ? 0 : -$!; } +sub x_unlink { return unlink_all( shift ) ? 0 : -$! } sub x_symlink { return symlink(shift,fixup(shift)) ? 0 : -$!; } @@ -213,24 +244,30 @@ warn "release $file, not written into\n"; } elsif ( defined( $pending->{$file}->{open} ) && $pending->{$file}->{open} == 1 ) { close( $pending->{$file}->{fh} ) || warn "can't close $file: $!"; + my $path = $pending->{$file}->{path} || confess "no path for $file ? ", dump( $pending ); + my $dest = fixup( $file ); + + # cleanup old compressed copy + if ( $dest =~ /\.gz$/ ) { + warn "## remove old $dest\n"; + unlink_all( $file ) || confess "can't remove $dest: $!"; + $dest =~ s/\.gz$//; + } + if ( $file =~ $skip_extensions_regex ) { warn "release $file $mode -- uncompressed\n"; + file_copy( '<', $path, '>', $dest ) if ( $path ne $dest ); + } elsif ( -s $path < $min_compress_size ) { + warn "release $file -- uncompressed, too small ", -s $path, " bytes\n"; + file_copy( '<', $path, '>', $dest ) if ( $path ne $dest ); } else { warn "release $file $mode -- compressing\n"; - my $path = $pending->{$file}->{path} || die "no path for $file ? ", dump( $pending ); - my $dest = fixup( $file ); - - if ( $dest =~ /\.gz$/ ) { - warn "## remove old $dest\n"; - unlink $dest || die "can't remove $dest: $!"; - $dest =~ s/\.gz$//; - } file_copy( '<', $path, '>:gzip', $dest . '.gz' ); # FIXME add timeout to remove uncompressed version? - unlink $path || warn "can't remove $path: $!"; + unlink_all( $file ) || warn "can't remove $path: $!"; } } else { warn "release $file, but still used ", $pending->{$file}->{open} , " times, delaying compression\n";