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