Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: gnu/java/nio/channels/FileChannelImpl.java


1   /* FileChannelImpl.java -- 
2      Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
3   
4   This file is part of GNU Classpath.
5   
6   GNU Classpath is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10  
11  GNU Classpath is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  General Public License for more details.
15  
16  You should have received a copy of the GNU General Public License
17  along with GNU Classpath; see the file COPYING.  If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301 USA.
20  
21  Linking this library statically or dynamically with other modules is
22  making a combined work based on this library.  Thus, the terms and
23  conditions of the GNU General Public License cover the whole
24  combination.
25  
26  As a special exception, the copyright holders of this library give you
27  permission to link this library with independent modules to produce an
28  executable, regardless of the license terms of these independent
29  modules, and to copy and distribute the resulting executable under
30  terms of your choice, provided that you also meet, for each linked
31  independent module, the terms and conditions of the license of that
32  module.  An independent module is a module which is not derived from
33  or based on this library.  If you modify this library, you may extend
34  this exception to your version of the library, but you are not
35  obligated to do so.  If you do not wish to do so, delete this
36  exception statement from your version. */
37  
38  
39  package gnu.java.nio.channels;
40  
41  import gnu.classpath.Configuration;
42  import gnu.java.nio.FileLockImpl;
43  
44  import java.io.File;
45  import java.io.FileNotFoundException;
46  import java.io.IOException;
47  import java.nio.ByteBuffer;
48  import java.nio.MappedByteBuffer;
49  import java.nio.channels.ClosedChannelException;
50  import java.nio.channels.FileChannel;
51  import java.nio.channels.FileLock;
52  import java.nio.channels.NonReadableChannelException;
53  import java.nio.channels.NonWritableChannelException;
54  import java.nio.channels.ReadableByteChannel;
55  import java.nio.channels.WritableByteChannel;
56  
57  /**
58   * This file is not user visible !
59   * But alas, Java does not have a concept of friendly packages
60   * so this class is public. 
61   * Instances of this class are created by invoking getChannel
62   * Upon a Input/Output/RandomAccessFile object.
63   */
64  public final class FileChannelImpl extends FileChannel
65  {
66    // These are mode values for open().
67    public static final int READ   = 1;
68    public static final int WRITE  = 2;
69    public static final int APPEND = 4;
70  
71    // EXCL is used only when making a temp file.
72    public static final int EXCL   = 8;
73    public static final int SYNC   = 16;
74    public static final int DSYNC  = 32;
75  
76    public static FileChannelImpl in;
77    public static FileChannelImpl out;
78    public static FileChannelImpl err;
79  
80    private static native void init();
81  
82    static
83    {
84      if (Configuration.INIT_LOAD_LIBRARY)
85        {
86          System.loadLibrary("javanio");
87        }
88      
89      init();
90  
91      in  = new FileChannelImpl(0, READ);
92      out = new FileChannelImpl(1, WRITE);
93      err = new FileChannelImpl(2, WRITE);
94    }
95  
96    /**
97     * This is the actual native file descriptor value
98     */
99    // System's notion of file descriptor.  It might seem redundant to
100   // initialize this given that it is reassigned in the constructors.
101   // However, this is necessary because if open() throws an exception
102   // we want to make sure this has the value -1.  This is the most
103   // efficient way to accomplish that.
104   private int fd = -1;
105 
106   private int mode;
107 
108   final String description;
109 
110   /* Open a file.  MODE is a combination of the above mode flags. */
111   /* This is a static factory method, so that VM implementors can decide
112    * substitute subclasses of FileChannelImpl. */
113   public static FileChannelImpl create(File file, int mode)
114     throws FileNotFoundException
115   {
116     return new FileChannelImpl(file, mode);
117   }
118 
119   private FileChannelImpl(File file, int mode)
120     throws FileNotFoundException
121   {
122     String path = file.getPath();
123     description = path;
124     fd = open (path, mode);
125     this.mode = mode;
126 
127     // First open the file and then check if it is a a directory
128     // to avoid race condition.
129     if (file.isDirectory())
130       {
131   try 
132     {
133         close();
134     }
135   catch (IOException e)
136     {
137         /* ignore it */
138     }
139 
140   throw new FileNotFoundException(description + " is a directory");
141       }
142   }
143 
144   /**
145    * Constructor for default channels in, out and err.
146    *
147    * Used by init() (native code).
148    *
149    * @param fd the file descriptor (0, 1, 2 for stdin, stdout, stderr).
150    *
151    * @param mode READ or WRITE
152    */
153   FileChannelImpl (int fd, int mode)
154   {
155     this.fd = fd;
156     this.mode = mode;
157     this.description = "descriptor(" + fd + ")";
158   }
159 
160   private native int open (String path, int mode) throws FileNotFoundException;
161 
162   public native int available () throws IOException;
163   private native long implPosition () throws IOException;
164   private native void seek (long newPosition) throws IOException;
165   private native void implTruncate (long size) throws IOException;
166   
167   public native void unlock (long pos, long len) throws IOException;
168 
169   public native long size () throws IOException;
170     
171   protected native void implCloseChannel() throws IOException;
172 
173   /**
174    * Makes sure the Channel is properly closed.
175    */
176   protected void finalize() throws IOException
177   {
178     this.close();
179   }
180 
181   public int read (ByteBuffer dst) throws IOException
182   {
183     int result;
184     byte[] buffer = new byte [dst.remaining ()];
185     
186     result = read (buffer, 0, buffer.length);
187 
188     if (result > 0)
189       dst.put (buffer, 0, result);
190 
191     return result;
192   }
193 
194   public int read (ByteBuffer dst, long position)
195     throws IOException
196   {
197     if (position < 0)
198       throw new IllegalArgumentException ("position: " + position);
199     long oldPosition = implPosition ();
200     position (position);
201     int result = read(dst);
202     position (oldPosition);
203     
204     return result;
205   }
206 
207   public native int read ()
208     throws IOException;
209 
210   public native int read (byte[] buffer, int offset, int length)
211     throws IOException;
212 
213   public long read (ByteBuffer[] dsts, int offset, int length)
214     throws IOException
215   {
216     long result = 0;
217 
218     for (int i = offset; i < offset + length; i++)
219       {
220         result += read (dsts [i]);
221       }
222 
223     return result;
224   }
225 
226   public int write (ByteBuffer src) throws IOException
227   {
228     int len = src.remaining ();
229     if (src.hasArray())
230       {
231   byte[] buffer = src.array();
232   write(buffer, src.arrayOffset() + src.position(), len);
233   src.position(src.position() + len);
234       }
235     else
236       {
237   // Use a more efficient native method! FIXME!
238   byte[] buffer = new byte [len];
239       src.get (buffer, 0, len);
240   write (buffer, 0, len);
241       }
242     return len;
243   }
244     
245   public int write (ByteBuffer src, long position)
246     throws IOException
247   {
248     if (position < 0)
249       throw new IllegalArgumentException ("position: " + position);
250 
251     if (!isOpen ())
252       throw new ClosedChannelException ();
253     
254     if ((mode & WRITE) == 0)
255        throw new NonWritableChannelException ();
256 
257     int result;
258     long oldPosition;
259 
260     oldPosition = implPosition ();
261     seek (position);
262     result = write(src);
263     seek (oldPosition);
264     
265     return result;
266   }
267 
268   public native void write (byte[] buffer, int offset, int length)
269     throws IOException;
270   
271   public native void write (int b) throws IOException;
272 
273   public long write(ByteBuffer[] srcs, int offset, int length)
274     throws IOException
275   {
276     long result = 0;
277 
278     for (int i = offset;i < offset + length;i++)
279       {
280         result += write (srcs[i]);
281       }
282     
283     return result;
284   }
285            
286   public native MappedByteBuffer mapImpl (char mode, long position, int size)
287     throws IOException;
288 
289   public MappedByteBuffer map (FileChannel.MapMode mode,
290              long position, long size)
291     throws IOException
292   {
293     char nmode = 0;
294     if (mode == MapMode.READ_ONLY)
295       {
296   nmode = 'r';
297   if ((this.mode & READ) == 0)
298     throw new NonReadableChannelException();
299       }
300     else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE)
301       {
302   nmode = mode == MapMode.READ_WRITE ? '+' : 'c';
303   if ((this.mode & (READ|WRITE)) != (READ|WRITE))
304     throw new NonWritableChannelException();
305       }
306     else
307       throw new IllegalArgumentException ("mode: " + mode);
308     
309     if (position < 0 || size < 0 || size > Integer.MAX_VALUE)
310       throw new IllegalArgumentException ("position: " + position
311             + ", size: " + size);
312     return mapImpl(nmode, position, (int) size);
313   }
314 
315   /**
316    * msync with the disk
317    */
318   public void force (boolean metaData) throws IOException
319   {
320     if (!isOpen ())
321       throw new ClosedChannelException ();
322 
323     force ();
324   }
325 
326   private native void force ();
327 
328   // like transferTo, but with a count of less than 2Gbytes
329   private int smallTransferTo (long position, int count, 
330              WritableByteChannel target)
331     throws IOException
332   {
333     ByteBuffer buffer;
334     try
335       {
336   // Try to use a mapped buffer if we can.  If this fails for
337   // any reason we'll fall back to using a ByteBuffer.
338   buffer = map (MapMode.READ_ONLY, position, count);
339       }
340     catch (IOException e)
341       {
342   buffer = ByteBuffer.allocate (count);
343   read (buffer, position);
344   buffer.flip();
345       }
346 
347     return target.write (buffer);
348   }
349 
350   public long transferTo (long position, long count, 
351         WritableByteChannel target)
352     throws IOException
353   {
354     if (position < 0
355         || count < 0)
356       throw new IllegalArgumentException ("position: " + position
357             + ", count: " + count);
358 
359     if (!isOpen ())
360       throw new ClosedChannelException ();
361 
362     if ((mode & READ) == 0)
363        throw new NonReadableChannelException ();
364    
365     final int pageSize = 65536;
366     long total = 0;
367 
368     while (count > 0)
369       {
370   int transferred 
371     = smallTransferTo (position, (int)Math.min (count, pageSize), 
372            target);
373   if (transferred < 0)
374     break;
375   total += transferred;
376   position += transferred;
377   count -= transferred;
378       }
379 
380     return total;
381   }
382 
383   // like transferFrom, but with a count of less than 2Gbytes
384   private int smallTransferFrom (ReadableByteChannel src, long position, 
385          int count)
386     throws IOException
387   {
388     ByteBuffer buffer = null;
389 
390     if (src instanceof FileChannel)
391       {
392   try
393     {
394       // Try to use a mapped buffer if we can.  If this fails
395       // for any reason we'll fall back to using a ByteBuffer.
396       buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position, 
397                count);
398     }
399   catch (IOException e)
400     {
401     }
402       }
403 
404     if (buffer == null)
405       {
406   buffer = ByteBuffer.allocate ((int) count);
407   src.read (buffer);
408   buffer.flip();
409       }
410 
411     return write (buffer, position);
412   }
413 
414   public long transferFrom (ReadableByteChannel src, long position, 
415           long count)
416     throws IOException
417   {
418     if (position < 0
419         || count < 0)
420       throw new IllegalArgumentException ("position: " + position
421             + ", count: " + count);
422 
423     if (!isOpen ())
424       throw new ClosedChannelException ();
425 
426     if ((mode & WRITE) == 0)
427        throw new NonWritableChannelException ();
428 
429     final int pageSize = 65536;
430     long total = 0;
431 
432     while (count > 0)
433       {
434   int transferred = smallTransferFrom (src, position, 
435                (int)Math.min (count, pageSize));
436   if (transferred < 0)
437     break;
438   total += transferred;
439   position += transferred;
440   count -= transferred;
441       }
442 
443     return total;
444   }
445 
446   // Shared sanity checks between lock and tryLock methods.
447   private void lockCheck(long position, long size, boolean shared)
448     throws IOException
449   {
450     if (position < 0
451         || size < 0)
452       throw new IllegalArgumentException ("position: " + position
453             + ", size: " + size);
454 
455     if (!isOpen ())
456       throw new ClosedChannelException();
457 
458     if (shared && ((mode & READ) == 0))
459       throw new NonReadableChannelException();
460   
461     if (!shared && ((mode & WRITE) == 0))
462       throw new NonWritableChannelException();
463   }
464 
465   public FileLock tryLock (long position, long size, boolean shared)
466     throws IOException
467   {
468     lockCheck(position, size, shared);
469 
470     boolean completed = false;
471     try
472       {
473   begin();
474   boolean lockable = lock(position, size, shared, false);
475   completed = true;
476   return (lockable
477     ? new FileLockImpl(this, position, size, shared)
478     : null);
479       }
480     finally
481       {
482   end(completed);
483       }
484   }
485 
486   /** Try to acquire a lock at the given position and size.
487    * On success return true.
488    * If wait as specified, block until we can get it.
489    * Otherwise return false.
490    */
491   private native boolean lock(long position, long size,
492             boolean shared, boolean wait) throws IOException;
493   
494   public FileLock lock (long position, long size, boolean shared)
495     throws IOException
496   {
497     lockCheck(position, size, shared);
498 
499     boolean completed = false;
500     try
501       {
502   boolean lockable = lock(position, size, shared, true);
503   completed = true;
504   return (lockable
505     ? new FileLockImpl(this, position, size, shared)
506     : null);
507       }
508     finally
509       {
510   end(completed);
511       }
512   }
513 
514   public long position ()
515     throws IOException
516   {
517     if (!isOpen ())
518       throw new ClosedChannelException ();
519 
520     return implPosition ();
521   }
522   
523   public FileChannel position (long newPosition)
524     throws IOException
525   {
526     if (newPosition < 0)
527       throw new IllegalArgumentException ("newPostition: " + newPosition);
528 
529     if (!isOpen ())
530       throw new ClosedChannelException ();
531 
532     // FIXME note semantics if seeking beyond eof.
533     // We should seek lazily - only on a write.
534     seek (newPosition);
535     return this;
536   }
537   
538   public FileChannel truncate (long size)
539     throws IOException
540   {
541     if (size < 0)
542       throw new IllegalArgumentException ("size: " + size);
543 
544     if (!isOpen ())
545       throw new ClosedChannelException ();
546 
547     if ((mode & WRITE) == 0)
548        throw new NonWritableChannelException ();
549 
550     if (size < size ())
551       implTruncate (size);
552 
553     return this;
554   }
555 
556   public String toString()
557   {
558     return (this.getClass()
559       + "[fd=" + fd
560       + ",mode=" + mode + ","
561       + description + "]");
562   }
563 }