package PVE::GuestImport;

use strict;
use warnings;

use File::Path;

use PVE::Storage;
use PVE::Tools qw(run_command);

sub extract_disk_from_import_file {
    my ($volid, $vmid, $target_storeid) = @_;

    my ($source_storeid, $volname) = PVE::Storage::parse_volume_id($volid);
    $target_storeid //= $source_storeid;
    my $cfg = PVE::Storage::config();

    my ($vtype, $name, undef, undef, undef, undef, $fmt) =
        PVE::Storage::parse_volname($cfg, $volid);

    die "only files with content type 'import' can be extracted\n"
        if $vtype ne 'import';

    die "only files from 'ova' format can be extracted\n"
        if $fmt !~ m/^ova\+/;

    # extract the inner file from the name
    my $archive_volid;
    my $inner_file;
    my $inner_fmt;
    if ($name =~ m!^(.*\.ova)/(${PVE::Storage::SAFE_CHAR_WITH_WHITESPACE_CLASS_RE}+)$!) {
        $archive_volid = "$source_storeid:import/$1";
        $inner_file = $2;
        ($inner_fmt) = $fmt =~ /^ova\+(.*)$/;
    } else {
        die "cannot extract $volid - invalid volname $volname\n";
    }

    die "cannot determine format of '$volid'\n" if !$inner_fmt;

    my $ova_path = PVE::Storage::path($cfg, $archive_volid);

    my $tmpdir = PVE::Storage::get_image_dir($cfg, $target_storeid, $vmid);
    my $pid = $$;
    $tmpdir .= "/tmp_${pid}_${vmid}";
    mkpath $tmpdir;

    my $source_path = "$tmpdir/$inner_file";
    my $target_path;
    my $target_volid;
    eval {
        run_command([
            'tar',
            '-x',
            '--force-local',
            '--no-same-owner',
            '-C',
            $tmpdir,
            '-f',
            $ova_path,
            $inner_file,
        ]);

        # check for symlinks and other non regular files
        if (-l $source_path || !-f $source_path) {
            die
                "extracted file '$inner_file' from archive '$archive_volid' is not a regular file\n";
        }

        # check potentially untrusted image file!
        PVE::Storage::file_size_info($source_path, undef, $inner_fmt, 1);

        # create temporary 1M image that will get overwritten by the rename
        # to reserve the filename and take care of locking
        $target_volid =
            PVE::Storage::vdisk_alloc($cfg, $target_storeid, $vmid, $inner_fmt, undef, 1024);
        $target_path = PVE::Storage::path($cfg, $target_volid);

        print "renaming $source_path to $target_path\n";

        rename($source_path, $target_path) or die "unable to move - $!\n";
    };
    if (my $err = $@) {
        File::Path::remove_tree($tmpdir);
        die "error during extraction: $err\n";
    }

    File::Path::remove_tree($tmpdir);

    return $target_volid;
}

1;
