diff options
author | Per Bothner <bothner@gcc.gnu.org> | 2004-02-29 11:09:28 -0800 |
---|---|---|
committer | Per Bothner <bothner@gcc.gnu.org> | 2004-02-29 11:09:28 -0800 |
commit | 612e6609875599726838087b64e1ec6d6c8ee4e9 (patch) | |
tree | b807dd37aa1642e417973a55531593d81aa3ef7f /libjava/gnu/java/nio/channels/natFileChannelPosix.cc | |
parent | 2f537af9e7c0463134c31431c60de13ca5729183 (diff) | |
download | gcc-612e6609875599726838087b64e1ec6d6c8ee4e9.zip gcc-612e6609875599726838087b64e1ec6d6c8ee4e9.tar.gz gcc-612e6609875599726838087b64e1ec6d6c8ee4e9.tar.bz2 |
FileChannelImpl.java: New class, renamed from java/nio/channels.
* gnu/java/nio/channels/FileChannelImpl.java: New class, renamed
from java/nio/channels. Don't depend on FileDescriptor.
(in, out, err): New static fields.
(mode): New field.
(SET, CUR, READ, WRITE, APPEND, EXCL, SYNC, DSYNC): Moved constants
from FileDescriptor.
(by): Removed MappedByteBuffer field.
(map): New working implementation.
* gnu/java/nio/channels/natFileChannelPosix.cc: New file, though
some code "ported" from natFileDescriptoPosix.cc.
* gnu/java/nio/channels/natFileChannelEcos.cc: Likewise.
* gnu/java/nio/channels/natFileChannelWin32.cc Likewise.
From-SVN: r78659
Diffstat (limited to 'libjava/gnu/java/nio/channels/natFileChannelPosix.cc')
-rw-r--r-- | libjava/gnu/java/nio/channels/natFileChannelPosix.cc | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/libjava/gnu/java/nio/channels/natFileChannelPosix.cc b/libjava/gnu/java/nio/channels/natFileChannelPosix.cc new file mode 100644 index 0000000..8653787 --- /dev/null +++ b/libjava/gnu/java/nio/channels/natFileChannelPosix.cc @@ -0,0 +1,522 @@ + +// natFileChannelImplPosix.cc - Native part of FileChannelImpl class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <gcj/cni.h> +#include <gcj/javaprims.h> +#include <jvm.h> + +#include "posix.h" + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/param.h> + +#include <gnu/gcj/RawData.h> +#include <gnu/java/nio/FileLockImpl.h> +#include <gnu/java/nio/channels/FileChannelImpl.h> +#include <java/io/FileNotFoundException.h> +#include <java/io/IOException.h> +#include <java/io/SyncFailedException.h> +#include <java/io/InterruptedIOException.h> +#include <java/io/EOFException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/System.h> +#include <java/lang/String.h> +#include <java/lang/Thread.h> +#include <java/nio/ByteBuffer.h> +#include <java/nio/MappedByteBufferImpl.h> +#include <java/nio/channels/FileChannel.h> +#include <java/nio/channels/FileLock.h> +#include <gnu/java/nio/channels/FileChannelImpl.h> + +#ifdef HAVE_SYS_IOCTL_H +#define BSD_COMP /* Get FIONREAD on Solaris2. */ +#include <sys/ioctl.h> +#endif + +// Pick up FIONREAD on Solaris 2.5. +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif + +#ifdef HAVE_MMAP +#include <sys/mman.h> +#endif + +using gnu::gcj::RawData; +using java::io::IOException; +using java::nio::MappedByteBufferImpl; +using java::io::InterruptedIOException; +using java::io::FileNotFoundException; +using java::lang::ArrayIndexOutOfBoundsException; +using gnu::java::nio::channels::FileChannelImpl; + +#define NO_FSYNC_MESSAGE "sync unsupported" + +void +FileChannelImpl::init(void) +{ + in = new FileChannelImpl((jint) 0, FileChannelImpl::READ); + out = new FileChannelImpl((jint) 1, FileChannelImpl::WRITE); + err = new FileChannelImpl((jint) 2, FileChannelImpl::WRITE); +} + +#if 0 +jboolean +FileChannelImpl::valid (void) +{ + struct stat sb; + return fd >= 0 && ::fstat (fd, &sb) == 0; +} + +void +FileChannelImpl::sync (void) +{ + // Some files don't support fsync. We don't bother reporting these + // as errors. +#ifdef HAVE_FSYNC + if (::fsync (fd) && errno != EROFS && errno != EINVAL) + throw new SyncFailedException (JvNewStringLatin1 (strerror (errno))); +#else + throw new SyncFailedException (JvNewStringLatin1 (NO_FSYNC_MESSAGE)); +#endif +} +#endif + +jint +FileChannelImpl::open (jstring path, jint jflags) +{ + fd = -1; + char *buf = (char *) _Jv_AllocBytes (_Jv_GetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + int flags = 0; +#ifdef O_BINARY + flags |= O_BINARY; +#endif + + JvAssert ((jflags & READ) || (jflags & WRITE)); + int mode = 0666; + if ((jflags & READ) && (jflags & WRITE)) + flags |= O_RDWR | O_CREAT; + else if ((jflags & READ)) + flags |= O_RDONLY; + else + { + flags |= O_WRONLY | O_CREAT; + if ((jflags & APPEND)) + flags |= O_APPEND; + else + flags |= O_TRUNC; + + if ((jflags & EXCL)) + { + flags |= O_EXCL; + // In this case we are making a temp file. + mode = 0600; + } + } + + if ((jflags & SYNC)) + flags |= O_SYNC; + + if ((jflags & DSYNC)) + flags |= O_DSYNC; + + int fd = ::open (buf, flags, mode); + if (fd == -1 && errno == EMFILE) + { + // Because finalize () calls close () we might be able to continue. + ::java::lang::System::gc (); + ::java::lang::System::runFinalization (); + fd = ::open (buf, flags, mode); + } + if (fd == -1) + { + char msg[MAXPATHLEN + 200]; + // We choose the formatting here for JDK compatibility, believe + // it or not. + sprintf (msg, "%.*s (%.*s)", + MAXPATHLEN + 150, buf, + 40, strerror (errno)); + throw new ::java::io::FileNotFoundException (JvNewStringLatin1 (msg)); + } + + _Jv_platform_close_on_exec (fd); + + return fd; +} + +void +FileChannelImpl::write (jint b) +{ + jbyte d = (jbyte) b; + int r = 0; + while (r != 1) + { + r = ::write (fd, &d, 1); + if (r == -1) + { + if (::java::lang::Thread::interrupted()) + { + ::java::io::InterruptedIOException *iioe + = new ::java::io::InterruptedIOException (JvNewStringLatin1 (strerror (errno))); + iioe->bytesTransferred = r == -1 ? 0 : r; + throw iioe; + } + if (errno != EINTR) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + } + } + pos++; +} + +void +FileChannelImpl::write (jbyteArray b, jint offset, jint len) +{ + if (! b) + throw new ::java::lang::NullPointerException; + if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b)) + throw new ArrayIndexOutOfBoundsException; + jbyte *bytes = elements (b) + offset; + + int written = 0; + while (len > 0) + { + int r = ::write (fd, bytes, len); + if (r == -1) + { + if (::java::lang::Thread::interrupted()) + { + InterruptedIOException *iioe + = new InterruptedIOException (JvNewStringLatin1 (strerror (errno))); + iioe->bytesTransferred = written; + throw iioe; + } + if (errno != EINTR) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + } + + written += r; + len -= r; + bytes += r; + pos += r; + } +} + +void +FileChannelImpl::implCloseChannel (void) +{ + jint save = fd; + fd = -1; + if (::close (save)) + throw new IOException (JvNewStringLatin1 (strerror (errno))); +} + +void +FileChannelImpl::implTruncate (jlong size) +{ + struct stat sb; + +#ifdef HAVE_FTRUNCATE + if (::fstat (fd, &sb)) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + + if ((jlong) sb.st_size == size) + return; + + // If the file is too short, we extend it. We can't rely on + // ftruncate() extending the file. So we lseek() to 1 byte less + // than we want, and then we write a single byte at the end. + if ((jlong) sb.st_size < size) + { + if (::lseek (fd, (off_t) (size - 1), SEEK_SET) == -1) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + char out = '\0'; + int r = ::write (fd, &out, 1); + if (r <= 0 || ::lseek (fd, pos, SEEK_SET) == -1) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + } + else + { + if (::ftruncate (fd, (off_t) pos)) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + pos = size; + } +#else /* HAVE_FTRUNCATE */ + throw new IOException (JvNewStringLatin1 ("FileDescriptor.setLength not implemented")); +#endif /* HAVE_FTRUNCATE */ +} + +void +FileChannelImpl::seek (jlong newPos) +{ + off_t r = ::lseek (fd, (off_t) newPos, SEEK_SET); + if (r == -1) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + pos = r; +} + +jlong +FileChannelImpl::size (void) +{ + struct stat sb; + if (::fstat (fd, &sb)) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + return sb.st_size; +} + +jlong +FileChannelImpl::implPosition (void) +{ + return pos; +} + +jint +FileChannelImpl::read (void) +{ + jbyte b; + int r; + do + { + r = ::read (fd, &b, 1); + if (r == 0) + return -1; + if (r == -1) + { + if (::java::lang::Thread::interrupted()) + { + InterruptedIOException *iioe + = new InterruptedIOException (JvNewStringLatin1 (strerror (errno))); + iioe->bytesTransferred = r == -1 ? 0 : r; + throw iioe; + } + if (errno != EINTR) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + } + } + while (r != 1); + pos++; + return b & 0xFF; +} + +jint +FileChannelImpl::read (jbyteArray buffer, jint offset, jint count) +{ + if (! buffer) + throw new ::java::lang::NullPointerException; + jsize bsize = JvGetArrayLength (buffer); + if (offset < 0 || count < 0 || offset + count > bsize) + throw new ::java::lang::ArrayIndexOutOfBoundsException; + + // Must return 0 if an attempt is made to read 0 bytes. + if (count == 0) + return 0; + + jbyte *bytes = elements (buffer) + offset; + int r; + do + { + r = ::read (fd, bytes, count); + if (r == 0) + return -1; + if (r == -1) + { + if (::java::lang::Thread::interrupted()) + { + InterruptedIOException *iioe + = new InterruptedIOException (JvNewStringLatin1 (strerror (errno))); + iioe->bytesTransferred = r == -1 ? 0 : r; + throw iioe; + } + if (errno != EINTR) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + } + } + while (r <= 0); + pos += r; + return r; +} + +jint +FileChannelImpl::available (void) +{ +#if defined (FIONREAD) || defined (HAVE_SELECT) || defined (HAVE_FSTAT) + long num = 0; + int r = 0; + bool num_set = false; + +#if defined (FIONREAD) + r = ::ioctl (fd, FIONREAD, &num); + if (r == -1 && errno == ENOTTY) + { + // If the ioctl doesn't work, we don't care. + r = 0; + num = 0; + } + else + num_set = true; +#elif defined (HAVE_SELECT) + if (fd < 0) + { + errno = EBADF; + r = -1; + } +#endif + + if (r == -1) + { + posix_error: + throw new IOException (JvNewStringLatin1 (strerror (errno))); + } + + // If we didn't get anything, and we have fstat, then see if see if + // we're reading a regular file. On many systems, FIONREAD does not + // work on regular files; select() likewise returns a useless + // result. This is run incorrectly when FIONREAD does work on + // regular files and we are at the end of the file. However, this + // case probably isn't very important. +#if defined (HAVE_FSTAT) + if (! num_set) + { + struct stat sb; + off_t where = 0; + if (fstat (fd, &sb) != -1 + && S_ISREG (sb.st_mode) + && (where = lseek (fd, 0, SEEK_CUR)) != (off_t) -1) + { + num = (long) (sb.st_size - where); + num_set = true; + } + } +#endif /* HAVE_FSTAT */ + +#if defined (HAVE_SELECT) + if (! num_set) + { + fd_set rd; + FD_ZERO (&rd); + FD_SET (fd, &rd); + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + r = _Jv_select (fd + 1, &rd, NULL, NULL, &tv); + if (r == -1) + goto posix_error; + num = r == 0 ? 0 : 1; + } +#endif /* HAVE_SELECT */ + + return (jint) num; +#else + return 0; +#endif +} + +jboolean +FileChannelImpl::lock +(jlong pos, jlong len, jboolean shared, jboolean wait) +{ + struct flock lockdata; + + lockdata.l_type = shared ? F_WRLCK : F_RDLCK; + lockdata.l_whence = SEEK_SET; + lockdata.l_start = pos; + lockdata.l_len = len; + + if (::fcntl (fd, wait ? F_SETLKW : F_SETLK, &lockdata) == -1) + { + if (! wait && (errno == EACCES || errno == EAGAIN)) + return false; + throw new IOException (JvNewStringLatin1 (strerror (errno))); + } + return true; +} + +void +FileChannelImpl::unlock (jlong pos, jlong len) +{ + struct flock lockdata; + + lockdata.l_type = F_UNLCK; + lockdata.l_whence = SEEK_SET; + lockdata.l_start = pos; + lockdata.l_len = len; + + if (::fcntl (fd, F_SETLK, &lockdata) == -1) + throw new IOException (JvNewStringLatin1 (strerror (errno))); +} + +java::nio::MappedByteBuffer * +FileChannelImpl::mapImpl (jchar mmode, jlong position, jint size) +{ +#if defined(HAVE_MMAP) + int prot, flags; + if (mmode == 'r') + { + prot = PROT_READ; + flags = MAP_PRIVATE; + } + else + { + prot = PROT_READ|PROT_WRITE; + flags = mmode == '+' ? MAP_SHARED : MAP_PRIVATE; + } + jint page_size = ::getpagesize(); + jint offset = position & ~(page_size-1); + jint align = position - offset; + void* ptr = ::mmap(NULL, size + align, prot, flags, fd, offset); + MappedByteBufferImpl *buf + = new MappedByteBufferImpl ((RawData *) ((char *) ptr + align), + size, mmode == 'r'); + if (ptr == MAP_FAILED) + throw new IOException (JvNewStringLatin1 (strerror (errno))); + buf->implPtr = reinterpret_cast<RawData*> (ptr); + buf->implLen = size+align; + return buf; +#else + throw new IOException (JvNewStringUTF ("mmap not implemented")); +#endif +} + +void +MappedByteBufferImpl::unmapImpl () +{ +#if defined(HAVE_MMAP) + munmap((void*) implPtr, implLen); +#endif +} + +void +MappedByteBufferImpl::loadImpl () +{ +} + +jboolean +MappedByteBufferImpl::isLoadedImpl () +{ + return true; +} + +void +MappedByteBufferImpl::forceImpl () +{ +#if defined(HAVE_MMAP) + ::msync((void*) implPtr, implLen, MS_SYNC); +#endif +} |