From: <ga...@us...> - 2012-03-09 13:06:40
|
Revision: 5890 http://jnode.svn.sourceforge.net/jnode/?rev=5890&view=rev Author: galatnm Date: 2012-03-09 13:06:29 +0000 (Fri, 09 Mar 2012) Log Message: ----------- Add gpt partition support from Luke. Added Paths: ----------- trunk/fs/descriptors/org.jnode.partitions.gpt.xml trunk/fs/src/fs/org/jnode/partitions/gpt/ trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTable.java trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTableEntry.java trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTableType.java trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTypes.java Added: trunk/fs/descriptors/org.jnode.partitions.gpt.xml =================================================================== --- trunk/fs/descriptors/org.jnode.partitions.gpt.xml (rev 0) +++ trunk/fs/descriptors/org.jnode.partitions.gpt.xml 2012-03-09 13:06:29 UTC (rev 5890) @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plugin SYSTEM "jnode.dtd"> + +<plugin id="org.jnode.partitions.gpt" + name="JNode GPT partition table classes" + version="0.2.9-dev" + license-name="lgpl" + provider-name="JNode.org"> + + <requires> + <import plugin="org.jnode.partitions"/> + </requires> + + <runtime> + <library name="jnode-fs.jar"> + <export name="org.jnode.partitions.gpt.*"/> + </library> + </runtime> + + <extension point="org.jnode.partitions.types"> + <type class="org.jnode.partitions.gpt.GptPartitionTableType"/> + </extension> + +</plugin> \ No newline at end of file Added: trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTable.java =================================================================== --- trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTable.java (rev 0) +++ trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTable.java 2012-03-09 13:06:29 UTC (rev 5890) @@ -0,0 +1,128 @@ +/* + * $Id: $ + * + * Copyright (C) 2003-2010 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.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 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; + + int 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); + + 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 }; + + 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. + * @return {@code true} if the boot sector contains a GPT partition table. + */ + public static boolean containsPartitionTable(byte[] first16KiB) { + return detectBlockSize(first16KiB) != -1; + } + + public Iterator<GptPartitionTableEntry> iterator() { + return Collections.unmodifiableList(partitions).iterator(); + } + + /** + * @see org.jnode.partitions.PartitionTable#getType() + */ + public PartitionTableType getType() { + return tableType; + } +} \ No newline at end of file Added: trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTableEntry.java =================================================================== --- trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTableEntry.java (rev 0) +++ trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTableEntry.java 2012-03-09 13:06:29 UTC (rev 5890) @@ -0,0 +1,132 @@ +/* + * $Id: $ + * + * Copyright (C) 2003-2010 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 org.jnode.partitions.PartitionTableEntry; +import org.jnode.partitions.ibm.IBMPartitionTable; +import org.jnode.util.LittleEndian; +import org.jnode.util.NumberUtils; + +/** + * A GPT partition table entry. + * + * @author Luke Quinane + */ +public class GptPartitionTableEntry implements PartitionTableEntry { + + /** The first 16KiB of the drive. */ + private final byte[] first16KiB; + + /** The block size. */ + private int blockSize; + + /** The offset to this partition table entry. */ + private final int offset; + + /** + * Creates a new entry. + * + * @param parent the parent table. + * @param first16KiB the first 16,384 bytes of the disk. + * @param offset the offset of this entry in the table. + * @param blockSize the block size. + */ + public GptPartitionTableEntry(GptPartitionTable parent, byte[] first16KiB, int offset, int blockSize) { + this.first16KiB = first16KiB; + this.blockSize = blockSize; + this.offset = offset; + } + + public boolean isValid() { + return first16KiB.length > offset + 128 && !isEmpty(); + } + + /** + * @see org.jnode.partitions.PartitionTableEntry#getChildPartitionTable() + */ + public IBMPartitionTable getChildPartitionTable() { + throw new UnsupportedOperationException("No child partitions."); + } + + /** + * @see org.jnode.partitions.PartitionTableEntry#hasChildPartitionTable() + */ + public boolean hasChildPartitionTable() { + return false; + } + + public boolean isEmpty() { + return GptPartitionTypes.lookUp(getPartitionTypeGuid()) == GptPartitionTypes.UNUSED_ENTRY; + } + + public byte[] getPartitionTypeGuid() { + byte[] guid = new byte[16]; + System.arraycopy(first16KiB, offset, guid, 0, guid.length); + return guid; + } + + public byte[] getPartitionGuid() { + byte[] guid = new byte[16]; + System.arraycopy(first16KiB, offset + 0x10, guid, 0, guid.length); + return guid; + } + + public long getStartOffset() { + return LittleEndian.getInt64(first16KiB, offset + 0x20) * blockSize; + } + + public long getEndOffset() { + return (LittleEndian.getInt64(first16KiB, offset + 0x28) + 1) * blockSize; + } + + public long getFlags() { + return LittleEndian.getInt64(first16KiB, offset + 0x30); + } + + public String getName() { + byte[] nameBytes = new byte[72]; + System.arraycopy(first16KiB, offset + 0x38, nameBytes, 0, nameBytes.length); + return new String(nameBytes, Charset.forName("UTF-16LE")).replace("\u0000", ""); + } + + public String dump() { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < 128; i++) { + b.append(NumberUtils.hex(LittleEndian.getUInt8(first16KiB, offset + i), 2)); + b.append(' '); + } + return b.toString(); + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuilder builder = new StringBuilder(32); + builder.append('[').append(getName()).append(' '); + builder.append(NumberUtils.hex(getPartitionTypeGuid())).append(' '); + builder.append(NumberUtils.hex(getPartitionGuid())).append(' '); + builder.append("s:").append(getStartOffset()).append(' '); + builder.append("e:").append(getEndOffset()).append(']'); + return builder.toString(); + } +} Added: trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTableType.java =================================================================== --- trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTableType.java (rev 0) +++ trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTableType.java 2012-03-09 13:06:29 UTC (rev 5890) @@ -0,0 +1,47 @@ +/* + * $Id: $ + * + * Copyright (C) 2003-2010 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 org.jnode.driver.Device; +import org.jnode.driver.block.BlockDeviceAPI; +import org.jnode.partitions.PartitionTable; +import org.jnode.partitions.PartitionTableException; +import org.jnode.partitions.PartitionTableType; + +/** + * GPT partition table type. + * + * @author Luke Quinane + */ +public class GptPartitionTableType implements PartitionTableType { + + public PartitionTable<?> create(byte[] firstSector, Device device) throws PartitionTableException { + return new GptPartitionTable(this, firstSector, device); + } + + public String getName() { + return "EFI PART"; + } + + public boolean supports(byte[] first16KiB, BlockDeviceAPI devApi) { + return GptPartitionTable.containsPartitionTable(first16KiB); + } +} \ No newline at end of file Added: trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTypes.java =================================================================== --- trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTypes.java (rev 0) +++ trunk/fs/src/fs/org/jnode/partitions/gpt/GptPartitionTypes.java 2012-03-09 13:06:29 UTC (rev 5890) @@ -0,0 +1,165 @@ +/* + * $Id: $ + * + * Copyright (C) 2003-2010 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.util.UUID; +import org.apache.log4j.Logger; +import org.jnode.util.NumberUtils; + +/** + * Known GPT partition types. + * + * @author Luke Quinane + */ +public enum GptPartitionTypes { + + // General + UNKNOWN(), + UNUSED_ENTRY("00000000-0000-0000-0000-000000000000"), + MBR_PARTITION_SCHEME("024DEE41-33E7-11D3-9D69-0008C781F39F"), + EFI_SYSTEM_PARTITION("C12A7328-F81F-11D2-BA4B-00A0C93EC93B"), + BIOS_BOOT_PARTITION("21686148-6449-6E6F-744E-656564454649"), + + // Windows + MICROSOFT_RESERVED_PARTITION("E3C9E316-0B5C-4DB8-817D-F92DF00215AE"), + MICROSOFT_BASIC_DATA_PARTITION("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"), + MICROSOFT_LOGICAL_DISK_MANAGER_METADATA_PARTITION("5808C8AA-7E8F-42E0-85D2-E1E90434CFB3"), + MICROSOFT_LOGICAL_DISK_MANAGER_DATA_PARTITION("AF9B60A0-1431-4F62-BC68-3311714A69AD"), + WINDOWS_RECOVERY_ENVIRONMENT("DE94BBA4-06D1-4D40-A16A-BFD50179D6AC"), + IBM_GENERAL_PARALLEL_FILE_SYSTEM_PARTITION("37AFFC90-EF7D-4E96-91C3-2D7AE055B174"), + + // HP-UX + HP_UX_DATA_PARTITION("75894C1E-3AEB-11D3-B7C1-7B03A0000000"), + HP_UX_SERVICE_PARTITION("E2A1E728-32E3-11D6-A682-7B03A0000000"), + + // Linux + LINUX_FILESYSTEM_DATA("0FC63DAF-8483-4772-8E79-3D69D8477DE4"), + LINUX_RAID_PARTITION("A19D880F-05FC-4D3B-A006-743F0F84911E"), + LINUX_SWAP_PARTITION("0657FD6D-A4AB-43C4-84E5-0933C84B4F4F"), + LINUX_LOGICAL_VOLUME_MANAGER_PARTITION("E6D6D379-F507-44C2-A23C-238F2A3DF928"), + LINUX_RESERVED("8DA63339-0007-60C0-C436-083AC8230908"), + + // FreeBSD + FREEBSD_BOOT_PARTITION("83BD6B9D-7F41-11DC-BE0B-001560B84F0F"), + FREEBSD_DATA_PARTITION("516E7CB4-6ECF-11D6-8FF8-00022D09712B"), + FREEBSD_SWAP_PARTITION("516E7CB5-6ECF-11D6-8FF8-00022D09712B"), + FREEBSD_UNIX_FILE_SYSTEM_PARTITION("516E7CB6-6ECF-11D6-8FF8-00022D09712B"), + FREEBSD_VINUM_VOLUME_MANAGER_PARTITION("516E7CB8-6ECF-11D6-8FF8-00022D09712B"), + FREEBSD_ZFS_PARITION("516E7CBA-6ECF-11D6-8FF8-00022D09712B"), + + // Apple + HFS_PLUS_PARTITION("48465300-0000-11AA-AA11-00306543ECAC"), + APPLE_UFS("55465300-0000-11AA-AA11-00306543ECAC"), + APPLE_ZFS("6A898CC3-1DD2-11B2-99A6-080020736631"), // This is the same GUID as SOLARIS_USR_PARTITION + APPLE_RAID_PARTITION("52414944-0000-11AA-AA11-00306543ECAC"), + APPLE_RAID_PARTITION_OFFLINE("52414944-5F4F-11AA-AA11-00306543ECAC"), + APPLE_BOOT_PARTITION("426F6F74-0000-11AA-AA11-00306543ECAC"), + APPLE_lABEL("4C616265-6C00-11AA-AA11-00306543ECAC"), + APPLE_TV_RECOVERY_PARTITION("5265636F-7665-11AA-AA11-00306543ECAC"), + APPLE_CORE_STORAGE_PARTITION("53746F72-6167-11AA-AA11-00306543ECAC"), + + // Solaris + SOLARIS_BOOT_PARTITION("6A82CB45-1DD2-11B2-99A6-080020736631"), + SOLARIS_ROOT_PARTITION("6A85CF4D-1DD2-11B2-99A6-080020736631"), + SOLARIS_SWAP_PARTITION("6A87C46F-1DD2-11B2-99A6-080020736631"), + SOLARIS_BACKUP_PARTITION("6A8B642B-1DD2-11B2-99A6-080020736631"), + SOLARIS_USR_PARTITION("6A898CC3-1DD2-11B2-99A6-080020736631"), // This is the same GUID as APPLE_ZFS + SOLARIS_VAR_PARTITION("6A8EF2E9-1DD2-11B2-99A6-080020736631"), + SOLARIS_HOME_PARTITION("6A90BA39-1DD2-11B2-99A6-080020736631"), + SOLARIS_ALTERNATE_SECTOR("6A9283A5-1DD2-11B2-99A6-080020736631"), + SOLARIS_RESERVED_PARTITION_1("6A945A3B-1DD2-11B2-99A6-080020736631"), + SOLARIS_RESERVED_PARTITION_2("6A9630D1-1DD2-11B2-99A6-080020736631"), + SOLARIS_RESERVED_PARTITION_3("6A980767-1DD2-11B2-99A6-080020736631"), + SOLARIS_RESERVED_PARTITION_4("6A96237F-1DD2-11B2-99A6-080020736631"), + SOLARIS_RESERVED_PARTITION_5("6A8D2AC7-1DD2-11B2-99A6-080020736631"), + + // NetBSD + NETBSD_SWAP_PARTITION("49F48D32-B10E-11DC-B99B-0019D1879648"), + NETBSD_FFS_PARTITION("49F48D5A-B10E-11DC-B99B-0019D1879648"), + NETBSD_LFS_PARTITION("49F48D82-B10E-11DC-B99B-0019D1879648"), + NETBSD_RAID_PARTITION("49F48DAA-B10E-11DC-B99B-0019D1879648"), + NETBSD_CONCATENATED_PARTITION("2DB519C4-B10F-11DC-B99B-0019D1879648"), + NETBSD_ENCRYPTED_PARTITION("2DB519EC-B10F-11DC-B99B-0019D1879648"), + + // ChromeOS + CHROMEOS_KERNEL("FE3A2A5D-4F32-41A7-B725-ACCC3285A309"), + CHROMEOS_ROOTFS("3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC"), + CHROMEOS_FUTURE_USE("2E0A753D-9E48-43B0-8337-B15192CB1B5E"); + + /** Logger */ + private static final Logger log = Logger.getLogger(GptPartitionTypes.class); + + private UUID uuid; + + private GptPartitionTypes() { + } + + private GptPartitionTypes(String guid) { + this.uuid = UUID.fromString(guid); + } + + /** + * Looks up a partition type from its GUID. + * + * @param partitionTypeGuid the GUID to lookup. + * @return the type or {@link #UNKNOWN} if no match is found. + */ + public static GptPartitionTypes lookUp(byte[] partitionTypeGuid) { + + StringBuilder uuidBuilder = new StringBuilder(); + + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[3], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[2], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[1], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[0], 2)); + uuidBuilder.append("-"); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[5], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[4], 2)); + uuidBuilder.append("-"); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[7], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[6], 2)); + uuidBuilder.append("-"); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[8], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[9], 2)); + uuidBuilder.append("-"); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[10], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[11], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[12], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[13], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[14], 2)); + uuidBuilder.append(NumberUtils.hex(partitionTypeGuid[15], 2)); + + try { + UUID uuidToMatch = UUID.fromString(uuidBuilder.toString()); + + for (GptPartitionTypes type : GptPartitionTypes.values()) { + if (uuidToMatch.equals(type.uuid)) { + return type; + } + } + } + catch (Exception e) { + log.warn("Exception checking uuid: " + uuidBuilder.toString()); + } + + return UNKNOWN; + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |