/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.apps.vmware.disk.handler.sparse; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.log4j.Logger; import org.jnode.apps.vmware.disk.ExtentDeclaration; import org.jnode.apps.vmware.disk.IOUtils; import org.jnode.apps.vmware.disk.descriptor.AdapterType; import org.jnode.apps.vmware.disk.descriptor.CreateType; import org.jnode.apps.vmware.disk.descriptor.Descriptor; import org.jnode.apps.vmware.disk.descriptor.DiskDatabase; import org.jnode.apps.vmware.disk.descriptor.Header; import org.jnode.apps.vmware.disk.extent.Access; import org.jnode.apps.vmware.disk.extent.Extent; import org.jnode.apps.vmware.disk.extent.ExtentType; import org.jnode.apps.vmware.disk.tools.DiskFactory; import org.jnode.driver.bus.ide.IDEConstants; /** * Wrote from the 'Virtual Disk Format 1.0' specifications (from VMWare). * * @author Fabien DUMINY (fduminy at jnode dot org) * */ public class SparseDiskFactory extends DiskFactory { private static final Logger LOG = Logger.getLogger(SparseDiskFactory.class); @Override protected File createDiskImpl(File directory, String name, long size) throws IOException { File mainFile = createMainFile(directory, name, size); return mainFile; } protected File createMainFile(File directory, String name, long size) throws IOException { File mainFile = new File(directory, createDiskFileName(name, 0)); RandomAccessFile raf = new RandomAccessFile(mainFile, "rw"); @SuppressWarnings("unused") FileChannel channel = raf.getChannel(); @SuppressWarnings("unused") Descriptor descriptor = buildDescriptor(mainFile, size); @SuppressWarnings("unused") SparseExtentHeader header = new SparseExtentHeader(); return mainFile; } protected Descriptor buildDescriptor(File mainFile, long size) { LOG.info("buildDescriptor: wanted size=" + size); long sizeInSectors = size / IDEConstants.SECTOR_SIZE; if ((size % IDEConstants.SECTOR_SIZE) != 0) { LOG.debug("buildDescriptor: adding 1 more sector to fit size"); sizeInSectors++; } // build DiskDatabase DiskDatabase ddb = new DiskDatabase(); ddb.setAdapterType(AdapterType.ide); ddb.setSectors(64); ddb.setHeads(32); int cylinderCapacity = ddb.getSectors() * ddb.getHeads(); int cylinders = (int) (sizeInSectors / cylinderCapacity); if ((sizeInSectors % cylinderCapacity) != 0) { LOG.debug("buildDescriptor: adding 1 more cylinder to fit size"); cylinders++; } ddb.setCylinders(cylinders); int nbSectors = ddb.getCylinders() * ddb.getHeads() * ddb.getSectors(); LOG.info("buildDescriptor: allocated size=" + (nbSectors * IDEConstants.SECTOR_SIZE)); // build Header Header header = new Header(); header.setVersion("1"); header.setContentID(0); header.setParentContentID(Header.CID_NOPARENT); header.setCreateType(CreateType.monolithicSparse); header.setParentFileNameHint(""); // build extents List<Extent> extents = new ArrayList<Extent>(); SparseExtent mainExtent = createMainExtent(mainFile, nbSectors); extents.add(mainExtent); Descriptor descriptor = new Descriptor(mainFile, header, extents, ddb); mainExtent.setDescriptor(descriptor); return descriptor; } private SparseExtent createMainExtent(File mainFile, int nbSectors) { long offset = 0L; // TODO should be changed ? ExtentDeclaration extentDecl = IOUtils.createExtentDeclaration(mainFile, mainFile.getName(), Access.RW, nbSectors, ExtentType.SPARSE, offset); // create extent header SparseExtentHeader sparseHeader = new SparseExtentHeader(); sparseHeader.setValidNewLineDetectionTest(true); sparseHeader.setRedundantGrainTableWillBeUsed(false); sparseHeader.setGrainSize(16); sparseHeader.setDescriptorOffset(0); // TODO set value sparseHeader.setDescriptorSize(0); // TODO set value sparseHeader.setRgdOffset(0); // TODO set value sparseHeader.setNumGTEsPerGT(512); sparseHeader.setGdOffset(0); // TODO set value sparseHeader.setOverHead(0); // TODO set value sparseHeader.setUncleanShutdown(false); int nbGrains = (int) (nbSectors / sparseHeader.getGrainSize()); int modulo = (int) (nbSectors % sparseHeader.getGrainSize()); if (modulo != 0) { nbGrains++; nbSectors += (sparseHeader.getGrainSize() - modulo); } sparseHeader.setCapacity(nbSectors); IOUtils.computeGrainTableCoverage(sparseHeader); // create allocation table int nbEntries = (int) (nbSectors / sparseHeader.getGrainTableCoverage()); int[] entries = new int[nbEntries]; Arrays.fill(entries, 0); GrainDirectory gd = new GrainDirectory(entries); GrainTable[] gTables = null; AllocationTable allocationTable = new AllocationTable(gd, gTables); SparseExtent mainExtent = new SparseExtent(null, extentDecl, sparseHeader, allocationTable, allocationTable); return mainExtent; } protected String createDiskFileName(String name, int index) { return name + "-" + index + ".vmdk"; } }