/* * $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.fs.ntfs; import java.io.IOException; import java.nio.ByteBuffer; import org.apache.log4j.Logger; import org.jnode.driver.block.BlockDeviceAPI; /** * @author Chira */ public class NTFSVolume { private static final Logger log = Logger.getLogger(NTFSVolume.class); public static final byte LONG_FILE_NAMES = 0x01; public static final byte DOS_8_3 = 0x02; private byte currentNameSpace = LONG_FILE_NAMES; private final BlockDeviceAPI api; // local chache for faster access private final int clusterSize; private final BootRecord bootRecord; private MasterFileTable mftFileRecord; private FileRecord rootDirectory; /** * Initialize this instance. */ public NTFSVolume(BlockDeviceAPI api) throws IOException { // I hope this is enaugh..should be this.api = api; // Read the boot sector final ByteBuffer buffer = ByteBuffer.allocate(512); api.read(0, buffer); this.bootRecord = new BootRecord(buffer.array()); this.clusterSize = bootRecord.getClusterSize(); } /** * @return Returns the bootRecord. */ public final BootRecord getBootRecord() { return bootRecord; } /** * Read a single cluster. * * @param cluster */ public void readCluster(long cluster, byte[] dst, int dstOffset) throws IOException { final int clusterSize = getClusterSize(); final long clusterOffset = cluster * clusterSize; log.debug("readCluster(" + cluster + ") " + (readClusterCount++)); api.read(clusterOffset, ByteBuffer.wrap(dst, dstOffset, clusterSize)); } private int readClusterCount; private int readClustersCount; /** * Read a number of clusters. * * @param firstCluster * @param nrClusters The number of clusters to read. * @param dst Must have space for (nrClusters * getClusterSize()) * @param dstOffset * @throws IOException */ public void readClusters(long firstCluster, byte[] dst, int dstOffset, int nrClusters) throws IOException { log.debug("readClusters(" + firstCluster + ", " + nrClusters + ") " + (readClustersCount++)); final int clusterSize = getClusterSize(); final long clusterOffset = firstCluster * clusterSize; api.read(clusterOffset, ByteBuffer.wrap(dst, dstOffset, nrClusters * clusterSize)); } /** * Gets the size of a cluster. * * @return the size */ public int getClusterSize() { return clusterSize; } /** * Gets the MFT. * * @return Returns the mTFRecord. */ public MasterFileTable getMFT() throws IOException { if (mftFileRecord == null) { final BootRecord bootRecord = getBootRecord(); final int bytesPerFileRecord = bootRecord.getFileRecordSize(); final int clusterSize = getClusterSize(); final int nrClusters; if (bytesPerFileRecord < clusterSize) { nrClusters = 1; } else { nrClusters = (bytesPerFileRecord + clusterSize - 1) / clusterSize; } final byte[] data = new byte[nrClusters * clusterSize]; readClusters(bootRecord.getMftLcn(), data, 0, nrClusters); mftFileRecord = new MasterFileTable(this, data, 0); mftFileRecord.checkIfValid(); } return mftFileRecord; } /** * Gets the root directory on this volume. * * @return the root directory record * @throws IOException */ public FileRecord getRootDirectory() throws IOException { if (rootDirectory == null) { // Read the root directory final MasterFileTable mft = getMFT(); rootDirectory = mft.getRecord(MasterFileTable.SystemFiles.ROOT); log.info("getRootDirectory: " + rootDirectory.getFileName()); } return rootDirectory; } /** * @return Returns the currentNameSpace. */ public byte getCurrentNameSpace() { return currentNameSpace; } }