/*
* $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.io.IOException;
import org.jnode.fs.FileSystemException;
/**
* This class represents a part of the inode table (that which is contained
* in one block group).
*
* It provides methods for reading and writing the (already allocated) inodes.
*
* An inode table contains just the inodes, with no extra metadata.
*
* @author Andras Nagy
*/
public class INodeTable {
private final int blockSize;
int blockCount;
Ext2FileSystem fs;
int firstBlock; // the first block of the inode table
public INodeTable(Ext2FileSystem fs, int firstBlock) {
this.fs = fs;
this.firstBlock = firstBlock;
blockSize = fs.getBlockSize();
blockCount =
(int) Ext2Utils.ceilDiv(
fs.getSuperblock().getINodesPerGroup() * fs.getSuperblock().getINodeSize(), blockSize);
}
public static int getSizeInBlocks(Ext2FileSystem fs) {
return (int) Ext2Utils.ceilDiv(
fs.getSuperblock().getINodesPerGroup() * fs.getSuperblock().getINodeSize(),
fs.getBlockSize());
}
/**
* get the <code>blockNo</code>th block from the beginning of the inode
* table
*
* @param blockNo
* @return the contents of the block as a byte[]
* @throws FileSystemException
* @throws IOException
*/
private byte[] getINodeTableBlock(long blockNo) throws FileSystemException, IOException {
if (blockNo < blockCount)
return fs.getBlock(firstBlock + blockNo);
else
throw new FileSystemException("Trying to get block #" + blockNo +
"of an inode table that only has " + blockCount + " blocks");
}
/**
* Write the <code>blockNo</code>th block (from the beginning of the
* inode table)
*
* @param data
* @param blockNo
* @throws FileSystemException
* @throws IOException
*/
private void writeINodeTableBlock(byte[] data, int blockNo)
throws FileSystemException, IOException {
if (blockNo < blockCount)
fs.writeBlock(firstBlock + blockNo, data, false);
else
throw new FileSystemException("Trying to write block #" + blockNo +
"of an inode table that only has " + blockCount + " blocks");
}
/**
* Get the indexth inode from the inode table. (index is not an inode
* number, it is just an index in the inode table)
*
* For each inode table, only one instance of INodeTable exists, so it is
* safe to synchronize to it
*/
public synchronized byte[] getInodeData(int index) throws IOException, FileSystemException {
int iNodeSize = fs.getSuperblock().getINodeSize();
byte data[] = new byte[iNodeSize];
int indexCopied = 0;
while (indexCopied < iNodeSize) {
long blockNo = (index * iNodeSize + indexCopied) / blockSize;
int blockOffset = (index * iNodeSize + indexCopied) % blockSize;
int copyLength = Math.min(blockSize - blockOffset, iNodeSize);
System.arraycopy(getINodeTableBlock(blockNo), blockOffset, data, indexCopied,
copyLength);
indexCopied += copyLength;
}
return data;
}
/*
* For each inode table, only one instance of INodeTable exists, so it is
* safe to synchronize to it
*/
public synchronized void writeInodeData(int index, byte[] data) throws IOException, FileSystemException {
int iNodeSize = fs.getSuperblock().getINodeSize();
int indexCopied = 0;
while (indexCopied < iNodeSize) {
int blockNo = (index * iNodeSize + indexCopied) / blockSize;
int blockOffset = (index * iNodeSize + indexCopied) % blockSize;
int copyLength = Math.min(blockSize - blockOffset, iNodeSize);
byte[] originalBlock = getINodeTableBlock(blockNo);
System.arraycopy(data, indexCopied, originalBlock, blockOffset, copyLength);
indexCopied += copyLength;
writeINodeTableBlock(originalBlock, blockNo);
}
}
}