/* * $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.ext2; import java.util.Arrays; import org.apache.log4j.Logger; import org.jnode.fs.FileSystemException; import org.jnode.util.LittleEndian; /** * A single directory record, i.e. the inode number and name of an entry in a * directory * * @author Andras Nagy */ public class Ext2DirectoryRecord { private final Logger log = Logger.getLogger(getClass()); /* * private int iNodeNr; private int recLen; private short nameLen; private * short type; private StringBuffer name; */ private int offset; private byte[] data; private long fileOffset; private Ext2FileSystem fs; /** * @param data the data that makes up the directory block * @param offset the offset where the current DirectoryRecord begins within * the block * @param fileOffset the offset from the beginning of the directory file */ public Ext2DirectoryRecord(Ext2FileSystem fs, byte[] data, int offset, int fileOffset) { this.fs = fs; this.data = data; this.offset = offset; this.fileOffset = fileOffset; // make a copy of the data synchronized (data) { byte[] newData = new byte[Math.max(8, getRecLen())]; System.arraycopy(data, offset, newData, 0, getRecLen()); this.data = newData; setOffset(0); } } /** * Create a new Ext2DirectoryRecord from scratch (it can be retrieved with * getData()) * * @param iNodeNr * @param type * @param name */ public Ext2DirectoryRecord(Ext2FileSystem fs, long iNodeNr, int type, String name) { this.offset = 0; this.fs = fs; data = new byte[8 + name.length()]; setName(name); setINodeNr(iNodeNr); setType(type); int newLength = name.length() + 8; // record length is padded to n*4 bytes if (newLength % 4 != 0) newLength += 4 - newLength % 4; setRecLen(newLength); } public byte[] getData() { return data; } public int getOffset() { return offset; } private void setOffset(int offset) { this.offset = offset; } public long getFileOffset() { return fileOffset; } private void setFileOffset(long fileOffset) { this.fileOffset = fileOffset; } /** * Returns the fileType. * * @return short */ public synchronized int getType() { return LittleEndian.getUInt8(data, offset + 7); } private synchronized void setType(int type) { if (!fs.hasIncompatFeature(Ext2Constants.EXT2_FEATURE_INCOMPAT_FILETYPE)) return; Ext2Utils.set8(data, offset + 7, type); } /** * Returns the iNodeNr. * * @return long */ public synchronized long getINodeNr() { return LittleEndian.getUInt32(data, offset); } private synchronized void setINodeNr(long nr) { Ext2Utils.set32(data, offset, nr); } /** * Returns the name. * * @return StringBuffer */ public synchronized String getName() { String name = ""; if (getINodeNr() != 0) { name = new String(data, offset + 8, getNameLen(), Ext2FileSystem.ENTRY_NAME_CHARSET); log.debug("Ext2DirectoryRecord(): iNode=" + getINodeNr() + ", name=" + name); } return name; } private synchronized void setName(String name) { byte[] nameData = name.getBytes(Ext2FileSystem.ENTRY_NAME_CHARSET); System.arraycopy(nameData, 0, data, offset + 8, nameData.length); setNameLen(nameData.length); } /** * Returns the recLen. * * @return int */ public synchronized int getRecLen() { return LittleEndian.getUInt16(data, offset + 4); } private synchronized void setRecLen(int len) { LittleEndian.setInt16(data, offset + 4, len); } public synchronized int getNameLen() { return LittleEndian.getUInt8(data, offset + 6); } private synchronized void setNameLen(int len) { Ext2Utils.set8(data, offset + 6, len); } /** * The last directory record's length is set such that it extends until the * end of the block. This method truncates it when a new record is added to * the directory */ protected synchronized void truncateRecord() { int newLength = getNameLen() + 8; // record length is padded to n*4 bytes if (newLength % 4 != 0) newLength += 4 - newLength % 4; setRecLen(newLength); log.debug("truncateRecord(): newLength: " + newLength); } /** * The last directory record's length is set such that it extends until the * end of the block. This method extends the directory record to this * length. The directoryRecord's <code>fileOffset</code> will be set to * <code>beginning</code>. * * @param beginning the offset where the record begins * @param end the offset where the record should end (usually the size a * filesystem block) */ protected synchronized void expandRecord(long beginning, long end) throws FileSystemException { log.debug("expandRecord(" + beginning + ", " + end + ")"); if (beginning + getNameLen() + 8 < end) { // the record fits in the block setRecLen((int) (end - beginning)); // pad the end of the record with zeroes byte[] newData = new byte[getRecLen()]; Arrays.fill(newData, 0, getRecLen(), (byte) 0); System.arraycopy(data, getOffset(), newData, 0, getNameLen() + 8); setOffset(0); setFileOffset(beginning); data = newData; } else { throw new FileSystemException("The directory record does not fit into the block!"); } log.debug("expandRecord(): newLength: " + getRecLen()); } }