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