/* * * 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; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import org.apache.log4j.Logger; import org.panbox.core.exception.ObfuscationException; import org.panbox.core.vfs.backend.VirtualFile; import org.panbox.desktop.common.gui.PanboxDesktopGUIConstants; import org.panbox.desktop.common.vfs.backend.IRootVolume; import org.panbox.desktop.common.vfs.backend.VirtualRootVolume; import org.panbox.desktop.common.vfs.backend.exceptions.SecretKeyNotFoundException; /** * @author palige * * Abstract class with platform independent code for the VFS. Actual VFS * API calls are to be implemented by platform-specific subclasses. */ public abstract class PanboxFS { private static final Logger logger = Logger .getLogger("org.panbox.desktop.common"); protected final PanboxFSAdapter vfsAdapter; private File mountPoint = null; public final IRootVolume backingStorage; public PanboxFS(PanboxFSAdapter backend) { this.vfsAdapter = backend; this.backingStorage = VirtualRootVolume.getInstance(); } private final boolean _mount(final File mountPoint, final boolean wasBlocking) { this.mountPoint = SymlinkResolver.resolveSymlinks(mountPoint); if (UnconsequentialFiles.clearUnconsequentialFiles(this.mountPoint)) { log("Mount", "Some unconsequential files were automatically deleted from mountpoint: " + this.mountPoint); } log("Mount", "Mounting to: " + this.mountPoint); final long beforeTime = System.nanoTime(); final boolean result = vfsAdapter.userfs_mount(this, mountPoint); final long time = (System.nanoTime() - beforeTime) / 1000000L; log("Mount", (wasBlocking ? "B" : "Non-b") + "locking attempt to mount at '" + this.mountPoint + "' (" + time + "ms ago) finished; resulted in " + (result ? "success" : "failure") + "."); return result; } final boolean _onUnmount() { log("Unmount", "Unmounting."); return onUnmount(mountPoint); } public final File getMountpoint() { return mountPoint; } // protected abstract int setChown(String path, long uid, long gid); final void implLog(final String method, final String message) { logger.debug("PanboxFS [Backend] : " + method + " : " + message); } private final void log(final String method, final String message) { logger.debug("PanboxFS : " + method + " : " + message); } public final boolean mount(final File mountPoint, final boolean blocking, final MountFailureHandler failureHandler) { if (!blocking) { new Thread() { @Override public void run() { if (!_mount(mountPoint, false)) { if (failureHandler != null) { failureHandler.exec(); } } } }.start(); return true; } return _mount(mountPoint, true); } protected boolean onUnmount(final File mountPoint) { return true; } public final boolean unmount() { return vfsAdapter.userfs_unmount(mountPoint); } /** * This will return the name of the file system for the Panbox VFS * * @return String name of the Panbox VFS */ protected String getFilesystemName() { return PanboxDesktopGUIConstants.PANBOX_VIRTUAL_FILESYSTEM_IDENTIFIER; } /** * This will return the bytes that are free for the file or directory * * @return long Number of free bytes */ protected long getFreeBytes() { return backingStorage.getFreeSpace(); } /** * This will return the total bytes that available for the file or directory * * @return long Number of total bytes */ protected long getTotalBytes() { return backingStorage.getTotalSpace(); } /** * This will return the bytes that are usable for the file or directory * * @return long Number of usable bytes */ protected long getUsableBytes() { return backingStorage.getUsableSpace(); } /** * This will return the volume name of the Panbox VFS drive * * @return String volume name of the Panbox VFS */ protected String getVolumeName() { // The name will be configured via system-specific configuration return ""; } protected synchronized VirtualFile getVirtualFileForFileName( final String fileName, boolean createIV) throws SecretKeyNotFoundException, FileNotFoundException, ObfuscationException { String realFileName = fileName; try { realFileName = backingStorage.obfuscatePath(fileName, createIV); } catch (SecretKeyNotFoundException ex) { if (!fileName.equals(File.separator)) { throw ex; } } try { return backingStorage.getFile(realFileName); // // if (ret instanceof VirtualRandomAccessFile) { // return (VirtualRandomAccessFile) ret; } catch (IOException e) { logger.error("PanboxFS: getVirtualFileForFileName : Exception in getFile: " + e.getMessage()); return null; } } /** * getFileInfo will get a FileInfo object for the specified file in the VFS * with or without obfuscation. The file information could be obtained from * a file or a directory and will contain at least the filename and the size * of a file. * * @param fileName * Relative path to the file or directory for which the file * information should be read * @param alreadyObfuscated * true if the relative path in fileName is already obfuscated * else false * @param outputObfuscated * true if the filename that will be returned in the FileInfo * object should be obfuscated else false * @return * @throws IOException */ // @SuppressWarnings("resource") protected synchronized AbstractFileInfo getFileInfo(final String fileName, boolean alreadyObfuscated, boolean outputObfuscated) throws IOException { logger.debug("getFileInfo : " + fileName + ", alreadyObfuscated: " + alreadyObfuscated + ", outputObfuscated: " + outputObfuscated); VirtualFile backing; try { backing = alreadyObfuscated ? backingStorage.getFile(fileName) : getVirtualFileForFileName(fileName, false); } catch (ObfuscationException e1) { throw new IOException("Obfuscation for filename " + fileName + " failed!"); } boolean symbolic = backing.isSymbolic(); if (!symbolic && !backing.exists()) { // do NOT close backing file as it may not have been opened at this // point // backing.close(); throw new FileNotFoundException( "PanboxFS : getFileInfo : Can not get file info for non-existing files!"); } long createTime = backing.getCreationTime(); long lastAccess = backing.getLastAccessTime(); long lastWrite = backing.getLastWriteTime(); AbstractFileInfo ret; String deobfPath = null; if (fileName.equals("/")) { deobfPath = fileName; } else { if (!outputObfuscated && alreadyObfuscated) { try { deobfPath = backingStorage.deobfuscatePath(backing); } catch (ObfuscationException e) { // TODO better handling in case of filenames which could not // be deobfuscated. E.g. lost+found folder, or something // similar throw new FileNotFoundException("Deobfuscation error: " + e.getMessage()); } } else { deobfPath = fileName; } } if (backing.isDirectory()) { if (!outputObfuscated) { ret = this.vfsAdapter.createFileInfo(deobfPath, true, 0, createTime, lastAccess, lastWrite, backing.getAttr(), symbolic); } else { ret = this.vfsAdapter.createFileInfo( backingStorage.getRelativePathForFile(backing), true, 0, createTime, lastAccess, lastWrite, backing.getAttr(), symbolic); } } else { long vlen = backing.length(); if (!outputObfuscated) { ret = this.vfsAdapter.createFileInfo(deobfPath, false, vlen, createTime, lastAccess, lastWrite, backing.getAttr(), symbolic); } else { ret = this.vfsAdapter.createFileInfo( backingStorage.getRelativePathForFile(backing), false, vlen, createTime, lastAccess, lastWrite, backing.getAttr(), symbolic); } } logger.debug("getFileInfo, GetFileInfo returned : " + ret); return ret; } }