# HG changeset patch # User Heiko Schlittermann (JUMPER) # Date 1312407654 -7200 # Node ID 963c6f95589784432a6431dbb380a5f019852e90 initial diff -r 000000000000 -r 963c6f955897 .perltidyrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.perltidyrc Wed Aug 03 23:40:54 2011 +0200 @@ -0,0 +1,2 @@ +--paren-tightness=2 +--square-bracket-tightness=2 diff -r 000000000000 -r 963c6f955897 blockfuse --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/blockfuse Wed Aug 03 23:40:54 2011 +0200 @@ -0,0 +1,99 @@ +#! /usr/bin/perl +# © Heiko Schlittermann +# +# RSYNC can't sync block devices to files (something like +# rsync /dev/sda2 /images/sda2 does not work. There are +# patches for rsync around, but I didn't like to patch +# rsync…) +# +# blockfuse maps the block devices found in /dev/ to regular +# files in your mountpoint. Currently it fakes the mtime to force +# rsync comparing the source and destination! + +# blockfuse /mnt +# rsync --inplace -Pa /mnt/sda1 /images/sda1 + +# Just a short hack, not documentation, nothing else. +# If your're insterested in extending this tool, please tell me, I'm +# willing to put it under some Open Source License. (Currently it's +# not!) + +use 5.010; +use strict; +use warnings; +use POSIX; +use autodie qw(:all); +use Fuse; + +my $mountpoint = shift // die "$0: need mountpoint!\n"; + +if (not `uname -m` =~ /64/) { + warn "Your're probably not running a 64bit system, the devices sizes " + . "will be incorrect!\n"; +} + +fork() and exit 0; + +open(STDIN, " $$); + + +Fuse::main( + mountpoint => $mountpoint, + getattr => \&my_getattr, + getdir => \&my_getdir, + open => \&my_open, + release => \&my_release, + read => \&my_read, +); +exit 0; + +sub my_getattr { + my $path = "/dev" . shift; + my @attr = stat $path; + if (-b $path) { + $attr[9] = time; # fake mtime + $attr[6] = 0; # clear major/minor + $attr[2] |= 0b1000_0000_0000_0000; # set regular file + $attr[2] &= 0b1001_1111_1111_1111; # clear block device + + + eval { + open(my $fh => $path); # size + seek($fh, 0, SEEK_END); + $attr[7] = tell($fh); + }; + + } + return @attr; +} + +sub my_getdir { + my $path = "/dev" . shift; + opendir(my $dh => $path); + (grep { -e "$path/$_" and not -c _ } readdir($dh)), 0; +} + +{ + my %FD; + + sub my_open { + my $path = "/dev" . shift; + eval { open($FD{$path} => $path) }; + return $!; + } + + sub my_release { + my $path = "/dev" . shift; + close delete $FD{$path}; + } + + sub my_read { + my $path = "/dev" . shift; + my ($size, $offset) = @_; + seek($FD{$path}, $offset, SEEK_SET); + my $_; + sysread($FD{$path}, $_, $size); + return $_; + } +}