aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2016-11-17 02:32:32 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2016-11-17 02:32:32 +0000
commite4c2cde9943e2bbd17076b78c27d84c7afaffad3 (patch)
treecf5e5dcaf622a0035ab56528fa89affc8b3c544f
parenta30708e2ce01439181dbd4dad6e3fc70b98700c4 (diff)
downloadjackcess-e4c2cde9943e2bbd17076b78c27d84c7afaffad3.tar.gz
jackcess-e4c2cde9943e2bbd17076b78c27d84c7afaffad3.zip
better fix for switching read-only file formats to read-only mode, wrap with read-only FileChannel. fixes feature #34
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1057 f203690c-595d-4dc9-a70b-905162fa7fd2
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java19
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/UsageMap.java6
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/util/ReadOnlyFileChannel.java144
3 files changed, 152 insertions, 17 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java
index ab01d0b..ac253fb 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java
@@ -69,6 +69,7 @@ import com.healthmarketscience.jackcess.util.CaseInsensitiveColumnMatcher;
import com.healthmarketscience.jackcess.util.ColumnValidatorFactory;
import com.healthmarketscience.jackcess.util.ErrorHandler;
import com.healthmarketscience.jackcess.util.LinkResolver;
+import com.healthmarketscience.jackcess.util.ReadOnlyFileChannel;
import com.healthmarketscience.jackcess.util.SimpleColumnValidatorFactory;
import com.healthmarketscience.jackcess.util.TableIterableBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
@@ -389,22 +390,14 @@ public class DatabaseImpl implements Database
JetFormat jetFormat = JetFormat.getFormat(channel);
if(jetFormat.READ_ONLY) {
-
- if(closeChannel) {
- // we own the channel, close and re-open read only
- ByteUtil.closeQuietly(channel);
- channel = null;
- readOnly = true;
- channel = openChannel(mdbFile, readOnly);
- } else {
- throw new IOException("file format " +
- jetFormat.getPossibleFileFormats().values() +
- " does not support writing for " + mdbFile);
- }
+ // wrap the channel with a read-only version to enforce
+ // non-writability
+ channel = new ReadOnlyFileChannel(channel);
+ readOnly = true;
}
}
- DatabaseImpl db = new DatabaseImpl(mdbFile, channel, closeChannel, autoSync,
+ DatabaseImpl db = new DatabaseImpl(mdbFile, channel, closeChannel, autoSync,
null, charset, timeZone, provider);
success = true;
return db;
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/UsageMap.java b/src/main/java/com/healthmarketscience/jackcess/impl/UsageMap.java
index 4a9eab0..c67bcba 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/UsageMap.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/UsageMap.java
@@ -477,8 +477,7 @@ public class UsageMap
{
private final int _maxInlinePages;
- protected InlineHandler()
- throws IOException
+ protected InlineHandler() throws IOException
{
_maxInlinePages = (getInlineDataEnd() - getInlineDataStart()) * 8;
int startPage = getTableBuffer().getInt(getRowStart() + 1);
@@ -714,8 +713,7 @@ public class UsageMap
TempPageHolder.newHolder(TempBufferHolder.Type.SOFT);
private final int _maxPagesPerUsageMapPage;
- private ReferenceHandler()
- throws IOException
+ private ReferenceHandler() throws IOException
{
_maxPagesPerUsageMapPage = ((getFormat().PAGE_SIZE -
getFormat().OFFSET_USAGE_MAP_PAGE_DATA) * 8);
diff --git a/src/main/java/com/healthmarketscience/jackcess/util/ReadOnlyFileChannel.java b/src/main/java/com/healthmarketscience/jackcess/util/ReadOnlyFileChannel.java
new file mode 100644
index 0000000..85620e8
--- /dev/null
+++ b/src/main/java/com/healthmarketscience/jackcess/util/ReadOnlyFileChannel.java
@@ -0,0 +1,144 @@
+/*
+Copyright (c) 2016 James Ahlborn
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.healthmarketscience.jackcess.util;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.NonWritableChannelException;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import com.healthmarketscience.jackcess.Database;
+
+/**
+ * Wrapper for existing FileChannel which is read-only.
+ * <p/>
+ * Implementation note: this class is optimized for use with {@link Database}.
+ * Therefore not all methods may be implemented.
+ *
+ * @author James Ahlborn
+ * @usage _advanced_class_
+ */
+public class ReadOnlyFileChannel extends FileChannel
+{
+ private final FileChannel _delegate;
+
+ public ReadOnlyFileChannel(FileChannel delegate) {
+ _delegate = delegate;
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ return _delegate.read(dst);
+ }
+
+ @Override
+ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
+ return _delegate.read(dsts, offset, length);
+ }
+
+ @Override
+ public int read(ByteBuffer dst, long position) throws IOException {
+ return _delegate.read(dst, position);
+ }
+
+ @Override
+ public long position() throws IOException {
+ return _delegate.position();
+ }
+
+ @Override
+ public FileChannel position(long newPosition) throws IOException {
+ _delegate.position(newPosition);
+ return this;
+ }
+
+ @Override
+ public long size() throws IOException {
+ return _delegate.size();
+ }
+
+ @Override
+ public FileChannel truncate(long size) throws IOException {
+ throw new NonWritableChannelException();
+ }
+
+ @Override
+ public void force(boolean metaData) throws IOException {
+ // do nothing
+ }
+
+ @Override
+ public long transferTo(long position, long count, WritableByteChannel target)
+ throws IOException
+ {
+ return _delegate.transferTo(position, count, target);
+ }
+
+ @Override
+ public long transferFrom(ReadableByteChannel src, long position, long count)
+ throws IOException
+ {
+ throw new NonWritableChannelException();
+ }
+
+ @Override
+ public int write(ByteBuffer src, long position) throws IOException {
+ throw new NonWritableChannelException();
+ }
+
+
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ throw new NonWritableChannelException();
+ }
+
+ @Override
+ public long write(ByteBuffer[] srcs, int offset, int length)
+ throws IOException
+ {
+ throw new NonWritableChannelException();
+ }
+
+ @Override
+ public MappedByteBuffer map(MapMode mode, long position, long size)
+ throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FileLock lock(long position, long size, boolean shared)
+ throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FileLock tryLock(long position, long size, boolean shared)
+ throws IOException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void implCloseChannel() throws IOException {
+ _delegate.close();
+ }
+}