]> gcc.gnu.org Git - gcc.git/commitdiff
FileChannelImpl.java: New class, renamed from java/nio/channels.
authorPer Bothner <bothner@gcc.gnu.org>
Sun, 29 Feb 2004 19:09:28 +0000 (11:09 -0800)
committerPer Bothner <bothner@gcc.gnu.org>
Sun, 29 Feb 2004 19:09:28 +0000 (11:09 -0800)
* gnu/java/nio/channels/FileChannelImpl.java:  New class, renamed
from java/nio/channels.  Don't depend on FileDescriptor.
(in, out, err):  New static fields.
(mode):  New field.
(SET, CUR, READ, WRITE, APPEND, EXCL, SYNC, DSYNC):  Moved constants
from FileDescriptor.
(by):  Removed MappedByteBuffer field.
(map):  New working implementation.
* gnu/java/nio/channels/natFileChannelPosix.cc:  New file, though
some code "ported" from natFileDescriptoPosix.cc.
* gnu/java/nio/channels/natFileChannelEcos.cc:  Likewise.
* gnu/java/nio/channels/natFileChannelWin32.cc  Likewise.

From-SVN: r78659

libjava/gnu/java/nio/channels/FileChannelImpl.java [new file with mode: 0644]
libjava/gnu/java/nio/channels/natFileChannelEcos.cc [new file with mode: 0644]
libjava/gnu/java/nio/channels/natFileChannelPosix.cc [new file with mode: 0644]
libjava/gnu/java/nio/channels/natFileChannelWin32.cc [new file with mode: 0644]

