OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / gnu / java / nio / channels / FileChannelImpl.java
1 /* FileChannelImpl.java -- 
2    Copyright (C) 2002, 2004, 2005, 2006  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   private static native void init();
77
78   static
79   {
80     if (Configuration.INIT_LOAD_LIBRARY)
81       {
82         System.loadLibrary("javanio");
83       }
84     
85     init();
86   }
87
88   /**
89    * This is the actual native file descriptor value
90    */
91   // System's notion of file descriptor.  It might seem redundant to
92   // initialize this given that it is reassigned in the constructors.
93   // However, this is necessary because if open() throws an exception
94   // we want to make sure this has the value -1.  This is the most
95   // efficient way to accomplish that.
96   private int fd = -1;
97
98   private long pos;
99   private int mode;
100
101   public FileChannelImpl ()
102   {
103   }
104
105   /* Open a file.  MODE is a combination of the above mode flags. */
106   /* This is a static factory method, so that VM implementors can decide
107    * substitute subclasses of FileChannelImpl. */
108   public static FileChannelImpl create(File file, int mode)
109     throws FileNotFoundException
110   {
111     return new FileChannelImpl(file, mode);
112   }
113
114   /* Open a file.  MODE is a combination of the above mode flags. */
115   private FileChannelImpl (File file, int mode) throws FileNotFoundException
116   {
117     final String path = file.getPath();
118     fd = open (path, mode);
119     this.mode = mode;
120
121     // First open the file and then check if it is a a directory
122     // to avoid race condition.
123     if (file.isDirectory())
124       {
125         try 
126           {
127               close();
128           }
129         catch (IOException e)
130           {
131               /* ignore it */
132           }
133
134         throw new FileNotFoundException(path + " is a directory");
135       }
136   }
137
138   /* Used by init() (native code) */
139   FileChannelImpl (int fd, int mode)
140   {
141     this.fd = fd;
142     this.mode = mode;
143   }
144
145   public static FileChannelImpl in;
146   public static FileChannelImpl out;
147   public static FileChannelImpl err;
148
149   private native int open (String path, int mode) throws FileNotFoundException;
150
151   public native int available () throws IOException;
152   private native long implPosition () throws IOException;
153   private native void seek (long newPosition) throws IOException;
154   private native void implTruncate (long size) throws IOException;
155   
156   public native void unlock (long pos, long len) throws IOException;
157
158   public native long size () throws IOException;
159     
160   protected native void implCloseChannel() throws IOException;
161
162   /**
163    * Makes sure the Channel is properly closed.
164    */
165   protected void finalize() throws IOException
166   {
167     this.close();
168   }
169
170   public int read (ByteBuffer dst) throws IOException
171   {
172     int result;
173     byte[] buffer = new byte [dst.remaining ()];
174     
175     result = read (buffer, 0, buffer.length);
176
177     if (result > 0)
178       dst.put (buffer, 0, result);
179
180     return result;
181   }
182
183   public int read (ByteBuffer dst, long position)
184     throws IOException
185   {
186     if (position < 0)
187       throw new IllegalArgumentException ();
188     long oldPosition = implPosition ();
189     position (position);
190     int result = read(dst);
191     position (oldPosition);
192     
193     return result;
194   }
195
196   public native int read ()
197     throws IOException;
198
199   public native int read (byte[] buffer, int offset, int length)
200     throws IOException;
201
202   public long read (ByteBuffer[] dsts, int offset, int length)
203     throws IOException
204   {
205     long result = 0;
206
207     for (int i = offset; i < offset + length; i++)
208       {
209         result += read (dsts [i]);
210       }
211
212     return result;
213   }
214
215   public int write (ByteBuffer src) throws IOException
216   {
217     int len = src.remaining ();
218     if (src.hasArray())
219       {
220         byte[] buffer = src.array();
221         write(buffer, src.arrayOffset() + src.position(), len);
222         src.position(src.position() + len);
223       }
224     else
225       {
226         // Use a more efficient native method! FIXME!
227         byte[] buffer = new byte [len];
228         src.get (buffer, 0, len);
229         write (buffer, 0, len);
230       }
231     return len;
232   }
233     
234   public int write (ByteBuffer src, long position)
235     throws IOException
236   {
237     if (position < 0)
238       throw new IllegalArgumentException ();
239
240     if (!isOpen ())
241       throw new ClosedChannelException ();
242     
243     if ((mode & WRITE) == 0)
244        throw new NonWritableChannelException ();
245
246     int result;
247     long oldPosition;
248
249     oldPosition = implPosition ();
250     seek (position);
251     result = write(src);
252     seek (oldPosition);
253     
254     return result;
255   }
256
257   public native void write (byte[] buffer, int offset, int length)
258     throws IOException;
259   
260   public native void write (int b) throws IOException;
261
262   public long write(ByteBuffer[] srcs, int offset, int length)
263     throws IOException
264   {
265     long result = 0;
266
267     for (int i = offset;i < offset + length;i++)
268       {
269         result += write (srcs[i]);
270       }
271     
272     return result;
273   }
274                                    
275   public native MappedByteBuffer mapImpl (char mode, long position, int size)
276     throws IOException;
277
278   public MappedByteBuffer map (FileChannel.MapMode mode,
279                                long position, long size)
280     throws IOException
281   {
282     char nmode = 0;
283     if (mode == MapMode.READ_ONLY)
284       {
285         nmode = 'r';
286         if ((this.mode & READ) == 0)
287           throw new NonReadableChannelException();
288       }
289     else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE)
290       {
291         nmode = mode == MapMode.READ_WRITE ? '+' : 'c';
292         if ((this.mode & (READ|WRITE)) != (READ|WRITE))
293           throw new NonWritableChannelException();
294       }
295     else
296       throw new IllegalArgumentException ();
297     
298     if (position < 0 || size < 0 || size > Integer.MAX_VALUE)
299       throw new IllegalArgumentException ();
300     return mapImpl(nmode, position, (int) size);
301   }
302
303   /**
304    * msync with the disk
305    */
306   public void force (boolean metaData) throws IOException
307   {
308     if (!isOpen ())
309       throw new ClosedChannelException ();
310   }
311
312   // like transferTo, but with a count of less than 2Gbytes
313   private int smallTransferTo (long position, int count, 
314                                WritableByteChannel target)
315     throws IOException
316   {
317     ByteBuffer buffer;
318     try
319       {
320         // Try to use a mapped buffer if we can.  If this fails for
321         // any reason we'll fall back to using a ByteBuffer.
322         buffer = map (MapMode.READ_ONLY, position, count);
323       }
324     catch (IOException e)
325       {
326         buffer = ByteBuffer.allocate (count);
327         read (buffer, position);
328         buffer.flip();
329       }
330
331     return target.write (buffer);
332   }
333
334   public long transferTo (long position, long count, 
335                           WritableByteChannel target)
336     throws IOException
337   {
338     if (position < 0
339         || count < 0)
340       throw new IllegalArgumentException ();
341
342     if (!isOpen ())
343       throw new ClosedChannelException ();
344
345     if ((mode & READ) == 0)
346        throw new NonReadableChannelException ();
347    
348     final int pageSize = 65536;
349     long total = 0;
350
351     while (count > 0)
352       {
353         int transferred 
354           = smallTransferTo (position, (int)Math.min (count, pageSize), 
355                              target);
356         if (transferred < 0)
357           break;
358         total += transferred;
359         position += transferred;
360         count -= transferred;
361       }
362
363     return total;
364   }
365
366   // like transferFrom, but with a count of less than 2Gbytes
367   private int smallTransferFrom (ReadableByteChannel src, long position, 
368                                  int count)
369     throws IOException
370   {
371     ByteBuffer buffer = null;
372
373     if (src instanceof FileChannel)
374       {
375         try
376           {
377             // Try to use a mapped buffer if we can.  If this fails
378             // for any reason we'll fall back to using a ByteBuffer.
379             buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position, 
380                                              count);
381           }
382         catch (IOException e)
383           {
384           }
385       }
386
387     if (buffer == null)
388       {
389         buffer = ByteBuffer.allocate ((int) count);
390         src.read (buffer);
391         buffer.flip();
392       }
393
394     return write (buffer, position);
395   }
396
397   public long transferFrom (ReadableByteChannel src, long position, 
398                             long count)
399     throws IOException
400   {
401     if (position < 0
402         || count < 0)
403       throw new IllegalArgumentException ();
404
405     if (!isOpen ())
406       throw new ClosedChannelException ();
407
408     if ((mode & WRITE) == 0)
409        throw new NonWritableChannelException ();
410
411     final int pageSize = 65536;
412     long total = 0;
413
414     while (count > 0)
415       {
416         int transferred = smallTransferFrom (src, position, 
417                                              (int)Math.min (count, pageSize));
418         if (transferred < 0)
419           break;
420         total += transferred;
421         position += transferred;
422         count -= transferred;
423       }
424
425     return total;
426   }
427
428   public FileLock tryLock (long position, long size, boolean shared)
429     throws IOException
430   {
431     if (position < 0
432         || size < 0)
433       throw new IllegalArgumentException ();
434
435     if (!isOpen ())
436       throw new ClosedChannelException ();
437
438     if (shared && (mode & READ) == 0)
439       throw new NonReadableChannelException ();
440         
441     if (!shared && (mode & WRITE) == 0)
442       throw new NonWritableChannelException ();
443         
444     boolean completed = false;
445     
446     try
447       {
448         begin();
449         boolean lockable = lock(position, size, shared, false);
450         completed = true;
451         return (lockable
452                 ? new FileLockImpl(this, position, size, shared)
453                 : null);
454       }
455     finally
456       {
457         end(completed);
458       }
459   }
460
461   /** Try to acquire a lock at the given position and size.
462    * On success return true.
463    * If wait as specified, block until we can get it.
464    * Otherwise return false.
465    */
466   private native boolean lock(long position, long size,
467                               boolean shared, boolean wait) throws IOException;
468   
469   public FileLock lock (long position, long size, boolean shared)
470     throws IOException
471   {
472     if (position < 0
473         || size < 0)
474       throw new IllegalArgumentException ();
475
476     if (!isOpen ())
477       throw new ClosedChannelException ();
478
479     boolean completed = false;
480
481     try
482       {
483         boolean lockable = lock(position, size, shared, true);
484         completed = true;
485         return (lockable
486                 ? new FileLockImpl(this, position, size, shared)
487                 : null);
488       }
489     finally
490       {
491         end(completed);
492       }
493   }
494
495   public long position ()
496     throws IOException
497   {
498     if (!isOpen ())
499       throw new ClosedChannelException ();
500
501     return implPosition ();
502   }
503   
504   public FileChannel position (long newPosition)
505     throws IOException
506   {
507     if (newPosition < 0)
508       throw new IllegalArgumentException ();
509
510     if (!isOpen ())
511       throw new ClosedChannelException ();
512
513     // FIXME note semantics if seeking beyond eof.
514     // We should seek lazily - only on a write.
515     seek (newPosition);
516     return this;
517   }
518   
519   public FileChannel truncate (long size)
520     throws IOException
521   {
522     if (size < 0)
523       throw new IllegalArgumentException ();
524
525     if (!isOpen ())
526       throw new ClosedChannelException ();
527
528     if ((mode & WRITE) == 0)
529        throw new NonWritableChannelException ();
530
531     if (size < size ())
532       implTruncate (size);
533
534     return this;
535   }
536
537   /**
538    * @return The native file descriptor.
539    */
540   public int getNativeFD()
541   {
542     return fd;
543   }
544 }