* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "qapi-visit.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi/qmp/qerror.h"
#include "qemu-common.h"
#include "qemu/option.h"
#include "qemu/error-report.h"
-#include "qemu/osdep.h"
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
#include "block/block_int.h"
QString *str;
QmpOutputVisitor *ov = qmp_output_visitor_new();
QObject *obj;
- visit_type_ImageCheck(qmp_output_get_visitor(ov),
- &check, NULL, &local_err);
+ visit_type_ImageCheck(qmp_output_get_visitor(ov), NULL, &check,
+ &local_err);
obj = qmp_output_get_qobject(ov);
str = qobject_to_json_pretty(obj);
assert(str != NULL);
}
for (;;) {
+ int64_t status1, status2;
+ BlockDriverState *file;
+
nb_sectors = sectors_to_process(total_sectors, sector_num);
if (nb_sectors <= 0) {
break;
}
- allocated1 = bdrv_is_allocated_above(bs1, NULL, sector_num, nb_sectors,
- &pnum1);
- if (allocated1 < 0) {
+ status1 = bdrv_get_block_status_above(bs1, NULL, sector_num,
+ total_sectors1 - sector_num,
+ &pnum1, &file);
+ if (status1 < 0) {
ret = 3;
error_report("Sector allocation test failed for %s", filename1);
goto out;
}
+ allocated1 = status1 & BDRV_BLOCK_ALLOCATED;
- allocated2 = bdrv_is_allocated_above(bs2, NULL, sector_num, nb_sectors,
- &pnum2);
- if (allocated2 < 0) {
+ status2 = bdrv_get_block_status_above(bs2, NULL, sector_num,
+ total_sectors2 - sector_num,
+ &pnum2, &file);
+ if (status2 < 0) {
ret = 3;
error_report("Sector allocation test failed for %s", filename2);
goto out;
}
- nb_sectors = MIN(pnum1, pnum2);
+ allocated2 = status2 & BDRV_BLOCK_ALLOCATED;
+ if (pnum1) {
+ nb_sectors = MIN(nb_sectors, pnum1);
+ }
+ if (pnum2) {
+ nb_sectors = MIN(nb_sectors, pnum2);
+ }
- if (allocated1 == allocated2) {
+ if (strict) {
+ if ((status1 & ~BDRV_BLOCK_OFFSET_MASK) !=
+ (status2 & ~BDRV_BLOCK_OFFSET_MASK)) {
+ ret = 1;
+ qprintf(quiet, "Strict mode: Offset %" PRId64
+ " block status mismatch!\n",
+ sectors_to_bytes(sector_num));
+ goto out;
+ }
+ }
+ if ((status1 & BDRV_BLOCK_ZERO) && (status2 & BDRV_BLOCK_ZERO)) {
+ nb_sectors = MIN(pnum1, pnum2);
+ } else if (allocated1 == allocated2) {
if (allocated1) {
ret = blk_read(blk1, sector_num, buf1, nb_sectors);
if (ret < 0) {
}
}
} else {
- if (strict) {
- ret = 1;
- qprintf(quiet, "Strict mode: Offset %" PRId64
- " allocation mismatch!\n",
- sectors_to_bytes(sector_num));
- goto out;
- }
if (allocated1) {
ret = check_empty_sectors(blk1, sector_num, nb_sectors,
n = MIN(s->total_sectors - sector_num, BDRV_REQUEST_MAX_SECTORS);
if (s->sector_next_status <= sector_num) {
+ BlockDriverState *file;
ret = bdrv_get_block_status(blk_bs(s->src[s->src_cur]),
sector_num - s->src_cur_offset,
- n, &n);
+ n, &n, &file);
if (ret < 0) {
return ret;
}
QString *str;
QmpOutputVisitor *ov = qmp_output_visitor_new();
QObject *obj;
- visit_type_ImageInfoList(qmp_output_get_visitor(ov),
- &list, NULL, &local_err);
+ visit_type_ImageInfoList(qmp_output_get_visitor(ov), NULL, &list,
+ &local_err);
obj = qmp_output_get_qobject(ov);
str = qobject_to_json_pretty(obj);
assert(str != NULL);
QString *str;
QmpOutputVisitor *ov = qmp_output_visitor_new();
QObject *obj;
- visit_type_ImageInfo(qmp_output_get_visitor(ov),
- &info, NULL, &local_err);
+ visit_type_ImageInfo(qmp_output_get_visitor(ov), NULL, &info, &local_err);
obj = qmp_output_get_qobject(ov);
str = qobject_to_json_pretty(obj);
assert(str != NULL);
return 0;
}
-
-typedef struct MapEntry {
- int flags;
- int depth;
- int64_t start;
- int64_t length;
- int64_t offset;
- BlockDriverState *bs;
-} MapEntry;
-
static void dump_map_entry(OutputFormat output_format, MapEntry *e,
MapEntry *next)
{
switch (output_format) {
case OFORMAT_HUMAN:
- if ((e->flags & BDRV_BLOCK_DATA) &&
- !(e->flags & BDRV_BLOCK_OFFSET_VALID)) {
+ if (e->data && !e->has_offset) {
error_report("File contains external, encrypted or compressed clusters.");
exit(1);
}
- if ((e->flags & (BDRV_BLOCK_DATA|BDRV_BLOCK_ZERO)) == BDRV_BLOCK_DATA) {
+ if (e->data && !e->zero) {
printf("%#-16"PRIx64"%#-16"PRIx64"%#-16"PRIx64"%s\n",
- e->start, e->length, e->offset, e->bs->filename);
+ e->start, e->length,
+ e->has_offset ? e->offset : 0,
+ e->has_filename ? e->filename : "");
}
/* This format ignores the distinction between 0, ZERO and ZERO|DATA.
* Modify the flags here to allow more coalescing.
*/
- if (next &&
- (next->flags & (BDRV_BLOCK_DATA|BDRV_BLOCK_ZERO)) != BDRV_BLOCK_DATA) {
- next->flags &= ~BDRV_BLOCK_DATA;
- next->flags |= BDRV_BLOCK_ZERO;
+ if (next && (!next->data || next->zero)) {
+ next->data = false;
+ next->zero = true;
}
break;
case OFORMAT_JSON:
- printf("%s{ \"start\": %"PRId64", \"length\": %"PRId64", \"depth\": %d,"
- " \"zero\": %s, \"data\": %s",
+ printf("%s{ \"start\": %"PRId64", \"length\": %"PRId64","
+ " \"depth\": %"PRId64", \"zero\": %s, \"data\": %s",
(e->start == 0 ? "[" : ",\n"),
e->start, e->length, e->depth,
- (e->flags & BDRV_BLOCK_ZERO) ? "true" : "false",
- (e->flags & BDRV_BLOCK_DATA) ? "true" : "false");
- if (e->flags & BDRV_BLOCK_OFFSET_VALID) {
+ e->zero ? "true" : "false",
+ e->data ? "true" : "false");
+ if (e->has_offset) {
printf(", \"offset\": %"PRId64"", e->offset);
}
putchar('}');
{
int64_t ret;
int depth;
+ BlockDriverState *file;
/* As an optimization, we could cache the current range of unallocated
* clusters in each file of the chain, and avoid querying the same
depth = 0;
for (;;) {
- ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors);
+ ret = bdrv_get_block_status(bs, sector_num, nb_sectors, &nb_sectors,
+ &file);
if (ret < 0) {
return ret;
}
e->start = sector_num * BDRV_SECTOR_SIZE;
e->length = nb_sectors * BDRV_SECTOR_SIZE;
- e->flags = ret & ~BDRV_BLOCK_OFFSET_MASK;
+ e->data = !!(ret & BDRV_BLOCK_DATA);
+ e->zero = !!(ret & BDRV_BLOCK_ZERO);
e->offset = ret & BDRV_BLOCK_OFFSET_MASK;
+ e->has_offset = !!(ret & BDRV_BLOCK_OFFSET_VALID);
e->depth = depth;
- e->bs = bs;
+ if (file && e->has_offset) {
+ e->has_filename = true;
+ e->filename = file->filename;
+ }
return 0;
}
+static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next)
+{
+ if (curr->length == 0) {
+ return false;
+ }
+ if (curr->zero != next->zero ||
+ curr->data != next->data ||
+ curr->depth != next->depth ||
+ curr->has_filename != next->has_filename ||
+ curr->has_offset != next->has_offset) {
+ return false;
+ }
+ if (curr->has_filename && strcmp(curr->filename, next->filename)) {
+ return false;
+ }
+ if (curr->has_offset && curr->offset + curr->length != next->offset) {
+ return false;
+ }
+ return true;
+}
+
static int img_map(int argc, char **argv)
{
int c;
goto out;
}
- if (curr.length != 0 && curr.flags == next.flags &&
- curr.depth == next.depth &&
- ((curr.flags & BDRV_BLOCK_OFFSET_VALID) == 0 ||
- curr.offset + curr.length == next.offset)) {
+ if (entry_mergeable(&curr, &next)) {
curr.length += next.length;
continue;
}
exit(EXIT_FAILURE);
}
+ module_call_init(MODULE_INIT_QOM);
bdrv_init();
if (argc < 2) {
error_exit("Not enough arguments");