]> git.proxmox.com Git - pve-storage.git/blame - PVE/Storage/Plugin.pm
Add apiinfo helper to pvesm
[pve-storage.git] / PVE / Storage / Plugin.pm
CommitLineData
1dc01b9f
DM
1package PVE::Storage::Plugin;
2
3use strict;
4use warnings;
074b2cb4 5
ff9c5451 6use Fcntl ':mode';
7fc619d5 7use File::chdir;
1dc01b9f 8use File::Path;
712e27f1 9use File::Basename;
9c629b3e 10use Time::Local qw(timelocal);
074b2cb4 11
1dc01b9f
DM
12use PVE::Tools qw(run_command);
13use PVE::JSONSchema qw(get_standard_option);
14use PVE::Cluster qw(cfs_register_file);
15
80699b1d
TL
16use JSON;
17
1dc01b9f
DM
18use base qw(PVE::SectionConfig);
19
766cfd9a
WB
20our @COMMON_TAR_FLAGS = qw(
21 --one-file-system
22 -p --sparse --numeric-owner --acls
23 --xattrs --xattrs-include=user.* --xattrs-include=security.capability
24 --warning=no-file-ignored --warning=no-xattr-write
25);
26
d7875239
WL
27our @SHARED_STORAGE = (
28 'iscsi',
29 'nfs',
30 'cifs',
31 'rbd',
e34ce144 32 'cephfs',
d7875239
WL
33 'iscsidirect',
34 'glusterfs',
35 'zfs',
36 'drbd');
37
c0535aa7
SI
38our $MAX_VOLUMES_PER_GUEST = 1024;
39
045ae0a7 40cfs_register_file ('storage.cfg',
1dc01b9f
DM
41 sub { __PACKAGE__->parse_config(@_); },
42 sub { __PACKAGE__->write_config(@_); });
43
35533c68 44
1dc01b9f
DM
45my $defaultData = {
46 propertyList => {
47 type => { description => "Storage type." },
f7621c01
DM
48 storage => get_standard_option('pve-storage-id',
49 { completion => \&PVE::Storage::complete_storage }),
1dc01b9f
DM
50 nodes => get_standard_option('pve-node-list', { optional => 1 }),
51 content => {
daccf21e
FG
52 description => "Allowed content types.\n\nNOTE: the value " .
53 "'rootdir' is used for Containers, and value 'images' for VMs.\n",
1dc01b9f
DM
54 type => 'string', format => 'pve-storage-content-list',
55 optional => 1,
98437f4c 56 completion => \&PVE::Storage::complete_content_type,
1dc01b9f
DM
57 },
58 disable => {
59 description => "Flag to disable the storage.",
60 type => 'boolean',
61 optional => 1,
62 },
63 maxfiles => {
64 description => "Maximal number of backup files per VM. Use '0' for unlimted.",
65 type => 'integer',
66 minimum => 0,
67 optional => 1,
68 },
69 shared => {
70 description => "Mark storage as shared.",
71 type => 'boolean',
72 optional => 1,
73 },
045ae0a7 74 'format' => {
daccf21e 75 description => "Default image format.",
1dc01b9f
DM
76 type => 'string', format => 'pve-storage-format',
77 optional => 1,
78 },
79 },
80};
81
82sub content_hash_to_string {
83 my $hash = shift;
84
85 my @cta;
86 foreach my $ct (keys %$hash) {
87 push @cta, $ct if $hash->{$ct};
045ae0a7 88 }
1dc01b9f
DM
89
90 return join(',', @cta);
91}
92
93sub valid_content_types {
94 my ($type) = @_;
95
96 my $def = $defaultData->{plugindata}->{$type};
97
98 return {} if !$def;
99
100 return $def->{content}->[0];
101}
102
103sub default_format {
104 my ($scfg) = @_;
105
106 my $type = $scfg->{type};
107 my $def = $defaultData->{plugindata}->{$type};
045ae0a7 108
1dc01b9f
DM
109 my $def_format = 'raw';
110 my $valid_formats = [ $def_format ];
111
112 if (defined($def->{format})) {
113 $def_format = $scfg->{format} || $def->{format}->[1];
114 $valid_formats = [ sort keys %{$def->{format}->[0]} ];
115 }
045ae0a7 116
1dc01b9f
DM
117 return wantarray ? ($def_format, $valid_formats) : $def_format;
118}
119
120PVE::JSONSchema::register_format('pve-storage-path', \&verify_path);
121sub verify_path {
122 my ($path, $noerr) = @_;
123
124 # fixme: exclude more shell meta characters?
125 # we need absolute paths
126 if ($path !~ m|^/[^;\(\)]+|) {
127 return undef if $noerr;
128 die "value does not look like a valid absolute path\n";
129 }
130 return $path;
131}
132
133PVE::JSONSchema::register_format('pve-storage-server', \&verify_server);
134sub verify_server {
135 my ($server, $noerr) = @_;
136
6bf617a9
WB
137 if (!(PVE::JSONSchema::pve_verify_ip($server, 1) ||
138 PVE::JSONSchema::pve_verify_dns_name($server, 1)))
139 {
1dc01b9f
DM
140 return undef if $noerr;
141 die "value does not look like a valid server name or IP address\n";
142 }
143 return $server;
144}
145
5dca5c7c
DM
146PVE::JSONSchema::register_format('pve-storage-vgname', \&parse_lvm_name);
147sub parse_lvm_name {
148 my ($name, $noerr) = @_;
149
97cf933f 150 if ($name !~ m/^[a-z0-9][a-z0-9\-\_\.]*[a-z0-9]$/i) {
5dca5c7c
DM
151 return undef if $noerr;
152 die "lvm name '$name' contains illegal characters\n";
153 }
154
155 return $name;
156}
157
1dc01b9f
DM
158# fixme: do we need this
159#PVE::JSONSchema::register_format('pve-storage-portal', \&verify_portal);
160#sub verify_portal {
161# my ($portal, $noerr) = @_;
162#
163# # IP with optional port
164# if ($portal !~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(:\d+)?$/) {
165# return undef if $noerr;
166# die "value does not look like a valid portal address\n";
167# }
168# return $portal;
169#}
170
171PVE::JSONSchema::register_format('pve-storage-portal-dns', \&verify_portal_dns);
172sub verify_portal_dns {
173 my ($portal, $noerr) = @_;
174
175 # IP or DNS name with optional port
1689e627 176 if (!PVE::Tools::parse_host_and_port($portal)) {
1dc01b9f
DM
177 return undef if $noerr;
178 die "value does not look like a valid portal address\n";
179 }
180 return $portal;
181}
182
183PVE::JSONSchema::register_format('pve-storage-content', \&verify_content);
184sub verify_content {
185 my ($ct, $noerr) = @_;
186
187 my $valid_content = valid_content_types('dir'); # dir includes all types
045ae0a7 188
1dc01b9f
DM
189 if (!$valid_content->{$ct}) {
190 return undef if $noerr;
191 die "invalid content type '$ct'\n";
192 }
193
194 return $ct;
195}
196
197PVE::JSONSchema::register_format('pve-storage-format', \&verify_format);
198sub verify_format {
199 my ($fmt, $noerr) = @_;
200
35533c68 201 if ($fmt !~ m/(raw|qcow2|vmdk|subvol)/) {
1dc01b9f
DM
202 return undef if $noerr;
203 die "invalid format '$fmt'\n";
204 }
205
206 return $fmt;
207}
208
209PVE::JSONSchema::register_format('pve-storage-options', \&verify_options);
210sub verify_options {
211 my ($value, $noerr) = @_;
212
213 # mount options (see man fstab)
214 if ($value !~ m/^\S+$/) {
215 return undef if $noerr;
216 die "invalid options '$value'\n";
217 }
218
219 return $value;
220}
221
a7f3d909
DM
222PVE::JSONSchema::register_format('pve-volume-id', \&parse_volume_id);
223sub parse_volume_id {
224 my ($volid, $noerr) = @_;
225
226 if ($volid =~ m/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):(.+)$/i) {
227 return wantarray ? ($1, $2) : $1;
228 }
229 return undef if $noerr;
230 die "unable to parse volume ID '$volid'\n";
231}
232
1dc01b9f
DM
233
234sub private {
235 return $defaultData;
236}
237
238sub parse_section_header {
239 my ($class, $line) = @_;
240
241 if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
242 my ($type, $storeid) = (lc($1), $2);
243 my $errmsg = undef; # set if you want to skip whole section
244 eval { PVE::JSONSchema::parse_storage_id($storeid); };
245 $errmsg = $@ if $@;
246 my $config = {}; # to return additional attributes
247 return ($type, $storeid, $errmsg, $config);
248 }
249 return undef;
250}
251
252sub decode_value {
253 my ($class, $type, $key, $value) = @_;
254
255 my $def = $defaultData->{plugindata}->{$type};
256
257 if ($key eq 'content') {
258 my $valid_content = $def->{content}->[0];
045ae0a7 259
1dc01b9f
DM
260 my $res = {};
261
262 foreach my $c (PVE::Tools::split_list($value)) {
263 if (!$valid_content->{$c}) {
703de49e
WL
264 warn "storage does not support content type '$c'\n";
265 next;
1dc01b9f
DM
266 }
267 $res->{$c} = 1;
045ae0a7 268 }
1dc01b9f
DM
269
270 if ($res->{none} && scalar (keys %$res) > 1) {
271 die "unable to combine 'none' with other content types\n";
272 }
273
274 return $res;
275 } elsif ($key eq 'format') {
276 my $valid_formats = $def->{format}->[0];
277
278 if (!$valid_formats->{$value}) {
703de49e
WL
279 warn "storage does not support format '$value'\n";
280 next;
1dc01b9f
DM
281 }
282
283 return $value;
284 } elsif ($key eq 'nodes') {
285 my $res = {};
286
287 foreach my $node (PVE::Tools::split_list($value)) {
288 if (PVE::JSONSchema::pve_verify_node_name($node)) {
289 $res->{$node} = 1;
290 }
291 }
292
293 # fixme:
294 # no node restrictions for local storage
295 #if ($storeid && $storeid eq 'local' && scalar(keys(%$res))) {
296 # die "storage '$storeid' does not allow node restrictions\n";
297 #}
298
299 return $res;
300 }
301
302 return $value;
303}
304
305sub encode_value {
306 my ($class, $type, $key, $value) = @_;
307
308 if ($key eq 'nodes') {
309 return join(',', keys(%$value));
310 } elsif ($key eq 'content') {
311 my $res = content_hash_to_string($value) || 'none';
312 return $res;
313 }
314
315 return $value;
316}
317
318sub parse_config {
319 my ($class, $filename, $raw) = @_;
320
321 my $cfg = $class->SUPER::parse_config($filename, $raw);
322 my $ids = $cfg->{ids};
323
324 # make sure we have a reasonable 'local:' storage
dc6ff39f 325 # we want 'local' to be always the same 'type' (on all cluster nodes)
1dc01b9f
DM
326 if (!$ids->{local} || $ids->{local}->{type} ne 'dir' ||
327 ($ids->{local}->{path} && $ids->{local}->{path} ne '/var/lib/vz')) {
328 $ids->{local} = {
329 type => 'dir',
330 priority => 0, # force first entry
331 path => '/var/lib/vz',
332 maxfiles => 0,
d1eb35ea 333 content => { images => 1, rootdir => 1, vztmpl => 1, iso => 1, snippets => 1},
1dc01b9f
DM
334 };
335 }
045ae0a7 336
1dc01b9f
DM
337 # make sure we have a path
338 $ids->{local}->{path} = '/var/lib/vz' if !$ids->{local}->{path};
339
340 # remove node restrictions for local storage
341 delete($ids->{local}->{nodes});
342
343 foreach my $storeid (keys %$ids) {
344 my $d = $ids->{$storeid};
345 my $type = $d->{type};
346
347 my $def = $defaultData->{plugindata}->{$type};
348
349 if ($def->{content}) {
350 $d->{content} = $def->{content}->[1] if !$d->{content};
351 }
d7875239 352 if (grep { $_ eq $type } @SHARED_STORAGE) {
1dc01b9f
DM
353 $d->{shared} = 1;
354 }
355 }
356
357 return $cfg;
358}
359
360# Storage implementation
361
3932ca0d
TL
362# called during addition of storage (before the new storage config got written)
363# die to abort additon if there are (grave) problems
364# NOTE: runs in a storage config *locked* context
365sub on_add_hook {
366 my ($class, $storeid, $scfg, %param) = @_;
367
368 # do nothing by default
369}
370
0ff4cfea
DM
371# called during storage configuration update (before the updated storage config got written)
372# die to abort the update if there are (grave) problems
373# NOTE: runs in a storage config *locked* context
374sub on_update_hook {
375 my ($class, $storeid, $scfg, %param) = @_;
376
377 # do nothing by default
378}
379
3932ca0d
TL
380# called during deletion of storage (before the new storage config got written)
381# and if the activate check on addition fails, to cleanup all storage traces
382# which on_add_hook may have created.
383# die to abort deletion if there are (very grave) problems
384# NOTE: runs in a storage config *locked* context
385sub on_delete_hook {
386 my ($class, $storeid, $scfg) = @_;
387
388 # do nothing by default
389}
390
1dc01b9f
DM
391sub cluster_lock_storage {
392 my ($class, $storeid, $shared, $timeout, $func, @param) = @_;
393
394 my $res;
395 if (!$shared) {
396 my $lockid = "pve-storage-$storeid";
397 my $lockdir = "/var/lock/pve-manager";
398 mkdir $lockdir;
045ae0a7 399 $res = PVE::Tools::lock_file("$lockdir/$lockid", $timeout, $func, @param);
1dc01b9f
DM
400 die $@ if $@;
401 } else {
402 $res = PVE::Cluster::cfs_lock_storage($storeid, $timeout, $func, @param);
403 die $@ if $@;
045ae0a7 404 }
1dc01b9f
DM
405 return $res;
406}
407
408sub parse_name_dir {
409 my $name = shift;
410
35533c68
DM
411 if ($name =~ m!^((base-)?[^/\s]+\.(raw|qcow2|vmdk|subvol))$!) {
412 return ($1, $3, $2); # (name, format, isBase)
1dc01b9f
DM
413 }
414
415 die "unable to parse volume filename '$name'\n";
416}
417
418sub parse_volname {
419 my ($class, $volname) = @_;
420
2502b33b
DM
421 if ($volname =~ m!^(\d+)/(\S+)/(\d+)/(\S+)$!) {
422 my ($basedvmid, $basename) = ($1, $2);
423 parse_name_dir($basename);
424 my ($vmid, $name) = ($3, $4);
35533c68
DM
425 my (undef, $format, $isBase) = parse_name_dir($name);
426 return ('images', $name, $vmid, $basename, $basedvmid, $isBase, $format);
2502b33b 427 } elsif ($volname =~ m!^(\d+)/(\S+)$!) {
1dc01b9f 428 my ($vmid, $name) = ($1, $2);
35533c68
DM
429 my (undef, $format, $isBase) = parse_name_dir($name);
430 return ('images', $name, $vmid, undef, undef, $isBase, $format);
4c693491 431 } elsif ($volname =~ m!^iso/([^/]+$PVE::Storage::iso_extension_re)$!) {
1dc01b9f 432 return ('iso', $1);
13d2cb79 433 } elsif ($volname =~ m!^vztmpl/([^/]+\.tar\.[gx]z)$!) {
1dc01b9f
DM
434 return ('vztmpl', $1);
435 } elsif ($volname =~ m!^rootdir/(\d+)$!) {
436 return ('rootdir', $1, $1);
a22854e5 437 } elsif ($volname =~ m!^backup/([^/]+(\.(tar|tar\.gz|tar\.lzo|tgz|vma|vma\.gz|vma\.lzo)))$!) {
1dc01b9f 438 my $fn = $1;
4cb6e060 439 if ($fn =~ m/^vzdump-(openvz|lxc|qemu)-(\d+)-.+/) {
1dc01b9f
DM
440 return ('backup', $fn, $2);
441 }
442 return ('backup', $fn);
7c7ae12f
DC
443 } elsif ($volname =~ m!^snippets/([^/]+)$!) {
444 return ('snippets', $1);
1dc01b9f
DM
445 }
446
447 die "unable to parse directory volume name '$volname'\n";
448}
449
045ae0a7 450my $vtype_subdirs = {
1dc01b9f
DM
451 images => 'images',
452 rootdir => 'private',
453 iso => 'template/iso',
454 vztmpl => 'template/cache',
455 backup => 'dump',
7c7ae12f 456 snippets => 'snippets',
1dc01b9f
DM
457};
458
459sub get_subdir {
460 my ($class, $scfg, $vtype) = @_;
461
462 my $path = $scfg->{path};
463
464 die "storage definintion has no path\n" if !$path;
465
466 my $subdir = $vtype_subdirs->{$vtype};
467
468 die "unknown vtype '$vtype'\n" if !defined($subdir);
469
045ae0a7 470 return "$path/$subdir";
1dc01b9f
DM
471}
472
08480ce7 473sub filesystem_path {
e67069eb 474 my ($class, $scfg, $volname, $snapname) = @_;
1dc01b9f 475
e67069eb
DM
476 my ($vtype, $name, $vmid, undef, undef, $isBase, $format) =
477 $class->parse_volname($volname);
478
479 # Note: qcow2/qed has internal snapshot, so path is always
480 # the same (with or without snapshot => same file).
481 die "can't snapshot this image format\n"
482 if defined($snapname) && $format !~ m/^(qcow2|qed)$/;
1dc01b9f
DM
483
484 my $dir = $class->get_subdir($scfg, $vtype);
485
486 $dir .= "/$vmid" if $vtype eq 'images';
487
488 my $path = "$dir/$name";
489
490 return wantarray ? ($path, $vmid, $vtype) : $path;
491}
492
08480ce7 493sub path {
e67069eb 494 my ($class, $scfg, $volname, $storeid, $snapname) = @_;
08480ce7 495
e67069eb 496 return $class->filesystem_path($scfg, $volname, $snapname);
08480ce7
DM
497}
498
2502b33b
DM
499sub create_base {
500 my ($class, $storeid, $scfg, $volname) = @_;
501
502 # this only works for file based storage types
5510f5c9 503 die "storage definition has no path\n" if !$scfg->{path};
2502b33b 504
35533c68 505 my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
2502b33b
DM
506 $class->parse_volname($volname);
507
508 die "create_base on wrong vtype '$vtype'\n" if $vtype ne 'images';
509
510 die "create_base not possible with base image\n" if $isBase;
511
08480ce7 512 my $path = $class->filesystem_path($scfg, $volname);
2502b33b 513
35533c68
DM
514 my ($size, undef, $used, $parent) = file_size_info($path);
515 die "file_size_info on '$volname' failed\n" if !($format && defined($size));
2502b33b
DM
516
517 die "volname '$volname' contains wrong information about parent\n"
518 if $basename && (!$parent || $parent ne "../$basevmid/$basename");
519
520 my $newname = $name;
521 $newname =~ s/^vm-/base-/;
522
523 my $newvolname = $basename ? "$basevmid/$basename/$vmid/$newname" :
524 "$vmid/$newname";
525
08480ce7 526 my $newpath = $class->filesystem_path($scfg, $newvolname);
2502b33b
DM
527
528 die "file '$newpath' already exists\n" if -f $newpath;
529
1a3459ac 530 rename($path, $newpath) ||
2502b33b
DM
531 die "rename '$path' to '$newpath' failed - $!\n";
532
c803c396 533 # We try to protect base volume
2502b33b 534
c803c396
DM
535 chmod(0444, $newpath); # nobody should write anything
536
537 # also try to set immutable flag
538 eval { run_command(['/usr/bin/chattr', '+i', $newpath]); };
539 warn $@ if $@;
1a3459ac 540
2502b33b
DM
541 return $newvolname;
542}
543
83a40b8d
TL
544my $get_vm_disk_number = sub {
545 my ($disk_name, $scfg, $vmid, $suffix) = @_;
345f8981 546
dd1fa860
TL
547 my $disk_regex = qr/(vm|base)-$vmid-disk-(\d+)$suffix/;
548
345f8981 549 my $type = $scfg->{type};
f4cc2c4a 550 my $def = { %{$defaultData->{plugindata}->{$type}} };
345f8981 551
dd1fa860
TL
552 my $valid = $def->{format}[0];
553 if ($valid->{subvol}) {
554 $disk_regex = qr/(vm|base|subvol|basevol)-$vmid-disk-(\d+)/;
555 }
345f8981 556
83a40b8d
TL
557 if ($disk_name =~ m/$disk_regex/) {
558 return $2;
345f8981 559 }
83a40b8d
TL
560
561 return undef;
562};
345f8981
SI
563
564sub get_next_vm_diskname {
565 my ($disk_list, $storeid, $vmid, $fmt, $scfg, $add_fmt_suffix) = @_;
566
345f8981
SI
567 $fmt //= '';
568 my $prefix = ($fmt eq 'subvol') ? 'subvol' : 'vm';
569 my $suffix = $add_fmt_suffix ? ".$fmt" : '';
570
83a40b8d
TL
571 my $disk_ids = {};
572 foreach my $disk (@$disk_list) {
573 my $disknum = $get_vm_disk_number->($disk, $scfg, $vmid, $suffix);
574 $disk_ids->{$disknum} = 1 if defined($disknum);
575 }
576
59fa9fd6 577 for (my $i = 0; $i < $MAX_VOLUMES_PER_GUEST; $i++) {
345f8981
SI
578 if (!$disk_ids->{$i}) {
579 return "$prefix-$vmid-disk-$i$suffix";
580 }
581 }
582
583 die "unable to allocate an image name for VM $vmid in storage '$storeid'\n"
584}
585
a44c0147
FE
586sub find_free_diskname {
587 my ($class, $storeid, $scfg, $vmid, $fmt, $add_fmt_suffix) = @_;
588
589 my $disks = $class->list_images($storeid, $scfg, $vmid);
2502b33b 590
01e872db 591 my $disk_list = [ map { $_->{volid} } @$disks ];
2502b33b 592
a44c0147
FE
593 return get_next_vm_diskname($disk_list, $storeid, $vmid, $fmt, $scfg, $add_fmt_suffix);
594}
2502b33b
DM
595
596sub clone_image {
f236eaf8 597 my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
2502b33b
DM
598
599 # this only works for file based storage types
600 die "storage definintion has no path\n" if !$scfg->{path};
601
35533c68 602 my ($vtype, $basename, $basevmid, undef, undef, $isBase, $format) =
2502b33b
DM
603 $class->parse_volname($volname);
604
605 die "clone_image on wrong vtype '$vtype'\n" if $vtype ne 'images';
606
f236eaf8
SP
607 die "this storage type does not support clone_image on snapshot\n" if $snap;
608
35533c68
DM
609 die "this storage type does not support clone_image on subvolumes\n" if $format eq 'subvol';
610
f236eaf8 611 die "clone_image only works on base images\n" if !$isBase;
1dc01b9f
DM
612
613 my $imagedir = $class->get_subdir($scfg, 'images');
614 $imagedir .= "/$vmid";
615
616 mkpath $imagedir;
617
a44c0147 618 my $name = $class->find_free_diskname($imagedir, $scfg, $vmid, "qcow2", 1);
2502b33b
DM
619
620 warn "clone $volname: $vtype, $name, $vmid to $name (base=../$basevmid/$basename)\n";
621
622 my $newvol = "$basevmid/$basename/$vmid/$name";
623
08480ce7 624 my $path = $class->filesystem_path($scfg, $newvol);
2502b33b 625
1a3459ac 626 # Note: we use relative paths, so we need to call chdir before qemu-img
2502b33b 627 eval {
7fc619d5 628 local $CWD = $imagedir;
2502b33b 629
1a3459ac 630 my $cmd = ['/usr/bin/qemu-img', 'create', '-b', "../$basevmid/$basename",
2502b33b 631 '-f', 'qcow2', $path];
1a3459ac 632
2502b33b
DM
633 run_command($cmd);
634 };
635 my $err = $@;
1dc01b9f 636
2502b33b
DM
637 die $err if $err;
638
639 return $newvol;
640}
641
642sub alloc_image {
643 my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
644
645 my $imagedir = $class->get_subdir($scfg, 'images');
646 $imagedir .= "/$vmid";
647
648 mkpath $imagedir;
649
a44c0147 650 $name = $class->find_free_diskname($imagedir, $scfg, $vmid, $fmt, 1) if !$name;
1a3459ac 651
1dc01b9f
DM
652 my (undef, $tmpfmt) = parse_name_dir($name);
653
045ae0a7 654 die "illegal name '$name' - wrong extension for format ('$tmpfmt != '$fmt')\n"
1dc01b9f
DM
655 if $tmpfmt ne $fmt;
656
657 my $path = "$imagedir/$name";
658
659 die "disk image '$path' already exists\n" if -e $path;
660
35533c68
DM
661 if ($fmt eq 'subvol') {
662 # only allow this if size = 0, so that user knows what he is doing
663 die "storage does not support subvol quotas\n" if $size != 0;
3918b96a 664
1f5734bb
WB
665 my $old_umask = umask(0022);
666 my $err;
667 mkdir($path) or $err = "unable to create subvol '$path' - $!\n";
668 umask $old_umask;
669 die $err if $err;
35533c68
DM
670 } else {
671 my $cmd = ['/usr/bin/qemu-img', 'create'];
045ae0a7 672
35533c68 673 push @$cmd, '-o', 'preallocation=metadata' if $fmt eq 'qcow2';
3918b96a 674
35533c68 675 push @$cmd, '-f', $fmt, $path, "${size}K";
1dc01b9f 676
a8ec2f02
CE
677 eval { run_command($cmd, errmsg => "unable to create image"); };
678 if ($@) {
679 unlink $path;
680 rmdir $imagedir;
681 die "$@";
682 }
35533c68 683 }
3918b96a 684
1dc01b9f
DM
685 return "$vmid/$name";
686}
687
688sub free_image {
35533c68 689 my ($class, $storeid, $scfg, $volname, $isBase, $format) = @_;
1dc01b9f 690
08480ce7 691 my $path = $class->filesystem_path($scfg, $volname);
1dc01b9f 692
f5451f28
DC
693 if ($isBase) {
694 # try to remove immutable flag
695 eval { run_command(['/usr/bin/chattr', '-i', $path]); };
696 warn $@ if $@;
697 }
698
4a7d2222 699 if (defined($format) && ($format eq 'subvol')) {
35533c68
DM
700 File::Path::remove_tree($path);
701 } else {
de0cd0c2 702 if (!(-f $path || -l $path)) {
481f6177 703 warn "disk image '$path' does not exist\n";
35533c68
DM
704 return undef;
705 }
1dc01b9f 706
35533c68
DM
707 unlink($path) || die "unlink '$path' failed - $!\n";
708 }
712e27f1
CE
709
710 # try to cleanup directory to not clutter storage with empty $vmid dirs if
711 # all images from a guest got deleted
712 my $dir = dirname($path);
713 rmdir($dir);
3918b96a 714
1dc01b9f
DM
715 return undef;
716}
717
718sub file_size_info {
719 my ($filename, $timeout) = @_;
720
51eee96d
DM
721 my @fs = stat($filename);
722 my $mode = $fs[2];
723 my $ctime = $fs[10];
724
725 if (S_ISDIR($mode)) {
726 return wantarray ? (0, 'subvol', 0, undef, $ctime) : 1;
35533c68 727 }
3918b96a 728
af0335e8 729 my $json = '';
1dbbd5ab 730 eval {
80699b1d
TL
731 run_command(['/usr/bin/qemu-img', 'info', '--output=json', $filename],
732 timeout => $timeout,
733 outfunc => sub { $json .= shift },
734 errfunc => sub { warn "$_[0]\n" }
735 );
1dbbd5ab 736 };
aa4594b1
TM
737 warn $@ if $@;
738
80699b1d
TL
739 my $info = eval { decode_json($json) };
740 warn "could not parse qemu-img info command output for '$filename'\n" if $@;
af0335e8 741
80699b1d 742 my ($size, $format, $used, $parent) = $info->@{qw(virtual-size format actual-size backing-filename)};
af0335e8 743
51eee96d 744 return wantarray ? ($size, $format, $used, $parent, $ctime) : $size;
1dc01b9f
DM
745}
746
e47e548e
AD
747sub volume_size_info {
748 my ($class, $scfg, $storeid, $volname, $timeout) = @_;
08480ce7 749 my $path = $class->filesystem_path($scfg, $volname);
e47e548e
AD
750 return file_size_info($path, $timeout);
751
752}
753
81f5058c
AD
754sub volume_resize {
755 my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
756
6d788031 757 die "can't resize this image format\n" if $volname !~ m/\.(raw|qcow2)$/;
81f5058c
AD
758
759 return 1 if $running;
760
08480ce7 761 my $path = $class->filesystem_path($scfg, $volname);
81f5058c 762
0589e5f9
WL
763 my $format = ($class->parse_volname($volname))[6];
764
765 my $cmd = ['/usr/bin/qemu-img', 'resize', '-f', $format, $path , $size];
81f5058c 766
1059cc99 767 run_command($cmd, timeout => 10);
81f5058c
AD
768
769 return undef;
770}
771
7dcb0697 772sub volume_snapshot {
f5640e7d 773 my ($class, $scfg, $storeid, $volname, $snap) = @_;
7dcb0697 774
6d788031 775 die "can't snapshot this image format\n" if $volname !~ m/\.(qcow2|qed)$/;
7dcb0697 776
08480ce7 777 my $path = $class->filesystem_path($scfg, $volname);
7dcb0697
AD
778
779 my $cmd = ['/usr/bin/qemu-img', 'snapshot','-c', $snap, $path];
780
3f13fd7d 781 run_command($cmd);
7dcb0697
AD
782
783 return undef;
784}
785
1597f1f9 786sub volume_rollback_is_possible {
3918b96a 787 my ($class, $scfg, $storeid, $volname, $snap) = @_;
1597f1f9 788
3918b96a 789 return 1;
1597f1f9
WL
790}
791
41dffa85
AD
792sub volume_snapshot_rollback {
793 my ($class, $scfg, $storeid, $volname, $snap) = @_;
794
6d788031 795 die "can't rollback snapshot this image format\n" if $volname !~ m/\.(qcow2|qed)$/;
41dffa85 796
08480ce7 797 my $path = $class->filesystem_path($scfg, $volname);
41dffa85
AD
798
799 my $cmd = ['/usr/bin/qemu-img', 'snapshot','-a', $snap, $path];
800
3f13fd7d 801 run_command($cmd);
41dffa85
AD
802
803 return undef;
804}
805
6000a061
AD
806sub volume_snapshot_delete {
807 my ($class, $scfg, $storeid, $volname, $snap, $running) = @_;
808
6d788031 809 die "can't delete snapshot for this image format\n" if $volname !~ m/\.(qcow2|qed)$/;
6000a061
AD
810
811 return 1 if $running;
812
08480ce7 813 my $path = $class->filesystem_path($scfg, $volname);
6000a061 814
399581a2
WB
815 $class->deactivate_volume($storeid, $scfg, $volname, $snap, {});
816
6000a061
AD
817 my $cmd = ['/usr/bin/qemu-img', 'snapshot','-d', $snap, $path];
818
3f13fd7d 819 run_command($cmd);
6000a061
AD
820
821 return undef;
822}
823
7118dd91
DM
824sub storage_can_replicate {
825 my ($class, $scfg, $storeid, $format) = @_;
826
827 return 0;
828}
829
f884fe11 830sub volume_has_feature {
e6f4eed4 831 my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running, $opts) = @_;
f884fe11
AD
832
833 my $features = {
5649ccfe
AD
834 snapshot => { current => { qcow2 => 1}, snap => { qcow2 => 1} },
835 clone => { base => {qcow2 => 1, raw => 1, vmdk => 1} },
35533c68 836 template => { current => {qcow2 => 1, raw => 1, vmdk => 1, subvol => 1} },
5649ccfe 837 copy => { base => {qcow2 => 1, raw => 1, vmdk => 1},
22b8cf97
AD
838 current => {qcow2 => 1, raw => 1, vmdk => 1},
839 snap => {qcow2 => 1} },
baafddbd
DC
840 sparseinit => { base => {qcow2 => 1, raw => 1, vmdk => 1},
841 current => {qcow2 => 1, raw => 1, vmdk => 1} },
f884fe11
AD
842 };
843
e6f4eed4
FE
844 # clone_image creates a qcow2 volume
845 return 0 if $feature eq 'clone' &&
846 defined($opts->{valid_target_formats}) &&
847 !(grep { $_ eq 'qcow2' } @{$opts->{valid_target_formats}});
848
35533c68 849 my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
dc4f2cb3
AD
850 $class->parse_volname($volname);
851
dc4f2cb3
AD
852 my $key = undef;
853 if($snapname){
2c5a7097 854 $key = 'snap';
dc4f2cb3
AD
855 }else{
856 $key = $isBase ? 'base' : 'current';
f884fe11 857 }
dc4f2cb3
AD
858
859 return 1 if defined($features->{$feature}->{$key}->{$format});
860
f884fe11
AD
861 return undef;
862}
863
1dc01b9f
DM
864sub list_images {
865 my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_;
866
867 my $imagedir = $class->get_subdir($scfg, 'images');
868
869 my ($defFmt, $vaidFmts) = default_format($scfg);
045ae0a7 870 my $fmts = join ('|', @$vaidFmts);
1dc01b9f
DM
871
872 my $res = [];
873
874 foreach my $fn (<$imagedir/[0-9][0-9]*/*>) {
875
876 next if $fn !~ m!^(/.+/(\d+)/([^/]+\.($fmts)))$!;
877 $fn = $1; # untaint
878
879 my $owner = $2;
880 my $name = $3;
1dc01b9f 881
2502b33b 882 next if !$vollist && defined($vmid) && ($owner ne $vmid);
1dc01b9f 883
51eee96d 884 my ($size, $format, $used, $parent, $ctime) = file_size_info($fn);
35533c68 885 next if !($format && defined($size));
2502b33b
DM
886
887 my $volid;
888 if ($parent && $parent =~ m!^../(\d+)/([^/]+\.($fmts))$!) {
889 my ($basevmid, $basename) = ($1, $2);
890 $volid = "$storeid:$basevmid/$basename/$owner/$name";
891 } else {
892 $volid = "$storeid:$owner/$name";
893 }
1dc01b9f 894
2502b33b
DM
895 if ($vollist) {
896 my $found = grep { $_ eq $volid } @$vollist;
897 next if !$found;
1dc01b9f
DM
898 }
899
51eee96d 900 my $info = {
2502b33b 901 volid => $volid, format => $format,
1a3459ac 902 size => $size, vmid => $owner, used => $used, parent => $parent
2502b33b 903 };
51eee96d
DM
904
905 $info->{ctime} = $ctime if $ctime;
906
907 push @$res, $info;
1dc01b9f
DM
908 }
909
910 return $res;
911}
912
c2fc9fbe
DM
913# list templates ($tt = <iso|vztmpl|backup|snippets>)
914my $get_subdir_files = sub {
915 my ($sid, $path, $tt, $vmid) = @_;
916
917 my $res = [];
918
919 foreach my $fn (<$path/*>) {
920
6c25dbd4
TL
921 my ($dev,
922 $ino,
923 $mode,
924 $nlink,
925 $uid,
926 $gid,
927 $rdev,
928 $size,
929 $atime,
930 $mtime,
931 $ctime,
932 $blksize,
933 $blocks
934 ) = stat($fn);
ff9c5451
DM
935
936 next if S_ISDIR($mode);
c2fc9fbe
DM
937
938 my $info;
939
940 if ($tt eq 'iso') {
4c693491 941 next if $fn !~ m!/([^/]+$PVE::Storage::iso_extension_re)$!i;
c2fc9fbe
DM
942
943 $info = { volid => "$sid:iso/$1", format => 'iso' };
944
945 } elsif ($tt eq 'vztmpl') {
946 next if $fn !~ m!/([^/]+\.tar\.([gx]z))$!;
947
948 $info = { volid => "$sid:vztmpl/$1", format => "t$2" };
949
950 } elsif ($tt eq 'backup') {
c2fc9fbe 951 next if defined($vmid) && $fn !~ m/\S+-$vmid-\S+/;
ce8b24a9 952 next if $fn !~ m!/([^/]+\.(tar|tar\.gz|tar\.lzo|tgz|vma|vma\.gz|vma\.lzo))$!;
c2fc9fbe 953
1b396425
DC
954 my $format = $2;
955 $info = { volid => "$sid:backup/$1", format => $format };
956
9c629b3e
DM
957 if ($fn =~ m!^vzdump\-(?:lxc|qemu)\-(?:[1-9][0-9]{2,8})\-(\d{4})_(\d{2})_(\d{2})\-(\d{2})_(\d{2})_(\d{2})\.${format}$!) {
958 my $epoch = timelocal($6, $5, $4, $3, $2-1, $1 - 1900);
959 $info->{ctime} = $epoch;
960 }
961
93afc379 962 if (defined($vmid) || $fn =~ m!\-([1-9][0-9]{2,8})\-[^/]+\.${format}$!) {
1b396425
DC
963 $info->{vmid} = $vmid // $1;
964 }
965
c2fc9fbe
DM
966
967 } elsif ($tt eq 'snippets') {
968
969 $info = {
970 volid => "$sid:snippets/". basename($fn),
971 format => 'snippet',
972 };
973 }
974
ff9c5451
DM
975 $info->{size} = $size;
976 $info->{ctime} //= $ctime;
c2fc9fbe
DM
977
978 push @$res, $info;
979 }
980
981 return $res;
982};
983
984sub list_volumes {
985 my ($class, $storeid, $scfg, $vmid, $content_types) = @_;
986
987 my $res = [];
5dae1a31 988 my $vmlist = PVE::Cluster::get_vmlist();
a4e41b0b 989 foreach my $type (@$content_types) {
c2fc9fbe
DM
990 my $data;
991
a4e41b0b 992 if ($type eq 'images' || $type eq 'rootdir') {
c2fc9fbe 993 $data = $class->list_images($storeid, $scfg, $vmid);
a14e0a5e 994 } elsif ($scfg->{path}) {
a4e41b0b 995 my $path = $class->get_subdir($scfg, $type);
a14e0a5e 996
a4e41b0b 997 if ($type eq 'iso' && !defined($vmid)) {
a14e0a5e 998 $data = $get_subdir_files->($storeid, $path, 'iso');
a4e41b0b 999 } elsif ($type eq 'vztmpl'&& !defined($vmid)) {
a14e0a5e 1000 $data = $get_subdir_files->($storeid, $path, 'vztmpl');
a4e41b0b 1001 } elsif ($type eq 'backup') {
a14e0a5e 1002 $data = $get_subdir_files->($storeid, $path, 'backup', $vmid);
a4e41b0b 1003 } elsif ($type eq 'snippets') {
a14e0a5e
FG
1004 $data = $get_subdir_files->($storeid, $path, 'snippets');
1005 }
c2fc9fbe
DM
1006 }
1007
1008 next if !$data;
1009
1010 foreach my $item (@$data) {
a4e41b0b 1011 if ($type eq 'images' || $type eq 'rootdir') {
a420842d
FG
1012 my $vminfo = $vmlist->{ids}->{$item->{vmid}};
1013 my $vmtype;
1014 if (defined($vminfo)) {
1015 $vmtype = $vminfo->{type};
1016 }
5dae1a31
TM
1017 if (defined($vmtype) && $vmtype eq 'lxc') {
1018 $item->{content} = 'rootdir';
1019 } else {
1020 $item->{content} = 'images';
1021 }
0877df04 1022 next if $type ne $item->{content};
5dae1a31 1023 } else {
a4e41b0b 1024 $item->{content} = $type;
5dae1a31
TM
1025 }
1026
c2fc9fbe
DM
1027 push @$res, $item;
1028 }
1029 }
1030
1031 return $res;
1032}
1033
1dc01b9f
DM
1034sub status {
1035 my ($class, $storeid, $scfg, $cache) = @_;
1036
1037 my $path = $scfg->{path};
1038
1039 die "storage definintion has no path\n" if !$path;
045ae0a7 1040
1dc01b9f
DM
1041 my $timeout = 2;
1042 my $res = PVE::Tools::df($path, $timeout);
1043
1044 return undef if !$res || !$res->{total};
1045
1046 return ($res->{total}, $res->{avail}, $res->{used}, 1);
1047}
1048
aefe82ea 1049sub volume_snapshot_list {
8b622c2d 1050 my ($class, $scfg, $storeid, $volname) = @_;
aefe82ea
WL
1051
1052 # implement in subclass
1053 die "Volume_snapshot_list is not implemented for $class";
1054
636ac5b8 1055 # return an empty array if dataset does not exist.
aefe82ea
WL
1056}
1057
1dc01b9f
DM
1058sub activate_storage {
1059 my ($class, $storeid, $scfg, $cache) = @_;
1060
1061 my $path = $scfg->{path};
1062
1063 die "storage definintion has no path\n" if !$path;
1064
e53050ed
EK
1065 # this path test may hang indefinitely on unresponsive mounts
1066 my $timeout = 2;
1067 if (! PVE::Tools::run_fork_with_timeout($timeout, sub {-d $path})) {
1068 die "unable to activate storage '$storeid' - " .
1069 "directory '$path' does not exist or is unreachable\n";
1070 }
1071
1dc01b9f 1072
c7616abc
WB
1073 return if defined($scfg->{mkdir}) && !$scfg->{mkdir};
1074
1dc01b9f
DM
1075 if (defined($scfg->{content})) {
1076 foreach my $vtype (keys %$vtype_subdirs) {
6bcc16d7
DM
1077 # OpenVZMigrate uses backup (dump) dir
1078 if (defined($scfg->{content}->{$vtype}) ||
1079 ($vtype eq 'backup' && defined($scfg->{content}->{'rootdir'}))) {
1080 my $subdir = $class->get_subdir($scfg, $vtype);
1081 mkpath $subdir if $subdir ne $path;
1082 }
1dc01b9f
DM
1083 }
1084 }
1085}
1086
1087sub deactivate_storage {
1088 my ($class, $storeid, $scfg, $cache) = @_;
1089
1090 # do nothing by default
1091}
1092
40d69893
DM
1093sub map_volume {
1094 my ($class, $storeid, $scfg, $volname, $snapname) = @_;
1095
d560ec28
ML
1096 my ($path) = $class->path($scfg, $volname, $storeid, $snapname);
1097 return $path;
40d69893
DM
1098}
1099
1100sub unmap_volume {
1101 my ($class, $storeid, $scfg, $volname, $snapname) = @_;
1102
1103 return 1;
1104}
1105
1dc01b9f 1106sub activate_volume {
02e797b8 1107 my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
1dc01b9f 1108
02e797b8 1109 my $path = $class->filesystem_path($scfg, $volname, $snapname);
1dc01b9f
DM
1110
1111 # check is volume exists
1112 if ($scfg->{path}) {
1113 die "volume '$storeid:$volname' does not exist\n" if ! -e $path;
1114 } else {
1115 die "volume '$storeid:$volname' does not exist\n" if ! -b $path;
1116 }
1117}
1118
1119sub deactivate_volume {
02e797b8 1120 my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
1dc01b9f
DM
1121
1122 # do nothing by default
1123}
1124
c9eeac01
AD
1125sub check_connection {
1126 my ($class, $storeid, $scfg) = @_;
1127 # do nothing by default
1128 return 1;
1129}
1130
e1f6cb39
DM
1131# Import/Export interface:
1132# Any path based storage is assumed to support 'raw' and 'tar' streams, so
1133# the default implementations will return this if $scfg->{path} is set,
1134# mimicking the old PVE::Storage::storage_migrate() function.
1135#
1136# Plugins may fall back to PVE::Storage::Plugin::volume_{export,import}...
1137# functions in case the format doesn't match their specialized
1138# implementations to reuse the raw/tar code.
1139#
1140# Format specification:
1141# The following formats are all prefixed with image information in the form
1142# of a 64 bit little endian unsigned integer (pack('Q<')) in order to be able
1143# to preallocate the image on storages which require it.
1144#
1145# raw+size: (image files only)
1146# A raw binary data stream such as produced via `dd if=TheImageFile`.
1147# qcow2+size, vmdk: (image files only)
1148# A raw qcow2/vmdk/... file such as produced via `dd if=some.qcow2` for
1149# files which are already in qcow2 format, or via `qemu-img convert`.
1150# Note that these formats are only valid with $with_snapshots being true.
1151# tar+size: (subvolumes only)
6b3a4a25
WB
1152# A GNU tar stream containing just the inner contents of the subvolume.
1153# This does not distinguish between the contents of a privileged or
1154# unprivileged container. In other words, this is from the root user
1155# namespace's point of view with no uid-mapping in effect.
1156# As produced via `tar -C vm-100-disk-1.subvol -cpf TheOutputFile.dat .`
e1f6cb39
DM
1157
1158# Plugins may reuse these helpers. Changes to the header format should be
1159# reflected by changes to the function prototypes.
1160sub write_common_header($$) {
1161 my ($fh, $image_size_in_bytes) = @_;
1162 syswrite($fh, pack("Q<", $image_size_in_bytes), 8);
1163}
1164
1165sub read_common_header($) {
1166 my ($fh) = @_;
1167 sysread($fh, my $size, 8);
1168 $size = unpack('Q<', $size);
f105c176 1169 die "import: no size found in export header, aborting.\n" if !defined($size);
b5eff97d 1170 die "import: got a bad size (not a multiple of 1K), aborting.\n" if ($size&1023);
e1f6cb39
DM
1171 # Size is in bytes!
1172 return $size;
1173}
1174
47f37b53
WB
1175# Export a volume into a file handle as a stream of desired format.
1176sub volume_export {
1177 my ($class, $scfg, $storeid, $fh, $volname, $format, $snapshot, $base_snapshot, $with_snapshots) = @_;
e1f6cb39
DM
1178 if ($scfg->{path} && !defined($snapshot) && !defined($base_snapshot)) {
1179 my $file = $class->path($scfg, $volname, $storeid)
1180 or goto unsupported;
1181 my ($size, $file_format) = file_size_info($file);
1182
1183 if ($format eq 'raw+size') {
1184 goto unsupported if $with_snapshots || $file_format eq 'subvol';
1185 write_common_header($fh, $size);
1186 if ($file_format eq 'raw') {
1187 run_command(['dd', "if=$file", "bs=4k"], output => '>&'.fileno($fh));
1188 } else {
1189 run_command(['qemu-img', 'convert', '-f', $file_format, '-O', 'raw', $file, '/dev/stdout'],
1190 output => '>&'.fileno($fh));
1191 }
1192 return;
1193 } elsif ($format =~ /^(qcow2|vmdk)\+size$/) {
1194 my $data_format = $1;
1195 goto unsupported if !$with_snapshots || $file_format ne $data_format;
1196 write_common_header($fh, $size);
1197 run_command(['dd', "if=$file", "bs=4k"], output => '>&'.fileno($fh));
1198 return;
1199 } elsif ($format eq 'tar+size') {
1200 goto unsupported if $file_format ne 'subvol';
1201 write_common_header($fh, $size);
6b3a4a25 1202 run_command(['tar', @COMMON_TAR_FLAGS, '-cf', '-', '-C', $file, '.'],
e1f6cb39
DM
1203 output => '>&'.fileno($fh));
1204 return;
1205 }
1206 }
1207 unsupported:
1208 die "volume export format $format not available for $class";
47f37b53
WB
1209}
1210
d390328b
WB
1211sub volume_export_formats {
1212 my ($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) = @_;
e1f6cb39
DM
1213 if ($scfg->{path} && !defined($snapshot) && !defined($base_snapshot)) {
1214 my $file = $class->path($scfg, $volname, $storeid)
1215 or return;
1216 my ($size, $format) = file_size_info($file);
1217
1218 if ($with_snapshots) {
1219 return ($format.'+size') if ($format eq 'qcow2' || $format eq 'vmdk');
1220 return ();
1221 }
1222 return ('tar+size') if $format eq 'subvol';
1223 return ('raw+size');
1224 }
1225 return ();
d390328b
WB
1226}
1227
47f37b53
WB
1228# Import data from a stream, creating a new or replacing or adding to an existing volume.
1229sub volume_import {
1230 my ($class, $scfg, $storeid, $fh, $volname, $format, $base_snapshot, $with_snapshots) = @_;
e1f6cb39
DM
1231
1232 die "volume import format '$format' not available for $class\n"
1233 if $format !~ /^(raw|tar|qcow2|vmdk)\+size$/;
1234 my $data_format = $1;
1235
1236 die "format $format cannot be imported without snapshots\n"
1237 if !$with_snapshots && ($data_format eq 'qcow2' || $data_format eq 'vmdk');
1238 die "format $format cannot be imported with snapshots\n"
1239 if $with_snapshots && ($data_format eq 'raw' || $data_format eq 'tar');
1240
1241 my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $file_format) =
1242 $class->parse_volname($volname);
1243
1244 # XXX: Should we bother with conversion routines at this level? This won't
1245 # happen without manual CLI usage, so for now we just error out...
1246 die "cannot import format $format into a file of format $file_format\n"
1247 if $data_format ne $file_format && !($data_format eq 'tar' && $file_format eq 'subvol');
1248
1249 # Check for an existing file first since interrupting alloc_image doesn't
1250 # free it.
1251 my $file = $class->path($scfg, $volname, $storeid);
1252 die "file '$file' already exists\n" if -e $file;
1253
1254 my ($size) = read_common_header($fh);
1255 $size = int($size/1024);
1256
1257 eval {
1258 my $allocname = $class->alloc_image($storeid, $scfg, $vmid, $file_format, $name, $size);
1259 if ($allocname ne $volname) {
1260 my $oldname = $volname;
1261 $volname = $allocname; # Let the cleanup code know what to free
1262 die "internal error: unexpected allocated name: '$allocname' != '$oldname'\n";
1263 }
1264 my $file = $class->path($scfg, $volname, $storeid)
1265 or die "internal error: failed to get path to newly allocated volume $volname\n";
1266 if ($data_format eq 'raw' || $data_format eq 'qcow2' || $data_format eq 'vmdk') {
1267 run_command(['dd', "of=$file", 'conv=sparse', 'bs=64k'],
1268 input => '<&'.fileno($fh));
1269 } elsif ($data_format eq 'tar') {
6b3a4a25 1270 run_command(['tar', @COMMON_TAR_FLAGS, '-C', $file, '-xf', '-'],
e1f6cb39
DM
1271 input => '<&'.fileno($fh));
1272 } else {
1273 die "volume import format '$format' not available for $class";
1274 }
1275 };
1276 if (my $err = $@) {
1277 eval { $class->free_image($storeid, $scfg, $volname, 0, $file_format) };
1278 warn $@ if $@;
1279 die $err;
1280 }
47f37b53 1281}
e47e548e 1282
d390328b
WB
1283sub volume_import_formats {
1284 my ($class, $scfg, $storeid, $volname, $base_snapshot, $with_snapshots) = @_;
e1f6cb39
DM
1285 if ($scfg->{path} && !defined($base_snapshot)) {
1286 my $format = ($class->parse_volname($volname))[6];
1287 if ($with_snapshots) {
1288 return ($format.'+size') if ($format eq 'qcow2' || $format eq 'vmdk');
1289 return ();
1290 }
1291 return ('tar+size') if $format eq 'subvol';
1292 return ('raw+size');
1293 }
1294 return ();
d390328b
WB
1295}
1296
1dc01b9f 12971;