2 // natFileChannelImplPosix.cc - Native part of FileChannelImpl class.
4 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation
6 This file is part of libgcj.
8 This software is copyrighted work licensed under the terms of the
9 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
16 #include <gcj/javaprims.h>
26 #include <sys/param.h>
28 #include <gnu/gcj/RawData.h>
29 #include <gnu/java/nio/FileLockImpl.h>
30 #include <gnu/java/nio/channels/FileChannelImpl.h>
31 #include <java/io/FileNotFoundException.h>
32 #include <java/io/IOException.h>
33 #include <java/io/SyncFailedException.h>
34 #include <java/io/InterruptedIOException.h>
35 #include <java/io/EOFException.h>
36 #include <java/lang/ArrayIndexOutOfBoundsException.h>
37 #include <java/lang/NullPointerException.h>
38 #include <java/lang/System.h>
39 #include <java/lang/String.h>
40 #include <java/lang/StringBuffer.h>
41 #include <java/lang/Thread.h>
42 #include <java/nio/ByteBuffer.h>
43 #include <java/nio/MappedByteBufferImpl.h>
44 #include <java/nio/channels/FileChannel.h>
45 #include <java/nio/channels/FileLock.h>
46 #include <gnu/java/nio/channels/FileChannelImpl.h>
48 #ifdef HAVE_SYS_IOCTL_H
49 #define BSD_COMP /* Get FIONREAD on Solaris2. */
50 #include <sys/ioctl.h>
53 // Pick up FIONREAD on Solaris 2.5.
54 #ifdef HAVE_SYS_FILIO_H
55 #include <sys/filio.h>
61 // Use overload resolution to find out the argument types.
62 // E.g. Solaris 2.6 uses different argument types for munmap and msync.
63 // This is in case _POSIX_C_SOURCES is smaller than 3.
65 template <typename T_implPtr, typename T_implLen>
67 munmap_adaptor(int (*munmap)(T_implPtr caddr, T_implLen sizet),
68 void* caddr, size_t sizet)
70 return munmap ((T_implPtr) caddr, (T_implLen) sizet);
73 template <typename T_implPtr, typename T_implLen, typename T_msync>
75 msync_adaptor(int (*msync)(T_implPtr caddr, T_implLen sizet, T_msync msynct),
76 void* caddr, size_t sizet, int msynct)
78 return msync ((T_implPtr) caddr, (T_implLen) sizet, (T_msync) msynct);
82 using gnu::gcj::RawData;
83 using java::io::IOException;
84 using java::nio::MappedByteBufferImpl;
85 using java::io::InterruptedIOException;
86 using java::io::FileNotFoundException;
87 using java::lang::ArrayIndexOutOfBoundsException;
88 using gnu::java::nio::channels::FileChannelImpl;
90 #define NO_FSYNC_MESSAGE "sync unsupported"
93 FileChannelImpl::init(void)
95 in = new FileChannelImpl((jint) 0, FileChannelImpl::READ);
96 out = new FileChannelImpl((jint) 1, FileChannelImpl::WRITE);
97 err = new FileChannelImpl((jint) 2, FileChannelImpl::WRITE);
102 FileChannelImpl::valid (void)
105 return fd >= 0 && ::fstat (fd, &sb) == 0;
109 FileChannelImpl::sync (void)
111 // Some files don't support fsync. We don't bother reporting these
114 if (::fsync (fd) && errno != EROFS && errno != EINVAL)
115 throw new SyncFailedException (JvNewStringLatin1 (strerror (errno)));
117 throw new SyncFailedException (JvNewStringLatin1 (NO_FSYNC_MESSAGE));
123 FileChannelImpl::open (jstring path, jint jflags)
126 char *buf = (char *) _Jv_AllocBytes (_Jv_GetStringUTFLength (path) + 1);
127 jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf);
134 JvAssert ((jflags & READ) || (jflags & WRITE));
136 if ((jflags & READ) && (jflags & WRITE))
137 flags |= O_RDWR | O_CREAT;
138 else if ((jflags & READ))
142 flags |= O_WRONLY | O_CREAT;
143 if ((jflags & APPEND))
151 // In this case we are making a temp file.
159 if ((jflags & DSYNC))
162 int fd = ::open (buf, flags, mode);
163 if (fd == -1 && errno == EMFILE)
165 // Because finalize () calls close () we might be able to continue.
166 ::java::lang::System::gc ();
167 ::java::lang::System::runFinalization ();
168 fd = ::open (buf, flags, mode);
172 // We choose the formatting here for JDK compatibility, believe
174 ::java::lang::StringBuffer *msg = new ::java::lang::StringBuffer (path);
175 msg->append (JvNewStringUTF (" ("));
176 msg->append (JvNewStringUTF (strerror (errno)));
177 msg->append (JvNewStringUTF (")"));
178 throw new ::java::io::FileNotFoundException (msg->toString ());
185 FileChannelImpl::write (jint b)
191 r = ::write (fd, &d, 1);
194 if (::java::lang::Thread::interrupted())
196 ::java::io::InterruptedIOException *iioe
197 = new ::java::io::InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
198 iioe->bytesTransferred = r == -1 ? 0 : r;
202 throw new IOException (JvNewStringLatin1 (strerror (errno)));
209 FileChannelImpl::write (jbyteArray b, jint offset, jint len)
212 throw new ::java::lang::NullPointerException;
213 if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
214 throw new ArrayIndexOutOfBoundsException;
215 jbyte *bytes = elements (b) + offset;
220 int r = ::write (fd, bytes, len);
223 if (::java::lang::Thread::interrupted())
225 InterruptedIOException *iioe
226 = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
227 iioe->bytesTransferred = written;
231 throw new IOException (JvNewStringLatin1 (strerror (errno)));
243 FileChannelImpl::implCloseChannel (void)
248 throw new IOException (JvNewStringLatin1 (strerror (errno)));
252 FileChannelImpl::implTruncate (jlong size)
256 #ifdef HAVE_FTRUNCATE
257 if (::fstat (fd, &sb))
258 throw new IOException (JvNewStringLatin1 (strerror (errno)));
260 if ((jlong) sb.st_size == size)
263 // If the file is too short, we extend it. We can't rely on
264 // ftruncate() extending the file. So we lseek() to 1 byte less
265 // than we want, and then we write a single byte at the end.
266 if ((jlong) sb.st_size < size)
268 if (::lseek (fd, (off_t) (size - 1), SEEK_SET) == -1)
269 throw new IOException (JvNewStringLatin1 (strerror (errno)));
271 int r = ::write (fd, &out, 1);
272 if (r <= 0 || ::lseek (fd, pos, SEEK_SET) == -1)
273 throw new IOException (JvNewStringLatin1 (strerror (errno)));
277 if (::ftruncate (fd, (off_t) size))
278 throw new IOException (JvNewStringLatin1 (strerror (errno)));
280 && ::lseek (fd, (off_t) size, SEEK_SET) == -1)
281 throw new IOException (JvNewStringLatin1 (strerror (errno)));
284 #else /* HAVE_FTRUNCATE */
285 throw new IOException (JvNewStringLatin1 ("FileDescriptor.setLength not implemented"));
286 #endif /* HAVE_FTRUNCATE */
290 FileChannelImpl::seek (jlong newPos)
292 off_t r = ::lseek (fd, (off_t) newPos, SEEK_SET);
294 throw new IOException (JvNewStringLatin1 (strerror (errno)));
299 FileChannelImpl::size (void)
302 if (::fstat (fd, &sb))
303 throw new IOException (JvNewStringLatin1 (strerror (errno)));
308 FileChannelImpl::implPosition (void)
314 FileChannelImpl::read (void)
320 r = ::read (fd, &b, 1);
325 if (::java::lang::Thread::interrupted())
327 InterruptedIOException *iioe
328 = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
329 iioe->bytesTransferred = r == -1 ? 0 : r;
333 throw new IOException (JvNewStringLatin1 (strerror (errno)));
342 FileChannelImpl::read (jbyteArray buffer, jint offset, jint count)
345 throw new ::java::lang::NullPointerException;
346 jsize bsize = JvGetArrayLength (buffer);
347 if (offset < 0 || count < 0 || offset + count > bsize)
348 throw new ::java::lang::ArrayIndexOutOfBoundsException;
350 // Must return 0 if an attempt is made to read 0 bytes.
354 jbyte *bytes = elements (buffer) + offset;
358 r = ::read (fd, bytes, count);
363 if (::java::lang::Thread::interrupted())
365 InterruptedIOException *iioe
366 = new InterruptedIOException (JvNewStringLatin1 (strerror (errno)));
367 iioe->bytesTransferred = r == -1 ? 0 : r;
371 throw new IOException (JvNewStringLatin1 (strerror (errno)));
380 FileChannelImpl::available (void)
382 #if defined (FIONREAD) || defined (HAVE_SELECT) || defined (HAVE_FSTAT)
385 bool num_set = false;
387 #if defined (FIONREAD)
388 r = ::ioctl (fd, FIONREAD, &num);
389 if (r == -1 && errno == ENOTTY)
391 // If the ioctl doesn't work, we don't care.
397 #elif defined (HAVE_SELECT)
408 throw new IOException (JvNewStringLatin1 (strerror (errno)));
411 // If we didn't get anything, and we have fstat, then see if see if
412 // we're reading a regular file. On many systems, FIONREAD does not
413 // work on regular files; select() likewise returns a useless
414 // result. This is run incorrectly when FIONREAD does work on
415 // regular files and we are at the end of the file. However, this
416 // case probably isn't very important.
417 #if defined (HAVE_FSTAT)
422 if (fstat (fd, &sb) != -1
423 && S_ISREG (sb.st_mode)
424 && (where = lseek (fd, 0, SEEK_CUR)) != (off_t) -1)
426 num = (int) (sb.st_size - where);
430 #endif /* HAVE_FSTAT */
432 #if defined (HAVE_SELECT)
441 r = _Jv_select (fd + 1, &rd, NULL, NULL, &tv);
444 num = r == 0 ? 0 : 1;
446 #endif /* HAVE_SELECT */
455 FileChannelImpl::lock
456 (jlong pos, jlong len, jboolean shared, jboolean wait)
458 struct flock lockdata;
460 lockdata.l_type = shared ? F_RDLCK : F_WRLCK;
461 lockdata.l_whence = SEEK_SET;
462 lockdata.l_start = pos;
463 lockdata.l_len = len;
465 if (::fcntl (fd, wait ? F_SETLKW : F_SETLK, &lockdata) == -1)
467 if (! wait && (errno == EACCES || errno == EAGAIN))
469 throw new IOException (JvNewStringLatin1 (strerror (errno)));
475 FileChannelImpl::unlock (jlong pos, jlong len)
477 struct flock lockdata;
479 lockdata.l_type = F_UNLCK;
480 lockdata.l_whence = SEEK_SET;
481 lockdata.l_start = pos;
482 lockdata.l_len = len;
484 if (::fcntl (fd, F_SETLK, &lockdata) == -1)
485 throw new IOException (JvNewStringLatin1 (strerror (errno)));
488 java::nio::MappedByteBuffer *
489 FileChannelImpl::mapImpl (jchar mmode, jlong position, jint size)
491 #if defined(HAVE_MMAP)
500 prot = PROT_READ|PROT_WRITE;
501 flags = mmode == '+' ? MAP_SHARED : MAP_PRIVATE;
503 jint page_size = ::getpagesize();
504 jint offset = position & ~(page_size-1);
505 jint align = position - offset;
506 void* ptr = ::mmap(NULL, size + align, prot, flags, fd, offset);
507 MappedByteBufferImpl *buf
508 = new MappedByteBufferImpl ((RawData *) ((char *) ptr + align),
510 if (ptr == (void *) MAP_FAILED)
511 throw new IOException (JvNewStringLatin1 (strerror (errno)));
512 buf->implPtr = reinterpret_cast<RawData*> (ptr);
513 buf->implLen = size+align;
516 throw new IOException (JvNewStringUTF ("mmap not implemented"));
521 MappedByteBufferImpl::unmapImpl ()
523 #if defined(HAVE_MMAP)
524 munmap_adaptor(munmap, implPtr, implLen);
529 MappedByteBufferImpl::loadImpl ()
534 MappedByteBufferImpl::isLoadedImpl ()
540 MappedByteBufferImpl::forceImpl ()
542 #if defined(HAVE_MMAP)
543 ::msync_adaptor(msync, implPtr, implLen, MS_SYNC);