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) = @_;

lib/Brackup/Mount.pm  view on Meta::CPAN

            return (1024, scalar(keys %$meta)+0, 0, 0, 0, 1024);
        },
    );
}

sub _build_metadata {
    my ($class, $header, $p) = @_;

    my %meta = ();

    while (my $it = $p->readline) {
        my $path = $it->{Path};
        my $type = $it->{Type} || 'f';
        my $mode = oct($it->{Mode} || ($type eq 'd' ? $header->{DefaultDirMode} : $header->{DefaultFileMode}));

        # Add the type to the mode
        $mode |= ({
            d => S_IFDIR,
            f => S_IFREG,
            l => S_IFLNK,
        }->{$type} || 0);

        my $record = {
            path => $path,
            type => $type,
            mode => $mode,
            size => $it->{Size},
            mtime => $it->{Mtime},
            atime => $it->{Atime},
            link => $it->{Link},
            child_nodes => [],
            fh => undef,
            digest => $it->{Digest},
            opencount => 0,
            meta => $it,
        };

        my $parent_path = undef;
        my $local_name = undef;

        if ($path =~ m!^(.+)/([^/]+)$!) {
            $parent_path = '/'.$1;
            $local_name = $2;
        }
        else {
            $parent_path = '/';
            $local_name = $path;
        }

        my $path_key = $path eq '.' ? '/' : '/'.$path;

        $meta{$path_key} = $record;
        push @{$meta{$parent_path}{child_nodes}}, $local_name;
    }

    return \%meta;
}

=head1 NAME

Brackup::Mount - Mount a backup as a usable filesystem using FUSE

=cut

1;



( run in 0.630 second using v1.01-cache-2.11-cpan-ceb78f64989 )