Merge from mainline
[official-gcc.git] / libjava / classpath / gnu / java / nio / channels / FileChannelImpl.java
bloba557c7d3ba602293efa5efa15ac7e3b90bca83b6
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)
9 any later version.
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
19 02110-1301 USA.
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.
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;
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;
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.
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();
82 static
84 if (Configuration.INIT_LOAD_LIBRARY)
86 System.loadLibrary("javanio");
89 init();
91 in = new FileChannelImpl(0, READ);
92 out = new FileChannelImpl(1, WRITE);
93 err = new FileChannelImpl(2, WRITE);
96 /**
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.
104 private int fd = -1;
106 private int mode;
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();
123 description = path;
124 fd = open (path, mode);
125 this.mode = mode;
127 // First open the file and then check if it is a a directory
128 // to avoid race condition.
129 if (file.isDirectory())
131 try
133 close();
135 catch (IOException e)
137 /* ignore it */
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)
155 this.fd = fd;
156 this.mode = 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
178 if (fd != -1)
179 close();
182 public int read (ByteBuffer dst) throws IOException
184 int result;
185 byte[] buffer = new byte [dst.remaining ()];
187 result = read (buffer, 0, buffer.length);
189 if (result > 0)
190 dst.put (buffer, 0, result);
192 return result;
195 public int read (ByteBuffer dst, long position)
196 throws IOException
198 if (position < 0)
199 throw new IllegalArgumentException ("position: " + position);
200 long oldPosition = implPosition ();
201 position (position);
202 int result = read(dst);
203 position (oldPosition);
205 return result;
208 public native int read ()
209 throws IOException;
211 public native int read (byte[] buffer, int offset, int length)
212 throws IOException;
214 public long read (ByteBuffer[] dsts, int offset, int length)
215 throws IOException
217 long result = 0;
219 for (int i = offset; i < offset + length; i++)
221 result += read (dsts [i]);
224 return result;
227 public int write (ByteBuffer src) throws IOException
229 int len = src.remaining ();
230 if (src.hasArray())
232 byte[] buffer = src.array();
233 write(buffer, src.arrayOffset() + src.position(), len);
234 src.position(src.position() + len);
236 else
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);
243 return len;
246 public int write (ByteBuffer src, long position)
247 throws IOException
249 if (position < 0)
250 throw new IllegalArgumentException ("position: " + position);
252 if (!isOpen ())
253 throw new ClosedChannelException ();
255 if ((mode & WRITE) == 0)
256 throw new NonWritableChannelException ();
258 int result;
259 long oldPosition;
261 oldPosition = implPosition ();
262 seek (position);
263 result = write(src);
264 seek (oldPosition);
266 return result;
269 public native void write (byte[] buffer, int offset, int length)
270 throws IOException;
272 public native void write (int b) throws IOException;
274 public long write(ByteBuffer[] srcs, int offset, int length)
275 throws IOException
277 long result = 0;
279 for (int i = offset;i < offset + length;i++)
281 result += write (srcs[i]);
284 return result;
287 public native MappedByteBuffer mapImpl (char mode, long position, int size)
288 throws IOException;
290 public MappedByteBuffer map (FileChannel.MapMode mode,
291 long position, long size)
292 throws IOException
294 char nmode = 0;
295 if (mode == MapMode.READ_ONLY)
297 nmode = 'r';
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();
309 else
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
323 if (!isOpen ())
324 throw new ClosedChannelException ();
326 force ();
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)
334 throws IOException
336 ByteBuffer buffer;
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);
347 buffer.flip();
350 return target.write (buffer);
353 public long transferTo (long position, long count,
354 WritableByteChannel target)
355 throws IOException
357 if (position < 0
358 || count < 0)
359 throw new IllegalArgumentException ("position: " + position
360 + ", count: " + count);
362 if (!isOpen ())
363 throw new ClosedChannelException ();
365 if ((mode & READ) == 0)
366 throw new NonReadableChannelException ();
368 final int pageSize = 65536;
369 long total = 0;
371 while (count > 0)
373 int transferred
374 = smallTransferTo (position, (int)Math.min (count, pageSize),
375 target);
376 if (transferred < 0)
377 break;
378 total += transferred;
379 position += transferred;
380 count -= transferred;
383 return total;
386 // like transferFrom, but with a count of less than 2Gbytes
387 private int smallTransferFrom (ReadableByteChannel src, long position,
388 int count)
389 throws IOException
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,
400 count);
402 catch (IOException e)
407 if (buffer == null)
409 buffer = ByteBuffer.allocate ((int) count);
410 src.read (buffer);
411 buffer.flip();
414 return write (buffer, position);
417 public long transferFrom (ReadableByteChannel src, long position,
418 long count)
419 throws IOException
421 if (position < 0
422 || count < 0)
423 throw new IllegalArgumentException ("position: " + position
424 + ", count: " + count);
426 if (!isOpen ())
427 throw new ClosedChannelException ();
429 if ((mode & WRITE) == 0)
430 throw new NonWritableChannelException ();
432 final int pageSize = 65536;
433 long total = 0;
435 while (count > 0)
437 int transferred = smallTransferFrom (src, position,
438 (int)Math.min (count, pageSize));
439 if (transferred < 0)
440 break;
441 total += transferred;
442 position += transferred;
443 count -= transferred;
446 return total;
449 // Shared sanity checks between lock and tryLock methods.
450 private void lockCheck(long position, long size, boolean shared)
451 throws IOException
453 if (position < 0
454 || size < 0)
455 throw new IllegalArgumentException ("position: " + position
456 + ", size: " + size);
458 if (!isOpen ())
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)
469 throws IOException
471 lockCheck(position, size, shared);
473 boolean completed = false;
476 begin();
477 boolean lockable = lock(position, size, shared, false);
478 completed = true;
479 return (lockable
480 ? new FileLockImpl(this, position, size, shared)
481 : null);
483 finally
485 end(completed);
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)
498 throws IOException
500 lockCheck(position, size, shared);
502 boolean completed = false;
505 boolean lockable = lock(position, size, shared, true);
506 completed = true;
507 return (lockable
508 ? new FileLockImpl(this, position, size, shared)
509 : null);
511 finally
513 end(completed);
517 public long position ()
518 throws IOException
520 if (!isOpen ())
521 throw new ClosedChannelException ();
523 return implPosition ();
526 public FileChannel position (long newPosition)
527 throws IOException
529 if (newPosition < 0)
530 throw new IllegalArgumentException ("newPostition: " + newPosition);
532 if (!isOpen ())
533 throw new ClosedChannelException ();
535 // FIXME note semantics if seeking beyond eof.
536 // We should seek lazily - only on a write.
537 seek (newPosition);
538 return this;
541 public FileChannel truncate (long size)
542 throws IOException
544 if (size < 0)
545 throw new IllegalArgumentException ("size: " + size);
547 if (!isOpen ())
548 throw new ClosedChannelException ();
550 if ((mode & WRITE) == 0)
551 throw new NonWritableChannelException ();
553 if (size < size ())
554 implTruncate (size);
556 return this;
559 public String toString()
561 return (this.getClass()
562 + "[fd=" + fd
563 + ",mode=" + mode + ","
564 + description + "]");