612e660987
* 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
433 lines
11 KiB
C++
433 lines
11 KiB
C++
// natFileChannelImplWin32.cc - Native part of FileChannelImpl class.
|
|
|
|
/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
|
|
Foundation, Inc.
|
|
|
|
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. */
|
|
|
|
// FIXME: In order to support interrupting of IO operations, we
|
|
// need to change to use the windows asynchronous IO functions
|
|
|
|
#include <config.h>
|
|
#include <platform.h>
|
|
|
|
#include <gcj/cni.h>
|
|
#include <gcj/javaprims.h>
|
|
#include <jvm.h>
|
|
|
|
#include <stdio.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>
|
|
|
|
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;
|
|
|
|
#undef STRICT
|
|
|
|
static bool testCanUseGetHandleInfo()
|
|
{
|
|
/* Test to see whether GetHandleInformation can be used
|
|
for console input or screen buffers. This is better
|
|
a kludgy OS version check. */
|
|
DWORD dwFlags;
|
|
return GetHandleInformation (GetStdHandle (STD_INPUT_HANDLE),
|
|
&dwFlags) != 0;
|
|
}
|
|
|
|
// FIXME: casting a FILE (pointer) to a jint will not work on Win64 --
|
|
// we should be using gnu.gcj.RawData's.
|
|
|
|
void
|
|
FileChannelImpl::init(void)
|
|
{
|
|
in = new FileChannelImpl((jint)(GetStdHandle (STD_INPUT_HANDLE)),
|
|
FileChannelImpl::READ);
|
|
out = new FileChannelImpl((jint)(GetStdHandle (STD_OUTPUT_HANDLE)),
|
|
FileChannelImpl::WRITE);
|
|
err = new FileChannelImpl((jint)(GetStdHandle (STD_ERROR_HANDLE)),
|
|
FileChannelImpl::WRITE);
|
|
}
|
|
|
|
#if 0
|
|
FileChannelImpl::sync (void) {
|
|
if (! FlushFileBuffers ((HANDLE)fd))
|
|
{
|
|
DWORD dwErrorCode = GetLastError ();
|
|
throw new SyncFailedException (_Jv_WinStrError (dwErrorCode));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
jint
|
|
FileChannelImpl::open (jstring path, jint jflags) {
|
|
|
|
HANDLE handle = NULL;
|
|
DWORD access = 0;
|
|
DWORD create = OPEN_EXISTING;
|
|
|
|
JV_TEMP_STRING_WIN32(cpath, path)
|
|
|
|
JvAssert((jflags & READ) || (jflags & WRITE));
|
|
|
|
if ((jflags & READ) && (jflags & WRITE))
|
|
{
|
|
access = GENERIC_READ | GENERIC_WRITE;
|
|
if (jflags & EXCL)
|
|
create = CREATE_NEW; // this will raise error if file exists.
|
|
else
|
|
create = OPEN_ALWAYS; // equivalent to O_CREAT
|
|
}
|
|
else if (jflags & READ)
|
|
{
|
|
access = GENERIC_READ;
|
|
create = OPEN_EXISTING; // ignore EXCL
|
|
}
|
|
else
|
|
{
|
|
access = GENERIC_WRITE;
|
|
if (jflags & EXCL)
|
|
create = CREATE_NEW;
|
|
else if (jflags & APPEND)
|
|
create = OPEN_ALWAYS;
|
|
else
|
|
create = CREATE_ALWAYS;
|
|
}
|
|
|
|
handle = CreateFile(cpath, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, create, 0, NULL);
|
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD dwErrorCode = GetLastError ();
|
|
throw new FileNotFoundException (_Jv_WinStrError (cpath, dwErrorCode));
|
|
}
|
|
|
|
// For APPEND mode, move the file pointer to the end of the file.
|
|
if (jflags & APPEND)
|
|
{
|
|
DWORD low = SetFilePointer (handle, 0, NULL, FILE_END);
|
|
if ((low == (DWORD) 0xffffffff) && (GetLastError () != NO_ERROR))
|
|
{
|
|
DWORD dwErrorCode = GetLastError ();
|
|
throw new FileNotFoundException (_Jv_WinStrError (cpath, dwErrorCode));
|
|
}
|
|
}
|
|
|
|
// Make this handle non-inheritable so that child
|
|
// processes don't inadvertently prevent us from
|
|
// closing this file.
|
|
_Jv_platform_close_on_exec (handle);
|
|
|
|
return (jint) handle;
|
|
}
|
|
|
|
void
|
|
FileChannelImpl::write (jint b)
|
|
{
|
|
DWORD bytesWritten;
|
|
jbyte buf = (jbyte)b;
|
|
|
|
if (WriteFile ((HANDLE)fd, &buf, 1, &bytesWritten, NULL))
|
|
{
|
|
if (::java::lang::Thread::interrupted())
|
|
{
|
|
InterruptedIOException *iioe = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
|
|
iioe->bytesTransferred = bytesWritten;
|
|
throw iioe;
|
|
}
|
|
if (bytesWritten != 1)
|
|
_Jv_ThrowIOException ();
|
|
}
|
|
else
|
|
_Jv_ThrowIOException ();
|
|
// FIXME: loop until bytesWritten == 1
|
|
}
|
|
|
|
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 *buf = elements (b) + offset;
|
|
DWORD bytesWritten;
|
|
|
|
if (WriteFile ((HANDLE)fd, buf, len, &bytesWritten, NULL))
|
|
{
|
|
if (::java::lang::Thread::interrupted())
|
|
{
|
|
InterruptedIOException *iioe = new InterruptedIOException (JvNewStringLatin1 ("write interrupted"));
|
|
iioe->bytesTransferred = bytesWritten;
|
|
throw iioe;
|
|
}
|
|
}
|
|
else
|
|
_Jv_ThrowIOException ();
|
|
// FIXME: loop until bytesWritten == len
|
|
}
|
|
|
|
void
|
|
FileChannelImpl::implCloseChannel (void)
|
|
{
|
|
HANDLE save = (HANDLE)fd;
|
|
fd = (jint)INVALID_HANDLE_VALUE;
|
|
if (! CloseHandle (save))
|
|
_Jv_ThrowIOException ();
|
|
}
|
|
|
|
void
|
|
FileChannelImpl::implTruncate (jlong size)
|
|
{
|
|
LONG liOrigFilePointer;
|
|
LONG liNewFilePointer;
|
|
LONG liEndFilePointer;
|
|
|
|
// Get the original file pointer.
|
|
if (SetFilePointer((HANDLE) fd, (LONG) 0, &liOrigFilePointer,
|
|
FILE_CURRENT) != (BOOL) 0
|
|
&& (GetLastError() != NO_ERROR))
|
|
_Jv_ThrowIOException ();
|
|
|
|
// Get the length of the file.
|
|
if (SetFilePointer((HANDLE) fd, (LONG) 0, &liEndFilePointer,
|
|
FILE_END) != (BOOL) 0
|
|
&& (GetLastError() != NO_ERROR))
|
|
_Jv_ThrowIOException ();
|
|
|
|
if ((jlong)liEndFilePointer == size)
|
|
{
|
|
// Restore the file pointer.
|
|
if (liOrigFilePointer != liEndFilePointer)
|
|
{
|
|
if (SetFilePointer((HANDLE) fd, liOrigFilePointer, &liNewFilePointer,
|
|
FILE_BEGIN) != (BOOL) 0
|
|
&& (GetLastError() != NO_ERROR))
|
|
_Jv_ThrowIOException ();
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Seek to the new end of file.
|
|
if (SetFilePointer((HANDLE) fd, (LONG) size, &liNewFilePointer,
|
|
FILE_BEGIN) != (BOOL) 0
|
|
&& (GetLastError() != NO_ERROR))
|
|
_Jv_ThrowIOException ();
|
|
|
|
// Truncate the file at this point.
|
|
if (SetEndOfFile((HANDLE) fd) != (BOOL) 0 && (GetLastError() != NO_ERROR))
|
|
_Jv_ThrowIOException ();
|
|
|
|
if (liOrigFilePointer < liNewFilePointer)
|
|
{
|
|
// Restore the file pointer.
|
|
if (SetFilePointer((HANDLE) fd, liOrigFilePointer, &liNewFilePointer,
|
|
FILE_BEGIN) != (BOOL) 0
|
|
&& (GetLastError() != NO_ERROR))
|
|
_Jv_ThrowIOException ();
|
|
}
|
|
}
|
|
|
|
void
|
|
FileChannelImpl::seek (jlong newPos)
|
|
{
|
|
LONG high = pos >> 32;
|
|
DWORD low = SetFilePointer ((HANDLE)fd, (DWORD)(0xffffffff & newPos), &high, FILE_BEGIN);
|
|
if ((low == 0xffffffff) && (GetLastError () != NO_ERROR))
|
|
_Jv_ThrowIOException ();
|
|
}
|
|
|
|
jlong
|
|
FileChannelImpl::implPosition (void)
|
|
{
|
|
LONG high = 0;
|
|
DWORD low = SetFilePointer ((HANDLE)fd, 0, &high, FILE_CURRENT);
|
|
if ((low == 0xffffffff) && (GetLastError() != NO_ERROR))
|
|
_Jv_ThrowIOException ();
|
|
return (((jlong)high) << 32L) | (jlong)low;
|
|
}
|
|
|
|
jlong
|
|
FileChannelImpl::size (void)
|
|
{
|
|
DWORD high;
|
|
DWORD low;
|
|
|
|
low = GetFileSize ((HANDLE)fd, &high);
|
|
// FIXME: Error checking
|
|
return (((jlong)high) << 32L) | (jlong)low;
|
|
}
|
|
|
|
jint
|
|
FileChannelImpl::read (void)
|
|
{
|
|
CHAR buf;
|
|
DWORD read;
|
|
|
|
if (! ReadFile ((HANDLE)fd, &buf, 1, &read, NULL))
|
|
{
|
|
if (GetLastError () == ERROR_BROKEN_PIPE)
|
|
return -1;
|
|
else
|
|
_Jv_ThrowIOException ();
|
|
}
|
|
|
|
if (! read)
|
|
return -1;
|
|
else
|
|
return (jint)(buf & 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 ArrayIndexOutOfBoundsException;
|
|
|
|
// Must return 0 if an attempt is made to read 0 bytes.
|
|
if (count == 0)
|
|
return 0;
|
|
|
|
jbyte *bytes = elements (buffer) + offset;
|
|
|
|
DWORD read;
|
|
if (! ReadFile((HANDLE)fd, bytes, count, &read, NULL))
|
|
{
|
|
if (GetLastError () == ERROR_BROKEN_PIPE)
|
|
return -1;
|
|
else
|
|
_Jv_ThrowIOException ();
|
|
}
|
|
|
|
if (read == 0) return -1;
|
|
|
|
return (jint)read;
|
|
}
|
|
|
|
jint
|
|
FileChannelImpl::available (void)
|
|
{
|
|
// FIXME:
|
|
return size() - position();
|
|
}
|
|
|
|
jboolean
|
|
FileChannelImpl::lock
|
|
(jlong /*pos*/, jlong /*len*/, jboolean /*shared*/, jboolean /*wait*/)
|
|
{
|
|
throw new IOException (JvNewStringLatin1
|
|
("FileChannel.lock() not implemented"));
|
|
}
|
|
|
|
void
|
|
FileChannelImpl::unlock (jlong /*pos*/, jlong /*len*/)
|
|
{
|
|
throw new IOException (JvNewStringLatin1
|
|
("FileChannel.unlock() not implemented"));
|
|
}
|
|
|
|
java::nio::MappedByteBuffer *
|
|
FileChannelImpl::mapImpl (jchar mmode, jlong position, jint size)
|
|
{
|
|
SYSTEM_INFO siSysInfo;
|
|
GetSystemInfo(&siSysInfo);
|
|
DWORD page_size = siSysInfo.dwPageSize;
|
|
jlong offset = position & ~(page_size-1);
|
|
jint align = position - offset;
|
|
jlong high = position + size;
|
|
jlong max_size;
|
|
if (mmode == '+')
|
|
max_size = high - offset;
|
|
else
|
|
max_size = 0;
|
|
DWORD access, protect;
|
|
if (mmode == 'r')
|
|
{
|
|
access = FILE_MAP_READ;
|
|
protect = PAGE_READONLY;
|
|
}
|
|
else if (mmode == '+')
|
|
{
|
|
access = FILE_MAP_WRITE;
|
|
protect = PAGE_READWRITE;
|
|
}
|
|
else
|
|
{
|
|
access = FILE_MAP_COPY;
|
|
protect = PAGE_WRITECOPY;
|
|
}
|
|
HANDLE hFileMapping = CreateFileMapping((HANDLE) fd,
|
|
(LPSECURITY_ATTRIBUTES) NULL,
|
|
protect,
|
|
(DWORD) (max_size >> 32),
|
|
(DWORD) max_size,
|
|
(LPCTSTR) NULL);
|
|
if (hFileMapping == NULL)
|
|
throw new IOException();
|
|
void *ptr = MapViewOfFile(hFileMapping, access,
|
|
(DWORD) (offset >> 32), (DWORD) offset,
|
|
(SIZE_T) (high - offset));
|
|
if (ptr == NULL)
|
|
throw new IOException();
|
|
MappedByteBufferImpl *buf
|
|
= new MappedByteBufferImpl((RawData *) ((char *) ptr + align),
|
|
size, mode == 'r');
|
|
buf->implPtr = reinterpret_cast<RawData*> (ptr);
|
|
buf->implLen = (jlong) (size_t) hFileMapping;
|
|
return buf;
|
|
}
|
|
|
|
void
|
|
MappedByteBufferImpl::unmapImpl ()
|
|
{
|
|
UnmapViewOfFile((void*)implPtr);
|
|
CloseHandle((HANDLE) (size_t) implLen);
|
|
}
|
|
|
|
void
|
|
MappedByteBufferImpl::loadImpl ()
|
|
{
|
|
}
|
|
|
|
jboolean
|
|
MappedByteBufferImpl::isLoadedImpl ()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void
|
|
MappedByteBufferImpl::forceImpl ()
|
|
{
|
|
}
|