de.schlichtherle.truezip.fs.archive.zip.KeyController Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of truezip-driver-zip Show documentation
Show all versions of truezip-driver-zip Show documentation
The file system driver family for ZIP and related archive file types.
Add the JAR artifact of this module to the run time class path to
make its file system drivers available for service location in the
client API modules.
/*
* Copyright (C) 2005-2013 Schlichtherle IT Services.
* All rights reserved. Use is subject to license terms.
*/
package de.schlichtherle.truezip.fs.archive.zip;
import de.schlichtherle.truezip.entry.Entry;
import static de.schlichtherle.truezip.entry.Entry.Type.SPECIAL;
import static de.schlichtherle.truezip.fs.FsEntryName.ROOT;
import de.schlichtherle.truezip.fs.*;
import de.schlichtherle.truezip.key.KeyManager;
import de.schlichtherle.truezip.key.KeyProvider;
import de.schlichtherle.truezip.key.SafeKeyManager;
import de.schlichtherle.truezip.util.BitField;
import de.schlichtherle.truezip.util.ControlFlowException;
import java.io.IOException;
import java.net.URI;
import javax.annotation.CheckForNull;
import javax.annotation.concurrent.Immutable;
/**
* This file system controller decorates another file system controller in
* order to manage the keys required for accessing encrypted ZIP files.
*
* @param the type of the file system model.
* @param the type of the ZIP driver.
* @author Christian Schlichtherle
*/
@Immutable
public abstract class KeyController<
M extends FsModel,
D extends ZipDriver>
extends FsDecoratingController> {
private static final String ROOT_PATH = ROOT.getPath();
protected final D driver;
private volatile KeyManager> manager;
/**
* Constructs a new key manager controller.
*
* @param controller the non-{@code null} file system controller to
* decorate.
* @param driver the ZIP driver.
*/
protected KeyController(
final FsController extends M> controller,
final D driver) {
super(controller);
if (null == driver)
throw new NullPointerException();
this.driver = driver;
}
protected abstract Class> getKeyType();
protected abstract Class extends IOException> getKeyExceptionType();
private KeyManager> getKeyManager() {
final KeyManager> manager = this.manager;
return null != manager
? manager
: (this.manager = driver.getKeyManagerProvider()
.get(getKeyType()));
}
@Override
public FsEntry getEntry(final FsEntryName name)
throws IOException {
try {
return delegate.getEntry(name);
} catch (final ControlFlowException ex) {
if (!name.isRoot() || null == findKeyException(ex)) throw ex;
Entry entry = getParent().getEntry(
getModel()
.getMountPoint()
.getPath()
.resolve(name)
.getEntryName());
// We're not holding any locks, so it's possible that someone else
// has concurrently modified the parent file system.
if (null == entry) return null;
// The entry is inaccessible for some reason.
// This may be because the cipher key is not available.
// Now mask the entry as a special file.
while (entry instanceof FsCovariantEntry>)
entry = ((FsCovariantEntry>) entry).getEntry();
final FsCovariantEntry
special = new FsCovariantEntry(ROOT_PATH);
special.put(SPECIAL, driver.newEntry(ROOT_PATH, SPECIAL, entry));
return special;
}
}
@Override
public void unlink(final FsEntryName name, BitField options)
throws IOException {
try {
delegate.unlink(name, options);
} catch (final ControlFlowException ex) {
// If the exception is caused by a key exception, then throw this
// cause instead in order to avoid treating the target archive file
// like a false positive and routing this operation to the parent
// file system.
// This prevents the application from inadvertently deleting an
// encrypted ZIP file just because the user cancelled key prompting.
final IOException keyEx = findKeyException(ex);
if (null != keyEx) throw keyEx;
throw ex;
}
if (name.isRoot())
getKeyManager().removeKeyProvider(
driver.resourceUri(getModel(), name.toString()));
}
private @CheckForNull IOException findKeyException(Throwable ex) {
final Class extends IOException> clazz = getKeyExceptionType();
do {
if (clazz.isInstance(ex)) return clazz.cast(ex);
} while (null != (ex = ex.getCause()));
return null;
}
@Override
public void sync(final BitField options)
throws FsSyncException {
delegate.sync(options);
final KeyManager> manager = getKeyManager();
final URI resource = driver.mountPointUri(getModel());
final KeyProvider> provider;
if (manager instanceof SafeKeyManager) {
// Don't create a key provider if there wasn't one mapped already.
provider = ((SafeKeyManager) manager).getMappedKeyProvider(resource);
} else {
// TODO: This might create a memory leak.
// It's unlikely that a third party implements the KeyManager
// interface and does NOT use extend the SafeKeyManager class,
// though.
provider = manager.getKeyProvider(resource);
}
if (null != provider)
driver.getKeyProviderSyncStrategy().sync(provider);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy