Brackup
view release on metacpan or search on metacpan
lib/Brackup/Mount.pm view on Meta::CPAN
package Brackup::Mount;
# Note: This package and the brackup-mount utility that calls it
# both depend on Fuse. Fuse isn't a dependency of the Brackup
# distribution as a whole, so don't load this from anywhere else
# in Brackup.
use Fuse;
use Brackup;
use Brackup::Restore;
use POSIX qw(ENOENT EISDIR EROFS ENOTDIR EBUSY EINVAL O_WRONLY O_RDWR);
use Fcntl qw(S_IFREG S_IFDIR S_IFLNK);
use File::Temp;
use IO::File;
use strict;
sub mount {
my ($class, $metafile, $mountpoint) = @_;
my $p = Brackup::Metafile->open($metafile) or die "Failed to open metafile $metafile";
my $header = $p->readline();
my $driver_header = Brackup::Restore::_driver_meta($header);
my $driver_class = $header->{BackupDriver};
die "No driver specified" unless $driver_class;
eval "use $driver_class; 1;" or die "Failed to load driver ($driver_class) to restore from: $@\n";
my $target = "$driver_class"->new_from_backup_header($driver_header);
my $meta = $class->_build_metadata($header, $p);
my $tempdir = File::Temp::tempdir(CLEANUP => 1);
my $file_temp_path = sub {
my ($record) = @_;
return $tempdir."/".$record->{digest};
};
return Fuse::main(
mountpoint => $mountpoint,
mountopts => "",
threaded => 0,
debug => 0,
getattr => sub {
my ($path) = @_;
my $record = $meta->{$path};
return -ENOENT unless $record;
return (
0, # device number (?)
0, # inode
$record->{mode},
0, # nlink
$<, # uid
0, # gid
0, # rdev
$record->{size},
$record->{atime},
$record->{mtime},
$record->{mtime}, # ctime
1024, # blocksize
1, # blocks
);
},
getdir => sub {
my ($path) = @_;
my $record = $meta->{$path};
return -ENOENT unless $record;
return -ENOTDIR unless $record->{type} eq 'd';
return ('..', @{$record->{child_nodes}}, 0);
},
readlink => sub {
my ($path) = @_;
my $record = $meta->{$path};
return -ENOENT unless $record;
return $record->{link} || 0;
},
open => sub {
my ($path, $mode) = @_;
my $record = $meta->{$path};
return -ENOENT unless $record;
return -EISDIR if $record->{type} eq 'd';
return -EROFS if ($mode & O_WRONLY) || ($mode & O_RDWR);
# Fetch the data relating to this file to a local
# file and open it.
unless ($record->{fh}) {
my $fn = $file_temp_path->($record);
# HACK: Do a bit of grovelling in Brackup::Restore's innards.
# We want to restore the file, and the process is quite involved,
# so we call Brackup::Restore::_restore_file in a kinda wacky
# way to trick it into putting the file where we want it.
my $fake_object = bless {
_target => $target,
_meta => $header,
}, 'Brackup::Restore';
Brackup::Restore::_restore_file($fake_object, $fn, $record->{meta});
my $fh = IO::File->new($fn, '<');
$record->{fh} = $fh;
}
$record->{opencount}++;
return 0;
},
( run in 0.509 second using v1.01-cache-2.11-cpan-e1769b4cff6 )