summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/vhd.py90
1 files changed, 90 insertions, 0 deletions
diff --git a/scripts/vhd.py b/scripts/vhd.py
new file mode 100755
index 0000000..6a26892
--- /dev/null
+++ b/scripts/vhd.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright: 2015 Bastian Blank
+# License: MIT, see LICENSE.txt for details.
+
+import array
+import struct
+import time
+import sys
+import os
+
+from uuid import uuid4
+
+
+class VHDFooter:
+ _struct = struct.Struct('>8sLLQL4sL4sQQ4sLL16sB427x')
+ size = _struct.size
+
+ vhd_timestamp_base = 946684800
+
+ def __init__(self, size, uuid=None, timestamp=None):
+ self.size = size
+ self.timestamp = timestamp or (int(time.time()) - self.vhd_timestamp_base)
+ self.uuid = uuid or uuid4()
+
+ @staticmethod
+ def _checksum(msg):
+ return 0x100000000 + ~sum(array.array("B", msg))
+
+ def _pack_geometry(self):
+ sectors = self.size // 512
+
+ if sectors > 65535 * 16 * 255:
+ sectors = 65535 * 16 * 255
+
+ if sectors >= 65535 * 16 * 63:
+ sectorsPerTrack = 255
+ heads = 16
+ cylinderTimesHeads = sectors // sectorsPerTrack
+
+ else:
+ sectorsPerTrack = 17
+ cylinderTimesHeads = sectors // sectorsPerTrack
+
+ heads = (cylinderTimesHeads + 1023) // 1024
+
+ if heads < 4:
+ heads = 4
+ if cylinderTimesHeads >= (heads * 1024) or heads > 16:
+ sectorsPerTrack = 31
+ heads = 16
+ cylinderTimesHeads = sectors // sectorsPerTrack
+ if cylinderTimesHeads >= (heads * 1024):
+ sectorsPerTrack = 63
+ heads = 16
+ cylinderTimesHeads = sectors // sectorsPerTrack
+
+ cylinders = cylinderTimesHeads // heads
+
+ return struct.pack('>HBB', cylinders, heads, sectorsPerTrack)
+
+ def _pack(self, checksum):
+ return self._struct.pack(
+ b'conectix', # Cookie
+ 0x00000002, # Features
+ 0x00010000, # File Format Version
+ 0xffffffffffffffff, # Data Offset
+ self.timestamp, # Time Stamp
+ b'qemu', # Creator Application
+ 0x00010000, # Creator Version
+ b'Wi2k', # Creator Host OS
+ self.size, # Original Size
+ self.size, # Current Size
+ self._pack_geometry(), # Disk Geometry
+ 2, # Disk Type
+ checksum, # Checksum
+ self.uuid.bytes, # Unique Id
+ 0, # Saved State
+ )
+
+ def pack(self):
+ c = self._checksum(self._pack(0))
+ return self._pack(c)
+
+with open(sys.argv[1], 'rb+') as f:
+ f.seek(0, 2)
+ image_size = f.tell()
+ image_size_complete = image_size + VHDFooter.size
+ footer = VHDFooter(image_size)
+ f.write(footer.pack())