I forgot to ask the obvious question:
I am writing a backup program that is using the new snapshot APIs. A
snapshot has been created, how do I read out the data from the
snapshot?

Here's how to access the data in the snapshot, at least for the first
round implementation of qcow2 snapshots:

If you created an internal snapshot (virDomainSnapshotCreateXML with no
flags), then the only way right now to read data out is to shut down any
qemu process (since qemu-img should not be used on a file in active use
by qemu), then:

qemu-img convert [options] -s snapshot file backup
to extract the named internal snapshot from 'file' into a new file 'backup'.

If you created an external snapshot (virDomainSnapshotCreateXML with the
new _DISK_ONLY flag), then the data from the snapshot is the old file
name. That is, if you start with '/path/to/old', then create a snapshot
with a target file of '/path/to/new', then /path/to/old _is_ the
snapshot, and /path/to/new is a qcow2 file with /path/to/old as its
backing file. The snapshot (old file) can safely be accessed even while
qemu is still running.

As for how to access which blocks have changed in the delta since the
snapshot, that is not yet exposed in libvirt, due to lack of support in
qemu and qemu-img.