/*
* $Id$
*
* Copyright (C) 2003-2013 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.partitions.gpt;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.jnode.driver.Device;
import org.jnode.partitions.PartitionTable;
import org.jnode.partitions.PartitionTableType;
import org.jnode.partitions.ibm.IBMPartitionTable;
import org.jnode.partitions.ibm.IBMPartitionTableEntry;
import org.jnode.partitions.ibm.IBMPartitionTypes;
import org.jnode.util.LittleEndian;
/**
* The main GPT partition table class.
*
* @author Luke Quinane
*/
public class GptPartitionTable implements PartitionTable<GptPartitionTableEntry> {
/** The type of partition table */
private final GptPartitionTableType tableType;
/** The detected block size. */
private final int blockSize;
/** The partition entries */
private final List<GptPartitionTableEntry> partitions = new ArrayList<GptPartitionTableEntry>();
/** My logger */
private static final Logger log = Logger.getLogger(GptPartitionTable.class);
/**
* Create a new instance
*
* @param tableType the partition table type.
* @param first16KiB the first 16,384 bytes of the disk.
* @param device the drive device.
*/
public GptPartitionTable(GptPartitionTableType tableType, byte[] first16KiB, Device device) {
this.tableType = tableType;
blockSize = detectBlockSize(first16KiB);
if (blockSize != -1) {
long entries = LittleEndian.getUInt32(first16KiB, blockSize + 0x50);
int entrySize = (int) LittleEndian.getUInt32(first16KiB, blockSize + 0x54);
for (int partitionNumber = 0; partitionNumber < entries; partitionNumber++) {
log.debug("try part " + partitionNumber);
int offset = blockSize * 2 + (partitionNumber * entrySize);
GptPartitionTableEntry entry = new GptPartitionTableEntry(this, first16KiB, offset, blockSize);
log.debug(entry);
if (entry.isValid()) {
partitions.add(entry);
}
}
}
}
/**
* Detects the block size of the GPT partition.
*
* @param first16KiB the start of the disk to search for the GPT partition in.
* @return the detected block size or {@code -1} if no GPT partition is found.
*/
private static int detectBlockSize(byte[] first16KiB) {
int[] detectionSizes = new int[] {0x200, 0x1000, 0x2000 };
for (int blockSize : detectionSizes) {
if (first16KiB.length < blockSize + 8) {
// Not enough data to check for a valid partition table
return -1;
}
byte[] signatureBytes = new byte[8];
System.arraycopy(first16KiB, blockSize, signatureBytes, 0, signatureBytes.length);
String signature = new String(signatureBytes, Charset.forName("US-ASCII"));
if ("EFI PART".equals(signature)) {
return blockSize;
}
}
return -1;
}
/**
* Checks if the given boot sector contain a GPT partition table.
*
* @param first16KiB the first 16,384 bytes of the disk.
* @param requireProtectiveMbr {@code true} if the protective MBR must be present.
* @return {@code true} if the boot sector contains a GPT partition table.
*/
public static boolean containsPartitionTable(byte[] first16KiB, boolean requireProtectiveMbr) {
if (requireProtectiveMbr) {
List<IBMPartitionTableEntry> entries = new ArrayList<IBMPartitionTableEntry>();
for (int partitionNumber = 0; partitionNumber < IBMPartitionTable.TABLE_SIZE; partitionNumber++) {
IBMPartitionTableEntry partition = new IBMPartitionTableEntry(null, first16KiB, partitionNumber);
if (partition.isValid()) {
entries.add(partition);
}
}
if (entries.isEmpty() || entries.get(0).getSystemIndicator() != IBMPartitionTypes.PARTTYPE_EFI_GPT) {
log.debug("No protective MBR found: " + entries);
return false;
}
}
return detectBlockSize(first16KiB) != -1;
}
@Override
public Iterator<GptPartitionTableEntry> iterator() {
return Collections.unmodifiableList(partitions).iterator();
}
/**
* Gets the block size.
*
* @return the block size.
*/
public int getBlockSize() {
return blockSize;
}
/**
* @see org.jnode.partitions.PartitionTable#getType()
*/
@Override
public PartitionTableType getType() {
return tableType;
}
}