1ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/*
2ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Copyright (C) 2010 The Android Open Source Project
3ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
4ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Licensed under the Apache License, Version 2.0 (the "License");
5ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * you may not use this file except in compliance with the License.
6ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * You may obtain a copy of the License at
7ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
8ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *      http://www.apache.org/licenses/LICENSE-2.0
9ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
10ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Unless required by applicable law or agreed to in writing, software
11ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * distributed under the License is distributed on an "AS IS" BASIS,
12ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * See the License for the specific language governing permissions and
14ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * limitations under the License.
15ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
16ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
17ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Limited driver for the Qcow2 filesystem, capable of extracting snapshot
18ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * metadata from Qcow2 formatted image file.
19ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
20ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Similar functionality is implemented in block/qcow2.c, block/qcow2-snapshot.c
21ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * and block.c. This separate implementation was made to further decouple the UI
22ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * of the Android emulator from the underlying Qemu system. It allows the UI to
23ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * show snapshot listings without having to fall back on Qemu's block driver
24ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * system, which would pull in a lot of code irrelevant for the UI.
25ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
26ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
27ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <errno.h>
28ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <fcntl.h>
29ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <stdint.h>
30ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <stdio.h>
31ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <stdlib.h>
32ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <string.h>
33ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <time.h>
34ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include <unistd.h>
35ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
36e5af8a259e619973538f393011b1c26a3e2f4afbDavid 'Digit' Turner#include "bswap.h"
37ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include "android/utils/debug.h"
38ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#include "android/utils/system.h"
39e5af8a259e619973538f393011b1c26a3e2f4afbDavid 'Digit' Turner#include "android/snapshot.h"
40ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
41ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* "Magic" sequence of four bytes required by spec to be the first four bytes
42ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * of any Qcow file.
43ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
44ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
45ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#define QCOW_VERSION 2
46ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
47ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Reads 'nbyte' bytes from 'fd' into 'buf', retrying on interrupts.
48ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * Exit()s if the read fails for any other reason.
49ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
50ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic int
51ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijeread_or_die(int fd, void *buf, size_t nbyte)
52ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
53ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int ret = 0;
54ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    do {
55ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        ret = read(fd, buf, nbyte);
56ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
57ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    while(ret < 0 && errno == EINTR);
58ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
59ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (ret < 0) {
60ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("read failed: %s", strerror(errno));
61ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
62ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
63ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
64ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return ret;
65ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
66ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
67ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Wrapper around lseek(), exit()s on error.
68ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
69ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic off_t
70ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijeseek_or_die(int fd, off_t offset, int whence)
71ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
72ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    off_t ret = lseek(fd, offset, whence);
73ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (ret < 0) {
74ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("seek failed: %s", strerror(errno));
75ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
76ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
77ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return ret;
78ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
79ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
80ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
81ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijetypedef struct SnapshotInfo {
82ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char *id_str;
83ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char *name;
84ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
85ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t date_sec;
86ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t date_nsec;
87ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
88ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t vm_clock_nsec;
89ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t vm_state_size;
90ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije} SnapshotInfo;
91ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
92ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic SnapshotInfo*
93ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_info_alloc()
94ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
95ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return android_alloc(sizeof(SnapshotInfo));
96ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
97ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
98ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
99ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_info_free( SnapshotInfo* info )
100ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
101ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    AFREE(info->id_str);
102ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    AFREE(info->name);
103ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    AFREE(info);
104ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
105ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
106ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
107ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Reads a snapshot record from a qcow2-formatted file.
108ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
109ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * The function assumes the file position of 'fd' points to the beginning of a
110ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * QcowSnapshotHeader record. When the call returns, the file position of fd is
111ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * at the place where the next QcowSnapshotHeader should start, if there is one.
112ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
113ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * C.f. QCowSnapshotHeader in block/qcow2-snapshot.c for the complete layout of
114ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * the header.
115ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
116ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
117ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_info_read( int fd, SnapshotInfo* info )
118ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
119ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t start_offset = seek_or_die(fd, 0, SEEK_CUR);
120ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
121ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t extra_data_size;
122ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint16_t id_str_size, name_size;
123ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
124ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* read fixed-length fields */
125ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, 12, SEEK_CUR);  /* skip l1 info */
126ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &id_str_size,         sizeof(id_str_size));
127ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &name_size,           sizeof(name_size));
128ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &info->date_sec,      sizeof(info->date_sec));
129ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &info->date_nsec,     sizeof(info->date_nsec));
130ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &info->vm_clock_nsec, sizeof(info->vm_clock_nsec));
131ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &info->vm_state_size, sizeof(info->vm_state_size));
132ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &extra_data_size,     sizeof(extra_data_size));
133ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
134ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* convert to host endianness */
135ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be16_to_cpus(&id_str_size);
136ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be16_to_cpus(&name_size);
137ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&info->date_sec);
138ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&info->date_nsec);
139ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be64_to_cpus(&info->vm_clock_nsec);
140ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&info->vm_state_size);
141ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&extra_data_size);
142ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&extra_data_size);
143ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
144ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* read variable-length buffers*/
145ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    info->id_str = android_alloc(id_str_size + 1); // +1: manual null-termination
146ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    info->name   = android_alloc(name_size + 1);
147ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, extra_data_size, SEEK_CUR);  /* skip extra data */
148ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, info->id_str, id_str_size);
149ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, info->name, name_size);
150ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
151ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    info->id_str[id_str_size] = '\0';
152ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    info->name[name_size] = '\0';
153ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
154ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* headers are 8 byte aligned, ceil to nearest multiple of 8 */
155ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t end_offset   = seek_or_die(fd, 0, SEEK_CUR);
156ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t total_size   = end_offset - start_offset;
157ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t aligned_size = ((total_size - 1) / 8 + 1) * 8;
158ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
159ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* skip to start of next record */
160ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, start_offset + aligned_size, SEEK_SET);
161ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
162ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
163ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
164ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije#define NB_SUFFIXES 4
165ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
166ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Returns the size of a snapshot in a human-readable format.
167ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
168ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * This function copyright (c) 2003 Fabrice Bellard
169ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
170ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic char*
171ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_format_size( char *buf, int buf_size, int64_t size )
172ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
173ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    static const char suffixes[NB_SUFFIXES] = "KMGT";
174ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int64_t base;
175ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int i;
176ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
177ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (size <= 999) {
178ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snprintf(buf, buf_size, "%" PRId64, size);
179ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    } else {
180ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        base = 1024;
181ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        for(i = 0; i < NB_SUFFIXES; i++) {
182ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije            if (size < (10 * base)) {
183ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                snprintf(buf, buf_size, "%0.1f%c",
184ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                         (double)size / base,
185ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                         suffixes[i]);
186ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                break;
187ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije            } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
188ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                snprintf(buf, buf_size, "%" PRId64 "%c",
189ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                         ((size + (base >> 1)) / base),
190ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                         suffixes[i]);
191ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                break;
192ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije            }
193ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije            base = base * 1024;
194ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        }
195ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
196ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return buf;
197ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
198ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
199ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic char*
200ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_format_create_date( char *buf, size_t buf_size, time_t *time )
201ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
202ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    struct tm *tm;
203ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    tm = localtime(time);
204ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm);
205ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return buf;
206ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
207ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
208ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic char*
209ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_format_vm_clock( char *buf, size_t buf_size, uint64_t vm_clock_nsec )
210ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
211ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t secs = vm_clock_nsec / 1000000000;
212ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snprintf(buf, buf_size, "%02d:%02d:%02d.%03d",
213ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                            (int)(secs / 3600),
214ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                            (int)((secs / 60) % 60),
215ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                            (int)(secs % 60),
216ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                            (int)((vm_clock_nsec / 1000000) % 1000));
217ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    return buf;
218ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
219ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
220ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Prints a row of the snapshot table to stdout. */
221ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
222ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_info_print( SnapshotInfo *info )
223ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
224ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char size_buf[8];
225ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char date_buf[21];
226ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    char clock_buf[21];
227ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
228ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_format_size(size_buf, sizeof(size_buf), info->vm_state_size);
229ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_format_create_date(date_buf, sizeof(date_buf),
230ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije                                (time_t*) &info->date_sec);
231ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_format_vm_clock(clock_buf, sizeof(clock_buf), info->vm_clock_nsec);
232ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
233ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    printf(" %-10s%-20s%7s%20s%15s\n",
234ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije           info->id_str, info->name, size_buf, date_buf, clock_buf);
235ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
236ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
237ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Prints table of all snapshots recorded in the file 'fd'.
238ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
239ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
240ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_print_table( int fd, uint32_t nb_snapshots, uint64_t snapshots_offset )
241ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
242ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    printf(" %-10s%-20s%7s%20s%15s\n",
243ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije           "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
244ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
245ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* skip ahead to snapshot data */
246ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, snapshots_offset, SEEK_SET);
247ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
248ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* iterate over snapshot records */
249ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int i;
250ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    for (i = 0; i < nb_snapshots; i++) {
251ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        SnapshotInfo *info = snapshot_info_alloc();
252ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snapshot_info_read(fd, info);
253ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snapshot_info_print(info);
254ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
255ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snapshot_info_free(info);
256ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
257ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
258ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
259ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Validates that 'fd' starts with a correct Qcow 2 header. Prints an error and
260ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * exit()s if validation fails.
261ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
262ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
263ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_validate_qcow_file( int fd )
264ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
265ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* read magic number and qcow version (2x4 bytes) */
266ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t magic, version;
267ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &magic, sizeof(magic));
268ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, &version, sizeof(version));
269ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&magic);
270ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(&version);
271ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
272ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (magic != QCOW_MAGIC) {
273ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("Not a valid Qcow snapshot file (expected magic value '%08x', got '%08x').",
274ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije               QCOW_MAGIC, magic);
275ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
276ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
277ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (version != QCOW_VERSION) {
278ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("Unsupported Qcow version (need %d, got %d).",
279ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije               QCOW_VERSION, version);
280ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
281ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
282ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
283ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
284ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Reads snapshot information from a Qcow2 file header.
285ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije *
286ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * C.f. QCowHeader in block/qcow2.h for an exact listing of the header
287ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * contents.
288ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
289ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijestatic void
290ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_read_qcow_header( int fd, uint32_t *nb_snapshots, uint64_t *snapshots_offset )
291ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
292ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_validate_qcow_file(fd);
293ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
294ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* skip non-snapshot related metadata (4x8 + 5x4 = 52 bytes)*/
295ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    seek_or_die(fd, 52, SEEK_CUR);
296ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
297ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, nb_snapshots, sizeof(*nb_snapshots));
298ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    read_or_die(fd, snapshots_offset, sizeof(*snapshots_offset));
299ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
300ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* convert to host endianness */
301ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be32_to_cpus(nb_snapshots);
302ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    be64_to_cpus(snapshots_offset);
303ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
304ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
305ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije/* Prints a table with information on the snapshots in the qcow2-formatted file
306ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije * 'snapstorage', then exit()s.
307ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije */
308ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijevoid
309ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thijesnapshot_print_and_exit( const char *snapstorage )
310ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije{
311ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* open snapshot file */
312ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    int fd = open(snapstorage, O_RDONLY);
313d80a7861fe5e21e3dcb80480a77b033e6b307dd5David 'Digit' Turner    if (fd < 0) {
314ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        derror("Could not open snapshot file '%s': %s", snapstorage, strerror(errno));
315ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        exit(1);
316ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
317ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
318ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    /* read snapshot info from file header */
319ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint32_t nb_snapshots;
320ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    uint64_t snapshots_offset;
321ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    snapshot_read_qcow_header(fd, &nb_snapshots, &snapshots_offset);
322ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
323ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    if (nb_snapshots > 0) {
324ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        printf("Snapshots in file '%s':\n", snapstorage);
325ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        snapshot_print_table(fd, nb_snapshots, snapshots_offset);
326ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
327ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    else {
328ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije        printf("File '%s' contains no snapshots yet.\n", snapstorage);
329ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    }
330ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije
331ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    close(fd);
332ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije    exit(0);
333ae835acc2d1a8b4aaeb599add9cfc02ea5789eafOt ten Thije}
334