/* * Copyright (C) 2007 Steve Ratcliffe * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program 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 General Public License for more details. * * * Author: Steve Ratcliffe * Create date: 03-Feb-2007 */ package uk.me.parabola.imgfmt.sys; import uk.me.parabola.log.Logger; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Holds block numbers for a file. It is part of the directory. For a file * that needs more than one block several directory entries exist. Each of * these has the header with the file name etc. in it, but the first one has * extra flags and info. * * <p>What is important here is that only part of a full block is used to * hold block numbers. * * <p>The entries are 512 bytes regardless of the block size. * * @author Steve Ratcliffe */ class BlockTable { private static final Logger log = Logger.getLogger(BlockTable.class); // Offset of the block table in the directory entry block. private static final int BLOCKS_TABLE_START = 0x20; private static final int ENTRY_SIZE = 512; private static final int TABLE_SIZE = (ENTRY_SIZE - BLOCKS_TABLE_START)/2; //private final int tableSize; private int curroff; private final List<char[]> blocks; private char[] currTable; BlockTable() { blocks = new ArrayList<char[]>(200); } /** * Write out the specified table to the given buffer. * * @param buf The buffer to write to. * @param n The number of the block table to write out. */ public void writeTable(ByteBuffer buf, int n) { char[] cbuf = blocks.get(n); log.debug("block with length", cbuf.length); for (char c : cbuf) { buf.putChar(c); } } /** * Read a block table from the given buffer. The table is added to the * list. * @param buf The buffer to read from. */ public void readTable(ByteBuffer buf) { buf.position(BLOCKS_TABLE_START); buf.limit(ENTRY_SIZE); char[] cbuf = newTable(); for (int i = 0; i < cbuf.length; i++) { char c = buf.getChar(); cbuf[i] = c; } } /** * Add the given block number to this directory. * * @param n The block number to add. */ public void addBlock(int n) { char[] thisTable = currTable; if (curroff >= TABLE_SIZE || currTable == null) thisTable = newTable(); thisTable[curroff++] = (char) n; } /** * Given a logical block number, return the physical block number. * * @param lblock The logical block number, ie with respect to the file. * @return The physical block number in the file system. */ public int physFromLogical(int lblock) { int blockNum = lblock / TABLE_SIZE; int offset = lblock - blockNum * TABLE_SIZE; if (blockNum >= blocks.size()) return 0xffff; char[] cbuf = blocks.get(blockNum); return cbuf[offset]; } /** * Get the number of block tables. This is the number of blocks that * will be used in the on disk directory structure. * * @return The number of blocks tables. */ public int getNBlockTables() { return blocks.size(); } /** * Allocate a new block to hold more directory block numbers. * * @return Array for more numbers. */ private char[] newTable() { char[] table = new char[TABLE_SIZE]; Arrays.fill(table, (char) 0xffff); curroff = 0; blocks.add(table); currTable = table; return table; } }