Annotation of qemu/tests/qemu-iotests/qcow2.py, revision 1.1.1.1

1.1       root        1: #!/usr/bin/env python
                      2: 
                      3: import sys
                      4: import struct
                      5: import string
                      6: 
                      7: class QcowHeaderExtension:
                      8: 
                      9:     def __init__(self, magic, length, data):
                     10:         self.magic  = magic
                     11:         self.length = length
                     12:         self.data   = data
                     13: 
                     14:     @classmethod
                     15:     def create(cls, magic, data):
                     16:         return QcowHeaderExtension(magic, len(data), data)
                     17: 
                     18: class QcowHeader:
                     19: 
                     20:     uint32_t = 'I'
                     21:     uint64_t = 'Q'
                     22: 
                     23:     fields = [
                     24:         # Version 2 header fields
                     25:         [ uint32_t, '%#x',  'magic' ],
                     26:         [ uint32_t, '%d',   'version' ],
                     27:         [ uint64_t, '%#x',  'backing_file_offset' ],
                     28:         [ uint32_t, '%#x',  'backing_file_size' ],
                     29:         [ uint32_t, '%d',   'cluster_bits' ],
                     30:         [ uint64_t, '%d',   'size' ],
                     31:         [ uint32_t, '%d',   'crypt_method' ],
                     32:         [ uint32_t, '%d',   'l1_size' ],
                     33:         [ uint64_t, '%#x',  'l1_table_offset' ],
                     34:         [ uint64_t, '%#x',  'refcount_table_offset' ],
                     35:         [ uint32_t, '%d',   'refcount_table_clusters' ],
                     36:         [ uint32_t, '%d',   'nb_snapshots' ],
                     37:         [ uint64_t, '%#x',  'snapshot_offset' ],
                     38: 
                     39:         # Version 3 header fields
                     40:         [ uint64_t, '%#x',  'incompatible_features' ],
                     41:         [ uint64_t, '%#x',  'compatible_features' ],
                     42:         [ uint64_t, '%#x',  'autoclear_features' ],
                     43:         [ uint32_t, '%d',   'refcount_order' ],
                     44:         [ uint32_t, '%d',   'header_length' ],
                     45:     ];
                     46: 
                     47:     fmt = '>' + ''.join(field[0] for field in fields)
                     48: 
                     49:     def __init__(self, fd):
                     50: 
                     51:         buf_size = struct.calcsize(QcowHeader.fmt)
                     52: 
                     53:         fd.seek(0)
                     54:         buf = fd.read(buf_size)
                     55: 
                     56:         header = struct.unpack(QcowHeader.fmt, buf)
                     57:         self.__dict__ = dict((field[2], header[i])
                     58:             for i, field in enumerate(QcowHeader.fields))
                     59: 
                     60:         self.set_defaults()
                     61:         self.cluster_size = 1 << self.cluster_bits
                     62: 
                     63:         fd.seek(self.header_length)
                     64:         self.load_extensions(fd)
                     65: 
                     66:         if self.backing_file_offset:
                     67:             fd.seek(self.backing_file_offset)
                     68:             self.backing_file = fd.read(self.backing_file_size)
                     69:         else:
                     70:             self.backing_file = None
                     71: 
                     72:     def set_defaults(self):
                     73:         if self.version == 2:
                     74:             self.incompatible_features = 0
                     75:             self.compatible_features = 0
                     76:             self.autoclear_features = 0
                     77:             self.refcount_order = 4
                     78:             self.header_length = 72
                     79: 
                     80:     def load_extensions(self, fd):
                     81:         self.extensions = []
                     82: 
                     83:         if self.backing_file_offset != 0:
                     84:             end = min(self.cluster_size, self.backing_file_offset)
                     85:         else:
                     86:             end = self.cluster_size
                     87: 
                     88:         while fd.tell() < end:
                     89:             (magic, length) = struct.unpack('>II', fd.read(8))
                     90:             if magic == 0:
                     91:                 break
                     92:             else:
                     93:                 padded = (length + 7) & ~7
                     94:                 data = fd.read(padded)
                     95:                 self.extensions.append(QcowHeaderExtension(magic, length, data))
                     96: 
                     97:     def update_extensions(self, fd):
                     98: 
                     99:         fd.seek(self.header_length)
                    100:         extensions = self.extensions
                    101:         extensions.append(QcowHeaderExtension(0, 0, ""))
                    102:         for ex in extensions:
                    103:             buf = struct.pack('>II', ex.magic, ex.length)
                    104:             fd.write(buf)
                    105:             fd.write(ex.data)
                    106: 
                    107:         if self.backing_file != None:
                    108:             self.backing_file_offset = fd.tell()
                    109:             fd.write(self.backing_file)
                    110: 
                    111:         if fd.tell() > self.cluster_size:
                    112:             raise Exception("I think I just broke the image...")
                    113: 
                    114: 
                    115:     def update(self, fd):
                    116:         header_bytes = self.header_length
                    117: 
                    118:         self.update_extensions(fd)
                    119: 
                    120:         fd.seek(0)
                    121:         header = tuple(self.__dict__[f] for t, p, f in QcowHeader.fields)
                    122:         buf = struct.pack(QcowHeader.fmt, *header)
                    123:         buf = buf[0:header_bytes-1]
                    124:         fd.write(buf)
                    125: 
                    126:     def dump(self):
                    127:         for f in QcowHeader.fields:
                    128:             print "%-25s" % f[2], f[1] % self.__dict__[f[2]]
                    129:         print ""
                    130: 
                    131:     def dump_extensions(self):
                    132:         for ex in self.extensions:
                    133: 
                    134:             data = ex.data[:ex.length]
                    135:             if all(c in string.printable for c in data):
                    136:                 data = "'%s'" % data
                    137:             else:
                    138:                 data = "<binary>"
                    139: 
                    140:             print "Header extension:"
                    141:             print "%-25s %#x" % ("magic", ex.magic)
                    142:             print "%-25s %d" % ("length", ex.length)
                    143:             print "%-25s %s" % ("data", data)
                    144:             print ""
                    145: 
                    146: 
                    147: def cmd_dump_header(fd):
                    148:     h = QcowHeader(fd)
                    149:     h.dump()
                    150:     h.dump_extensions()
                    151: 
                    152: def cmd_add_header_ext(fd, magic, data):
                    153:     try:
                    154:         magic = int(magic, 0)
                    155:     except:
                    156:         print "'%s' is not a valid magic number" % magic
                    157:         sys.exit(1)
                    158: 
                    159:     h = QcowHeader(fd)
                    160:     h.extensions.append(QcowHeaderExtension.create(magic, data))
                    161:     h.update(fd)
                    162: 
                    163: def cmd_del_header_ext(fd, magic):
                    164:     try:
                    165:         magic = int(magic, 0)
                    166:     except:
                    167:         print "'%s' is not a valid magic number" % magic
                    168:         sys.exit(1)
                    169: 
                    170:     h = QcowHeader(fd)
                    171:     found = False
                    172: 
                    173:     for ex in h.extensions:
                    174:         if ex.magic == magic:
                    175:             found = True
                    176:             h.extensions.remove(ex)
                    177: 
                    178:     if not found:
                    179:         print "No such header extension"
                    180:         return
                    181: 
                    182:     h.update(fd)
                    183: 
                    184: cmds = [
                    185:     [ 'dump-header',    cmd_dump_header,    0, 'Dump image header and header extensions' ],
                    186:     [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ],
                    187:     [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ],
                    188: ]
                    189: 
                    190: def main(filename, cmd, args):
                    191:     fd = open(filename, "r+b")
                    192:     try:
                    193:         for name, handler, num_args, desc in cmds:
                    194:             if name != cmd:
                    195:                 continue
                    196:             elif len(args) != num_args:
                    197:                 usage()
                    198:                 return
                    199:             else:
                    200:                 handler(fd, *args)
                    201:                 return
                    202:         print "Unknown command '%s'" % cmd
                    203:     finally:
                    204:         fd.close()
                    205: 
                    206: def usage():
                    207:     print "Usage: %s <file> <cmd> [<arg>, ...]" % sys.argv[0]
                    208:     print ""
                    209:     print "Supported commands:"
                    210:     for name, handler, num_args, desc in cmds:
                    211:         print "    %-20s - %s" % (name, desc)
                    212: 
                    213: if len(sys.argv) < 3:
                    214:     usage()
                    215:     sys.exit(1)
                    216: 
                    217: main(sys.argv[1], sys.argv[2], sys.argv[3:])

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.