initial
authorHeiko Schlittermann (JUMPER) <hs@schlittermann.de>
Wed, 03 Aug 2011 23:40:54 +0200
changeset 0 963c6f955897
child 1 ec7a3333127a
initial
.perltidyrc
blockfuse
--- /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
--- /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 <hs@schlittermann.de>
+#
+# 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, "</dev/null");
+setpgid($$ => $$);
+
+
+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 $_;
+    }
+}