mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			573 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			573 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* FileChannelImpl.java --
 | |
|    Copyright (C) 2002, 2004, 2005, 2006  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., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 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;
 | |
| 
 | |
| import gnu.classpath.Configuration;
 | |
| import gnu.java.nio.FileLockImpl;
 | |
| import gnu.java.nio.VMChannel;
 | |
| 
 | |
| import java.io.File;
 | |
| import java.io.FileNotFoundException;
 | |
| import java.io.IOException;
 | |
| import java.nio.ByteBuffer;
 | |
| import java.nio.MappedByteBuffer;
 | |
| import java.nio.channels.ClosedChannelException;
 | |
| import java.nio.channels.FileChannel;
 | |
| import java.nio.channels.FileLock;
 | |
| import java.nio.channels.NonReadableChannelException;
 | |
| import java.nio.channels.NonWritableChannelException;
 | |
| import java.nio.channels.ReadableByteChannel;
 | |
| import java.nio.channels.WritableByteChannel;
 | |
| 
 | |
| /**
 | |
|  * 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 final class FileChannelImpl extends FileChannel
 | |
| {
 | |
|   // These are mode values for open().
 | |
|   public static final int READ   = 1;
 | |
|   public static final int WRITE  = 2;
 | |
|   public static final int APPEND = 4;
 | |
| 
 | |
|   // EXCL is used only when making a temp file.
 | |
|   public static final int EXCL   = 8;
 | |
|   public static final int SYNC   = 16;
 | |
|   public static final int DSYNC  = 32;
 | |
| 
 | |
|   public static final FileChannelImpl in;
 | |
|   public static final FileChannelImpl out;
 | |
|   public static final FileChannelImpl err;
 | |
| 
 | |
|   //private static native void init();
 | |
| 
 | |
|   static
 | |
|   {
 | |
|     if (Configuration.INIT_LOAD_LIBRARY)
 | |
|       {
 | |
|         System.loadLibrary("javanio");
 | |
|       }
 | |
| 
 | |
|     //init();
 | |
| 
 | |
|     FileChannelImpl ch = null;
 | |
|     try
 | |
|       {
 | |
|         ch = new FileChannelImpl(VMChannel.getStdin(), READ);
 | |
|       }
 | |
|     catch (IOException ioe)
 | |
|       {
 | |
|         throw new Error(ioe);
 | |
|       }
 | |
|     in = ch;
 | |
| 
 | |
|     ch = null;
 | |
|     try
 | |
|       {
 | |
|         ch = new FileChannelImpl(VMChannel.getStdout(), WRITE);
 | |
|       }
 | |
|     catch (IOException ioe)
 | |
|       {
 | |
|         throw new Error(ioe);
 | |
|       }
 | |
|     out = ch;
 | |
| 
 | |
|     ch = null;
 | |
|     try
 | |
|       {
 | |
|         ch = new FileChannelImpl(VMChannel.getStderr(), WRITE);
 | |
|       }
 | |
|     catch (IOException ioe)
 | |
|       {
 | |
|         throw new Error(ioe);
 | |
|       }
 | |
|     err = ch;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This is the actual native file descriptor value
 | |
|    */
 | |
|   private VMChannel ch;
 | |
| 
 | |
|   private int mode;
 | |
| 
 | |
|   final String description;
 | |
| 
 | |
|   /* Open a file.  MODE is a combination of the above mode flags. */
 | |
|   /* This is a static factory method, so that VM implementors can decide
 | |
|    * substitute subclasses of FileChannelImpl. */
 | |
|   public static FileChannelImpl create(File file, int mode)
 | |
|     throws IOException
 | |
|   {
 | |
|     return new FileChannelImpl(file, mode);
 | |
|   }
 | |
| 
 | |
|   private FileChannelImpl(File file, int mode)
 | |
|     throws IOException
 | |