diff --git a/libjava/gnu/java/nio/channels/FileChannelImpl.java b/libjava/gnu/java/nio/channels/FileChannelImpl.java
new file mode 100644 (file)
index 0000000..b5e5ffe
--- /dev/null
@@ -0,0 +1,420 @@
+/* FileChannelImpl.java -- 
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath 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 2, or (at your option)
+any later version.
+
+GNU Classpath 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 GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.nio.channels;
+
+import gnu.classpath.Configuration;
+import gnu.gcj.RawData;
+import gnu.java.nio.FileLockImpl;
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.*;
+
+/**
+ * This file is not user visible !
+ * But alas, Java does not have a concept of friendly packages
+ * so this class is public. 
+ * Instances of this class are created by invoking getChannel
+ * Upon a Input/Output/RandomAccessFile object.
+ */
+
+public class FileChannelImpl extends FileChannel
+{
+  int mode;
+  // These are WHENCE values for seek.
+  static final int SET = 0;
+  static final int CUR = 1;
+
+  // These are mode values for open().
+  static final int READ   = 1;
+  static final int WRITE  = 2;
+  static final int APPEND = 4;
+
+  // EXCL is used only when making a temp file.
+  static final int EXCL   = 8;
+  static final int SYNC   = 16;
+  static final int DSYNC  = 32;
+
+  /**
+   * This is the actual native file descriptor value
+   */
+  // System's notion of file descriptor.  It might seem redundant to
+  // initialize this given that it is reassigned in the constructors.
+  // However, this is necessary because if open() throws an exception
+  // we want to make sure this has the value -1.  This is the most
+  // efficient way to accomplish that.
+  private int fd = -1;
+
+  int length;
+  private long pos;
+
+  public FileChannelImpl ()
+  {
+  }
+
+  /* Open a file.  MODE is a combination of the above mode flags. */
+  public FileChannelImpl (String path, int mode) throws FileNotFoundException
+  {
+    fd = open (path, mode);
+    this.mode = mode;
+  }
+
+  private static native void init();
+  static { init (); }
+
+  public static FileChannelImpl in;
+  public static FileChannelImpl out;
+  public static FileChannelImpl err;
+
+  private native int open (String path, int mode) throws FileNotFoundException;
+
+  /** Attach to an already-opened file.  */
+  public FileChannelImpl (int desc, int mode)
+  {
+    fd = desc;
+    this.mode = mode;
+  }
+
+  native int available () throws IOException;
+  private native long implPosition ();
+  private native void seek (long newPosition);
+  private native void implTruncate (long size);
+  
+  public native void unlock (long pos, long len);
+
+  public native long size () throws IOException;
+    
+  protected native void implCloseChannel() throws IOException;
+
+  public int read (ByteBuffer dst) throws IOException
+  {
+    return implRead (dst);
+  }
+
+  public int read (ByteBuffer dst, long position)
+    throws IOException
+  {
+    if (position < 0)
+      throw new IllegalArgumentException ();
+    long oldPosition = implPosition ();
+    position (position);
+    int result = implRead (dst);
+    position (oldPosition);
+    
+    return result;
+  }
+
+  private int implRead (ByteBuffer dst) throws IOException
+  {
+    int result;
+    byte[] buffer = new byte [dst.remaining ()];
+    
+    result = read (buffer, 0, buffer.length);
+
+    if (result > 0)
+      dst.put (buffer, 0, result);
+
+    return result;
+  }
+  
+  public native int read ()
+    throws IOException;
+
+  public native int read (byte[] buffer, int offset, int length)
+    throws IOException;
+
+  public long read (ByteBuffer[] dsts, int offset, int length)
+    throws IOException
+  {
+    long result = 0;
+
+    for (int i = offset; i < offset + length; i++)
+      {
+        result += read (dsts [i]);
+      }
+
+    return result;
+  }
+
+  public int write (ByteBuffer src) throws IOException
+  {
+    return implWrite (src);
+  }
+    
+  public int write (ByteBuffer src, long position)
+    throws IOException
+  {
+    if (position < 0)
+      throw new IllegalArgumentException ();
+
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+    
+    if ((mode & WRITE) == 0)
+       throw new NonWritableChannelException ();
+
+    int result;
+    long oldPosition;
+
+    oldPosition = implPosition ();
+    seek (position);
+    result = implWrite (src);
+    seek (oldPosition);
+    
+    return result;
+  }
+
+  private int implWrite (ByteBuffer src) throws IOException
+  {
+    int len = src.remaining ();
+    if (src.hasArray())
+      {
+       byte[] buffer = src.array();
+       write(buffer, src.arrayOffset() + src.position(), len);
+      }
+    else
+      {
+       // Use a more efficient native method! FIXME!
+       byte[] buffer = new byte [len];
+       src.get (buffer, 0, len);
+       write (buffer, 0, len);
+      }
+    return len;
+  }
+  
+  public native void write (byte[] buffer, int offset, int length)
+    throws IOException;
+  
+  public native void write (int b) throws IOException;
+
+  public long write(ByteBuffer[] srcs, int offset, int length)
+    throws IOException
+  {
+    long result = 0;
+
+    for (int i = offset;i < offset + length;i++)
+      {
+        result += write (srcs[i]);
+      }
+    
+    return result;
+  }
+                                  
+  public native MappedByteBuffer mapImpl (char mode, long position, int size)
+    throws IOException;
+
+  public MappedByteBuffer map (FileChannel.MapMode mode,
+                              long position, long size)
+    throws IOException
+  {
+    char nmode = 0;
+    if (mode == MapMode.READ_ONLY)
+      {
+       nmode = 'r';
+       if ((this.mode & READ) == 0)
+         throw new NonReadableChannelException();
+      }
+    else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE)
+      {
+       nmode = mode == MapMode.READ_WRITE ? '+' : 'c';
+       if ((this.mode & (READ|WRITE)) != (READ|WRITE))
+         throw new NonWritableChannelException();
+      }
+    else
+      throw new IllegalArgumentException ();
+    
+    if (position < 0 || size < 0 || size > Integer.MAX_VALUE)
+      throw new IllegalArgumentException ();
+    return mapImpl(nmode, position, (int) size);
+  }
+
+  /**
+   * msync with the disk
+   */
+  public void force (boolean metaData) throws IOException
+  {
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+  }
+
+  public long transferTo (long position, long count, WritableByteChannel target)
+    throws IOException
+  {
+    if (position < 0
+        || count < 0)
+      throw new IllegalArgumentException ();
+
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+
+    if ((mode & READ) == 0)
+       throw new NonReadableChannelException ();
+   
+    // XXX: count needs to be casted from long to int. Dataloss ?
+    ByteBuffer buffer = ByteBuffer.allocate ((int) count);
+    read (buffer, position);
+    buffer.flip();
+    return target.write (buffer);
+  }
+
+  public long transferFrom (ReadableByteChannel src, long position, long count)
+    throws IOException
+  {
+    if (position < 0
+        || count < 0)
+      throw new IllegalArgumentException ();
+
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+
+    if ((mode & WRITE) == 0)
+       throw new NonWritableChannelException ();
+
+    // XXX: count needs to be casted from long to int. Dataloss ?
+    ByteBuffer buffer = ByteBuffer.allocate ((int) count);
+    src.read (buffer);
+    buffer.flip();
+    return write (buffer, position);
+  }
+
+  public FileLock tryLock (long position, long size, boolean shared)
+    throws IOException
+  {
+    if (position < 0
+        || size < 0)
+      throw new IllegalArgumentException ();
+
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+
+    if (shared && (mode & READ) == 0)
+      throw new NonReadableChannelException ();
+       
+    if (!shared && (mode & WRITE) == 0)
+      throw new NonWritableChannelException ();
+       
+    boolean completed = false;
+    
+    try
+      {
+       begin();
+        lock(position, size, shared, true);
+       completed = true;
+       return new FileLockImpl(this, position, size, shared);
+      }
+    finally
+      {
+       end(completed);
+      }
+  }
+
+  /** Try to acquire a lock at the given position and size.
+   * On success return true.
+   * If wait as specified, block until we can get it.
+   * Otherwise return false.
+   */
+  private native boolean lock(long position, long size,
+                             boolean shared, boolean wait);
+  
+  public FileLock lock (long position, long size, boolean shared)
+    throws IOException
+  {
+    if (position < 0
+        || size < 0)
+      throw new IllegalArgumentException ();
+
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+
+    boolean completed = false;
+
+    try
+      {
+       boolean lockable = lock(position, size, shared, false);
+       completed = true;
+       return (lockable
+               ? new FileLockImpl(this, position, size, shared)
+               : null);
+      }
+    finally
+      {
+       end(completed);
+      }
+  }
+
+  public long position ()
+    throws IOException
+  {
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+
+    return implPosition ();
+  }
+  
+  public FileChannel position (long newPosition)
+    throws IOException
+  {
+    if (newPosition < 0)
+      throw new IllegalArgumentException ();
+
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+
+    // FIXME note semantics if seeking beyond eof.
+    // We should seek lazily - only on a write.
+    seek (newPosition);
+    return this;
+  }
+  
+  public FileChannel truncate (long size)
+    throws IOException
+  {
+    if (size < 0)
+      throw new IllegalArgumentException ();
+
+    if (!isOpen ())
+      throw new ClosedChannelException ();
+
+    if ((mode & WRITE) == 0)
+       throw new NonWritableChannelException ();
+
+    implTruncate (size);
+    return this;
+  }
+}
diff --git a/libjava/gnu/java/nio/channels/natFileChannelEcos.cc b/libjava/gnu/java/nio/channels/natFileChannelEcos.cc
new file mode 100644 (file)
index 0000000..6671307
--- /dev/null
@@ -0,0 +1,159 @@
+// natFileDescriptor.cc - Native part of FileDescriptor class.
+
+/* Copyright (C) 1998, 1999, 2001, 2002  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+#include <java/io/FileDescriptor.h>
+#include <java/io/SyncFailedException.h>
+#include <java/io/IOException.h>
+#include <java/io/EOFException.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/String.h>
+#include <java/io/FileNotFoundException.h>
+
+extern "C" void diag_write_char (char c);
+
+static void 
+diag_write (char *data, int len)
+{
+  while (len > 0)
+    {
+      diag_write_char (*data++);
+      len--;
+    }
+}
+
+#define NO_FSYNC_MESSAGE "sync unsupported"
+
+void
+java::io::FileDescriptor::init(void)
+{
+  in = new java::io::FileDescriptor(0);
+  out = new java::io::FileDescriptor(1);
+  err = new java::io::FileDescriptor(2);
+}
+
+jboolean
+java::io::FileDescriptor::valid (void)
+{
+  return true;
+}
+
+void
+java::io::FileDescriptor::sync (void)
+{
+  // Some files don't support fsync.  We don't bother reporting these
+  // as errors.
+#ifdef HAVE_FSYNC
+#else
+  throw new SyncFailedException (JvNewStringLatin1 (NO_FSYNC_MESSAGE));
+#endif
+}
+
+jint
+java::io::FileDescriptor::open (jstring path, jint jflags)
+{
+  return fd;
+}
+
+void
+java::io::FileDescriptor::write (jint b)
+{
+  char d = (char) b;
+  ::diag_write (&d, 1);
+}
+
+void
+java::io::FileDescriptor::write (jbyteArray b, jint offset, jint len)
+{
+  if (! b)
+    throw new java::lang::NullPointerException;
+  if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
+    throw new java::lang::ArrayIndexOutOfBoundsException;
+  char *bytes = (char *)elements (b) + offset;
+  ::diag_write (bytes, len);
+}
+
+void
+java::io::FileDescriptor::close (void)
+{
+}
+
+void
+java::io::FileDescriptor::setLength (long)
+{
+}
+
+jint
+java::io::FileDescriptor::seek (jlong pos, jint whence, jboolean)
+{
+  JvAssert (whence == SET || whence == CUR);
+  return 0;
+}
+
+jlong
+java::io::FileDescriptor::getLength (void)
+{
+  return 0;
+}
+
+jlong
+java::io::FileDescriptor::getFilePointer (void)
+{
+  return 0;
+}
+
+jint
+java::io::FileDescriptor::read (void)
+{
+  return 0;
+}
+
+jint
+java::io::FileDescriptor::read (jbyteArray buffer, jint offset, jint count)
+{
+  return 0;
+}
+
+jint
+java::io::FileDescriptor::available (void)
+{
+  return 0;
+}
+
+void
+java::io::FileDescriptor::lock (jlong pos, jint len, jboolean shared)
+{
+  throw new IOException (JvNewStringLatin1
+    ("java.io.FileDescriptor.lock() not implemented"));
+}
+
+jboolean
+java::io::FileDescriptor::tryLock (jlong pos, jint len, jboolean shared)
+{
+  throw new IOException (JvNewStringLatin1
+    ("java.io.FileDescriptor.tryLock() not implemented"));
+}
+
+void
+java::io::FileDescriptor::unlock (jlong pos, jint len)
+{
+  throw new IOException (JvNewStringLatin1
+    ("java.io.FileDescriptor.unlock() not implemented"));
+}
diff --git a/libjava/gnu/java/nio/channels/natFileChannelPosix.cc b/libjava/gnu/java/nio/channels/natFileChannelPosix.cc
new file mode 100644 (file)
index 0000000..8653787
--- /dev/null
@@ -0,0 +1,522 @@
+
+// natFileChannelImplPosix.cc - Native part of FileChannelImpl class.
+
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+#include <config.h>
+#include <platform.h>
+
+#include <gcj/cni.h>
+#include <gcj/javaprims.h>
+#include <jvm.h>
+
+#include "posix.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <gnu/gcj/RawData.h>
+#include <gnu/java/nio/FileLockImpl.h>
+#include <gnu/java/nio/channels/FileChannelImpl.h>
+#include <java/io/FileNotFoundException.h>
+#include <java/io/IOException.h>
+#include <java/io/SyncFailedException.h>
+#include <java/io/InterruptedIOException.h>
+#include <java/io/EOFException.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/System.h>
+#include <java/lang/String.h>
+#include <java/lang/Thread.h>
+#include <java/nio/ByteBuffer.h>
+#include <java/nio/MappedByteBufferImpl.h>
+#include <java/nio/channels/FileChannel.h>
+#include <java/nio/channels/FileLock.h>
+#include <gnu/java/nio/channels/FileChannelImpl.h>
+
+#ifdef HAVE_SYS_IOCTL_H
+#define BSD_COMP /* Get FIONREAD on Solaris2. */
+#include <sys/ioctl.h>
+#endif
+
+// Pick up FIONREAD on Solaris 2.5.
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+using gnu::gcj::RawData;
+using java::io::IOException;
+using java::nio::MappedByteBufferImpl;
+using java::io::InterruptedIOException;
+using java::io::FileNotFoundException;
+using java::lang::ArrayIndexOutOfBoundsException;
+using gnu::java::nio::channels::FileChannelImpl;
+
+#define NO_FSYNC_MESSAGE "sync unsupported"
+
+void
+FileChannelImpl::init(void)
+{
+  in = new FileChannelImpl((jint) 0, FileChannelImpl::READ);
+  out = new FileChannelImpl((jint) 1, FileChannelImpl::WRITE);
+  err = new FileChannelImpl((jint) 2, FileChannelImpl::WRITE);
+}
+
+#if 0
+jboolean
+FileChannelImpl::valid (void)
+{
+  struct stat sb;
+  return fd >= 0 && ::fstat (fd, &sb) == 0;
+}
+
+void
+FileChannelImpl::sync (void)
+{
+  // Some files don't support fsync.  We don't bother reporting these
+  // as errors.
+#ifdef HAVE_FSYNC
+  if (::fsync (fd) && errno != EROFS && errno != EINVAL)
+    throw new SyncFailedException (JvNewStringLatin1 (strerror (errno)));
+#else
+  throw new SyncFailedException (JvNewStringLatin1 (NO_FSYNC_MESSAGE));
+#endif
+}
+#endif
+
+jint
+FileChannelImpl::open (jstring path, jint jflags)
+{
+  fd = -1;
+  char *buf = (char *) _Jv_AllocBytes (_Jv_GetStringUTFLength (path) + 1);
+  jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
+  buf[total] = '\0';
+  int flags = 0;
+#ifdef O_BINARY
+  flags |= O_BINARY;
+#endif
+
+  JvAssert ((jflags & READ) || (jflags & WRITE));
+  int mode = 0666;
+  if ((jflags & READ) && (jflags & WRITE))
+    flags |= O_RDWR | O_CREAT;
+  else if ((jflags & READ))
+    flags |= O_RDONLY;
+  else
+    {
+      flags |= O_WRONLY | O_CREAT;
+      if ((jflags & APPEND))
+       flags |= O_APPEND;
+      else
+       flags |= O_TRUNC;
+
+      if ((jflags & EXCL))
+       {
+         flags |= O_EXCL;
+         // In this case we are making a temp file.
+         mode = 0600;
+       }
+    }
+
+  if ((jflags & SYNC))
+    flags |= O_SYNC;
+
+  if ((jflags & DSYNC))
+    flags |= O_DSYNC;
+
+  int fd = ::open (buf, flags, mode);
+  if (fd == -1 && errno == EMFILE)
+    {
+      // Because finalize () calls close () we might be able to continue.
+      ::java::lang::System::gc ();
+      ::java::lang::System::runFinalization ();
+      fd = ::open (buf, flags, mode);
+    }
+  if (fd == -1)
+    {
+      char msg[MAXPATHLEN + 200];
+      // We choose the formatting here for JDK compatibility, believe
+      // it or not.
+      sprintf (msg, "%.*s (%.*s)",
+              MAXPATHLEN + 150, buf,
+              40, strerror (errno));
+      throw new ::java::io::FileNotFoundException (JvNewStringLatin1 (msg));
+    }
+
+  _Jv_platform_close_on_exec (fd);
+
+  return fd;
+}
+
+void
+FileChannelImpl::write (jint b)
+{
+  jbyte d = (jbyte) b;
+  int r = 0;
+  while (r != 1)
+    {
+      r = ::write (fd, &d, 1);
+      if (r == -1)
+        {
+         if (::java::lang::Thread::interrupted())
+           {
+             ::java::io::InterruptedIOException *iioe
+               = new ::java::io::InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
+             iioe->bytesTransferred = r == -1 ? 0 : r;
+             throw iioe;
+           }       
+         if (errno != EINTR)
+           throw new IOException (JvNewStringLatin1 (strerror (errno)));
+       }
+    }
+  pos++;
+}
+
+void
+FileChannelImpl::write (jbyteArray b, jint offset, jint len)
+{
+  if (! b)
+    throw new ::java::lang::NullPointerException;
+  if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
+    throw new ArrayIndexOutOfBoundsException;
+  jbyte *bytes = elements (b) + offset;
+
+  int written = 0;
+  while (len > 0)
+    {
+      int r = ::write (fd, bytes, len);
+      if (r == -1)
+        {
+         if (::java::lang::Thread::interrupted())
+           {
+             InterruptedIOException *iioe
+               = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
+             iioe->bytesTransferred = written;
+             throw iioe;
+           }
+         if (errno != EINTR)
+           throw new IOException (JvNewStringLatin1 (strerror (errno)));
+       }
+
+      written += r;
+      len -= r;
+      bytes += r;
+      pos += r;
+    }
+}
+
+void
+FileChannelImpl::implCloseChannel (void)
+{
+  jint save = fd;
+  fd = -1;
+  if (::close (save))
+    throw new IOException (JvNewStringLatin1 (strerror (errno)));
+}
+
+void
+FileChannelImpl::implTruncate (jlong size)
+{
+  struct stat sb;
+
+#ifdef HAVE_FTRUNCATE
+  if (::fstat (fd, &sb))
+    throw new IOException (JvNewStringLatin1 (strerror (errno)));
+
+  if ((jlong) sb.st_size == size) 
+    return;
+
+  // If the file is too short, we extend it.  We can't rely on
+  // ftruncate() extending the file.  So we lseek() to 1 byte less
+  // than we want, and then we write a single byte at the end.
+  if ((jlong) sb.st_size < size)
+    {
+      if (::lseek (fd, (off_t) (size - 1), SEEK_SET) == -1)
+       throw new IOException (JvNewStringLatin1 (strerror (errno)));
+      char out = '\0';
+      int r = ::write (fd, &out, 1);
+      if (r <= 0 || ::lseek (fd, pos, SEEK_SET) == -1)
+       throw new IOException (JvNewStringLatin1 (strerror (errno)));
+    }
+  else
+    {
+      if (::ftruncate (fd, (off_t) pos))
+       throw new IOException (JvNewStringLatin1 (strerror (errno)));
+      pos = size;
+    }
+#else /* HAVE_FTRUNCATE */
+  throw new IOException (JvNewStringLatin1 ("FileDescriptor.setLength not implemented"));
+#endif /* HAVE_FTRUNCATE */
+}
+
+void
+FileChannelImpl::seek (jlong newPos)
+{
+  off_t r = ::lseek (fd, (off_t) newPos, SEEK_SET);
+  if (r == -1)
+    throw new IOException (JvNewStringLatin1 (strerror (errno)));
+  pos = r;
+}
+
+jlong
+FileChannelImpl::size (void)
+{
+  struct stat sb;
+  if (::fstat (fd, &sb))
+    throw new IOException (JvNewStringLatin1 (strerror (errno)));
+  return sb.st_size;
+}
+
+jlong
+FileChannelImpl::implPosition (void)
+{
+  return pos;
+}
+
+jint
+FileChannelImpl::read (void)
+{
+  jbyte b;
+  int r;
+  do
+    {
+      r = ::read (fd, &b, 1);
+      if (r == 0)
+       return -1;
+      if (r == -1)
+       {
+         if (::java::lang::Thread::interrupted())
+           {
+             InterruptedIOException *iioe
+               = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
+             iioe->bytesTransferred = r == -1 ? 0 : r;
+             throw iioe;
+           }
+         if (errno != EINTR)
+           throw new IOException (JvNewStringLatin1 (strerror (errno)));
+       }
+    }
+  while (r != 1);
+  pos++;
+  return b & 0xFF;
+}
+
+jint
+FileChannelImpl::read (jbyteArray buffer, jint offset, jint count)
+{
+  if (! buffer)
+    throw new ::java::lang::NullPointerException;
+  jsize bsize = JvGetArrayLength (buffer);
+  if (offset < 0 || count < 0 || offset + count > bsize)
+    throw new ::java::lang::ArrayIndexOutOfBoundsException;
+
+  // Must return 0 if an attempt is made to read 0 bytes.
+  if (count == 0)
+    return 0;
+
+  jbyte *bytes = elements (buffer) + offset;
+  int r;
+  do
+    {
+      r = ::read (fd, bytes, count);
+      if (r == 0)
+       return -1;
+      if (r == -1)
+       {
+         if (::java::lang::Thread::interrupted())
+           {
+             InterruptedIOException *iioe
+               = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
+             iioe->bytesTransferred = r == -1 ? 0 : r;
+             throw iioe;
+           }
+         if (errno != EINTR)
+           throw new IOException (JvNewStringLatin1 (strerror (errno)));
+       }
+    }
+  while (r <= 0);
+  pos += r;
+  return r;
+}
+
+jint
+FileChannelImpl::available (void)
+{
+#if defined (FIONREAD) || defined (HAVE_SELECT) || defined (HAVE_FSTAT)
+  long num = 0;
+  int r = 0;
+  bool num_set = false;
+
+#if defined (FIONREAD)
+  r = ::ioctl (fd, FIONREAD, &num);
+  if (r == -1 && errno == ENOTTY)
+    {
+      // If the ioctl doesn't work, we don't care.
+      r = 0;
+      num = 0;
+    }
+  else
+    num_set = true;
+#elif defined (HAVE_SELECT)
+  if (fd < 0)
+    {
+      errno = EBADF;
+      r = -1;
+    }
+#endif
+
+  if (r == -1)
+    {
+    posix_error:
+      throw new IOException (JvNewStringLatin1 (strerror (errno)));
+    }
+
+  // If we didn't get anything, and we have fstat, then see if see if
+  // we're reading a regular file.  On many systems, FIONREAD does not
+  // work on regular files; select() likewise returns a useless
+  // result.  This is run incorrectly when FIONREAD does work on
+  // regular files and we are at the end of the file.  However, this
+  // case probably isn't very important.
+#if defined (HAVE_FSTAT)
+  if (! num_set)
+    {
+      struct stat sb;
+      off_t where = 0;
+      if (fstat (fd, &sb) != -1
+         && S_ISREG (sb.st_mode)
+         && (where = lseek (fd, 0, SEEK_CUR)) != (off_t) -1)
+       {
+         num = (long) (sb.st_size - where);
+         num_set = true;
+       }
+    }
+#endif /* HAVE_FSTAT */
+
+#if defined (HAVE_SELECT)
+  if (! num_set)
+    {
+      fd_set rd;
+      FD_ZERO (&rd);
+      FD_SET (fd, &rd);
+      struct timeval tv;
+      tv.tv_sec = 0;
+      tv.tv_usec = 0;
+      r = _Jv_select (fd + 1, &rd, NULL, NULL, &tv);
+      if (r == -1)
+       goto posix_error;
+      num = r == 0 ? 0 : 1;
+    }
+#endif /* HAVE_SELECT */
+
+  return (jint) num;
+#else
+  return 0;
+#endif
+}
+
+jboolean
+FileChannelImpl::lock
+(jlong pos, jlong len, jboolean shared, jboolean wait)
+{
+  struct flock lockdata;
+
+  lockdata.l_type = shared ? F_WRLCK : F_RDLCK;
+  lockdata.l_whence = SEEK_SET;
+  lockdata.l_start = pos;
+  lockdata.l_len = len;
+
+  if (::fcntl (fd, wait ? F_SETLKW : F_SETLK, &lockdata) == -1)
+    {
+      if (! wait && (errno == EACCES || errno == EAGAIN))
+       return false;
+      throw new IOException (JvNewStringLatin1 (strerror (errno)));
+    }
+  return true;
+}
+
+void
+FileChannelImpl::unlock (jlong pos, jlong len)
+{
+  struct flock lockdata;
+
+  lockdata.l_type = F_UNLCK;
+  lockdata.l_whence = SEEK_SET;
+  lockdata.l_start = pos;
+  lockdata.l_len = len;
+
+  if (::fcntl (fd, F_SETLK, &lockdata) == -1)
+    throw new IOException (JvNewStringLatin1 (strerror (errno)));
+}
+
+java::nio::MappedByteBuffer *
+FileChannelImpl::mapImpl (jchar mmode, jlong position, jint size)
+{
+#if defined(HAVE_MMAP)
+  int prot, flags;
+  if (mmode == 'r')
+    {
+      prot = PROT_READ;
+      flags = MAP_PRIVATE;
+    }
+  else
+    {
+      prot = PROT_READ|PROT_WRITE;
+      flags = mmode == '+' ? MAP_SHARED : MAP_PRIVATE;
+    }
+  jint page_size = ::getpagesize();
+  jint offset = position & ~(page_size-1);
+  jint align = position - offset;
+  void* ptr = ::mmap(NULL, size + align, prot, flags, fd, offset);
+  MappedByteBufferImpl *buf
+    = new MappedByteBufferImpl ((RawData *) ((char *) ptr + align),
+                               size, mmode == 'r');
+  if (ptr == MAP_FAILED)
+    throw new IOException (JvNewStringLatin1 (strerror (errno)));
+  buf->implPtr = reinterpret_cast<RawData*> (ptr);
+  buf->implLen = size+align;
+  return buf;
+#else
+  throw new IOException (JvNewStringUTF ("mmap not implemented"));
+#endif
+}
+
+void
+MappedByteBufferImpl::unmapImpl ()
+{
+#if defined(HAVE_MMAP)
+  munmap((void*) implPtr, implLen);
+#endif
+}
+
+void
+MappedByteBufferImpl::loadImpl ()
+{
+}
+
+jboolean
+MappedByteBufferImpl::isLoadedImpl ()
+{
+  return true;
+}
+
+void
+MappedByteBufferImpl::forceImpl ()
+{
+#if defined(HAVE_MMAP)
+  ::msync((void*) implPtr, implLen, MS_SYNC);
+#endif
+}
diff --git a/libjava/gnu/java/nio/channels/natFileChannelWin32.cc b/libjava/gnu/java/nio/channels/natFileChannelWin32.cc
new file mode 100644 (file)
index 0000000..ca6387d
--- /dev/null
@@ -0,0 +1,432 @@
+// natFileChannelImplWin32.cc - Native part of FileChannelImpl class.
+
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004  Free Software 
+   Foundation, Inc.
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+// FIXME: In order to support interrupting of IO operations, we
+// need to change to use the windows asynchronous IO functions
+
+#include <config.h>
+#include <platform.h>
+
+#include <gcj/cni.h>
+#include <gcj/javaprims.h>
+#include <jvm.h>
+
+#include <stdio.h>
+
+#include <gnu/gcj/RawData.h>
+#include <gnu/java/nio/FileLockImpl.h>
+#include <gnu/java/nio/channels/FileChannelImpl.h>
+#include <java/io/FileNotFoundException.h>
+#include <java/io/IOException.h>
+#include <java/io/SyncFailedException.h>
+#include <java/io/InterruptedIOException.h>
+#include <java/io/EOFException.h>
+#include <java/lang/ArrayIndexOutOfBoundsException.h>
+#include <java/lang/NullPointerException.h>
+#include <java/lang/System.h>
+#include <java/lang/String.h>
+#include <java/lang/Thread.h>
+#include <java/nio/ByteBuffer.h>
+#include <java/nio/MappedByteBufferImpl.h>
+#include <java/nio/channels/FileChannel.h>
+#include <java/nio/channels/FileLock.h>
+#include <gnu/java/nio/channels/FileChannelImpl.h>
+
+using gnu::gcj::RawData;
+using java::io::IOException;
+using java::nio::MappedByteBufferImpl;
+using java::io::InterruptedIOException;
+using java::io::FileNotFoundException;
+using java::lang::ArrayIndexOutOfBoundsException;
+using gnu::java::nio::channels::FileChannelImpl;
+
+#undef STRICT
+
+static bool testCanUseGetHandleInfo()
+{
+  /* Test to see whether GetHandleInformation can be used
+     for console input or screen buffers. This is better
+     a kludgy OS version check. */
+  DWORD dwFlags;
+  return GetHandleInformation (GetStdHandle (STD_INPUT_HANDLE),
+    &dwFlags) != 0;
+}
+
+// FIXME: casting a FILE (pointer) to a jint will not work on Win64 --
+//        we should be using gnu.gcj.RawData's.
+
+void
+FileChannelImpl::init(void)
+{
+  in = new FileChannelImpl((jint)(GetStdHandle (STD_INPUT_HANDLE)),
+                          FileChannelImpl::READ);
+  out = new FileChannelImpl((jint)(GetStdHandle (STD_OUTPUT_HANDLE)),
+                           FileChannelImpl::WRITE);
+  err = new FileChannelImpl((jint)(GetStdHandle (STD_ERROR_HANDLE)),
+                           FileChannelImpl::WRITE);
+}
+
+#if 0
+FileChannelImpl::sync (void) {
+  if (! FlushFileBuffers ((HANDLE)fd))
+  {
+    DWORD dwErrorCode = GetLastError ();
+    throw new SyncFailedException (_Jv_WinStrError (dwErrorCode));
+  }
+}
+#endif
+
+jint
+FileChannelImpl::open (jstring path, jint jflags) {
+
+  HANDLE handle = NULL;
+  DWORD access = 0;
+  DWORD create = OPEN_EXISTING;
+  
+  JV_TEMP_STRING_WIN32(cpath, path)
+
+  JvAssert((jflags & READ) || (jflags & WRITE));
+
+  if ((jflags & READ) && (jflags & WRITE))
+    {
+      access = GENERIC_READ | GENERIC_WRITE;
+      if (jflags & EXCL)
+        create = CREATE_NEW; // this will raise error if file exists.
+      else
+        create = OPEN_ALWAYS; // equivalent to O_CREAT
+    }
+  else if (jflags & READ)
+    {
+      access = GENERIC_READ;
+      create = OPEN_EXISTING; // ignore EXCL
+    }
+  else
+    { 
+      access = GENERIC_WRITE;
+      if (jflags & EXCL)
+        create = CREATE_NEW;
+      else if (jflags & APPEND)
+        create = OPEN_ALWAYS;
+      else
+        create = CREATE_ALWAYS;
+    }
+
+  handle = CreateFile(cpath, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
+    NULL, create, 0, NULL);
+
+  if (handle == INVALID_HANDLE_VALUE)
+    {
+       DWORD dwErrorCode = GetLastError ();
+       throw new FileNotFoundException (_Jv_WinStrError (cpath, dwErrorCode));
+    }
+
+  // For APPEND mode, move the file pointer to the end of the file.
+  if (jflags & APPEND)
+    {
+      DWORD low = SetFilePointer (handle, 0, NULL, FILE_END);
+      if ((low == (DWORD) 0xffffffff) && (GetLastError () != NO_ERROR)) 
+      {
+        DWORD dwErrorCode = GetLastError ();
+        throw new FileNotFoundException (_Jv_WinStrError (cpath, dwErrorCode));
+      }
+    }
+    
+  // Make this handle non-inheritable so that child
+  // processes don't inadvertently prevent us from
+  // closing this file.
+  _Jv_platform_close_on_exec (handle);
+
+  return (jint) handle;
+}
+
+void
+FileChannelImpl::write (jint b)
+{
+  DWORD bytesWritten;
+  jbyte buf = (jbyte)b;
+
+  if (WriteFile ((HANDLE)fd, &buf, 1, &bytesWritten, NULL))
+    {
+      if (::java::lang::Thread::interrupted())
+        {
+          InterruptedIOException *iioe = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
+          iioe->bytesTransferred = bytesWritten;
+    throw iioe;
+        }
+      if (bytesWritten != 1)
+        _Jv_ThrowIOException ();
+    }
+  else
+    _Jv_ThrowIOException ();
+  // FIXME: loop until bytesWritten == 1
+}
+
+void
+FileChannelImpl::write(jbyteArray b, jint offset, jint len)
+{
+  if (! b)
+    throw new ::java::lang::NullPointerException;
+  if(offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
+    throw new ArrayIndexOutOfBoundsException;
+
+  jbyte *buf = elements (b) + offset;
+  DWORD bytesWritten;
+
+  if (WriteFile ((HANDLE)fd, buf, len, &bytesWritten, NULL))
+    {
+      if (::java::lang::Thread::interrupted())
+        {
+          InterruptedIOException *iioe = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
+          iioe->bytesTransferred = bytesWritten;
+          throw iioe;
+        }
+    }
+  else
+    _Jv_ThrowIOException ();
+  // FIXME: loop until bytesWritten == len
+}
+
+void
+FileChannelImpl::implCloseChannel (void)
+{
+  HANDLE save = (HANDLE)fd;
+  fd = (jint)INVALID_HANDLE_VALUE;
+  if (! CloseHandle (save))
+    _Jv_ThrowIOException ();
+}
+
+void
+FileChannelImpl::implTruncate (jlong size)
+{
+  LONG liOrigFilePointer;
+  LONG liNewFilePointer;
+  LONG liEndFilePointer;
+
+  // Get the original file pointer.
+  if (SetFilePointer((HANDLE) fd, (LONG) 0, &liOrigFilePointer,
+         FILE_CURRENT) != (BOOL) 0
+      && (GetLastError() != NO_ERROR))
+    _Jv_ThrowIOException ();
+
+  // Get the length of the file.
+  if (SetFilePointer((HANDLE) fd, (LONG) 0, &liEndFilePointer,
+         FILE_END) != (BOOL) 0
+      && (GetLastError() != NO_ERROR))
+    _Jv_ThrowIOException ();
+
+  if ((jlong)liEndFilePointer == size)
+    {
+      // Restore the file pointer.
+      if (liOrigFilePointer != liEndFilePointer)
+  {
+    if (SetFilePointer((HANDLE) fd, liOrigFilePointer, &liNewFilePointer,
+           FILE_BEGIN) != (BOOL) 0
+        && (GetLastError() != NO_ERROR))
+      _Jv_ThrowIOException ();
+  }
+      return;
+    }
+
+  // Seek to the new end of file.
+  if (SetFilePointer((HANDLE) fd, (LONG) size, &liNewFilePointer,
+         FILE_BEGIN) != (BOOL) 0
+      && (GetLastError() != NO_ERROR))
+    _Jv_ThrowIOException ();
+
+  // Truncate the file at this point.
+  if (SetEndOfFile((HANDLE) fd) != (BOOL) 0 && (GetLastError() != NO_ERROR))
+    _Jv_ThrowIOException ();
+
+  if (liOrigFilePointer < liNewFilePointer)
+    {
+      // Restore the file pointer.
+      if (SetFilePointer((HANDLE) fd, liOrigFilePointer, &liNewFilePointer,
+        FILE_BEGIN) != (BOOL) 0
+        && (GetLastError() != NO_ERROR))
+        _Jv_ThrowIOException ();
+    }
+}
+
+void
+FileChannelImpl::seek (jlong newPos)
+{
+  LONG high = pos >> 32;
+  DWORD low = SetFilePointer ((HANDLE)fd, (DWORD)(0xffffffff & newPos), &high, FILE_BEGIN);
+  if ((low == 0xffffffff) && (GetLastError () != NO_ERROR))
+    _Jv_ThrowIOException ();
+}
+
+jlong
+FileChannelImpl::implPosition (void)
+{
+  LONG high = 0;
+  DWORD low = SetFilePointer ((HANDLE)fd, 0, &high, FILE_CURRENT);
+  if ((low == 0xffffffff) && (GetLastError() != NO_ERROR))
+    _Jv_ThrowIOException ();
+  return (((jlong)high) << 32L) | (jlong)low;
+}
+
+jlong
+FileChannelImpl::size (void)
+{
+  DWORD high;
+  DWORD low;
+
+  low = GetFileSize ((HANDLE)fd, &high);
+  // FIXME: Error checking
+  return (((jlong)high) << 32L) | (jlong)low;
+}
+
+jint
+FileChannelImpl::read (void)
+{
+  CHAR buf;
+  DWORD read;
+
+  if (! ReadFile ((HANDLE)fd, &buf, 1, &read, NULL))
+    {
+      if (GetLastError () == ERROR_BROKEN_PIPE)
+        return -1;
+      else
+        _Jv_ThrowIOException ();
+    }
+
+  if (! read)
+    return -1;
+  else
+    return (jint)(buf & 0xff);
+}
+
+jint
+FileChannelImpl::read (jbyteArray buffer, jint offset, jint count)
+{
+  if (! buffer)
+    throw new ::java::lang::NullPointerException;
+
+  jsize bsize = JvGetArrayLength (buffer);
+  if (offset < 0 || count < 0 || offset + count > bsize)
+    throw new ArrayIndexOutOfBoundsException;
+
+  // Must return 0 if an attempt is made to read 0 bytes.
+  if (count == 0)
+    return 0;
+
+  jbyte *bytes = elements (buffer) + offset;
+
+  DWORD read;
+  if (! ReadFile((HANDLE)fd, bytes, count, &read, NULL))
+    {
+      if (GetLastError () == ERROR_BROKEN_PIPE)
+        return -1;
+      else
+        _Jv_ThrowIOException ();
+    }
+
+  if (read == 0) return -1;
+
+  return (jint)read;
+}
+
+jint
+FileChannelImpl::available (void)
+{
+  // FIXME:
+  return size() - position();
+}
+
+jboolean
+FileChannelImpl::lock
+(jlong /*pos*/, jlong /*len*/, jboolean /*shared*/, jboolean /*wait*/)
+{
+  throw new IOException (JvNewStringLatin1
+    ("FileChannel.lock() not implemented"));
+}
+
+void
+FileChannelImpl::unlock (jlong /*pos*/, jlong /*len*/)
+{
+  throw new IOException (JvNewStringLatin1
+    ("FileChannel.unlock() not implemented"));
+}
+
+java::nio::MappedByteBuffer *
+FileChannelImpl::mapImpl (jchar mmode, jlong position, jint size)
+{
+  SYSTEM_INFO siSysInfo;
+  GetSystemInfo(&siSysInfo); 
+  DWORD page_size = siSysInfo.dwPageSize;
+  jlong offset = position & ~(page_size-1);
+  jint align = position - offset;
+  jlong high = position + size;
+  jlong max_size;
+  if (mmode == '+')
+    max_size = high - offset;
+  else
+    max_size = 0;
+  DWORD access, protect;
+  if (mmode == 'r')
+    {
+      access = FILE_MAP_READ;
+      protect = PAGE_READONLY;
+    }
+  else if (mmode == '+')
+    {
+      access = FILE_MAP_WRITE;
+      protect = PAGE_READWRITE;
+    }
+  else
+    {
+      access = FILE_MAP_COPY;
+      protect = PAGE_WRITECOPY;
+    }
+  HANDLE hFileMapping = CreateFileMapping((HANDLE) fd,
+                                         (LPSECURITY_ATTRIBUTES) NULL,
+                                         protect,
+                                         (DWORD) (max_size >> 32),
+                                         (DWORD) max_size,
+                                         (LPCTSTR) NULL);
+  if (hFileMapping == NULL)
+    throw new IOException();
+  void *ptr = MapViewOfFile(hFileMapping, access,
+                           (DWORD) (offset >> 32), (DWORD) offset,
+                           (SIZE_T) (high - offset));
+  if (ptr == NULL)
+    throw new IOException();
+  MappedByteBufferImpl *buf
+    = new MappedByteBufferImpl((RawData *) ((char *) ptr + align),
+                              size, mode == 'r');
+  buf->implPtr = reinterpret_cast<RawData*> (ptr);
+  buf->implLen = (jlong) (size_t) hFileMapping;
+  return buf;
+}
+
+void
+MappedByteBufferImpl::unmapImpl ()
+{
+  UnmapViewOfFile((void*)implPtr);
+  CloseHandle((HANDLE) (size_t) implLen);
+}
+
+void
+MappedByteBufferImpl::loadImpl ()
+{
+}
+
+jboolean
+MappedByteBufferImpl::isLoadedImpl ()
+{
+  return true;
+}
+
+void
+MappedByteBufferImpl::forceImpl ()
+{
+}
This page took 0.091325 seconds and 5 git commands to generate.