1 /* FileChannelImpl.java --
2 Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 package gnu
.java
.nio
.channels
;
41 import gnu
.classpath
.Configuration
;
42 import gnu
.java
.nio
.FileLockImpl
;
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
;
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.
64 public final class FileChannelImpl
extends FileChannel
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;
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;
76 public static FileChannelImpl in
;
77 public static FileChannelImpl out
;
78 public static FileChannelImpl err
;
80 private static native void init();
84 if (Configuration
.INIT_LOAD_LIBRARY
)
86 System
.loadLibrary("javanio");
91 in
= new FileChannelImpl(0, READ
);
92 out
= new FileChannelImpl(1, WRITE
);
93 err
= new FileChannelImpl(2, WRITE
);
97 * This is the actual native file descriptor value
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.
108 final String description
;
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
116 return new FileChannelImpl(file
, mode
);
119 private FileChannelImpl(File file
, int mode
)
120 throws FileNotFoundException
122 String path
= file
.getPath();
124 fd
= open (path
, mode
);
127 // First open the file and then check if it is a a directory
128 // to avoid race condition.
129 if (file
.isDirectory())
135 catch (IOException e
)
140 throw new FileNotFoundException(description
+ " is a directory");
145 * Constructor for default channels in, out and err.
147 * Used by init() (native code).
149 * @param fd the file descriptor (0, 1, 2 for stdin, stdout, stderr).
151 * @param mode READ or WRITE
153 FileChannelImpl (int fd
, int mode
)
157 this.description
= "descriptor(" + fd
+ ")";
160 private native int open (String path
, int mode
) throws FileNotFoundException
;
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
;
167 public native void unlock (long pos
, long len
) throws IOException
;
169 public native long size () throws IOException
;
171 protected native void implCloseChannel() throws IOException
;
174 * Makes sure the Channel is properly closed.
176 protected void finalize() throws IOException
182 public int read (ByteBuffer dst
) throws IOException
185 byte[] buffer
= new byte [dst
.remaining ()];
187 result
= read (buffer
, 0, buffer
.length
);
190 dst
.put (buffer
, 0, result
);
195 public int read (ByteBuffer dst
, long position
)
199 throw new IllegalArgumentException ("position: " + position
);
200 long oldPosition
= implPosition ();
202 int result
= read(dst
);
203 position (oldPosition
);
208 public native int read ()
211 public native int read (byte[] buffer
, int offset
, int length
)
214 public long read (ByteBuffer
[] dsts
, int offset
, int length
)
219 for (int i
= offset
; i
< offset
+ length
; i
++)
221 result
+= read (dsts
[i
]);
227 public int write (ByteBuffer src
) throws IOException
229 int len
= src
.remaining ();
232 byte[] buffer
= src
.array();
233 write(buffer
, src
.arrayOffset() + src
.position(), len
);
234 src
.position(src
.position() + len
);
238 // Use a more efficient native method! FIXME!
239 byte[] buffer
= new byte [len
];
240 src
.get (buffer
, 0, len
);
241 write (buffer
, 0, len
);
246 public int write (ByteBuffer src
, long position
)
250 throw new IllegalArgumentException ("position: " + position
);
253 throw new ClosedChannelException ();
255 if ((mode
& WRITE
) == 0)
256 throw new NonWritableChannelException ();
261 oldPosition
= implPosition ();
269 public native void write (byte[] buffer
, int offset
, int length
)
272 public native void write (int b
) throws IOException
;
274 public long write(ByteBuffer
[] srcs
, int offset
, int length
)
279 for (int i
= offset
;i
< offset
+ length
;i
++)
281 result
+= write (srcs
[i
]);
287 public native MappedByteBuffer
mapImpl (char mode
, long position
, int size
)
290 public MappedByteBuffer
map (FileChannel
.MapMode mode
,
291 long position
, long size
)
295 if (mode
== MapMode
.READ_ONLY
)
298 if ((this.mode
& READ
) == 0)
299 throw new NonReadableChannelException();
301 else if (mode
== MapMode
.READ_WRITE
|| mode
== MapMode
.PRIVATE
)
303 nmode
= mode
== MapMode
.READ_WRITE ?
'+' : 'c';
304 if ((this.mode
& WRITE
) != WRITE
)
305 throw new NonWritableChannelException();
306 if ((this.mode
& READ
) != READ
)
307 throw new NonReadableChannelException();
310 throw new IllegalArgumentException ("mode: " + mode
);
312 if (position
< 0 || size
< 0 || size
> Integer
.MAX_VALUE
)
313 throw new IllegalArgumentException ("position: " + position
314 + ", size: " + size
);
315 return mapImpl(nmode
, position
, (int) size
);
319 * msync with the disk
321 public void force (boolean metaData
) throws IOException
324 throw new ClosedChannelException ();
329 private native void force ();
331 // like transferTo, but with a count of less than 2Gbytes
332 private int smallTransferTo (long position
, int count
,
333 WritableByteChannel target
)
339 // Try to use a mapped buffer if we can. If this fails for
340 // any reason we'll fall back to using a ByteBuffer.
341 buffer
= map (MapMode
.READ_ONLY
, position
, count
);
343 catch (IOException e
)
345 buffer
= ByteBuffer
.allocate (count
);
346 read (buffer
, position
);
350 return target
.write (buffer
);
353 public long transferTo (long position
, long count
,
354 WritableByteChannel target
)
359 throw new IllegalArgumentException ("position: " + position
360 + ", count: " + count
);
363 throw new ClosedChannelException ();
365 if ((mode
& READ
) == 0)
366 throw new NonReadableChannelException ();
368 final int pageSize
= 65536;
374 = smallTransferTo (position
, (int)Math
.min (count
, pageSize
),
378 total
+= transferred
;
379 position
+= transferred
;
380 count
-= transferred
;
386 // like transferFrom, but with a count of less than 2Gbytes
387 private int smallTransferFrom (ReadableByteChannel src
, long position
,
391 ByteBuffer buffer
= null;
393 if (src
instanceof FileChannel
)
397 // Try to use a mapped buffer if we can. If this fails
398 // for any reason we'll fall back to using a ByteBuffer.
399 buffer
= ((FileChannel
)src
).map (MapMode
.READ_ONLY
, position
,
402 catch (IOException e
)
409 buffer
= ByteBuffer
.allocate ((int) count
);
414 return write (buffer
, position
);
417 public long transferFrom (ReadableByteChannel src
, long position
,
423 throw new IllegalArgumentException ("position: " + position
424 + ", count: " + count
);
427 throw new ClosedChannelException ();
429 if ((mode
& WRITE
) == 0)
430 throw new NonWritableChannelException ();
432 final int pageSize
= 65536;
437 int transferred
= smallTransferFrom (src
, position
,
438 (int)Math
.min (count
, pageSize
));
441 total
+= transferred
;
442 position
+= transferred
;
443 count
-= transferred
;
449 // Shared sanity checks between lock and tryLock methods.
450 private void lockCheck(long position
, long size
, boolean shared
)
455 throw new IllegalArgumentException ("position: " + position
456 + ", size: " + size
);
459 throw new ClosedChannelException();
461 if (shared
&& ((mode
& READ
) == 0))
462 throw new NonReadableChannelException();
464 if (!shared
&& ((mode
& WRITE
) == 0))
465 throw new NonWritableChannelException();
468 public FileLock
tryLock (long position
, long size
, boolean shared
)
471 lockCheck(position
, size
, shared
);
473 boolean completed
= false;
477 boolean lockable
= lock(position
, size
, shared
, false);
480 ?
new FileLockImpl(this, position
, size
, shared
)
489 /** Try to acquire a lock at the given position and size.
490 * On success return true.
491 * If wait as specified, block until we can get it.
492 * Otherwise return false.
494 private native boolean lock(long position
, long size
,
495 boolean shared
, boolean wait
) throws IOException
;
497 public FileLock
lock (long position
, long size
, boolean shared
)
500 lockCheck(position
, size
, shared
);
502 boolean completed
= false;
505 boolean lockable
= lock(position
, size
, shared
, true);
508 ?
new FileLockImpl(this, position
, size
, shared
)
517 public long position ()
521 throw new ClosedChannelException ();
523 return implPosition ();
526 public FileChannel
position (long newPosition
)
530 throw new IllegalArgumentException ("newPostition: " + newPosition
);
533 throw new ClosedChannelException ();
535 // FIXME note semantics if seeking beyond eof.
536 // We should seek lazily - only on a write.
541 public FileChannel
truncate (long size
)
545 throw new IllegalArgumentException ("size: " + size
);
548 throw new ClosedChannelException ();
550 if ((mode
& WRITE
) == 0)
551 throw new NonWritableChannelException ();
559 public String
toString()
561 return (this.getClass()
563 + ",mode=" + mode
+ ","
564 + description
+ "]");