|   {
 | |
|     String path = file.getPath();
 | |
|     description = path;
 | |
|     this.mode = mode;
 | |
|     this.ch = new VMChannel();
 | |
|     ch.openFile(path, mode);
 | |
| 
 | |
|     // First open the file and then check if it is a a directory
 | |
|     // to avoid race condition.
 | |
|     if (file.isDirectory())
 | |
|       {
 | |
|         try
 | |
|           {
 | |
|             close();
 | |
|           }
 | |
|         catch (IOException e)
 | |
|           {
 | |
|             /* ignore it */
 | |
|           }
 | |
| 
 | |
|         throw new FileNotFoundException(description + " is a directory");
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Constructor for default channels in, out and err.
 | |
|    *
 | |
|    * Used by init() (native code).
 | |
|    *
 | |
|    * @param fd the file descriptor (0, 1, 2 for stdin, stdout, stderr).
 | |
|    *
 | |
|    * @param mode READ or WRITE
 | |
|    */
 | |
|   FileChannelImpl (VMChannel ch, int mode)
 | |
|   {
 | |
|     this.mode = mode;
 | |
|     this.description = "descriptor(" + ch.getState() + ")";
 | |
|     this.ch = ch;
 | |
|   }
 | |
| 
 | |
|   public int available() throws IOException
 | |
|   {
 | |
|     return ch.available();
 | |
|   }
 | |
| 
 | |
|   private long implPosition() throws IOException
 | |
|   {
 | |
|     return ch.position();
 | |
|   }
 | |
| 
 | |
|   private void seek(long newPosition) throws IOException
 | |
|   {
 | |
|     ch.seek(newPosition);
 | |
|   }
 | |
| 
 | |
|   private void implTruncate(long size) throws IOException
 | |
|   {
 | |
|     ch.truncate(size);
 | |
|   }
 | |
| 
 | |
|   public void unlock(long pos, long len) throws IOException
 | |
|   {
 | |
|     ch.unlock(pos, len);
 | |
|   }
 | |
| 
 | |
|   public long size () throws IOException
 | |
|   {
 | |
|     return ch.size();
 | |
|   }
 | |
| 
 | |
|   protected void implCloseChannel() throws IOException
 | |
|   {
 | |
|     ch.close();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Makes sure the Channel is properly closed.
 | |
|    */
 | |
|   protected void finalize() throws IOException
 | |
|   {
 | |
|     if (ch.getState().isValid())
 | |
|       close();
 | |
|   }
 | |
| 
 | |
|   public int read (ByteBuffer dst) throws IOException
 | |
|   {
 | |
|     return ch.read(dst);
 | |
|   }
 | |
| 
 | |
|   public int read (ByteBuffer dst, long position)
 | |
|     throws IOException
 | |
|   {
 | |
|     if (position < 0)
 | |
|       throw new IllegalArgumentException ("position: " + position);
 | |
|     long oldPosition = implPosition ();
 | |
|     position (position);
 | |
|     int result = read(dst);
 | |
|     position (oldPosition);
 | |
| 
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   public int read() throws IOException
 | |
|   {
 | |
|     return ch.read();
 | |
|   }
 | |
| 
 | |
|   public long read (ByteBuffer[] dsts, int offset, int length)
 | |
|     throws IOException
 | |
|   {
 | |
|     return ch.readScattering(dsts, offset, length);
 | |
|   }
 | |
| 
 | |
|   public int write (ByteBuffer src) throws IOException
 | |
|   {
 | |
|     return ch.write(src);
 | |
|   }
 | |
| 
 | |
|   public int write (ByteBuffer src, long position)
 | |
|     throws IOException
 | |
|   {
 | |
|     if (position < 0)
 | |
|       throw new IllegalArgumentException ("position: " + position);
 | |
| 
 | |
|     if (!isOpen ())
 | |
|       throw new ClosedChannelException ();
 | |
| 
 | |
|     if ((mode & WRITE) == 0)
 | |
|        throw new NonWritableChannelException ();
 | |
| 
 | |
|     int result;
 | |
|     long oldPosition;
 | |
| 
 | |
|     oldPosition = implPosition ();
 | |
|     seek (position);
 | |
|     result = write(src);
 | |
|     seek (oldPosition);
 | |
| 
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   public void write (int b) throws IOException
 | |
|   {
 | |
|     ch.write(b);
 | |
|   }
 | |
| 
 | |
|   public long write(ByteBuffer[] srcs, int offset, int length)
 | |
|     throws IOException
 | |
|   {
 | |
|     return ch.writeGathering(srcs, offset, length);
 | |
|   }
 | |
| 
 | |
|   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 & WRITE) != WRITE)
 | |
|           throw new NonWritableChannelException();
 | |
|         if ((this.mode & READ) != READ)
 | |
|           throw new NonReadableChannelException();
 | |
|       }
 | |
|     else
 | |
|       throw new IllegalArgumentException ("mode: " + mode);
 | |
| 
 | |
|     if (position < 0 || size < 0 || size > Integer.MAX_VALUE)
 | |
|       throw new IllegalArgumentException ("position: " + position
 | |
|                                           + ", size: " + size);
 | |
|     return ch.map(nmode, position, (int) size);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * msync with the disk
 | |
|    */
 | |
|   public void force (boolean metaData) throws IOException
 | |
|   {
 | |
|     if (!isOpen ())
 | |
|       throw new ClosedChannelException ();
 | |
| 
 | |
|     ch.flush(metaData);
 | |
|   }
 | |
| 
 | |
|   // like transferTo, but with a count of less than 2Gbytes
 | |
|   private int smallTransferTo (long position, int count,
 | |
|                                WritableByteChannel target)
 | |
|     throws IOException
 | |
|   {
 | |
|     ByteBuffer buffer;
 | |
|     try
 | |
|       {
 | |
|         // Try to use a mapped buffer if we can.  If this fails for
 | |
|         // any reason we'll fall back to using a ByteBuffer.
 | |
|         buffer = map (MapMode.READ_ONLY, position, count);
 | |
|       }
 | |
|     catch (IOException e)
 | |
|       {
 | |
|         buffer = ByteBuffer.allocate (count);
 | |
|         read (buffer, position);
 | |
|         buffer.flip();
 | |
|       }
 | |
| 
 | |
|     return target.write (buffer);
 | |
|   }
 | |
| 
 | |
|   public long transferTo (long position, long count,
 | |
|                           WritableByteChannel target)
 | |
|     throws IOException
 | |
|   {
 | |
|     if (position < 0
 | |
|         || count < 0)
 | |
|       throw new IllegalArgumentException ("position: " + position
 | |
|                                           + ", count: " + count);
 | |
| 
 | |
|     if (!isOpen ())
 | |
|       throw new ClosedChannelException ();
 | |
| 
 | |
|     if ((mode & READ) == 0)
 | |
|        throw new NonReadableChannelException ();
 | |
| 
 | |
|     final int pageSize = 65536;
 | |
|     long total = 0;
 | |
| 
 | |
|     while (count > 0)
 | |
|       {
 | |
|         int transferred
 | |
|           = smallTransferTo (position, (int)Math.min (count, pageSize),
 | |
|                              target);
 | |
|         if (transferred < 0)
 | |
|           break;
 | |
|         total += transferred;
 | |
|         position += transferred;
 | |
|         count -= transferred;
 | |
|       }
 | |
| 
 | |
|     return total;
 | |
|   }
 | |
| 
 | |
|   // like transferFrom, but with a count of less than 2Gbytes
 | |
|   private int smallTransferFrom (ReadableByteChannel src, long position,
 | |
|                                  int count)
 | |
|     throws IOException
 | |
|   {
 | |
|     ByteBuffer buffer = null;
 | |
| 
 | |
|     if (src instanceof FileChannel)
 | |
|       {
 | |
|         try
 | |
|           {
 | |
|             // Try to use a mapped buffer if we can.  If this fails
 | |
|             // for any reason we'll fall back to using a ByteBuffer.
 | |
|             buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position,
 | |
|                                              count);
 | |
|           }
 | |
|         catch (IOException e)
 | |
|           {
 | |
|           }
 | |
|       }
 | |
| 
 | |
|     if (buffer == null)
 | |
|       {
 | |
|         buffer = ByteBuffer.allocate (count);
 | |
|         src.read (buffer);
 | |
|         buffer.flip();
 | |
|       }
 | |
| 
 | |
|     return write (buffer, position);
 | |
|   }
 | |
| 
 | |
|   public long transferFrom (ReadableByteChannel src, long position,
 | |
|                             long count)
 | |
|     throws IOException
 | |
|   {
 | |
|     if (position < 0
 | |
|         || count < 0)
 | |
|       throw new IllegalArgumentException ("position: " + position
 | |
|                                           + ", count: " + count);
 | |
| 
 | |
|     if (!isOpen ())
 | |
|       throw new ClosedChannelException ();
 | |
| 
 | |
|     if ((mode & WRITE) == 0)
 | |
|        throw new NonWritableChannelException ();
 | |
| 
 | |
|     final int pageSize = 65536;
 | |
|     long total = 0;
 | |
| 
 | |
|     while (count > 0)
 | |
|       {
 | |
|         int transferred = smallTransferFrom (src, position,
 | |
|                                              (int)Math.min (count, pageSize));
 | |
|         if (transferred < 0)
 | |
|           break;
 | |
|         total += transferred;
 | |
|         position += transferred;
 | |
|         count -= transferred;
 | |
|       }
 | |
| 
 | |
|     return total;
 | |
|   }
 | |
| 
 | |
|   // Shared sanity checks between lock and tryLock methods.
 | |
|   private void lockCheck(long position, long size, boolean shared)
 | |
|     throws IOException
 | |
|   {
 | |
|     if (position < 0
 | |
|         || size < 0)
 | |
|       throw new IllegalArgumentException ("position: " + position
 | |
|                                           + ", size: " + size);
 | |
| 
 | |
|     if (!isOpen ())
 | |
|       throw new ClosedChannelException();
 | |
| 
 | |
|     if (shared && ((mode & READ) == 0))
 | |
|       throw new NonReadableChannelException();
 | |
| 
 | |
|     if (!shared && ((mode & WRITE) == 0))
 | |
|       throw new NonWritableChannelException();
 | |
|   }
 | |
| 
 | |
|   public FileLock tryLock (long position, long size, boolean shared)
 | |
|     throws IOException
 | |
|   {
 | |
|     lockCheck(position, size, shared);
 | |
| 
 | |
|     boolean completed = false;
 | |
|     try
 | |
|       {
 | |
|         begin();
 | |
|         boolean lockable = ch.lock(position, size, shared, false);
 | |
|         completed = true;
 | |
|         return (lockable
 | |
|                 ? new FileLockImpl(this, position, size, shared)
 | |
|                 : null);
 | |
|       }
 | |
|     finally
 | |
|       {
 | |
|         end(completed);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public FileLock lock (long position, long size, boolean shared)
 | |
|     throws IOException
 | |
|   {
 | |
|     lockCheck(position, size, shared);
 | |
| 
 | |
|     boolean completed = false;
 | |
|     try
 | |
|       {
 | |
|         boolean lockable = ch.lock(position, size, shared, true);
 | |
|         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 ("newPosition: " + newPosition);
 | |
| 
 | |
|     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 ("size: " + size);
 | |
| 
 | |
|     if (!isOpen ())
 | |
|       throw new ClosedChannelException ();
 | |
| 
 | |
|     if ((mode & WRITE) == 0)
 | |
|        throw new NonWritableChannelException ();
 | |
| 
 | |
|     if (size < size ())
 | |
|       implTruncate (size);
 | |
| 
 | |
|     return this;
 | |
|   }
 | |
| 
 | |
|   public String toString()
 | |
|   {
 | |
|     return (super.toString()
 | |
|             + "[ fd: " + ch.getState()
 | |
|             + "; mode: " + Integer.toOctalString(mode)
 | |
|             + "; " + description + " ]");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @return The native file descriptor.
 | |
|    * /
 | |
|   public int getNativeFD()
 | |
|   {
 | |
|     return fd;
 | |
|   }*/
 | |
| }
 |