15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Block driver for the QCOW version 2 format
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 2004-2006 Fabrice Bellard
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a copy
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * of this software and associated documentation files (the "Software"), to deal
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in the Software without restriction, including without limitation the rights
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * copies of the Software, and to permit persons to whom the Software is
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * furnished to do so, subject to the following conditions:
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The above copyright notice and this permission notice shall be included in
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * all copies or substantial portions of the Software.
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE.
235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h"
26e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "block/block_int.h"
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "block/qcow2.h"
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct __attribute__((packed)) QCowSnapshotHeader {
305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* header is 8 byte aligned */
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint64_t l1_table_offset;
325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t l1_size;
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint16_t id_str_size;
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint16_t name_size;
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t date_sec;
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t date_nsec;
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint64_t vm_clock_nsec;
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t vm_state_size;
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t extra_data_size; /* for extension */
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* extra data follows */
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* id_str follows */
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* name follows  */
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} QCowSnapshotHeader;
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qcow2_free_snapshots(BlockDriverState *bs)
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->nb_snapshots; i++) {
55aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        g_free(s->snapshots[i].name);
56aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        g_free(s->snapshots[i].id_str);
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
58aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(s->snapshots);
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->snapshots = NULL;
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->nb_snapshots = 0;
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qcow2_read_snapshots(BlockDriverState *bs)
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshotHeader h;
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshot *sn;
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, id_str_size, name_size;
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int64_t offset;
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t extra_data_size;
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->nb_snapshots) {
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->snapshots = NULL;
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->snapshots_size = 0;
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    offset = s->snapshots_offset;
79aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    s->snapshots = g_malloc0(s->nb_snapshots * sizeof(QCowSnapshot));
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->nb_snapshots; i++) {
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset = align_offset(offset, 8);
82cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (bdrv_pread(bs->file, offset, &h, sizeof(h)) != sizeof(h))
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto fail;
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += sizeof(h);
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn = s->snapshots + i;
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn->l1_table_offset = be64_to_cpu(h.l1_table_offset);
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn->l1_size = be32_to_cpu(h.l1_size);
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn->vm_state_size = be32_to_cpu(h.vm_state_size);
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn->date_sec = be32_to_cpu(h.date_sec);
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn->date_nsec = be32_to_cpu(h.date_nsec);
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn->vm_clock_nsec = be64_to_cpu(h.vm_clock_nsec);
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        extra_data_size = be32_to_cpu(h.extra_data_size);
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        id_str_size = be16_to_cpu(h.id_str_size);
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        name_size = be16_to_cpu(h.name_size);
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += extra_data_size;
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
99aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        sn->id_str = g_malloc(id_str_size + 1);
100cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (bdrv_pread(bs->file, offset, sn->id_str, id_str_size) != id_str_size)
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto fail;
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += id_str_size;
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn->id_str[id_str_size] = '\0';
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
105aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        sn->name = g_malloc(name_size + 1);
106cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (bdrv_pread(bs->file, offset, sn->name, name_size) != name_size)
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto fail;
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += name_size;
1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn->name[name_size] = '\0';
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->snapshots_size = offset - s->snapshots_offset;
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail:
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qcow2_free_snapshots(bs);
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* add at the end of the file a new list of snapshots */
1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int qcow_write_snapshots(BlockDriverState *bs)
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshot *sn;
1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshotHeader h;
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, name_size, id_str_size, snapshots_size;
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint64_t data64;
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t data32;
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int64_t offset, snapshots_offset;
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* compute the size of the snapshots */
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    offset = 0;
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->nb_snapshots; i++) {
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn = s->snapshots + i;
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset = align_offset(offset, 8);
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += sizeof(h);
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += strlen(sn->id_str);
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += strlen(sn->name);
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snapshots_size = offset;
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    offset = snapshots_offset;
142cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (offset < 0) {
143cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return offset;
144cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->nb_snapshots; i++) {
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn = s->snapshots + i;
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memset(&h, 0, sizeof(h));
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h.l1_table_offset = cpu_to_be64(sn->l1_table_offset);
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h.l1_size = cpu_to_be32(sn->l1_size);
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h.vm_state_size = cpu_to_be32(sn->vm_state_size);
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h.date_sec = cpu_to_be32(sn->date_sec);
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h.date_nsec = cpu_to_be32(sn->date_nsec);
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        id_str_size = strlen(sn->id_str);
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        name_size = strlen(sn->name);
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h.id_str_size = cpu_to_be16(id_str_size);
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        h.name_size = cpu_to_be16(name_size);
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset = align_offset(offset, 8);
161cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (bdrv_pwrite_sync(bs->file, offset, &h, sizeof(h)) < 0)
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto fail;
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += sizeof(h);
164cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (bdrv_pwrite_sync(bs->file, offset, sn->id_str, id_str_size) < 0)
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto fail;
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += id_str_size;
167cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (bdrv_pwrite_sync(bs->file, offset, sn->name, name_size) < 0)
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto fail;
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += name_size;
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* update the various header fields */
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    data64 = cpu_to_be64(snapshots_offset);
174cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, snapshots_offset),
175cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                    &data64, sizeof(data64)) < 0)
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    data32 = cpu_to_be32(s->nb_snapshots);
178cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, nb_snapshots),
179cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                    &data32, sizeof(data32)) < 0)
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* free the old snapshot table */
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qcow2_free_clusters(bs, s->snapshots_offset, s->snapshots_size);
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->snapshots_offset = snapshots_offset;
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->snapshots_size = snapshots_size;
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail:
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void find_new_snapshot_id(BlockDriverState *bs,
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 char *id_str, int id_str_size)
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshot *sn;
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, id, id_max = 0;
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->nb_snapshots; i++) {
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn = s->snapshots + i;
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        id = strtoul(sn->id_str, NULL, 10);
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (id > id_max)
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            id_max = id;
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(id_str, id_str_size, "%d", id_max + 1);
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int find_snapshot_by_id(BlockDriverState *bs, const char *id_str)
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->nb_snapshots; i++) {
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!strcmp(s->snapshots[i].id_str, id_str))
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return i;
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int find_snapshot_by_id_or_name(BlockDriverState *bs, const char *name)
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, ret;
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = find_snapshot_by_id(bs, name);
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret >= 0)
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return ret;
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->nb_snapshots; i++) {
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!strcmp(s->snapshots[i].name, name))
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return i;
2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* if no id is provided, a new one is constructed */
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshot *snapshots1, sn1, *sn = &sn1;
2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, ret;
2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint64_t *l1_table = NULL;
241cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int64_t l1_table_offset;
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(sn, 0, sizeof(*sn));
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sn_info->id_str[0] == '\0') {
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* compute a new id */
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str));
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* check that the ID is unique */
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (find_snapshot_by_id(bs, sn_info->id_str) >= 0)
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOENT;
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
254aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    sn->id_str = g_strdup(sn_info->id_str);
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!sn->id_str)
2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
257aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    sn->name = g_strdup(sn_info->name);
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!sn->name)
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->vm_state_size = sn_info->vm_state_size;
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->date_sec = sn_info->date_sec;
2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->date_nsec = sn_info->date_nsec;
2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->vm_clock_nsec = sn_info->vm_clock_nsec;
2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1);
2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0)
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* create the L1 table of the snapshot */
270cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
271cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (l1_table_offset < 0) {
272cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        goto fail;
273cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
274cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
275cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    sn->l1_table_offset = l1_table_offset;
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn->l1_size = s->l1_size;
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
278cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (s->l1_size != 0) {
279aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
280cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else {
281cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        l1_table = NULL;
282cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
283cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->l1_size; i++) {
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        l1_table[i] = cpu_to_be64(s->l1_table[i]);
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
287cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (bdrv_pwrite_sync(bs->file, sn->l1_table_offset,
288cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                    l1_table, s->l1_size * sizeof(uint64_t)) < 0)
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
290aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(l1_table);
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    l1_table = NULL;
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
293aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    snapshots1 = g_malloc((s->nb_snapshots + 1) * sizeof(QCowSnapshot));
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->snapshots) {
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(snapshots1, s->snapshots, s->nb_snapshots * sizeof(QCowSnapshot));
296aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        g_free(s->snapshots);
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->snapshots = snapshots1;
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->snapshots[s->nb_snapshots++] = *sn;
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qcow_write_snapshots(bs) < 0)
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG_ALLOC
304cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    qcow2_check_refcounts(bs);
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail:
308aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(sn->name);
309aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(l1_table);
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* copy the snapshot 'snapshot_name' into the current disk image */
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshot *sn;
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, snapshot_index, l1_size2;
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (snapshot_index < 0)
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOENT;
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn = &s->snapshots[snapshot_index];
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1) < 0)
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qcow2_grow_l1_table(bs, sn->l1_size) < 0)
3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->l1_size = sn->l1_size;
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    l1_size2 = s->l1_size * sizeof(uint64_t);
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* copy the snapshot l1 table to the current l1 table */
334cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (bdrv_pread(bs->file, sn->l1_table_offset,
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                   s->l1_table, l1_size2) != l1_size2)
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
337cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (bdrv_pwrite_sync(bs->file, s->l1_table_offset,
338cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                    s->l1_table, l1_size2) < 0)
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0;i < s->l1_size; i++) {
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        be64_to_cpus(&s->l1_table[i]);
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 1) < 0)
3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG_ALLOC
348cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    qcow2_check_refcounts(bs);
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail:
3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -EIO;
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshot *sn;
3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int snapshot_index, ret;
3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (snapshot_index < 0)
3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOENT;
3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sn = &s->snapshots[snapshot_index];
3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0)
3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return ret;
3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* must update the copied flag on the current cluster offsets */
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0)
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return ret;
3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
375aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(sn->id_str);
376aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(sn->name);
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->nb_snapshots--;
3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qcow_write_snapshots(bs);
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* XXX: restore snapshot if error ? */
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return ret;
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG_ALLOC
385cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    qcow2_check_refcounts(bs);
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BDRVQcowState *s = bs->opaque;
3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUSnapshotInfo *sn_tab, *sn_info;
3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QCowSnapshot *sn;
3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->nb_snapshots) {
3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *psn_tab = NULL;
3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return s->nb_snapshots;
4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
402aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    sn_tab = g_malloc0(s->nb_snapshots * sizeof(QEMUSnapshotInfo));
4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < s->nb_snapshots; i++) {
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn_info = sn_tab + i;
4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn = s->snapshots + i;
4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pstrcpy(sn_info->id_str, sizeof(sn_info->id_str),
4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                sn->id_str);
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pstrcpy(sn_info->name, sizeof(sn_info->name),
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                sn->name);
4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn_info->vm_state_size = sn->vm_state_size;
4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn_info->date_sec = sn->date_sec;
4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn_info->date_nsec = sn->date_nsec;
4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sn_info->vm_clock_nsec = sn->vm_clock_nsec;
4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *psn_tab = sn_tab;
4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->nb_snapshots;
4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
419