/*
*
* 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.windows.vfs;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.FileAlreadyExistsException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import net.decasdev.dokan.CreationDisposition;
import net.decasdev.dokan.DokanDiskFreeSpace;
import net.decasdev.dokan.DokanFileInfo;
import net.decasdev.dokan.DokanVolumeInformation;
import net.decasdev.dokan.Win32FindData;
import org.apache.log4j.Logger;
import org.panbox.core.exception.ObfuscationException;
import org.panbox.core.keymgmt.ShareKey;
import org.panbox.core.vfs.backend.VirtualFile;
import org.panbox.desktop.common.ex.PanboxCreateFailedException;
import org.panbox.desktop.common.ex.PanboxDeleteFailedException;
import org.panbox.desktop.common.ex.PanboxEncryptionException;
import org.panbox.desktop.common.vfs.FileCreationFlags;
import org.panbox.desktop.common.vfs.PanboxFS;
import org.panbox.desktop.common.vfs.PanboxFSAdapter;
import org.panbox.desktop.common.vfs.backend.VirtualRandomAccessFile;
import org.panbox.desktop.common.vfs.backend.exceptions.SecretKeyNotFoundException;
public class PanboxFSWindows extends PanboxFS {
private static final Logger logger = Logger
.getLogger("org.panbox.desktop.common");
private final static ConcurrentHashMap<Long, VirtualRandomAccessFile> fileInstanceTable = new ConcurrentHashMap<Long, VirtualRandomAccessFile>();
// 1611421524 = P A N B O X in alphabet
private final static AtomicInteger WINDOWS_DOKAN_VFS_SERIAL_NUMBER = new AtomicInteger(
1611421524);
/**
* {@link Random}-instance for file handle generation
*/
private final Random handlerandom = new Random(System.nanoTime());
private long setHandle(DokanFileInfo info) {
if (info.handle == 0) {
return (info.handle = handlerandom.nextLong());
} else {
return info.handle;
}
}
protected synchronized VirtualFile getVirtualFileForFileName(String fileName)
throws SecretKeyNotFoundException, FileNotFoundException,
ObfuscationException {
return super.getVirtualFileForFileName(fileName, true);
}
public static FileCreationFlags fromDokan(final int value) {
switch (value) {
case CreationDisposition.CREATE_NEW:
return FileCreationFlags.CREATE_NEW;
case CreationDisposition.OPEN_ALWAYS:
return FileCreationFlags.OPEN_ALWAYS;
case CreationDisposition.OPEN_EXISTING:
return FileCreationFlags.OPEN_EXISTING;
case CreationDisposition.CREATE_ALWAYS:
return FileCreationFlags.CREATE_ALWAYS;
case CreationDisposition.TRUNCATE_EXISTING:
return FileCreationFlags.TRUNCATE_EXISTING;
}
return null;
}
public PanboxFSWindows(PanboxFSAdapter backend) {
super(backend);
}
public synchronized void closeFile(String fileName, DokanFileInfo fileInfo,
boolean isDeletable) throws IOException {
logger.debug("PanboxFS : closeFile : " + fileName + ", fileInfo: "
+ fileInfo);
if (!isDeletable) {
VirtualRandomAccessFile v = fileInstanceTable.get(fileInfo.handle);
if (v != null) {
logger.debug("PanboxFS : closeFile : Found an instance with the handle number. Will close it now!");
if (v.isOpened()) {
v.close();
}
} else {
logger.debug("PanboxFS : closeFile : Could not find instance to be closed. If this is a directory it should be just fine!");
}
}
fileInstanceTable.remove(fileInfo.handle);
}
public synchronized void cleanup(String fileName, DokanFileInfo fileInfo)
throws IOException {
logger.debug("PanboxFS : cleanup : " + fileName + ", fileInfo: "
+ fileInfo);
VirtualRandomAccessFile v = fileInstanceTable.get(fileInfo.handle);
if (v != null) {
logger.debug("PanboxFS : cleanup : Found file, will flush it now!");
if (v.isOpened()) {
v.flush();
}
logger.debug("PanboxFS : cleanup : VirtualFile(" + fileName
+ ").flush() was successful.");
} else {
logger.debug("PanboxFS : cleanup : Could not find instance to be flushed. If this is a directory it should be just fine!");
}
}
public synchronized void createDirectory(String fileName,
DokanFileInfo fileInfo) throws SecretKeyNotFoundException,
FileNotFoundException, PanboxCreateFailedException, FilenameExceededRangeException {
logger.debug("PanboxFS : createDirectory : " + fileName);
try {
// Only create directory if it does not exist already!
VirtualFile directory = getVirtualFileForFileName(fileName, true);
if (!directory.exists()) {
// Check if directoryname is too long for backend Windows path
if(directory.getFile().getAbsolutePath().length() >= 255) {
throw new FilenameExceededRangeException( directory.getFile().getAbsolutePath().length() );
}
boolean success = directory.createNewDirectory();
if (!success) {
throw new PanboxCreateFailedException(
"Failed to create directory '" + fileName + "'.");
} else {
logger.debug("PanboxFS : createDirectory : VirtualFile("
+ fileName
+ ").createNewDirectory() was successful.");
}
}
} catch (ObfuscationException e) {
throw new PanboxCreateFailedException("Obfuscation failed!");
}
}
public synchronized boolean createFile(String fileName,
int creationDisposition, int flagsAndAttributes,
boolean shareModeDeletable, boolean deleteOnClose,
DokanFileInfo fileInfo) throws PanboxCreateFailedException,
PathNotFoundException, FilenameExceededRangeException {
final FileCreationFlags disposition = fromDokan(creationDisposition);
logger.debug("PanboxFS : createFile : fileName: " + fileName
+ ", disposition: " + disposition + ", flagsAndAttributes: "
+ flagsAndAttributes + ", shareModeDeletable: "
+ shareModeDeletable + ", deleteOnClose: " + deleteOnClose
+ ", fileInfo: " + fileInfo);
long handle = setHandle(fileInfo);
try {
VirtualFile virt = getVirtualFileForFileName(fileName, true);
if (virt.isDirectory()) {
// this is a directory!
fileInfo.isDirectory = true;
if (!virt.exists() && !disposition.shouldCreate()) {
return false;
}
return true;
} else {
// this is a file!
if (disposition.shouldCreate() || disposition.shouldOpen()) {
@SuppressWarnings("resource")
// will be closed in close call!
VirtualRandomAccessFile file = (VirtualRandomAccessFile) virt;
// Check if filename is too long for backend Windows path
if(file.getFile().getAbsolutePath().length() >= 255) {
throw new FilenameExceededRangeException( file.getFile().getAbsolutePath().length() );
}
if (!file.exists()) {
if (!getVirtualFileForFileName(
fileName.substring(0,
fileName.lastIndexOf("\\")), false)
.exists()) {
throw new PathNotFoundException();
}
if (!disposition.shouldCreate()) {
return false;
}
try {
ShareKey shareKey = backingStorage
.getLatestShareKeyForFile(fileName);
// -- BEGIN --
/*
* This piece of code is needed since Windows
* sometimes still holds file instances after a
* delete call was done. Therefore the create()-call
* will cause an IOException with the message
* "Access denied.". After Windows gave this file
* free on file system the create call will work
* just fine. We will try this 10 times with a sleep
* of 10ms betweeen the files. This is a work-around
* for SVN and Git! It might also be needed for
* other files or applications that are being
* created and deleted in very short times.
*/
int maxTries = 10;
while (maxTries > 0) {
try {
file.create(shareKey.version, shareKey.key);
break;
} catch (IOException ex) {
--maxTries;
logger.debug("PanboxFS : createFile : Exception creating file. Will try it "
+ maxTries + " more tries.");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// ignore
}
}
}
if (maxTries == 0 && !file.isOpened()) {
throw new PanboxCreateFailedException(
"Could not create file. Perhaps access is denied!");
}
// -- END --
if (deleteOnClose) {
file.setDeleteOnClose();
}
logger.debug("PanboxFS : createFile : VirtualFile("
+ fileName + ").create() was successful.");
} catch (IOException | PanboxEncryptionException e) {
throw new PanboxCreateFailedException(
"Failed to create file '" + fileName
+ "': ", e);
}
} else {
if (!shareModeDeletable) {
file.open();
file.initWithShareKey(backingStorage
.getShareKeyForFile(fileName,
file.getShareKeyVersion()));
if (deleteOnClose) {
file.setDeleteOnClose();
}
logger.debug("PanboxFS : createFile : VirtualFile("
+ fileName
+ ").open() and .init() was successful.");
} else {
logger.debug("PanboxFS : createFile : VirtualFile("
+ fileName
+ ") should be deletable. Therefor it has not been opened!");
long osVersion = Long.valueOf(System.getProperty("os.version"));
if ( osVersion >= 6.2 ) {
// This is a workaround for Windows 8/2012 Server and newer
// This includes Windows 8.1, 2012 R2 Server, 10, 2016 Server and more
// The DeleteFile call is not working in Dokan
// on Windows 8+ so we need to run this
// workaround here in order to remove the file!
boolean deleted = file.delete();
if (deleted) {
logger.debug("PanboxFS : createFile : Delete workaround successful!");
} else {
logger.debug("PanboxFS : createFile : Delete workaround failed!");
}
return true;
}
}
logger.debug("PanboxFS : createFile : shouldCreate or shouldOpen for '"
+ fileName + "' has been successful.");
}
} else if (disposition.shouldTruncate()) {
try {
@SuppressWarnings("resource")
// will be closed in close call!
VirtualRandomAccessFile file = (VirtualRandomAccessFile) virt;
file.open();
file.initWithShareKey(backingStorage
.getShareKeyForFile(fileName,
file.getShareKeyVersion()));
file.setLength(0);
} catch (IOException | PanboxEncryptionException e) {
throw new PanboxCreateFailedException(
"Failed to open existing file for truncating '"
+ fileName + "'.");
}
}
if (disposition.hasToExist()) {
try {
getFileInfo(fileName, false, true);
} catch (IOException ex) {
logger.debug("PanboxFS : createFile : creation.hasToExist() but did not exist.");
return false;
}
}
fileInstanceTable.put(handle, (VirtualRandomAccessFile) virt);
logger.debug("PanboxFS : createFile : handle for file "
+ fileName + " has been set: " + fileInfo);
return true;
}
} catch (IOException | ObfuscationException | PanboxEncryptionException e) {
throw new PanboxCreateFailedException(
"Failed to get VirtualFile for filename '" + fileName
+ "':", e);
}
}
public synchronized void deleteDirectory(String fileName,
DokanFileInfo fileInfo) throws IOException,
PanboxDeleteFailedException {
logger.debug("PanboxFS : deleteDirectory : " + fileName);
try {
// there is no need to do some manual recursion anymore.
boolean success = getVirtualFileForFileName(fileName).delete();
if (!success) {
logger.error("PanboxFS : deleteDirectory : VirtualFile("
+ fileName + ").deleteDirectory() failed.");
throw new PanboxDeleteFailedException("VirtualFile(" + fileName
+ ").deleteDirectory() failed.");
} else {
logger.debug("PanboxFS : deleteDirectory : VirtualFile("
+ fileName + ").deleteDirectory() was successful.");
}
} catch (ObfuscationException e) {
throw new IOException("Obfuscation failed!");
}
}
public synchronized void deleteFile(String fileName, DokanFileInfo fileInfo)
throws PanboxDeleteFailedException, IOException {
logger.debug("PanboxFS : deleteFile : " + fileName);
VirtualRandomAccessFile v = fileInstanceTable.get(fileInfo.handle);
if (v != null) {
logger.debug("PanboxFS : deleteFile : Found an instance with the handle number. Will delete it now!");
while (v.isOpened()) {
logger.debug("PanboxFS : deleteFile : Instance is still opened! Will close it before deletion.");
v.close();
}
// -- BEGIN --
/*
* This piece of code is needed since Windows sometimes still holds
* file instances after a close call was done. Therefore the
* delete()-call will cause an IOException with the message
* "Access denied.". After Windows gave this file free on file
* system the delete call will work just fine. We will try this 10
* times with a sleep of 10ms between the files. This is a
* work-around for SVN and Git! It might also be needed for other
* files or applications that are being created and deleted in very
* short times.
*/
int maxTries = 10;
boolean success = false;
while (maxTries > 0) {
success = v.delete();
if (success) {
break;
} else {
--maxTries;
logger.debug("PanboxFS : deleteFile : Error deleting file. Will try it "
+ maxTries + " more tries.");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// ignore
}
}
}
// -- END --
if (!success) {
logger.error("PanboxFS : deleteFile : VirtualFile(" + fileName
+ ").deleteFile() failed.");
throw new PanboxDeleteFailedException("VirtualFile(" + fileName
+ ").deleteFile() failed.");
} else {
logger.debug("PanboxFS : deleteFile : VirtualFile(" + fileName
+ ").deleteFile() was successful.");
}
} else {
logger.error("PanboxFS : closeFile : Could not find instance to be deleted. Ignored request.");
throw new PanboxDeleteFailedException(
"Could not find handle for rquest: VirtualFile(" + fileName
+ ").");
}
}
public synchronized Win32FindData[] findFiles(String fileName,
String pattern, DokanFileInfo fileInfo)
throws FileNotFoundException {
logger.debug("PanboxFS : findFiles : " + fileName);
VirtualFile[] files = null;
try {
if (fileName.equals(File.separator)) {
files = backingStorage.getFile(fileName).list();
} else {
files = getVirtualFileForFileName(fileName).list();
}
} catch (IOException | ObfuscationException e) {
files = new VirtualFile[0];
}
final ArrayList<String> list = new ArrayList<String>();
for (final VirtualFile s : files) {
// Ignore files starts with .dropbox or are .panbox and desktop.ini
String nameOfFile = s.getFileName().substring(
s.getFileName().lastIndexOf(File.separator) + 1);
logger.trace("PanboxFS : findFiles : nameOfFile: " + nameOfFile);
if (nameOfFile.toLowerCase().startsWith(".dropbox")
|| nameOfFile.toLowerCase().equals("desktop.ini")
|| nameOfFile.toLowerCase().equals(".panbox")) {
// ignore file
logger.trace("PanboxFS : findFiles : Ignoring file starting with '.': "
+ nameOfFile + " (" + fileName + ")");
continue;
}
list.add(backingStorage.getRelativePathForFile(s));
}
final List<Win32FindData> data = new ArrayList<Win32FindData>();
FileInfo info;
for (final String s : list) {
try {
info = getFileInformation(s, true, false, null);
} catch (SecretKeyNotFoundException e) {
logger.error(
"DokanUserFS::onFindFiles(_getFileInfo) : Caught exception SecretKeyNotFoundException from PanboxFS, Ignore file: ",
e);
continue;
} catch (FileNotFoundException e) {
logger.error(
"DokanUserFS::onFindFiles(_getFileInfo) : Caught exception FileNotFoundException from PanboxFS, Ignore file: ",
e);
continue;
} catch (IOException e) {
logger.error(
"DokanUserFS::onFindFiles(_getFileInfo) : Caught exception IOException from PanboxFS, Ignore file: ",
e);
continue;
}
data.add(info.toFindData());
}
return data.toArray(new Win32FindData[] {});
}
public synchronized void flushFileBuffers(String fileName,
DokanFileInfo fileInfo) throws IOException {
logger.debug("PanboxFS : flushFileBuffers : Will forward flush to cleanup call!");
cleanup(fileName, fileInfo);
}
public synchronized DokanDiskFreeSpace getDiskFreeSpace(
DokanFileInfo fileInfo) {
return new DokanDiskFreeSpace(getFreeBytes(), getUsableBytes(),
getTotalBytes());
}
public synchronized FileInfo getFileInformation(String fileName,
boolean alreadyObfuscated, boolean outputObfuscated,
DokanFileInfo fileInfo) throws IOException {
logger.debug("PanboxFS : getFileInformation : " + fileName
+ ", alreadyObfuscated: " + alreadyObfuscated
+ ", outputObfuscated: " + outputObfuscated);
return (FileInfo) getFileInfo(fileName, alreadyObfuscated,
outputObfuscated);
}
public synchronized DokanVolumeInformation getVolumeInformation(
String volumeName, DokanFileInfo fileInfo) {
logger.debug("PanboxFS : getVolumeInformation : " + volumeName
+ ", fileInfo: " + fileInfo);
return new DokanVolumeInformation(getVolumeName(), getFilesystemName(),
50, WINDOWS_DOKAN_VFS_SERIAL_NUMBER.get());
}
public synchronized void lockFile(String fileName, long byteOffset,
long length, DokanFileInfo fileInfo) {
logger.debug("PanboxFS : lockFile : No implementation executed!");
}
public synchronized void moveFile(String existingFileName,
String newFileName, boolean replaceExisiting, DokanFileInfo fileInfo)
throws IOException {
logger.debug("PanboxFS : moveFile : " + existingFileName + " -> "
+ newFileName);
try {
final VirtualFile newFile = getVirtualFileForFileName(newFileName,
true);
if (newFile.exists() && !replaceExisiting) {
throw new FileAlreadyExistsException(newFileName, newFile
.getFile().getAbsolutePath(),
"New file exists and should not be replaced.");
}
VirtualRandomAccessFile v = fileInstanceTable.get(fileInfo.handle);
if (v != null) {
logger.debug("PanboxFS : moveFile : Found an instance with the handle number. Will move it now!");
while (v.isOpened()) {
logger.debug("PanboxFS : moveFile : Instance is still opened! Will flush and close it before moving.");
v.flush();
v.close();
}
// -- BEGIN --
/*
* This piece of code is needed since Windows sometimes still
* holds file instances after a close call was done. Therefore
* the renameTo()-call will cause an IOException with the
* message "Access denied.". After Windows gave this file free
* on file system the move call will work just fine. We will try
* this 10 times with a sleep of 10ms between the files. This is
* a work-around for SVN and Git! It might also be needed for
* other files or applications that are being created and
* deleted in very short times.
*/
int maxTries = 10;
boolean success = false;
while (maxTries > 0) {
success = v.renameTo(newFile);
if (success) {
break;
} else {
--maxTries;
logger.debug("PanboxFS : moveFile : Error moving file. Will try it "
+ maxTries + " more tries.");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// ignore
}
}
}
// -- END --
if (!success) {
logger.error("PanboxFS : moveFile : VirtualFile("
+ existingFileName + ").renameTo(" + newFileName
+ ") failed.");
} else {
logger.debug("PanboxFS : moveFile : VirtualFile("
+ existingFileName + ").renameTo(" + newFileName
+ ") was successful.");
}
} else {
logger.debug("PanboxFS : moveFile : Could not find instance to be moved. If this is a directory it should be just fine!");
boolean success = getVirtualFileForFileName(existingFileName)
.renameTo(newFile);
if (!success) {
logger.error("PanboxFS : moveFile : VirtualFile("
+ existingFileName + ").renameTo(" + newFileName
+ ") failed.");
} else {
logger.debug("PanboxFS : moveFile : VirtualFile("
+ existingFileName + ").renameTo(" + newFileName
+ ") was successful.");
}
}
} catch (ObfuscationException e) {
throw new IOException("Obfuscation failed!");
}
}
public synchronized long openDirectory(String fileName,
DokanFileInfo fileInfo) {
logger.debug("PanboxFS : openDirectory : " + fileName + ", fileInfo: "
+ fileInfo);
return fileInfo.handle;
}
public synchronized int readFile(String fileName, ByteBuffer buffer,
long offset, DokanFileInfo fileInfo) throws IOException,
PanboxEncryptionException {
logger.debug("PanboxFS : readFile : " + fileName + ", fileInfo: "
+ fileInfo);
VirtualRandomAccessFile v = fileInstanceTable.get(fileInfo.handle);
if (v != null) {
logger.debug("PanboxFS : readFile : Found an instance with the handle number. Will delete it now!");
logger.debug("PanboxFS : readFile, File : " + v + ", buffersize: "
+ buffer.remaining() + ", offset: " + offset);
try {
return v.read(offset, buffer);
} catch (PanboxEncryptionException ex) {
throw new PanboxEncryptionException(
"PanboxFS : readFile : Decryption failed with exception: ",
ex);
}
} else {
logger.error("PanboxFS : readFile : Could not find instance to be read. Ignored request.");
throw new FileNotFoundException(
"PanboxFS : readFile : Could not find handle for rquest: VirtualFile("
+ fileName + ").");
}
}
public synchronized void setEndOfFile(String fileName, long length,
DokanFileInfo fileInfo) throws IOException,
PanboxEncryptionException {
logger.debug("PanboxFS : setEndOfFile : " + fileName);
// end of file requests are ignored at this point as size will be
// managed by VirtualRandomAccessFile
}
public synchronized void setFileAttributes(String fileName,
int fileAttributes, DokanFileInfo fileInfo) {
logger.debug("PanboxFS : setFileAttributes : No implementation executed!");
}
public synchronized void setFileTime(String fileName, long creationTime,
long lastAccessTime, long lastWriteTime, DokanFileInfo fileInfo) throws FileNotFoundException {
logger.debug("PanboxFS : setFileTime : " + fileName + ", fileInfo: "
+ fileInfo + ", creatinTime: " + creationTime + ", lastAccessTime: "
+ lastAccessTime + ", lastWriteTime: " + lastWriteTime
+ ", fileInfo: " + fileInfo);
VirtualRandomAccessFile v = fileInstanceTable.get(fileInfo.handle);
if (v != null) {
logger.debug("PanboxFS : setFileTime : Found an instance with the handle number. Will set file times now!");
try {
v.setLastAccessTime(lastAccessTime);
v.setModifiedTime(lastWriteTime);
} catch (IOException e) {
logger.error("PanboxFS : setFileTime : Failed to set file time to file " + fileName + ". Exception: ", e);
}
} else {
logger.error("PanboxFS : setFileTime : Could not find instance for setting fileTime. Ignored request.");
throw new FileNotFoundException(
"PanboxFS : setFileTime : Could not find handle for request: VirtualFile("
+ fileName + ").");
}
}
public synchronized void unlockFile(String fileName, long byteOffset,
long length, DokanFileInfo fileInfo) {
logger.debug("PanboxFS : unlockFile : No implementation executed!");
}
public synchronized int writeFile(String fileName, ByteBuffer buffer,
long offset, DokanFileInfo fileInfo) throws IOException,
PanboxEncryptionException {
logger.debug("PanboxFS : writeFile : " + fileName + ", fileInfo: "
+ fileInfo);
VirtualRandomAccessFile v = fileInstanceTable.get(fileInfo.handle);
if (v != null) {
logger.debug("PanboxFS : writeFile : Found an instance with the handle number. Will writeFile to it now!");
logger.debug("PanboxFS : writeFile : File: " + v + ", buffersize: "
+ buffer.remaining() + ", offset: " + offset);
if (!v.canWrite()) {
logger.error("PanboxFS : writeFile : File instance was opened for readOnly!");
throw new IllegalAccessError();
}
return v.write(offset, buffer);
} else {
logger.error("PanboxFS : writeFile : Could not find instance to be written. Ignored request.");
throw new FileNotFoundException(
"PanboxFS : writeFile : Could not find handle for request: VirtualFile("
+ fileName + ").");
}
}
public synchronized void unmount(DokanFileInfo fileInfo) {
logger.debug("PanboxFS : unmount : No implementation executed!");
}
public void beforeUnmount(File mountPoint) {
logger.info("PanboxFS : beforeUnmount : Panbox Service is about to shutdown - flush and close all open AES* instances...");
Collection<VirtualRandomAccessFile> coll = fileInstanceTable.values();
for (Iterator<VirtualRandomAccessFile> it = coll.iterator(); it
.hasNext();) {
VirtualRandomAccessFile file = it.next();
try {
try {
file.flush();
} catch (NullPointerException ex) {
logger.warn("PanboxFS : beforeUnmount : File '"
+ file.getFileName()
+ "' was already flushed. No cache set.");
}
if (file.isOpened()) {
file.close();
} else {
logger.debug("PanboxFS : beforeUnmount : File war already closed. No need to close this file.");
}
logger.info("PanboxFS : beforeUnmount : Successfully closed VirtualFile instance for file "
+ file.getFileName());
} catch (Exception e) {
logger.error(
"PanboxFS : beforeUnmount : Error on closing VirtualFile instance for file "
+ file.getFileName(), e);
}
}
}
}