/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
public class FileChannelImpl
extends FileChannel
{
// Memory allocation size for mapping buffers
private static final long allocationGranularity;
// Used to make native read and write calls
// File descriptor
// File access mode (immutable)
private final boolean writable;
private final boolean readable;
private final boolean append;
// Required to prevent finalization of creating stream (immutable)
// The path of the referenced file (null if the parent stream is created with a file descriptor)
// Thread-safe set of IDs of native threads, for signalling
// Lock for operations involving position and size
{
}
// Used by FileInputStream.getChannel() and RandomAccessFile.getChannel()
{
}
// Used by FileOutputStream.getChannel
{
}
if (!isOpen())
throw new ClosedChannelException();
}
// -- Standard channel operations --
// Release and invalidate any locks that we still hold
if (fileLockTable != null) {
synchronized (fl) {
}
}
}
}
// 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.
//
} else {
}
}
ensureOpen();
if (!readable)
throw new NonReadableChannelException();
synchronized (positionLock) {
int n = 0;
int ti = -1;
try {
begin();
if (!isOpen())
return 0;
do {
} finally {
end(n > 0);
}
}
}
throws IOException
{
throw new IndexOutOfBoundsException();
ensureOpen();
if (!readable)
throw new NonReadableChannelException();
synchronized (positionLock) {
long n = 0;
int ti = -1;
try {
begin();
if (!isOpen())
return 0;
do {
} finally {
end(n > 0);
}
}
}
ensureOpen();
if (!writable)
throw new NonWritableChannelException();
synchronized (positionLock) {
int n = 0;
int ti = -1;
try {
begin();
if (!isOpen())
return 0;
do {
} finally {
end(n > 0);
}
}
}
throws IOException
{
throw new IndexOutOfBoundsException();
ensureOpen();
if (!writable)
throw new NonWritableChannelException();
synchronized (positionLock) {
long n = 0;
int ti = -1;
try {
begin();
if (!isOpen())
return 0;
do {
} finally {
end(n > 0);
}
}
}
// -- Other operations --
ensureOpen();
synchronized (positionLock) {
long p = -1;
int ti = -1;
try {
begin();
if (!isOpen())
return 0;
do {
// in append-mode then position is advanced to end before writing
} finally {
end(p > -1);
}
}
}
ensureOpen();
if (newPosition < 0)
throw new IllegalArgumentException();
synchronized (positionLock) {
long p = -1;
int ti = -1;
try {
begin();
if (!isOpen())
return null;
do {
return this;
} finally {
end(p > -1);
}
}
}
ensureOpen();
synchronized (positionLock) {
long s = -1;
int ti = -1;
try {
begin();
if (!isOpen())
return -1;
do {
} finally {
end(s > -1);
}
}
}
ensureOpen();
if (size < 0)
throw new IllegalArgumentException();
return this;
if (!writable)
throw new NonWritableChannelException();
synchronized (positionLock) {
int rv = -1;
long p = -1;
int ti = -1;
try {
begin();
if (!isOpen())
return null;
// get current position
do {
if (!isOpen())
return null;
assert p >= 0;
// truncate file
do {
if (!isOpen())
return null;
// set position to size if greater than size
if (p > size)
p = size;
do {
return this;
} finally {
}
}
}
ensureOpen();
int rv = -1;
int ti = -1;
try {
begin();
if (!isOpen())
return;
do {
} finally {
}
}
// 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;
throws IOException
{
if (!transferSupported)
return IOStatus.UNSUPPORTED;
if (target instanceof FileChannelImpl) {
if (!fileSupported)
return IOStatus.UNSUPPORTED_CASE;
// Direct transfer to pipe causes EINVAL on some configurations
return IOStatus.UNSUPPORTED_CASE;
}
return IOStatus.UNSUPPORTED;
return IOStatus.UNSUPPORTED;
long n = -1;
int ti = -1;
try {
begin();
if (!isOpen())
return -1;
do {
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;
}
} finally {
end (n > -1);
}
}
// Maximum size to map when using a mapped buffer
throws IOException
{
return IOStatus.UNSUPPORTED;
// Trusted target: Use a mapped buffer
while (remaining > 0L) {
try {
try {
// ## Bug: Closing this channel will not terminate the write
assert n >= 0;
remaining -= n;
if (isSelChImpl) {
// one attempt to write to selectable channel
break;
}
assert n > 0;
position += n;
} finally {
}
} catch (ClosedByInterruptException e) {
// target closed by interrupt as ClosedByInterruptException needs
// to be thrown after closing this channel.
try {
close();
} catch (Throwable suppressed) {
}
throw e;
} catch (IOException ioe) {
// Only throw exception if no bytes have been written
throw ioe;
break;
}
}
}
throws IOException
{
// Untrusted target: Use a newly-erased buffer
try {
if (nr <= 0)
break;
// ## Bug: Will block writing target if this channel
// ## is asynchronously closed
break;
}
return tw;
} catch (IOException x) {
if (tw > 0)
return tw;
throw x;
} finally {
}
}
throws IOException
{
ensureOpen();
throw new ClosedChannelException();
if (!readable)
throw new NonReadableChannelException();
if (target instanceof FileChannelImpl &&
throw new NonWritableChannelException();
throw new IllegalArgumentException();
return 0;
long n;
// Attempt a direct transfer, if the kernel supports it
return n;
// Attempt a mapped transfer, but only to trusted channel types
return n;
// Slow path for untrusted targets
}
throws IOException
{
throw new NonReadableChannelException();
synchronized (src.positionLock) {
long p = pos;
while (remaining > 0L) {
// ## Bug: Closing this channel will not terminate the write
try {
assert n > 0;
p += n;
position += n;
remaining -= n;
} catch (IOException ioe) {
// Only throw exception if no bytes have been written
throw ioe;
break;
} finally {
}
}
return nwritten;
}
}
throws IOException
{
// Untrusted target: Use a newly-erased buffer
try {
// ## Bug: Will block reading src if this channel
// ## is asynchronously closed
if (nr <= 0)
break;
break;
}
return tw;
} catch (IOException x) {
if (tw > 0)
return tw;
throw x;
} finally {
}
}
throws IOException
{
ensureOpen();
throw new ClosedChannelException();
if (!writable)
throw new NonWritableChannelException();
throw new IllegalArgumentException();
return 0;
if (src instanceof FileChannelImpl)
}
throw new NullPointerException();
if (position < 0)
throw new IllegalArgumentException("Negative position");
if (!readable)
throw new NonReadableChannelException();
ensureOpen();
if (nd.needsPositionLock()) {
synchronized (positionLock) {
}
} else {
}
}
int n = 0;
int ti = -1;
try {
begin();
if (!isOpen())
return -1;
do {
} finally {
end(n > 0);
}
}
throw new NullPointerException();
if (position < 0)
throw new IllegalArgumentException("Negative position");
if (!writable)
throw new NonWritableChannelException();
ensureOpen();
if (nd.needsPositionLock()) {
synchronized (positionLock) {
}
} else {
}
}
int n = 0;
int ti = -1;
try {
begin();
if (!isOpen())
return -1;
do {
} finally {
end(n > 0);
}
}
// -- Memory-mapped buffers --
private static class Unmapper
implements Runnable
{
// may be required to close file
// keep track of mapped buffer usage
static volatile int count;
static volatile long totalSize;
static volatile long totalCapacity;
private volatile long address;
private final long size;
private final int cap;
{
assert (address != 0);
synchronized (Unmapper.class) {
count++;
totalCapacity += cap;
}
}
public void run() {
if (address == 0)
return;
address = 0;
// if this mapping has a valid file descriptor then we close it
try {
} catch (IOException ignore) {
// nothing we can do
}
}
synchronized (Unmapper.class) {
count--;
totalCapacity -= cap;
}
}
}
}
throws IOException
{
ensureOpen();
if (position < 0L)
throw new IllegalArgumentException("Negative position");
if (size < 0L)
throw new IllegalArgumentException("Negative size");
throw new IllegalArgumentException("Position + size overflow");
throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
int imode = -1;
assert (imode >= 0);
throw new NonWritableChannelException();
if (!readable)
throw new NonReadableChannelException();
long addr = -1;
int ti = -1;
try {
begin();
if (!isOpen())
return null;
if (!writable) {
throw new IOException("Channel not open for writing " +
"- cannot extend file to required size");
}
int rv;
do {
}
if (size == 0) {
addr = 0;
// a valid file descriptor is not required
else
}
try {
// If no exception was thrown from map0, the address is valid
} catch (OutOfMemoryError x) {
// An OutOfMemoryError may indicate that we've exhausted memory
// so force gc and re-attempt map
try {
} catch (InterruptedException y) {
}
try {
} catch (OutOfMemoryError y) {
// After a second OOME, fail
throw new IOException("Map failed", y);
}
}
// On Windows, and potentially other platforms, we need an open
// file descriptor for some mapping operations.
try {
} catch (IOException ioe) {
throw ioe;
}
addr + pagePosition,
mfd,
um);
} else {
addr + pagePosition,
mfd,
um);
}
} finally {
}
}
/**
* Invoked by sun.management.ManagementFactoryHelper to create the management
* interface for mapped buffers.
*/
return "mapped";
}
public long getCount() {
}
public long getTotalCapacity() {
return Unmapper.totalCapacity;
}
public long getMemoryUsed() {
}
};
}
// -- Locks --
// keeps track of locks on this file
// indicates if file locks are maintained system-wide (as per spec)
private static boolean isSharedFileLockTable;
// indicates if the disableSystemWideOverlappingFileLockCheck property
// has been checked
private static volatile boolean propertyChecked;
// The lock list in J2SE 1.4/5.0 was local to each FileChannel instance so
// the overlap check wasn't system wide when there were multiple channels to
// the same file. This property is used to get 1.4/5.0 behavior if desired.
private static boolean isSharedFileLockTable() {
if (!propertyChecked) {
synchronized (FileChannelImpl.class) {
if (!propertyChecked) {
new GetPropertyAction(
"sun.nio.ch.disableSystemWideOverlappingFileLockCheck"));
propertyChecked = true;
}
}
}
return isSharedFileLockTable;
}
if (fileLockTable == null) {
synchronized (this) {
if (fileLockTable == null) {
if (isSharedFileLockTable()) {
try {
ensureOpen();
} finally {
}
} else {
fileLockTable = new SimpleFileLockTable();
}
}
}
}
return fileLockTable;
}
throws IOException
{
ensureOpen();
throw new NonReadableChannelException();
throw new NonWritableChannelException();
boolean completed = false;
int ti = -1;
try {
begin();
if (!isOpen())
return null;
int n;
do {
if (isOpen()) {
if (n == FileDispatcher.RET_EX_LOCK) {
assert shared;
false);
}
completed = true;
}
} finally {
if (!completed)
try {
} catch (ClosedByInterruptException e) {
throw new FileLockInterruptionException();
}
}
return fli;
}
throws IOException
{
ensureOpen();
throw new NonReadableChannelException();
throw new NonWritableChannelException();
int result;
try {
try {
ensureOpen();
} catch (IOException e) {
throw e;
}
return null;
}
assert shared;
false);
return fli2;
}
return fli;
} finally {
}
}
try {
ensureOpen();
} finally {
}
assert fileLockTable != null;
}
// -- File lock support --
/**
* A simple file lock table that maintains a list of FileLocks obtained by a
* FileChannel. Use to get 1.4/5.0 behaviour.
*/
// synchronize on list for access
public SimpleFileLockTable() {
}
throws OverlappingFileLockException
{
throw new OverlappingFileLockException();
}
}
}
synchronized (lockList) {
}
}
synchronized (lockList) {
}
}
synchronized(lockList) {
return result;
}
}
synchronized (lockList) {
}
}
}
// -- Native methods --
// Creates a new mapping
throws IOException;
// Removes an existing mapping
// Transfers from src to dst, or returns -2 if kernel can't do that
// Sets or reports this file's position
// If offset is -1, the current position is returned
// otherwise the position is set to offset
// Caches fieldIDs
private static native long initIDs();
static {
}
}