1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
#!/usr/bin/perl
use strict;
use warnings;
use Sys::Virt;
use Fcntl;
my $FILE;
sub download_handler {
my $st = shift;
my $data = shift;
my $nbytes = shift;
return syswrite FILE, $data, $nbytes;
}
sub download_hole_handler {
my $st = shift;
my $offset = shift;
my $pos = sysseek FILE, $offset, Fcntl::SEEK_CUR or die "Unable to seek in $FILE: $!";
truncate FILE, $pos;
}
sub download {
my $vol = shift;
my $st = shift;
my $filename = shift;
my $offset = 0;
my $length = 0;
open FILE, ">$filename" or die "unable to create $filename: $!";
eval {
$vol->download($st, $offset, $length, Sys::Virt::StorageVol::VOL_DOWNLOAD_SPARSE_STREAM);
$st->sparse_recv_all(\&download_handler, \&download_hole_handler);
$st->finish();
};
if ($@) {
unlink $filename if $@;
close FILE;
die $@;
}
close FILE or die "cannot save $filename: $!"
}
sub upload_handler {
my $st = $_[0];
my $nbytes = $_[2];
return sysread FILE, $_[1], $nbytes;
}
sub upload_hole_handler {
my $st = shift;
my $in_data;
my $section_len;
# HACK, Perl lacks SEEK_DATA and SEEK_HOLE.
my $SEEK_DATA = 3;
my $SEEK_HOLE = 4;
my $cur = sysseek FILE, 0, Fcntl::SEEK_CUR;
eval {
my $data = sysseek FILE, $cur, $SEEK_DATA;
# There are three options:
# 1) $data == $cur; $cur is in data
# 2) $data > $cur; $cur is in a hole, next data at $data
# 3) $data < 0; either $cur is in trailing hole, or $cur is beyond EOF.
if (!defined($data)) {
# case 3
$in_data = 0;
my $end = sysseek FILE, 0, Fcntl::SEEK_END or die "Unable to get EOF position: $!";
$section_len = $end - $cur;
} elsif ($data > $cur) {
#case 2
$in_data = 0;
$section_len = $data - $cur;
} else {
#case 1
my $hole = sysseek FILE, $data, $SEEK_HOLE;
if (!defined($hole) or $hole eq $data) {
die "Blah";
}
$in_data = 1;
$section_len = $hole - $data;
}
};
die "Blah" if ($@);
# reposition file back
sysseek FILE, $cur, Fcntl::SEEK_SET;
return ($in_data, $section_len);
}
sub upload_skip_handler {
my $st = shift;
my $offset = shift;
sysseek FILE, $offset, Fcntl::SEEK_CUR or die "Unable to seek in $FILE";
return 0;
}
sub upload {
my $vol = shift;
my $st = shift;
my $filename = shift;
my $offset = 0;
my $length = 0;
open FILE, "<$filename" or die "unable to open $filename: $!";
eval {
$vol->upload($st, $offset, $length, Sys::Virt::StorageVol::VOL_UPLOAD_SPARSE_STREAM);
$st->sparse_send_all(\&upload_handler, \&upload_hole_handler, \&upload_skip_handler);
$st->finish();
};
if ($@) {
close FILE;
die $@;
}
close FILE or die "cannot close $filename: $!"
}
die "syntax: $0 URI --download/--upload VOLUME FILE" unless int(@ARGV) == 4;
my $uri = shift @ARGV;
my $action = shift @ARGV;
my $volpath = shift @ARGV;
my $filename = shift @ARGV;
my $c = Sys::Virt->new(uri => $uri) or die "Unable to connect to $uri";
my $vol = $c->get_storage_volume_by_key($volpath) or die "No such volume";
my $st = $c->new_stream();
if ($action eq "--download") {
download($vol, $st, $filename);
} elsif ($action eq "--upload") {
upload($vol, $st, $filename);
} else {
die "unknown action $action";
}
|