gt: 			int reallyRead = aesRandomAccessFile.read(b);
context: /*
   * 
   *               Panbox - encryption for cloud storage 
   *      Copyright (C) 2014-2015 by Fraunhofer SIT and Sirrix AG 
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   * 
   * 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.
   * 
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   * 
   * Additonally, third party code may be provided with notices and open source
   * licenses from communities and third parties that govern the use of those
   * portions, and any licenses granted hereunder do not alter any rights and
   * obligations you may have under such open source licenses, however, the
   * disclaimer of warranty and limitation of liability provisions of the GPLv3 
   * will apply to all the product.
   * 
   */
  package org.panbox.desktop.common.vfs.backend.generic;
  
  import java.io.File;
  import java.io.IOException;
  import java.nio.ByteBuffer;
  import java.nio.file.Files;
  import java.nio.file.LinkOption;
  import java.nio.file.attribute.BasicFileAttributes;
  import java.nio.file.attribute.FileTime;
  import java.util.Hashtable;
  
  import javax.crypto.SecretKey;
  
  import org.apache.commons.io.FileUtils;
  import org.apache.log4j.Logger;
  import org.panbox.core.crypto.io.AESGCMRandomAccessFileCompat;
  import org.panbox.core.exception.FileEncryptionException;
  import org.panbox.core.exception.FileIntegrityException;
  import org.panbox.core.vfs.backend.VirtualFile;
  import org.panbox.core.vfs.backend.VirtualVolume;
  import org.panbox.desktop.common.ex.PanboxEncryptionException;
  import org.panbox.desktop.common.ex.PanboxIntegrityException;
  import org.panbox.desktop.common.vfs.backend.VirtualRandomAccessFile;
  
  public class GenericVirtualFileImpl extends VirtualRandomAccessFile {
  
  	protected File file;
  	protected AESGCMRandomAccessFileCompat aesRandomAccessFile;
  
  	protected boolean deleteFileOnClose = false;
  	
  	private final static Logger logger = Logger
  			.getLogger(GenericVirtualFileImpl.class);
  
  	/**
  	 * stores number of open file handles for each opened file
  	 */
  	final static Hashtable<AESGCMRandomAccessFileCompat, Integer> filehandleCtrMap = new Hashtable<AESGCMRandomAccessFileCompat, Integer>();
  
  	protected GenericVirtualFileImpl(String fileName, VirtualVolume volume) {
  		super(fileName, volume);
  		file = new File(fileName);
  		try {
  			if (!isDirectory()) {
  				if (exists()) {
  					aesRandomAccessFile = file.canWrite() ? AESGCMRandomAccessFileCompat
  							.getInstance(file, true)
  							: AESGCMRandomAccessFileCompat.getInstance(file,
  									false);
  					// System.err.println("getInstance(" + file.getName() + ","
  					// + aesRandomAccessFile.writable + ") -> "
  					// + aesRandomAccessFile.toString());
  				} else {
  					aesRandomAccessFile = file.getParentFile().canWrite() ? AESGCMRandomAccessFileCompat
  							.getInstance(file, true)
  							: AESGCMRandomAccessFileCompat.getInstance(file,
  									false);
  					// System.err.println("getInstance(" + file.getName() + ","
  					// + aesRandomAccessFile.writable + ") -> "
  					// + aesRandomAccessFile.toString());
  				}
  			}
  		} catch (IOException | FileEncryptionException e) {
  			logger.error("Unable to initialize AES backend", e);
  		}
  	}
  
  	@Override
  	public boolean isDirectory() {
  		return file.isDirectory();
  	}
  
  	@Override
  	public boolean delete() {
  		if (file.isDirectory()) {
  			try {
  				FileUtils.deleteDirectory(file);
  				return true;
  			} catch (IOException e) {
  				e.printStackTrace();
  				return false;
  			}
  		} else {
  			return file.delete();
  		}
  	}
  
  	@Override
  	public boolean createNewDirectory() {
  		return file.mkdirs();
  	}
  
  	@Override
  	public boolean exists() {
  		return file.exists();
  	}
  
  	@Override
  	public long length() throws IOException {
  		// return aesRandomAccessFile.length();
  		return AESGCMRandomAccessFileCompat
  				.realToVirtualFileSize(file.length());
  	}
  
  	@Override
  	public VirtualFile[] list() {
  		String[] files = file.list();
  
  		GenericVirtualFileImpl[] fileList = new GenericVirtualFileImpl[files.length];
  
  		for (int i = 0; i < files.length; ++i) {
  			fileList[i] = new GenericVirtualFileImpl(
  					new File(file, files[i]).getPath(), volume);
  		}
  
  		return fileList;
  	}
  
  	@Override
  	public String getPath() {
  		return file.getPath();
  	}
  
  	@Override
  	public String getRelativePath() {
  		return volume.getRelativePathForFile(this);
  	}
  
  	@Override
  	public boolean renameTo(VirtualFile newFile) {
  		if (isDirectory()) {
  			return file.renameTo(newFile.getFile());
  		} else {
  			// use backend rename function
  			GenericVirtualFileImpl newDFile = (GenericVirtualFileImpl) newFile;
  			if (aesRandomAccessFile.renameTo(newDFile.getFile())) {
  				this.file = newDFile.getFile();
  				return true;
  			} else {
  				return false;
  			}
  		}
  	}
  
  	@Override
  	public File getFile() {
  		return file;
  	}
  
  	@Override
  	public String toString() {
  		return file.getName() + " at " + file.getAbsoluteFile();
  	}
  
  	@Override
  	public long getCreationTime() {
  		try {
  			BasicFileAttributes attr = Files.readAttributes(file.toPath(),
  					BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
  			return attr.creationTime().toMillis();
  		} catch (IOException e) {
  			logger.error("Error in getCreationTime()", e);
  			return 0;
  		}
  	}
  
  	@Override
  	public long getLastAccessTime() {
  		try {
  			BasicFileAttributes attr = Files.readAttributes(file.toPath(),
  					BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
  			return attr.lastAccessTime().toMillis();
  		} catch (IOException e) {
  			logger.error("Error in getLastAccessTime()", e);
  			return 0;
  		}
  	}
  
  	@Override
  	public long getLastWriteTime() {
  		// return file.lastModified();
  		try {
  			BasicFileAttributes attr = Files.readAttributes(file.toPath(),
  					BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
  			return attr.lastModifiedTime().toMillis();
  		} catch (IOException e) {
  			logger.error("Error in getLastWriteTime()", e);
  			return 0;
  		}
  	}
  
  	@Override
  	public void setLastAccessTime(long atime) throws IOException {
  		if (atime > 0) {
  			FileTime fileTime = FileTime.fromMillis(atime);
  			Files.setAttribute(file.toPath(), "lastAccessTime", fileTime);
  		}
  	}
  
  	@Override
  	public void setModifiedTime(long mtime) throws IOException {
  		if (mtime > 0) {
  			FileTime fileTime = FileTime.fromMillis(mtime);
  			Files.setLastModifiedTime(file.toPath(), fileTime);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#seek(long)
  	 */
  	@Override
  	public void seek(long pos) throws IOException, PanboxEncryptionException {
  		try {
  			aesRandomAccessFile.seek(pos);
  		} catch (IOException e) {
  			throw new IOException(e.getMessage(), e);
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#getFilePointer()
  	 */
  	@Override
  	public long getFilePointer() throws IOException {
  		try {
  			return aesRandomAccessFile.getFilePointer();
  		} catch (IOException e) {
  			throw new IOException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#skipBytes(int)
  	 */
  	@Override
  	public int skipBytes(int n) throws IOException, PanboxEncryptionException {
  		try {
  			return aesRandomAccessFile.skipBytes(n);
  		} catch (IOException e) {
  			throw new IOException(e.getMessage(), e);
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#write(byte[])
  	 */
  	@Override
  	public void write(byte[] b) throws IOException, PanboxEncryptionException {
  		try {
  			aesRandomAccessFile.write(b);
  		} catch (IOException e) {
  			throw new IOException(e.getMessage(), e);
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		} catch (FileIntegrityException e) {
  			throw new PanboxIntegrityException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#write(long,
  	 * java.nio.ByteBuffer)
  	 */
  	@Override
  	public int write(long seekpos, ByteBuffer b) throws IOException,
  			PanboxEncryptionException {
  		try {
  			aesRandomAccessFile.seek(seekpos);
  			byte[] buf;
  			if (b.hasArray()) {
  				buf = b.array();
  				this.write(buf, 0, buf.length);
  			} else {
  				buf = new byte[b.remaining()];
  				b.get(buf);
  				this.write(buf, 0, buf.length);
  			}
  			return buf.length;
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#write(long,
  	 * java.nio.ByteBuffer)
  	 */
  	@Override
  	public int write(long seekpos, byte[] b) throws IOException,
  			PanboxEncryptionException {
  		try {
  			aesRandomAccessFile.seek(seekpos);
  			this.write(b, 0, b.length);
  			return b.length;
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#write(byte[], int,
  	 * int)
  	 */
  	@Override
  	public void write(byte[] b, int off, int len) throws IOException,
  			PanboxEncryptionException {
  		try {
  			aesRandomAccessFile.write(b, off, len);
  		} catch (IOException e) {
  			throw new IOException(e.getMessage(), e);
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		} catch (FileIntegrityException e) {
  			throw new PanboxIntegrityException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#write(int)
  	 */
  	@Override
  	public void write(int b) throws IOException, PanboxEncryptionException {
  		try {
  			aesRandomAccessFile.write(b);
  		} catch (IOException e) {
  			throw new IOException(e.getMessage(), e);
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		} catch (FileIntegrityException e) {
  			throw new PanboxIntegrityException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#read(byte[], int,
  	 * int)
  	 */
  	@Override
  	public int read(byte[] b, int off, int len) throws IOException,
  			PanboxEncryptionException {
  		try {
  			return aesRandomAccessFile.read(b, off, len);
  		} catch (IOException e) {
  			throw new IOException(e.getMessage(), e);
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		} catch (FileIntegrityException e) {
  			throw new PanboxIntegrityException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#read(byte[])
  	 */
  	@Override
  	public int read(byte[] b) throws IOException, PanboxEncryptionException {
  		try {
  			return aesRandomAccessFile.read(b);
  		} catch (IOException e) {
  			throw new IOException(e.getMessage(), e);
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		} catch (FileIntegrityException e) {
  			throw new PanboxIntegrityException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#read(long,
  	 * java.nio.ByteBuffer)
  	 */
  	@Override
  	public int read(long seekpos, ByteBuffer b) throws IOException,
  			PanboxEncryptionException {
  		byte[] buf = new byte[b.remaining()]; // raf.array() does not
  		// work, because backend
  		// byte[] is missing!
  		try {
  			aesRandomAccessFile.seek(seekpos);
  			int reallyRead = aesRandomAccessFile.read(buf, 0, buf.length);
  			if (reallyRead != -1) {
  				// Trim NUL-Bytes from file
  				b.put(buf, 0, reallyRead);
  				return reallyRead;
  			} else {
  				// EOF is indicated by -1; returning -1 will be misinterpreted
  				// as an ERRNO (i.e. EPERM)
  				return 0;
  			}
  		} catch (FileEncryptionException e) {
  			throw new PanboxEncryptionException(e.getMessage(), e);
  		} catch (FileIntegrityException e) {
  			throw new PanboxIntegrityException(e.getMessage(), e);
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see org.panbox.desktop.common.vfs.backend.VirtualFile#read(long,
  	 * java.nio.ByteBuffer)
  	 */
  	@Override
  	public int read(long seekpos, byte[] b) throws IOException,
  			PanboxEncryptionException {
  		try {
  			aesRandomAccessFile.seek(seekpos);
  