/* * $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 org.jnode.fs.ntfs.attribute.NTFSAttribute; import org.jnode.fs.ntfs.index.IndexEntry; /** * @author Ewout Prangsma (epr@users.sourceforge.net) */ public class MasterFileTable extends FileRecord { /** * MFT indexes of system files */ public static class SystemFiles { /** * Master file table (mft). Data attribute contains the entries and bitmap attribute records which ones are in * use (bit==1). */ public static final int MFT = 0; /** * Mft mirror: copy of first four mft records in data attribute. If cluster size > 4kiB, copy of first N mft * records, with N = cluster_size / mft_record_size. */ public static final int MFTMIRR = 1; /** * Journalling log in data attribute. */ public static final int LOGFILE = 2; /** * Volume name attribute and volume information attribute (flags and ntfs version). Windows refers to this file * as volume DASD (Direct Access Storage Device). */ public static final int VOLUME = 3; /** * Array of attribute definitions in data attribute. */ public static final int ATTRDEF = 4; /** * Root directory. */ public static final int ROOT = 5; /** * Allocation bitmap of all clusters (lcns) in data attribute. */ public static final int BITMAP = 6; /** * Boot sector (always at cluster 0) in data attribute. */ public static final int BOOT = 7; /** * Contains all bad clusters in the non-resident data attribute. */ public static final int BADCLUS = 8; /** * Shared security descriptors in data attribute and two indexes into the descriptors. Appeared in Windows 2000. * Before that, this file was named $Quota but was unused. */ public static final int SECURE = 9; /** * Uppercase equivalents of all 65536 Unicode characters in data attribute. */ public static final int UPCASE = 10; /** * Directory containing other system files (eg. $ObjId, $Quota, $Reparse and $UsnJrnl). This is new to NTFS3.0. */ public static final int EXTEND = 11; /** * Reserved for future use (records 12-15). */ public static final int RESERVED12 = 12; /** * Reserved for future use (records 12-15). */ public static final int RESERVED13 = 13; /** * Reserved for future use (records 12-15). */ public static final int RESERVED14 = 14; /** * Reserved for future use (records 12-15). */ public static final int RESERVED15 = 15; /** * First user file, used as test limit for whether to allow opening a file or not. */ public static final int FIRST_USER = 16; } /** * The cached length of the MFT. */ private long mftLength; /** * @param volume * @param buffer * @throws IOException */ public MasterFileTable(NTFSVolume volume, byte[] buffer, int offset) throws IOException { super(volume, SystemFiles.MFT, buffer, offset); } /** * Creates a new MFT instance. * * @param volume the NTFS volume. * @param bytesPerSector the bytes per-sector. * @param clusterSize the cluster size. * @param strictFixUp indicates whether to throw an exception if a fix-up error is detected. * @param buffer the buffer to read from. * @param offset the offset to read at. * @throws IOException if an error occurs creating the MFT. */ public MasterFileTable(NTFSVolume volume, int bytesPerSector, int clusterSize, boolean strictFixUp, byte[] buffer, int offset) throws IOException { super(volume, bytesPerSector, clusterSize, strictFixUp, SystemFiles.MFT, buffer, offset); } /** * Gets the length of the MFT. * * @return the length. */ public long getMftLength() { if (mftLength == 0) { // The MFT doesn't update the FileRecord file-size for itself, so fall back to check the size of the DATA // attribute. mftLength = getAttributeTotalSize(NTFSAttribute.Types.DATA, null); } return mftLength; } /** * Reads the bytes for a MFT record with a given index but does not check if it is a valid file record. * * @param index the index to get. * @return the file record. */ public byte[] readRecord(long index) throws IOException { final NTFSVolume volume = getVolume(); final int bytesPerFileRecord = volume.getBootRecord().getFileRecordSize(); final long offset = bytesPerFileRecord * index; // read the buffer final byte[] buffer = new byte[bytesPerFileRecord]; readData(offset, buffer, 0, bytesPerFileRecord); return buffer; } /** * Gets a MFT record with a given index but does not check if it is a valid file record. * * @param index the index to get. * @return the file record. */ public FileRecord getRecordUnchecked(long index) throws IOException { log.debug("getRecord(" + index + ")"); final NTFSVolume volume = getVolume(); // read the buffer final byte[] buffer = readRecord(index); return new FileRecord(volume, index, buffer, 0); } /** * Gets a MFT record with a given index. * * @param index the index to get. * @return the file record. * @throws IOException if the record at the index is not valid or there is an error reading in the data. */ public FileRecord getRecord(long index) throws IOException { final NTFSVolume volume = getVolume(); final int bytesPerFileRecord = volume.getBootRecord().getFileRecordSize(); final long offset = bytesPerFileRecord * index; if (offset + bytesPerFileRecord > getMftLength()) { throw new IOException("Attempt to read past the end of the MFT, offset: " + offset); } FileRecord fileRecord = getRecordUnchecked(index); fileRecord.checkIfValid(); return fileRecord; } public FileRecord getIndexedFileRecord(IndexEntry indexEntry) throws IOException { return getRecord(indexEntry.getFileReferenceNumber()); } }