/*
* $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.jfat;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.NoSuchElementException;
import org.apache.log4j.Logger;
import org.jnode.fs.FSFile;
import org.jnode.fs.FSFileSlackSpace;
public class FatFile extends FatEntry implements FSFile, FSFileSlackSpace {
private static final Logger log = Logger.getLogger(FatFile.class);
public FatFile(FatFileSystem fs, FatDirectory parent, FatRecord record) {
super(fs, parent, record);
}
public boolean isFile() {
return true;
}
public FSFile getFile() {
return this;
}
public long getLength() {
return getEntry().getLength();
}
private void freeClusters(long oldLength, long newLength) throws IOException {
if (newLength >= oldLength) throw new UnsupportedOperationException("new[" + newLength + "] >= old["
+ oldLength + "]");
long clusterSize = getFatFileSystem().getFat().getClusterSize();
int oldClusters = (int) (oldLength / clusterSize);
if ((oldLength % clusterSize) != 0) oldClusters++;
int newClusters = (int) (newLength / clusterSize);
if ((newLength % clusterSize) != 0) newClusters++;
getChain().free(oldClusters - newClusters);
}
public void setLength(long length) throws IOException {
long l = getLength();
if (length == l) return;
if (length > l) {
seek(length);
} else {
freeClusters(l, length);
getEntry().setLength(length);
flush();
}
}
public void read(long offset, ByteBuffer dst) throws IOException {
int limit = dst.limit();
long length = getLength();
long rem = length - offset;
if (rem <= 0) return;
try {
if (rem < dst.remaining()) dst.limit(dst.position() + (int) rem);
getChain().read(offset, dst);
} catch (NoSuchElementException ex) {
log.debug("End Of Chain reached: shouldn't happen");
} finally {
dst.limit(limit);
}
}
public void seek(long offset) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(0);
write(offset, buf);
}
public void write(long offset, ByteBuffer src) throws IOException {
if (offset < 0) throw new IllegalArgumentException("offset<0");
long lst = offset + src.remaining();
long length = getLength();
FatChain chain = getChain();
chain.write(length, offset, src);
if (lst > length) getEntry().setLength(lst);
if (lst != offset) setLastModified(System.currentTimeMillis());
flush();
}
@Override
public byte[] getSlackSpace() throws IOException {
int clusterSize = ((FatFileSystem) getFileSystem()).getClusterSize();
Fat fat = ((FatFileSystem) getFileSystem()).getFat();
int offset = (int) (getLength() % clusterSize);
int slackSpaceSize = clusterSize - offset;
if (slackSpaceSize == clusterSize) {
return new byte[0];
}
byte[] slackSpace = new byte[slackSpaceSize];
if (getEntry().isFreeDirEntry()) {
int cluster = getStartCluster() + (int) (getLength() / clusterSize);
fat.readCluster(cluster, offset, ByteBuffer.wrap(slackSpace));
} else {
getChain().read(getLength(), ByteBuffer.wrap(slackSpace));
}
return slackSpace;
}
@Override
public String toString() {
return String.format("FatFile [%s] index:%d size:%d", getName(), getIndex(), getLength());
}
public String toDebugString() {
StrWriter out = new StrWriter();
out.println("*******************************************");
out.println("FatFile");
out.println("*******************************************");
out.println("Index\t\t" + getIndex());
out.println(toStringValue());
out.println("Length\t\t" + getLength());
out.print("*******************************************");
return out.toString();
}
}