Annotation of qemu/tests/qemu-iotests/qcow2.py, revision 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.