Revision e108efd2 image_creator/disk.py
b/image_creator/disk.py | ||
---|---|---|
165 | 165 |
def __init__(self, device, bootable=True): |
166 | 166 |
"""Create a new DiskDevice.""" |
167 | 167 |
|
168 |
self.device = device |
|
168 |
self.real_device = device
|
|
169 | 169 |
self.bootable = bootable |
170 | 170 |
self.progress_bar = None |
171 |
self.guestfs_device = None |
|
172 |
self.size = None |
|
173 |
self.parttype = None |
|
171 | 174 |
|
172 | 175 |
self.g = guestfs.GuestFS() |
173 |
self.g.add_drive_opts(self.device, readonly=0) |
|
176 |
self.g.add_drive_opts(self.real_device, readonly=0)
|
|
174 | 177 |
|
175 | 178 |
#self.g.set_trace(1) |
176 | 179 |
#self.g.set_verbose(1) |
... | ... | |
200 | 203 |
raise FatalError("Multiple operating systems found." |
201 | 204 |
"We only support images with one filesystem.") |
202 | 205 |
self.root = roots[0] |
203 |
self.gdev = self.g.part_to_dev(self.root) |
|
204 |
self.parttype = self.g.part_get_parttype(self.gdev) |
|
206 |
self.guestfs_device = self.g.part_to_dev(self.root) |
|
207 |
self.size = self.g.blockdev_getsize64(self.guestfs_device) |
|
208 |
self.parttype = self.g.part_get_parttype(self.guestfs_device) |
|
205 | 209 |
|
206 | 210 |
self.ostype = self.g.inspect_get_type(self.root) |
207 | 211 |
self.distro = self.g.inspect_get_distro(self.root) |
... | ... | |
256 | 260 |
This is accomplished by shrinking the last filesystem in the |
257 | 261 |
disk and then updating the partition table. The new disk size |
258 | 262 |
(in bytes) is returned. |
263 |
|
|
264 |
ATTENTION: make sure unmount is called before shrink |
|
259 | 265 |
""" |
260 | 266 |
output("Shrinking image (this may take a while)...", False) |
261 | 267 |
|
... | ... | |
263 | 269 |
raise FatalError("You have a %s partition table. " |
264 | 270 |
"Only msdos and gpt partitions are supported" % self.parttype) |
265 | 271 |
|
266 |
last_partition = self.g.part_list(self.gdev)[-1]
|
|
272 |
last_partition = self.g.part_list(self.guestfs_device)[-1]
|
|
267 | 273 |
|
268 | 274 |
if last_partition['part_num'] > 4: |
269 | 275 |
raise FatalError("This disk contains logical partitions. " |
270 | 276 |
"Only primary partitions are supported.") |
271 | 277 |
|
272 |
part_dev = "%s%d" % (self.gdev, last_partition['part_num'])
|
|
278 |
part_dev = "%s%d" % (self.guestfs_device, last_partition['part_num'])
|
|
273 | 279 |
fs_type = self.g.vfs_type(part_dev) |
274 | 280 |
if not re.match("ext[234]", fs_type): |
275 | 281 |
warn("Don't know how to resize %s partitions." % vfs_type) |
... | ... | |
284 | 290 |
block_cnt = int( |
285 | 291 |
filter(lambda x: x[0] == 'Block count', out)[0][1]) |
286 | 292 |
|
287 |
sector_size = self.g.blockdev_getss(self.gdev)
|
|
293 |
sector_size = self.g.blockdev_getss(self.guestfs_device)
|
|
288 | 294 |
|
289 | 295 |
start = last_partition['part_start'] / sector_size |
290 | 296 |
end = start + (block_size * block_cnt) / sector_size - 1 |
291 | 297 |
|
292 |
self.g.part_del(self.gdev, last_partition['part_num'])
|
|
293 |
self.g.part_add(self.gdev, 'p', start, end)
|
|
298 |
self.g.part_del(self.guestfs_device, last_partition['part_num'])
|
|
299 |
self.g.part_add(self.guestfs_device, 'p', start, end)
|
|
294 | 300 |
|
295 |
new_size = (end + 1) * sector_size
|
|
301 |
self.size = (end + 1) * sector_size
|
|
296 | 302 |
success("new image size is %dMB" % |
297 |
((new_size + 2 ** 20 - 1) // 2 ** 20))
|
|
303 |
((self.size + 2 ** 20 - 1) // 2 ** 20))
|
|
298 | 304 |
|
299 | 305 |
if self.parttype == 'gpt': |
300 |
ptable = GPTPartitionTable(self.device) |
|
301 |
return ptable.shrink(new_size) |
|
302 |
|
|
303 |
return new_size |
|
306 |
ptable = GPTPartitionTable(self.real_device) |
|
307 |
self.size = ptable.shrink(self.size) |
|
304 | 308 |
|
305 |
def size(self): |
|
306 |
"""Returns the "payload" size of the device. |
|
307 |
|
|
308 |
The size returned by this method is the size of the space occupied by |
|
309 |
the partitions (including the space before the first partition). |
|
310 |
""" |
|
311 |
|
|
312 |
if self.parttype == 'msdos': |
|
313 |
dev = self.g.part_to_dev(self.root) |
|
314 |
last = self.g.part_list(dev)[-1] |
|
315 |
return last['part_end'] + 1 |
|
316 |
elif self.parttype == 'gpt': |
|
317 |
ptable = GPTPartitionTable(self.device) |
|
318 |
return ptable.size() |
|
319 |
else: |
|
320 |
raise FatalError("Unsupported partition table type: %s" % parttype) |
|
309 |
return self.size |
|
321 | 310 |
|
322 | 311 |
def dump(self, outfile): |
323 | 312 |
"""Dumps the content of device into a file. |
... | ... | |
326 | 315 |
partition table. Empty space in the end of the device will be ignored. |
327 | 316 |
""" |
328 | 317 |
blocksize = 2 ** 22 # 4MB |
329 |
size = self.size() |
|
330 |
progress_size = (size + 2 ** 20 - 1) // 2 ** 20 # in MB |
|
318 |
progress_size = (self.size + 2 ** 20 - 1) // 2 ** 20 # in MB |
|
331 | 319 |
progressbar = progress("Dumping image file: ", 'mb') |
332 | 320 |
progressbar.max = progress_size |
333 |
source = open(self.device, "r") |
|
334 |
try: |
|
335 |
dest = open(outfile, "w") |
|
336 |
try: |
|
337 |
left = size |
|
321 |
with open(self.real_device, 'r') as source: |
|
322 |
with open(outfile, "w") as dest: |
|
323 |
left = self.size |
|
338 | 324 |
offset = 0 |
339 | 325 |
progressbar.next() |
340 | 326 |
while left > 0: |
... | ... | |
343 | 329 |
length) |
344 | 330 |
offset += sent |
345 | 331 |
left -= sent |
346 |
progressbar.goto((size - left) // 2 ** 20) |
|
347 |
finally: |
|
348 |
dest.close() |
|
349 |
finally: |
|
350 |
source.close() |
|
332 |
progressbar.goto((self.size - left) // 2 ** 20) |
|
351 | 333 |
output("\rDumping image file...\033[K", False) |
352 | 334 |
success('image file %s was successfully created' % outfile) |
353 | 335 |
|
Also available in: Unified diff