提交 c10132a6 编写于 作者: A alanb

6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file...

6709457: (fc) lock/tryLock() throws IOException "Access is denied" when file opened for append [win]
Reviewed-by: chegar
上级 eb8c7086
......@@ -56,7 +56,15 @@ class FileOutputStream extends OutputStream
*/
private final FileDescriptor fd;
private FileChannel channel= null;
/**
* True if the file is opened for append.
*/
private final boolean append;
/**
* The associated channel, initalized lazily.
*/
private FileChannel channel;
private final Object closeLock = new Object();
private volatile boolean closed = false;
......@@ -196,7 +204,9 @@ class FileOutputStream extends OutputStream
if (name == null) {
throw new NullPointerException();
}
fd = new FileDescriptor();
this.fd = new FileDescriptor();
this.append = append;
fd.incrementAndGetUseCount();
open(name, append);
}
......@@ -232,7 +242,8 @@ class FileOutputStream extends OutputStream
if (security != null) {
security.checkWrite(fdObj);
}
fd = fdObj;
this.fd = fdObj;
this.append = false;
/*
* FileDescriptor is being shared by streams.
......@@ -250,6 +261,15 @@ class FileOutputStream extends OutputStream
private native void open(String name, boolean append)
throws FileNotFoundException;
/**
* Writes the specified byte to this file output stream.
*
* @param b the byte to be written.
* @param append {@code true} if the write operation first
* advances the position to the end of file
*/
private native void write(int b, boolean append) throws IOException;
/**
* Writes the specified byte to this file output stream. Implements
* the <code>write</code> method of <code>OutputStream</code>.
......@@ -257,16 +277,21 @@ class FileOutputStream extends OutputStream
* @param b the byte to be written.
* @exception IOException if an I/O error occurs.
*/
public native void write(int b) throws IOException;
public void write(int b) throws IOException {
write(b, append);
}
/**
* Writes a sub array as a sequence of bytes.
* @param b the data to be written
* @param off the start offset in the data
* @param len the number of bytes that are written
* @param append {@code true} to first advance the position to the
* end of file
* @exception IOException If an I/O error has occurred.
*/
private native void writeBytes(byte b[], int off, int len) throws IOException;
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;
/**
* Writes <code>b.length</code> bytes from the specified byte array
......@@ -276,7 +301,7 @@ class FileOutputStream extends OutputStream
* @exception IOException if an I/O error occurs.
*/
public void write(byte b[]) throws IOException {
writeBytes(b, 0, b.length);
writeBytes(b, 0, b.length, append);
}
/**
......@@ -289,7 +314,7 @@ class FileOutputStream extends OutputStream
* @exception IOException if an I/O error occurs.
*/
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len);
writeBytes(b, off, len, append);
}
/**
......@@ -372,7 +397,7 @@ class FileOutputStream extends OutputStream
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, false, true, this);
channel = FileChannelImpl.open(fd, false, true, append, this);
/*
* Increment fd's use count. Invoking the channel's close()
......
......@@ -537,7 +537,11 @@ public final class ProcessBuilder
*/
public File file() { return null; }
FileOutputStream toFileOutputStream() throws IOException {
/**
* When redirected to a destination file, indicates if the output
* is to be written to the end of the file.
*/
boolean append() {
throw new UnsupportedOperationException();
}
......@@ -588,9 +592,7 @@ public final class ProcessBuilder
public String toString() {
return "redirect to write to file \"" + file + "\"";
}
FileOutputStream toFileOutputStream() throws IOException {
return new FileOutputStream(file, false);
}
boolean append() { return false; }
};
}
......@@ -620,9 +622,7 @@ public final class ProcessBuilder
public String toString() {
return "redirect to append to file \"" + file + "\"";
}
FileOutputStream toFileOutputStream() throws IOException {
return new FileOutputStream(file, true);
}
boolean append() { return true; }
};
}
......
......@@ -39,13 +39,12 @@ import sun.security.action.GetPropertyAction;
public class FileChannelImpl
extends FileChannel
{
// Used to make native read and write calls
private static final FileDispatcher nd;
// Memory allocation size for mapping buffers
private static final long allocationGranularity;
// Used to make native read and write calls
private final FileDispatcher nd;
// File descriptor
private final FileDescriptor fd;
......@@ -63,22 +62,29 @@ public class FileChannelImpl
private final Object positionLock = new Object();
private FileChannelImpl(FileDescriptor fd, boolean readable,
boolean writable, Object parent)
boolean writable, boolean append, Object parent)
{
this.fd = fd;
this.readable = readable;
this.writable = writable;
this.parent = parent;
this.nd = new FileDispatcherImpl(append);
}
// Invoked by getChannel() methods
// of java.io.File{Input,Output}Stream and RandomAccessFile
//
// Used by FileInputStream.getChannel() and RandomAccessFile.getChannel()
public static FileChannel open(FileDescriptor fd,
boolean readable, boolean writable,
Object parent)
{
return new FileChannelImpl(fd, readable, writable, parent);
return new FileChannelImpl(fd, readable, writable, false, parent);
}
// Used by FileOutputStream.getChannel
public static FileChannel open(FileDescriptor fd,
boolean readable, boolean writable,
boolean append, Object parent)
{
return new FileChannelImpl(fd, readable, writable, append, parent);
}
private void ensureOpen() throws IOException {
......@@ -704,6 +710,9 @@ public class FileChannelImpl
private static class Unmapper
implements Runnable
{
// may be required to close file
private static final NativeDispatcher nd = new FileDispatcherImpl();
// keep track of mapped buffer usage
static volatile int count;
static volatile long totalSize;
......@@ -1119,7 +1128,6 @@ public class FileChannelImpl
static {
Util.load();
allocationGranularity = initIDs();
nd = new FileDispatcherImpl();
}
}
......@@ -76,13 +76,13 @@ Java_java_io_RandomAccessFile_readBytes(JNIEnv *env,
JNIEXPORT void JNICALL
Java_java_io_RandomAccessFile_write(JNIEnv *env, jobject this, jint byte) {
writeSingle(env, this, byte, raf_fd);
writeSingle(env, this, byte, JNI_FALSE, raf_fd);
}
JNIEXPORT void JNICALL
Java_java_io_RandomAccessFile_writeBytes(JNIEnv *env,
jobject this, jbyteArray bytes, jint off, jint len) {
writeBytes(env, this, bytes, off, len, raf_fd);
writeBytes(env, this, bytes, off, len, JNI_FALSE, raf_fd);
}
JNIEXPORT jlong JNICALL
......
......@@ -127,7 +127,7 @@ readBytes(JNIEnv *env, jobject this, jbyteArray bytes,
}
void
writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid) {
writeSingle(JNIEnv *env, jobject this, jint byte, jboolean append, jfieldID fid) {
// Discard the 24 high-order bits of byte. See OutputStream#write(int)
char c = (char) byte;
jint n;
......@@ -136,7 +136,11 @@ writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid) {
JNU_ThrowIOException(env, "Stream Closed");
return;
}
n = IO_Write(fd, &c, 1);
if (append == JNI_TRUE) {
n = IO_Append(fd, &c, 1);
} else {
n = IO_Write(fd, &c, 1);
}
if (n == JVM_IO_ERR) {
JNU_ThrowIOExceptionWithLastError(env, "Write error");
} else if (n == JVM_IO_INTR) {
......@@ -146,7 +150,7 @@ writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid) {
void
writeBytes(JNIEnv *env, jobject this, jbyteArray bytes,
jint off, jint len, jfieldID fid)
jint off, jint len, jboolean append, jfieldID fid)
{
jint n;
char stackBuf[BUF_SIZE];
......@@ -185,7 +189,11 @@ writeBytes(JNIEnv *env, jobject this, jbyteArray bytes,
JNU_ThrowIOException(env, "Stream Closed");
break;
}
n = IO_Write(fd, buf+off, len);
if (append == JNI_TRUE) {
n = IO_Append(fd, buf+off, len);
} else {
n = IO_Write(fd, buf+off, len);
}
if (n == JVM_IO_ERR) {
JNU_ThrowIOExceptionWithLastError(env, "Write error");
break;
......
......@@ -41,9 +41,9 @@ extern jfieldID IO_handle_fdID;
jint readSingle(JNIEnv *env, jobject this, jfieldID fid);
jint readBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off,
jint len, jfieldID fid);
void writeSingle(JNIEnv *env, jobject this, jint byte, jfieldID fid);
void writeSingle(JNIEnv *env, jobject this, jint byte, jboolean append, jfieldID fid);
void writeBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off,
jint len, jfieldID fid);
jint len, jboolean append, jfieldID fid);
void fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags);
void throwFileNotFoundException(JNIEnv *env, jstring path);
......
......@@ -111,7 +111,8 @@ final class ProcessImpl {
else if (redirects[1] == Redirect.INHERIT)
std_fds[1] = 1;
else {
f1 = redirects[1].toFileOutputStream();
f1 = new FileOutputStream(redirects[1].file(),
redirects[1].append());
std_fds[1] = fdAccess.get(f1.getFD());
}
......@@ -120,7 +121,8 @@ final class ProcessImpl {
else if (redirects[2] == Redirect.INHERIT)
std_fds[2] = 2;
else {
f2 = redirects[2].toFileOutputStream();
f2 = new FileOutputStream(redirects[2].file(),
redirects[2].append());
std_fds[2] = fdAccess.get(f2.getFD());
}
}
......
......@@ -35,6 +35,13 @@ class FileDispatcherImpl extends FileDispatcher
init();
}
FileDispatcherImpl(boolean append) {
/* append is ignored */
}
FileDispatcherImpl() {
}
int read(FileDescriptor fd, long address, int len) throws IOException {
return read0(fd, address, len);
}
......
......@@ -60,14 +60,14 @@ Java_java_io_FileOutputStream_open(JNIEnv *env, jobject this,
}
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte) {
writeSingle(env, this, byte, fos_fd);
Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte, jboolean append) {
writeSingle(env, this, byte, append, fos_fd);
}
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_writeBytes(JNIEnv *env,
jobject this, jbyteArray bytes, jint off, jint len) {
writeBytes(env, this, bytes, off, len, fos_fd);
jobject this, jbyteArray bytes, jint off, jint len, jboolean append) {
writeBytes(env, this, bytes, off, len, append, fos_fd);
}
JNIEXPORT void JNICALL
......
......@@ -53,8 +53,9 @@
#define THIS_FD(obj) (*env)->GetIntField(env, obj, IO_fd_fdID)
/*
* Route the routines through HPI
* Route the routines through VM
*/
#define IO_Append JVM_Write
#define IO_Write JVM_Write
#define IO_Sync JVM_Sync
#define IO_Read JVM_Read
......
......@@ -35,6 +35,8 @@ import java.io.FileDescriptor;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.lang.ProcessBuilder.Redirect;
import java.security.AccessController;
import java.security.PrivilegedAction;
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
......@@ -47,6 +49,35 @@ final class ProcessImpl extends Process {
private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
= sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
/**
* Open a file for writing. If {@code append} is {@code true} then the file
* is opened for atomic append directly and a FileOutputStream constructed
* with the resulting handle. This is because a FileOutputStream created
* to append to a file does not open the file in a manner that guarantees
* that writes by the child process will be atomic.
*/
private static FileOutputStream newFileOutputStream(File f, boolean append)
throws IOException
{
if (append) {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkWrite(f.getPath());
long handle = openForAtomicAppend(f.getPath());
final FileDescriptor fd = new FileDescriptor();
fdAccess.setHandle(fd, handle);
return AccessController.doPrivileged(
new PrivilegedAction<FileOutputStream>() {
public FileOutputStream run() {
return new FileOutputStream(fd);
}
}
);
} else {
return new FileOutputStream(f);
}
}
// System-dependent portion of ProcessBuilder.start()
static Process start(String cmdarray[],
java.util.Map<String,String> environment,
......@@ -82,7 +113,8 @@ final class ProcessImpl extends Process {
else if (redirects[1] == Redirect.INHERIT)
stdHandles[1] = fdAccess.getHandle(FileDescriptor.out);
else {
f1 = redirects[1].toFileOutputStream();
f1 = newFileOutputStream(redirects[1].file(),
redirects[1].append());
stdHandles[1] = fdAccess.getHandle(f1.getFD());
}
......@@ -91,7 +123,8 @@ final class ProcessImpl extends Process {
else if (redirects[2] == Redirect.INHERIT)
stdHandles[2] = fdAccess.getHandle(FileDescriptor.err);
else {
f2 = redirects[2].toFileOutputStream();
f2 = newFileOutputStream(redirects[2].file(),
redirects[2].append());
stdHandles[2] = fdAccess.getHandle(f2.getFD());
}
}
......@@ -251,5 +284,15 @@ final class ProcessImpl extends Process {
boolean redirectErrorStream)
throws IOException;
/**
* Opens a file for atomic append. The file is created if it doesn't
* already exist.
*
* @param file the file to open or create
* @return the native HANDLE
*/
private static native long openForAtomicAppend(String path)
throws IOException;
private static native boolean closeHandle(long handle);
}
......@@ -35,6 +35,20 @@ class FileDispatcherImpl extends FileDispatcher
Util.load();
}
/**
* Indicates if the dispatcher should first advance the file position
* to the end of file when writing.
*/
private final boolean append;
FileDispatcherImpl(boolean append) {
this.append = append;
}
FileDispatcherImpl() {
this(false);
}
int read(FileDescriptor fd, long address, int len)
throws IOException
{
......@@ -54,7 +68,7 @@ class FileDispatcherImpl extends FileDispatcher
}
int write(FileDescriptor fd, long address, int len) throws IOException {
return write0(fd, address, len);
return write0(fd, address, len, append);
}
int pwrite(FileDescriptor fd, long address, int len,
......@@ -66,7 +80,7 @@ class FileDispatcherImpl extends FileDispatcher
}
long writev(FileDescriptor fd, long address, int len) throws IOException {
return writev0(fd, address, len);
return writev0(fd, address, len, append);
}
int force(FileDescriptor fd, boolean metaData) throws IOException {
......@@ -116,13 +130,13 @@ class FileDispatcherImpl extends FileDispatcher
static native long readv0(FileDescriptor fd, long address, int len)
throws IOException;
static native int write0(FileDescriptor fd, long address, int len)
static native int write0(FileDescriptor fd, long address, int len, boolean append)
throws IOException;
static native int pwrite0(FileDescriptor fd, long address, int len,
long position) throws IOException;
static native long writev0(FileDescriptor fd, long address, int len)
static native long writev0(FileDescriptor fd, long address, int len, boolean append)
throws IOException;
static native int force0(FileDescriptor fd, boolean metaData)
......
......@@ -157,7 +157,7 @@ class WindowsChannelFactory {
throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
return FileChannelImpl.open(fdObj, flags.read, flags.write, null);
return FileChannelImpl.open(fdObj, flags.read, flags.write, flags.append, null);
}
/**
......@@ -230,7 +230,7 @@ class WindowsChannelFactory {
if (flags.read)
dwDesiredAccess |= GENERIC_READ;
if (flags.write)
dwDesiredAccess |= (flags.append) ? FILE_APPEND_DATA : GENERIC_WRITE;
dwDesiredAccess |= GENERIC_WRITE;
int dwShareMode = 0;
if (flags.shareRead)
......
......@@ -61,14 +61,15 @@ Java_java_io_FileOutputStream_open(JNIEnv *env, jobject this,
}
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte) {
writeSingle(env, this, byte, fos_fd);
Java_java_io_FileOutputStream_write(JNIEnv *env, jobject this, jint byte, jboolean append) {
writeSingle(env, this, byte, append, fos_fd);
}
JNIEXPORT void JNICALL
Java_java_io_FileOutputStream_writeBytes(JNIEnv *env,
jobject this, jbyteArray bytes, jint off, jint len) {
writeBytes(env, this, bytes, off, len, fos_fd);
jobject this, jbyteArray bytes, jint off, jint len, jboolean append)
{
writeBytes(env, this, bytes, off, len, append, fos_fd);
}
JNIEXPORT void JNICALL
......
......@@ -225,14 +225,7 @@ pathToNTPath(JNIEnv *env, jstring path, jboolean throwFNFE) {
jlong
winFileHandleOpen(JNIEnv *env, jstring path, int flags)
{
/* To implement O_APPEND, we use the strategy from
http://msdn2.microsoft.com/en-us/library/aa363858.aspx
"You can get atomic append by opening a file with
FILE_APPEND_DATA access and _without_ FILE_WRITE_DATA access.
If you do this then all writes will ignore the current file
pointer and be done at the end-of file." */
const DWORD access =
(flags & O_APPEND) ? (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA) :
(flags & O_WRONLY) ? GENERIC_WRITE :
(flags & O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) :
GENERIC_READ;
......@@ -511,24 +504,42 @@ handleRead(jlong fd, void *buf, jint len)
return read;
}
JNIEXPORT
size_t
handleWrite(jlong fd, const void *buf, jint len)
static size_t writeInternal(jlong fd, const void *buf, jint len, jboolean append)
{
BOOL result = 0;
DWORD written = 0;
HANDLE h = (HANDLE)fd;
if (h != INVALID_HANDLE_VALUE) {
result = WriteFile(h, /* File handle to write */
buf, /* pointers to the buffers */
len, /* number of bytes to write */
&written, /* receives number of bytes written */
NULL); /* no overlapped struct */
OVERLAPPED ov;
LPOVERLAPPED lpOv;
if (append == JNI_TRUE) {
ov.Offset = (DWORD)0xFFFFFFFF;
ov.OffsetHigh = (DWORD)0xFFFFFFFF;
ov.hEvent = NULL;
lpOv = &ov;
} else {
lpOv = NULL;
}
result = WriteFile(h, /* File handle to write */
buf, /* pointers to the buffers */
len, /* number of bytes to write */
&written, /* receives number of bytes written */
lpOv); /* overlapped struct */
}
if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
return -1;
}
return written;
return (size_t)written;
}
JNIEXPORT
size_t handleWrite(jlong fd, const void *buf, jint len) {
return writeInternal(fd, buf, len, JNI_FALSE);
}
JNIEXPORT
size_t handleAppend(jlong fd, const void *buf, jint len) {
return writeInternal(fd, buf, len, JNI_TRUE);
}
jint
......
......@@ -41,6 +41,7 @@ JNIEXPORT int handleSync(jlong fd);
int handleSetLength(jlong fd, jlong length);
JNIEXPORT size_t handleRead(jlong fd, void *buf, jint len);
JNIEXPORT size_t handleWrite(jlong fd, const void *buf, jint len);
JNIEXPORT size_t handleAppend(jlong fd, const void *buf, jint len);
jint handleClose(JNIEnv *env, jobject this, jfieldID fid);
jlong handleLseek(jlong fd, jlong offset, jint whence);
......@@ -74,8 +75,9 @@ jlong winFileHandleOpen(JNIEnv *env, jstring path, int flags);
#define THIS_FD(obj) (*env)->GetLongField(env, obj, IO_handle_fdID)
/*
* Route the routines away from HPI layer
* Route the routines away from VM
*/
#define IO_Append handleAppend
#define IO_Write handleWrite
#define IO_Sync handleSync
#define IO_Read handleRead
......
......@@ -315,3 +315,51 @@ Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle
{
return CloseHandle((HANDLE) handle);
}
/**
* Returns a copy of the Unicode characters of a string. Fow now this
* function doesn't handle long path names and other issues.
*/
static WCHAR* getPath(JNIEnv *env, jstring ps) {
WCHAR *pathbuf = NULL;
const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
if (chars != NULL) {
size_t pathlen = wcslen(chars);
pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
if (pathbuf == NULL) {
JNU_ThrowOutOfMemoryError(env, NULL);
} else {
wcscpy(pathbuf, chars);
}
(*env)->ReleaseStringChars(env, ps, chars);
}
return pathbuf;
}
JNIEXPORT jlong JNICALL
Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
{
const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
const DWORD disposition = OPEN_ALWAYS;
const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
HANDLE h;
WCHAR *pathbuf = getPath(env, path);
if (pathbuf == NULL) {
/* Exception already pending */
return -1;
}
h = CreateFileW(
pathbuf, /* Wide char path name */
access, /* Read and/or write permission */
sharing, /* File sharing flags */
NULL, /* Security attributes */
disposition, /* creation disposition */
flagsAndAttributes, /* flags and attributes */
NULL);
free(pathbuf);
if (h == INVALID_HANDLE_VALUE) {
JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
}
return ptr_to_jlong(h);
}
......@@ -184,18 +184,28 @@ Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo
JNIEXPORT jint JNICALL
Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo,
jlong address, jint len)
jlong address, jint len, jboolean append)
{
BOOL result = 0;
DWORD written = 0;
HANDLE h = (HANDLE)(handleval(env, fdo));
if (h != INVALID_HANDLE_VALUE) {
OVERLAPPED ov;
LPOVERLAPPED lpOv;
if (append == JNI_TRUE) {
ov.Offset = (DWORD)0xFFFFFFFF;
ov.OffsetHigh = (DWORD)0xFFFFFFFF;
ov.hEvent = NULL;
lpOv = &ov;
} else {
lpOv = NULL;
}
result = WriteFile(h, /* File handle to write */
(LPCVOID)address, /* pointers to the buffers */
len, /* number of bytes to write */
&written, /* receives number of bytes written */
NULL); /* no overlapped struct */
lpOv); /* overlapped struct */
}
if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
......@@ -207,7 +217,7 @@ Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo,
jlong address, jint len)
jlong address, jint len, jboolean append)
{
BOOL result = 0;
DWORD written = 0;
......@@ -219,7 +229,16 @@ Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fd
int i = 0;
DWORD num = 0;
struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
OVERLAPPED ov;
LPOVERLAPPED lpOv;
if (append == JNI_TRUE) {
ov.Offset = (DWORD)0xFFFFFFFF;
ov.OffsetHigh = (DWORD)0xFFFFFFFF;
ov.hEvent = NULL;
lpOv = &ov;
} else {
lpOv = NULL;
}
for(i=0; i<len; i++) {
loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
num = iovecp[i].iov_len;
......@@ -227,7 +246,7 @@ Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fd
loc, /* pointers to the buffers */
num, /* number of bytes to write */
&written,/* receives number of bytes written */
NULL); /* no overlapped struct */
lpOv); /* overlapped struct */
if (written > 0) {
totalWritten += written;
}
......@@ -444,9 +463,10 @@ Java_sun_nio_ch_FileDispatcherImpl_closeByHandle(JNIEnv *env, jclass clazz,
}
JNIEXPORT jlong JNICALL
Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong hFile)
Java_sun_nio_ch_FileDispatcherImpl_duplicateHandle(JNIEnv *env, jclass this, jlong handle)
{
HANDLE hProcess = GetCurrentProcess();
HANDLE hFile = jlong_to_ptr(handle);
HANDLE hResult;
BOOL res = DuplicateHandle(hProcess, hFile, hProcess, &hResult, 0, FALSE,
DUPLICATE_SAME_ACCESS);
......
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Check that appends are atomic
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import static java.nio.file.StandardOpenOption.*;
public class AtomicAppend {
static final Random rand = new Random();
// Open file for appending, returning FileChannel
static FileChannel newFileChannel(File file) throws IOException {
if (rand.nextBoolean()) {
return new FileOutputStream(file, true).getChannel();
} else {
return FileChannel.open(file.toPath(), APPEND);
}
}
// Open file for append, returning OutputStream
static OutputStream newOutputStream(File file) throws IOException {
if (rand.nextBoolean()) {
return new FileOutputStream(file, true);
} else {
return file.toPath().newOutputStream(APPEND);
}
}
// write a byte to the given channel
static void write(FileChannel fc, int b) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(1);
buf.put((byte)b);
buf.flip();
if (rand.nextBoolean()) {
ByteBuffer[] bufs = new ByteBuffer[1];
bufs[0] = buf;
fc.write(bufs);
} else {
fc.write(buf);
}
}
public static void main(String[] args) throws Throwable {
final int nThreads = 16;
final int writes = 1000;
final File file = File.createTempFile("foo", null);
try {
ExecutorService pool = Executors.newFixedThreadPool(nThreads);
for (int i = 0; i < nThreads; i++)
pool.execute(new Runnable() { public void run() {
try {
// randomly choose FileChannel or OutputStream
if (rand.nextBoolean()) {
try (FileChannel fc = newFileChannel(file)) {
for (int j=0; j<writes; j++) write(fc, 'x');
}
} else {
try (OutputStream out = newOutputStream(file)) {
for (int j = 0; j<writes; j++) out.write('x');
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}});
pool.shutdown();
pool.awaitTermination(1L, TimeUnit.MINUTES);
if (file.length() != (long) (nThreads * writes))
throw new RuntimeException("File not expected length");
} finally {
file.delete();
}
}
}
......@@ -22,13 +22,13 @@
*/
/* @test
* @bug 4429043 4493595 6332756
* @bug 4429043 4493595 6332756 6709457
* @summary The FileChannel file locking
*/
import java.io.*;
import java.nio.channels.*;
import java.nio.*;
import static java.nio.file.StandardOpenOption.*;
/**
* Testing FileChannel's lock method.
......@@ -55,6 +55,7 @@ public class Lock {
test2(blah, true);
test2(blah, false);
test3(blah);
test4(blah);
blah.delete();
}
......@@ -163,6 +164,24 @@ public class Lock {
fc1.close();
fc2.close();
}
/**
* Test file locking when file is opened for append
*/
static void test4(File blah) throws Exception {
try (FileChannel fc = new FileOutputStream(blah, true).getChannel()) {
fc.tryLock().release();
fc.tryLock(0L, 1L, false).release();
fc.lock().release();
fc.lock(0L, 1L, false).release();
}
try (FileChannel fc = FileChannel.open(blah.toPath(), APPEND)) {
fc.tryLock().release();
fc.tryLock(0L, 1L, false).release();
fc.lock().release();
fc.lock(0L, 1L, false).release();
}
}
}
class MadWriter {
......
......@@ -22,14 +22,14 @@
*/
/* @test
* @bug 6191269
* @bug 6191269 6709457
* @summary Test truncate method of FileChannel
*/
import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import static java.nio.file.StandardOpenOption.*;
import java.util.Random;
......@@ -38,43 +38,79 @@ import java.util.Random;
*/
public class Truncate {
private static Random generator = new Random();
private static File blah;
private static final Random generator = new Random();
public static void main(String[] args) throws Exception {
blah = File.createTempFile("blah", null);
File blah = File.createTempFile("blah", null);
blah.deleteOnExit();
try {
basicTest(blah);
appendTest(blah);
} finally {
blah.delete();
}
}
/**
* Basic test of asserts in truncate's specification.
*/
static void basicTest(File blah) throws Exception {
for(int i=0; i<100; i++) {
long testSize = generator.nextInt(1000) + 10;
initTestFile(blah, testSize);
RandomAccessFile fis = new RandomAccessFile(blah, "rw");
FileChannel c = fis.getChannel();
if (c.size() != testSize)
throw new RuntimeException("Size failed");
FileChannel fc = (i < 50) ?
new RandomAccessFile(blah, "rw").getChannel() :
FileChannel.open(blah.toPath(), READ, WRITE);
try (fc) {
if (fc.size() != testSize)
throw new RuntimeException("Size failed");
long position = generator.nextInt((int)testSize);
c.position(position);
long position = generator.nextInt((int)testSize);
fc.position(position);
long newSize = generator.nextInt((int)testSize);
c.truncate(newSize);
long newSize = generator.nextInt((int)testSize);
fc.truncate(newSize);
if (c.size() != newSize)
throw new RuntimeException("Truncate failed");
if (fc.size() != newSize)
throw new RuntimeException("Truncate failed");
if (position > newSize) {
if (c.position() != newSize)
throw new RuntimeException("Position greater than size");
} else {
if (c.position() != position)
throw new RuntimeException("Truncate changed position");
if (position > newSize) {
if (fc.position() != newSize)
throw new RuntimeException("Position greater than size");
} else {
if (fc.position() != position)
throw new RuntimeException("Truncate changed position");
};
}
}
}
/**
* Test behavior of truncate method when file is opened for append
*/
static void appendTest(File blah) throws Exception {
for (int i=0; i<10; i++) {
long testSize = generator.nextInt(1000) + 10;
initTestFile(blah, testSize);
FileChannel fc = (i < 5) ?
new FileOutputStream(blah, true).getChannel() :
FileChannel.open(blah.toPath(), APPEND);
try (fc) {
// truncate file
long newSize = generator.nextInt((int)testSize);
fc.truncate(newSize);
if (fc.size() != newSize)
throw new RuntimeException("Truncate failed");
c.close();
fis.close();
// write one byte
ByteBuffer buf = ByteBuffer.allocate(1);
buf.put((byte)'x');
buf.flip();
fc.write(buf);
if (fc.size() != (newSize+1))
throw new RuntimeException("Unexpected size");
}
}
blah.delete();
}
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册