001/* 002 * To change this license header, choose License Headers in Project Properties. 003 * To change this template file, choose Tools | Templates 004 * and open the template in the editor. 005 */ 006package org.anarres.qemu.image; 007 008import com.fasterxml.jackson.databind.ObjectMapper; 009import com.google.common.base.Preconditions; 010import com.google.common.io.ByteStreams; 011import java.io.File; 012import java.io.IOException; 013import javax.annotation.Nonnegative; 014import javax.annotation.Nonnull; 015 016/** 017 * An abstraction around a QEmu image. 018 * <p> 019 * The underlying image file may or may not exist; this class allows for 020 * simple creation, inspection and deletion. 021 * 022 * @author shevek 023 */ 024public class QEmuImage { 025 026 private final File file; 027 028 public QEmuImage(@Nonnull File file) { 029 this.file = Preconditions.checkNotNull(file); 030 } 031 032 public QEmuImage(@Nonnull String path) { 033 this(new File(path)); 034 } 035 036 /** 037 * @return the file underlying this QEmuImage. 038 */ 039 @Nonnull 040 public File getFile() { 041 return file; 042 } 043 044 @Nonnull 045 public QEmuImageInfo query() throws IOException { 046 ProcessBuilder builder = new ProcessBuilder("qemu-img", "info", "--output=json", file.getAbsolutePath()); 047 Process process = builder.start(); 048 byte[] data = ByteStreams.toByteArray(process.getInputStream()); 049 ObjectMapper mapper = new ObjectMapper(); 050 return mapper.readValue(data, QEmuImageInfo.class); 051 } 052 053 /** 054 * Creates this image. 055 * 056 * @param format The image format for the new image. 057 * @param size The virtual size of the new image. 058 */ 059 public void create(@Nonnull QEmuImageFormat format, @Nonnegative long size) throws IOException { 060 ProcessBuilder builder = new ProcessBuilder("qemu-img", "create", "-f", format.name(), file.getAbsolutePath(), String.valueOf(size)); 061 Process process = builder.start(); 062 ByteStreams.copy(process.getInputStream(), System.err); 063 } 064 065 /** 066 * Creates this image. 067 * <p> 068 * The size of the new image is derived from the existing backing file. 069 * <p> 070 * backingFile is referenced by a relative path. If you want it referenced 071 * absolutely, canonicalize the argument with {@link File#getAbsoluteFile()} 072 * before calling this method. 073 * 074 * @param format The image format for the new image. 075 * @param backingFile The backing file for the new image. 076 */ 077 public void create(@Nonnull QEmuImageFormat format, @Nonnull File backingFile) throws IOException { 078 ProcessBuilder builder = new ProcessBuilder("qemu-img", "create", "-f", format.name(), "-b", backingFile.getPath(), file.getAbsolutePath()); 079 Process process = builder.start(); 080 ByteStreams.copy(process.getInputStream(), System.err); 081 } 082 083 /** 084 * Deletes the file underlying this image, if it exists. 085 */ 086 public void delete() throws IOException { 087 if (file.exists()) 088 if (!file.delete()) 089 throw new IOException("Unable to delete " + file); 090 } 091}