/* * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.nio.ch; import java.io.FileDescriptor;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.MappedByteBuffer;import java.nio.channels.*;import java.util.ArrayList;import java.util.List;import java.security.AccessController;import sun.misc.Cleaner;import sun.security.action.GetPropertyAction; public class FileChannelImpl extends FileChannel{ // Memory allocation size for mapping buffers private static final long allocationGranularity; // Used to make native read and write calls private final FileDispatcher nd; // File descriptor private final FileDescriptor fd; // File access mode (immutable) private final boolean writable; private final boolean readable; private final boolean append; // Required to prevent finalization of creating stream (immutable) private final Object parent; // Thread-safe set of IDs of native threads, for signalling private final NativeThreadSet threads = new NativeThreadSet(2); // Lock for operations involving position and size private final Object positionLock = new Object(); private FileChannelImpl(FileDescriptor fd, boolean readable, boolean writable, boolean append, Object parent) { this.fd = fd; this.readable = readable; this.writable = writable; this.append = append; this.parent = parent; this.nd = new FileDispatcherImpl(append); } // Used by FileInputStream.getChannel() and RandomAccessFile.getChannel() public static FileChannel open(FileDescriptor fd, boolean readable, boolean writable, Object parent) { return new FileChannelImpl(fd, readable, writable, false, parent); } // Used by FileOutputStream.getChannel public static FileChannel open(FileDescriptor fd, boolean readable, boolean writable, boolean append, Object parent) { return new FileChannelImpl(fd, readable, writable, append, parent); } private void ensureOpen() throws IOException { if (!isOpen()) throw new ClosedChannelException(); } // -- Standard channel operations -- protected void implCloseChannel() throws IOException { // Release and invalidate any locks that we still hold if (fileLockTable != null) { for (FileLock fl: fileLockTable.removeAll()) { synchronized (fl) { if (fl.isValid()) { nd.release(fd, fl.position(), fl.size()); ((FileLockImpl)fl).invalidate(); } } } } nd.preClose(fd); threads.signalAndWait(); if (parent != null) { // Close the fd via the parent stream's close method. The parent // will reinvoke our close method, which is defined in the // superclass AbstractInterruptibleChannel, but the isOpen logic in // that method will prevent this method from being reinvoked. // ((java.io.Closeable)parent).close(); } else { nd.close(fd); } } public int read(ByteBuffer dst) throws IOException { ensureOpen(); if (!readable) throw new NonReadableChannelException(); synchronized (positionLock) { int n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.read(fd, dst, -1, nd, positionLock); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) throw new IndexOutOfBoundsException(); ensureOpen(); if (!readable) throw new NonReadableChannelException(); synchronized (positionLock) { long n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.read(fd, dsts, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public int write(ByteBuffer src) throws IOException { ensureOpen(); if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { int n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.write(fd, src, -1, nd, positionLock); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) throw new IndexOutOfBoundsException(); ensureOpen(); if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { long n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.write(fd, srcs, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } // -- Other operations -- public long position() throws IOException { ensureOpen(); synchronized (positionLock) { long p = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { // in append-mode then position is advanced to end before writing p = (append) ? nd.size(fd) : position0(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(p); } finally { threads.remove(ti); end(p > -1); assert IOStatus.check(p); } } } public FileChannel position(long newPosition) throws IOException { ensureOpen(); if (newPosition < 0) throw new IllegalArgumentException(); synchronized (positionLock) { long p = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return null; do { p = position0(fd, newPosition); } while ((p == IOStatus.INTERRUPTED) && isOpen()); return this; } finally { threads.remove(ti); end(p > -1); assert IOStatus.check(p); } } } public long size() throws IOException { ensureOpen(); synchronized (positionLock) { long s = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { s = nd.size(fd); } while ((s == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(s); } finally { threads.remove(ti); end(s > -1); assert IOStatus.check(s); } } } public FileChannel truncate(long size) throws IOException { ensureOpen(); if (size < 0) throw new IllegalArgumentException(); if (size > size()) return this; if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { int rv = -1; long p = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return null; // get current position do { p = position0(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; assert p >= 0; // truncate file do { rv = nd.truncate(fd, size); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; // set position to size if greater than size if (p > size) p = size; do { rv = (int)position0(fd, p); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); return this; } finally { threads.remove(ti); end(rv > -1); assert IOStatus.check(rv); } } } public void force(boolean metaData) throws IOException { ensureOpen(); int rv = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return; do { rv = nd.force(fd, metaData); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); } finally { threads.remove(ti); end(rv > -1); assert IOStatus.check(rv); } } // Assume at first that the underlying kernel supports sendfile(); // set this to false if we find out later that it doesn't // private static volatile boolean transferSupported = true; // Assume that the underlying kernel sendfile() will work if the target // fd is a pipe; set this to false if we find out later that it doesn't // private static volatile boolean pipeSupported = true; // Assume that the underlying kernel sendfile() will work if the target // fd is a file; set this to false if we find out later that it doesn't // private static volatile boolean fileSupported = true; private long transferToDirectly(long position, int icount, WritableByteChannel target) throws IOException { if (!transferSupported) return IOStatus.UNSUPPORTED; FileDescriptor targetFD = null; if (target instanceof FileChannelImpl) { if (!fileSupported) return IOStatus.UNSUPPORTED_CASE; targetFD = ((FileChannelImpl)target).fd; } else if (target instanceof SelChImpl) { // Direct transfer to pipe causes EINVAL on some configurations if ((target instanceof SinkChannelImpl) && !pipeSupported) return IOStatus.UNSUPPORTED_CASE; targetFD = ((SelChImpl)target).getFD(); } if (targetFD == null) return IOStatus.UNSUPPORTED; int thisFDVal = IOUtil.fdVal(fd); int targetFDVal = IOUtil.fdVal(targetFD); if (thisFDVal == targetFDVal) // Not supported on some configurations return IOStatus.UNSUPPORTED; long n = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { n = transferTo0(thisFDVal, position, icount, targetFDVal); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n == IOStatus.UNSUPPORTED_CASE) { if (target instanceof SinkChannelImpl) pipeSupported = false; if (target instanceof FileChannelImpl) fileSupported = false; return IOStatus.UNSUPPORTED_CASE; } if (n == IOStatus.UNSUPPORTED) { // Don't bother trying again transferSupported = false; return IOStatus.UNSUPPORTED; } return IOStatus.normalize(n); } finally { threads.remove(ti); end (n > -1); } } // Maximum size to map when using a mapped buffer private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L; private long transferToTrustedChannel(long position, long count, WritableByteChannel target) throws IOException { boolean isSelChImpl = (target instanceof SelChImpl); if (!((target instanceof FileChannelImpl) || isSelChImpl)) return IOStatus.UNSUPPORTED; // Trusted target: Use a mapped buffer long remaining = count; while (remaining > 0L) { long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); try { MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size); try { // ## Bug: Closing this channel will not terminate the write int n = target.write(dbb); assert n >= 0; remaining -= n; if (isSelChImpl) { // one attempt to write to selectable channel break; } assert n > 0; position += n; } finally { unmap(dbb); } } catch (ClosedByInterruptException e) { // target closed by interrupt as ClosedByInterruptException needs // to be thrown after closing this channel. assert !target.isOpen(); try { close(); } catch (Throwable suppressed) { e.addSuppressed(suppressed); } throw e; } catch (IOException ioe) { // Only throw exception if no bytes have been written if (remaining == count) throw ioe; break; } } return count - remaining; } private long transferToArbitraryChannel(long position, int icount, WritableByteChannel target) throws IOException { // Untrusted target: Use a newly-erased buffer int c = Math.min(icount, TRANSFER_SIZE); ByteBuffer bb = Util.getTemporaryDirectBuffer(c); long tw = 0; // Total bytes written long pos = position;Lines 1–500 of 1136. Load more
/* * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.nio.ch; import java.io.FileDescriptor; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.*; import java.util.ArrayList; import java.util.List; import java.security.AccessController; import sun.misc.Cleaner; import sun.security.action.GetPropertyAction; public class FileChannelImpl extends FileChannel { // Memory allocation size for mapping buffers private static final long allocationGranularity; // Used to make native read and write calls private final FileDispatcher nd; // File descriptor private final FileDescriptor fd; // File access mode (immutable) private final boolean writable; private final boolean readable; private final boolean append; // Required to prevent finalization of creating stream (immutable) private final Object parent; // Thread-safe set of IDs of native threads, for signalling private final NativeThreadSet threads = new NativeThreadSet(2); // Lock for operations involving position and size private final Object positionLock = new Object(); private FileChannelImpl(FileDescriptor fd, boolean readable, boolean writable, boolean append, Object parent) { this.fd = fd; this.readable = readable; this.writable = writable; this.append = append; this.parent = parent; this.nd = new FileDispatcherImpl(append); } // Used by FileInputStream.getChannel() and RandomAccessFile.getChannel() public static FileChannel open(FileDescriptor fd, boolean readable, boolean writable, Object parent) { return new FileChannelImpl(fd, readable, writable, false, parent); } // Used by FileOutputStream.getChannel public static FileChannel open(FileDescriptor fd, boolean readable, boolean writable, boolean append, Object parent) { return new FileChannelImpl(fd, readable, writable, append, parent); } private void ensureOpen() throws IOException { if (!isOpen()) throw new ClosedChannelException(); } // -- Standard channel operations -- protected void implCloseChannel() throws IOException { // Release and invalidate any locks that we still hold if (fileLockTable != null) { for (FileLock fl: fileLockTable.removeAll()) { synchronized (fl) { if (fl.isValid()) { nd.release(fd, fl.position(), fl.size()); ((FileLockImpl)fl).invalidate(); } } } } nd.preClose(fd); threads.signalAndWait(); if (parent != null) { // Close the fd via the parent stream's close method. The parent // will reinvoke our close method, which is defined in the // superclass AbstractInterruptibleChannel, but the isOpen logic in // that method will prevent this method from being reinvoked. // ((java.io.Closeable)parent).close(); } else { nd.close(fd); } } public int read(ByteBuffer dst) throws IOException { ensureOpen(); if (!readable) throw new NonReadableChannelException(); synchronized (positionLock) { int n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.read(fd, dst, -1, nd, positionLock); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) throw new IndexOutOfBoundsException(); ensureOpen(); if (!readable) throw new NonReadableChannelException(); synchronized (positionLock) { long n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.read(fd, dsts, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public int write(ByteBuffer src) throws IOException { ensureOpen(); if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { int n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.write(fd, src, -1, nd, positionLock); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) throw new IndexOutOfBoundsException(); ensureOpen(); if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { long n = 0; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { n = IOUtil.write(fd, srcs, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { threads.remove(ti); end(n > 0); assert IOStatus.check(n); } } } // -- Other operations -- public long position() throws IOException { ensureOpen(); synchronized (positionLock) { long p = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return 0; do { // in append-mode then position is advanced to end before writing p = (append) ? nd.size(fd) : position0(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(p); } finally { threads.remove(ti); end(p > -1); assert IOStatus.check(p); } } } public FileChannel position(long newPosition) throws IOException { ensureOpen(); if (newPosition < 0) throw new IllegalArgumentException(); synchronized (positionLock) { long p = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return null; do { p = position0(fd, newPosition); } while ((p == IOStatus.INTERRUPTED) && isOpen()); return this; } finally { threads.remove(ti); end(p > -1); assert IOStatus.check(p); } } } public long size() throws IOException { ensureOpen(); synchronized (positionLock) { long s = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { s = nd.size(fd); } while ((s == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(s); } finally { threads.remove(ti); end(s > -1); assert IOStatus.check(s); } } } public FileChannel truncate(long size) throws IOException { ensureOpen(); if (size < 0) throw new IllegalArgumentException(); if (size > size()) return this; if (!writable) throw new NonWritableChannelException(); synchronized (positionLock) { int rv = -1; long p = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return null; // get current position do { p = position0(fd, -1); } while ((p == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; assert p >= 0; // truncate file do { rv = nd.truncate(fd, size); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); if (!isOpen()) return null; // set position to size if greater than size if (p > size) p = size; do { rv = (int)position0(fd, p); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); return this; } finally { threads.remove(ti); end(rv > -1); assert IOStatus.check(rv); } } } public void force(boolean metaData) throws IOException { ensureOpen(); int rv = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return; do { rv = nd.force(fd, metaData); } while ((rv == IOStatus.INTERRUPTED) && isOpen()); } finally { threads.remove(ti); end(rv > -1); assert IOStatus.check(rv); } } // Assume at first that the underlying kernel supports sendfile(); // set this to false if we find out later that it doesn't // private static volatile boolean transferSupported = true; // Assume that the underlying kernel sendfile() will work if the target // fd is a pipe; set this to false if we find out later that it doesn't // private static volatile boolean pipeSupported = true; // Assume that the underlying kernel sendfile() will work if the target // fd is a file; set this to false if we find out later that it doesn't // private static volatile boolean fileSupported = true; private long transferToDirectly(long position, int icount, WritableByteChannel target) throws IOException { if (!transferSupported) return IOStatus.UNSUPPORTED; FileDescriptor targetFD = null; if (target instanceof FileChannelImpl) { if (!fileSupported) return IOStatus.UNSUPPORTED_CASE; targetFD = ((FileChannelImpl)target).fd; } else if (target instanceof SelChImpl) { // Direct transfer to pipe causes EINVAL on some configurations if ((target instanceof SinkChannelImpl) && !pipeSupported) return IOStatus.UNSUPPORTED_CASE; targetFD = ((SelChImpl)target).getFD(); } if (targetFD == null) return IOStatus.UNSUPPORTED; int thisFDVal = IOUtil.fdVal(fd); int targetFDVal = IOUtil.fdVal(targetFD); if (thisFDVal == targetFDVal) // Not supported on some configurations return IOStatus.UNSUPPORTED; long n = -1; int ti = -1; try { begin(); ti = threads.add(); if (!isOpen()) return -1; do { n = transferTo0(thisFDVal, position, icount, targetFDVal); } while ((n == IOStatus.INTERRUPTED) && isOpen()); if (n == IOStatus.UNSUPPORTED_CASE) { if (target instanceof SinkChannelImpl) pipeSupported = false; if (target instanceof FileChannelImpl) fileSupported = false; return IOStatus.UNSUPPORTED_CASE; } if (n == IOStatus.UNSUPPORTED) { // Don't bother trying again transferSupported = false; return IOStatus.UNSUPPORTED; } return IOStatus.normalize(n); } finally { threads.remove(ti); end (n > -1); } } // Maximum size to map when using a mapped buffer private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L; private long transferToTrustedChannel(long position, long count, WritableByteChannel target) throws IOException { boolean isSelChImpl = (target instanceof SelChImpl); if (!((target instanceof FileChannelImpl) || isSelChImpl)) return IOStatus.UNSUPPORTED; // Trusted target: Use a mapped buffer long remaining = count; while (remaining > 0L) { long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); try { MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size); try { // ## Bug: Closing this channel will not terminate the write int n = target.write(dbb); assert n >= 0; remaining -= n; if (isSelChImpl) { // one attempt to write to selectable channel break; } assert n > 0; position += n; } finally { unmap(dbb); } } catch (ClosedByInterruptException e) { // target closed by interrupt as ClosedByInterruptException needs // to be thrown after closing this channel. assert !target.isOpen(); try { close(); } catch (Throwable suppressed) { e.addSuppressed(suppressed); } throw e; } catch (IOException ioe) { // Only throw exception if no bytes have been written if (remaining == count) throw ioe; break; } } return count - remaining; } private long transferToArbitraryChannel(long position, int icount, WritableByteChannel target) throws IOException { // Untrusted target: Use a newly-erased buffer int c = Math.min(icount, TRANSFER_SIZE); ByteBuffer bb = Util.getTemporaryDirectBuffer(c); long tw = 0; // Total bytes written long pos = position;