mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8233451: (fs) Files.newInputStream() cannot be used with character special files
Reviewed-by: alanb
This commit is contained in:
parent
002de86081
commit
de92fe3757
8 changed files with 415 additions and 31 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2024, 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
|
||||
|
@ -38,6 +38,7 @@ import java.nio.channels.WritableByteChannel;
|
|||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
/**
|
||||
* An InputStream that reads bytes from a channel.
|
||||
|
@ -53,6 +54,10 @@ class ChannelInputStream extends InputStream {
|
|||
private byte[] bs; // Invoker's previous array
|
||||
private byte[] b1;
|
||||
|
||||
// if isOther is true, then the file being read is not a regular file,
|
||||
// nor a directory, nor a symbolic link, hence possibly not seekable
|
||||
private @Stable Boolean isOther;
|
||||
|
||||
/**
|
||||
* Initialize a ChannelInputStream that reads from the given channel.
|
||||
*/
|
||||
|
@ -60,6 +65,17 @@ class ChannelInputStream extends InputStream {
|
|||
this.ch = ch;
|
||||
}
|
||||
|
||||
private boolean isOther() throws IOException {
|
||||
Boolean isOther = this.isOther;
|
||||
if (isOther == null) {
|
||||
if (ch instanceof FileChannelImpl fci)
|
||||
this.isOther = isOther = fci.isOther();
|
||||
else
|
||||
this.isOther = isOther = Boolean.FALSE;
|
||||
}
|
||||
return isOther;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a sequence of bytes from the channel into the given buffer.
|
||||
*/
|
||||
|
@ -105,7 +121,8 @@ class ChannelInputStream extends InputStream {
|
|||
|
||||
@Override
|
||||
public byte[] readAllBytes() throws IOException {
|
||||
if (!(ch instanceof SeekableByteChannel sbc))
|
||||
if (!(ch instanceof SeekableByteChannel sbc) ||
|
||||
(ch instanceof FileChannelImpl fci && isOther()))
|
||||
return super.readAllBytes();
|
||||
|
||||
long length = sbc.size();
|
||||
|
@ -156,7 +173,8 @@ class ChannelInputStream extends InputStream {
|
|||
if (len == 0)
|
||||
return new byte[0];
|
||||
|
||||
if (!(ch instanceof SeekableByteChannel sbc))
|
||||
if (!(ch instanceof SeekableByteChannel sbc) ||
|
||||
(ch instanceof FileChannelImpl fci && isOther()))
|
||||
return super.readNBytes(len);
|
||||
|
||||
long length = sbc.size();
|
||||
|
@ -192,7 +210,9 @@ class ChannelInputStream extends InputStream {
|
|||
@Override
|
||||
public int available() throws IOException {
|
||||
// special case where the channel is to a file
|
||||
if (ch instanceof SeekableByteChannel sbc) {
|
||||
if (ch instanceof FileChannelImpl fci) {
|
||||
return fci.available();
|
||||
} else if (ch instanceof SeekableByteChannel sbc) {
|
||||
long rem = Math.max(0, sbc.size() - sbc.position());
|
||||
return (rem > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)rem;
|
||||
}
|
||||
|
@ -202,7 +222,8 @@ class ChannelInputStream extends InputStream {
|
|||
@Override
|
||||
public synchronized long skip(long n) throws IOException {
|
||||
// special case where the channel is to a file
|
||||
if (ch instanceof SeekableByteChannel sbc) {
|
||||
if (ch instanceof SeekableByteChannel sbc &&
|
||||
!(ch instanceof FileChannelImpl fci && isOther())) {
|
||||
long pos = sbc.position();
|
||||
long newPos;
|
||||
if (n > 0) {
|
||||
|
@ -224,7 +245,8 @@ class ChannelInputStream extends InputStream {
|
|||
public long transferTo(OutputStream out) throws IOException {
|
||||
Objects.requireNonNull(out, "out");
|
||||
|
||||
if (ch instanceof FileChannel fc) {
|
||||
if (ch instanceof FileChannel fc &&
|
||||
!(fc instanceof FileChannelImpl fci && isOther())) {
|
||||
// FileChannel -> SocketChannel
|
||||
if (out instanceof SocketOutputStream sos) {
|
||||
SocketChannelImpl sc = sos.channel();
|
||||
|
|
|
@ -454,6 +454,7 @@ public class FileChannelImpl
|
|||
}
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
// -- Other operations --
|
||||
|
||||
@Override
|
||||
|
@ -529,6 +530,49 @@ public class FileChannelImpl
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an estimate of the number of remaining bytes that can be read
|
||||
* from this channel without blocking.
|
||||
*/
|
||||
int available() throws IOException {
|
||||
ensureOpen();
|
||||
synchronized (positionLock) {
|
||||
int a = -1;
|
||||
int ti = -1;
|
||||
try {
|
||||
beginBlocking();
|
||||
ti = threads.add();
|
||||
if (!isOpen())
|
||||
return -1;
|
||||
a = nd.available(fd);
|
||||
} finally {
|
||||
threads.remove(ti);
|
||||
endBlocking(a > -1);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the channel represents something other than a regular
|
||||
* file, directory, or symbolic link.
|
||||
*/
|
||||
boolean isOther() throws IOException {
|
||||
ensureOpen();
|
||||
int ti = -1;
|
||||
Boolean isOther = null;
|
||||
try {
|
||||
beginBlocking();
|
||||
ti = threads.add();
|
||||
if (!isOpen())
|
||||
return false;
|
||||
return isOther = nd.isOther(fd);
|
||||
} finally {
|
||||
threads.remove(ti);
|
||||
endBlocking(isOther != null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileChannel truncate(long newSize) throws IOException {
|
||||
ensureOpen();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2024, 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
|
||||
|
@ -49,6 +49,10 @@ abstract class FileDispatcher extends NativeDispatcher {
|
|||
|
||||
abstract long size(FileDescriptor fd) throws IOException;
|
||||
|
||||
abstract int available(FileDescriptor fd) throws IOException;
|
||||
|
||||
abstract boolean isOther(FileDescriptor fd) throws IOException;
|
||||
|
||||
abstract int lock(FileDescriptor fd, boolean blocking, long pos, long size,
|
||||
boolean shared) throws IOException;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2024, 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
|
||||
|
@ -93,6 +93,14 @@ class UnixFileDispatcherImpl extends FileDispatcher {
|
|||
return size0(fd);
|
||||
}
|
||||
|
||||
int available(FileDescriptor fd) throws IOException {
|
||||
return available0(fd);
|
||||
}
|
||||
|
||||
boolean isOther(FileDescriptor fd) throws IOException {
|
||||
return isOther0(fd);
|
||||
}
|
||||
|
||||
int lock(FileDescriptor fd, boolean blocking, long pos, long size,
|
||||
boolean shared) throws IOException
|
||||
{
|
||||
|
@ -196,6 +204,10 @@ class UnixFileDispatcherImpl extends FileDispatcher {
|
|||
|
||||
static native long size0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native int available0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native boolean isOther0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native int lock0(FileDescriptor fd, boolean blocking, long pos,
|
||||
long size, boolean shared) throws IOException;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -41,8 +42,10 @@
|
|||
#include "nio.h"
|
||||
#include "nio_util.h"
|
||||
#include "sun_nio_ch_UnixFileDispatcherImpl.h"
|
||||
#include "java_lang_Integer.h"
|
||||
#include "java_lang_Long.h"
|
||||
#include <assert.h>
|
||||
#include "io_util_md.h"
|
||||
|
||||
#if defined(_AIX)
|
||||
#define statvfs statvfs64
|
||||
|
@ -178,6 +181,57 @@ Java_sun_nio_ch_UnixFileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject
|
|||
return fbuf.st_size;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_UnixFileDispatcherImpl_available0(JNIEnv *env, jobject this, jobject fdo)
|
||||
{
|
||||
jint fd = fdval(env, fdo);
|
||||
struct stat fbuf;
|
||||
jlong size = -1;
|
||||
|
||||
if (fstat(fd, &fbuf) != -1) {
|
||||
int mode = fbuf.st_mode;
|
||||
if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
|
||||
int n = ioctl(fd, FIONREAD, &n);
|
||||
if (n >= 0) {
|
||||
return n;
|
||||
}
|
||||
} else if (S_ISREG(mode)) {
|
||||
size = fbuf.st_size;
|
||||
}
|
||||
}
|
||||
|
||||
jlong position;
|
||||
if ((position = lseek(fd, 0, SEEK_CUR)) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size < position) {
|
||||
if ((size = lseek(fd, 0, SEEK_END)) == -1)
|
||||
return 0;
|
||||
else if (lseek(fd, position, SEEK_SET) == -1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
jlong available = size - position;
|
||||
return available > java_lang_Integer_MAX_VALUE ?
|
||||
java_lang_Integer_MAX_VALUE : (jint)available;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_ch_UnixFileDispatcherImpl_isOther0(JNIEnv *env, jobject this, jobject fdo)
|
||||
{
|
||||
jint fd = fdval(env, fdo);
|
||||
struct stat fbuf;
|
||||
|
||||
if (fstat(fd, &fbuf) == -1)
|
||||
handle(env, -1, "isOther failed");
|
||||
|
||||
if (S_ISREG(fbuf.st_mode) || S_ISDIR(fbuf.st_mode) || S_ISLNK(fbuf.st_mode))
|
||||
return JNI_FALSE;
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_UnixFileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
|
||||
jboolean block, jlong pos, jlong size,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2024, 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
|
||||
|
@ -101,6 +101,14 @@ class FileDispatcherImpl extends FileDispatcher {
|
|||
return size0(fd);
|
||||
}
|
||||
|
||||
int available(FileDescriptor fd) throws IOException {
|
||||
return available0(fd);
|
||||
}
|
||||
|
||||
boolean isOther(FileDescriptor fd) throws IOException {
|
||||
return isOther0(fd);
|
||||
}
|
||||
|
||||
int lock(FileDescriptor fd, boolean blocking, long pos, long size,
|
||||
boolean shared) throws IOException
|
||||
{
|
||||
|
@ -223,6 +231,10 @@ class FileDispatcherImpl extends FileDispatcher {
|
|||
|
||||
static native long size0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native int available0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native boolean isOther0(FileDescriptor fd) throws IOException;
|
||||
|
||||
static native int lock0(FileDescriptor fd, boolean blocking, long pos,
|
||||
long size, boolean shared) throws IOException;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2024, 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
|
||||
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include "jni.h"
|
||||
#include "jni_util.h"
|
||||
#include "jvm.h"
|
||||
|
@ -33,6 +34,7 @@
|
|||
#include "nio_util.h"
|
||||
#include "java_lang_Integer.h"
|
||||
#include "sun_nio_ch_FileDispatcherImpl.h"
|
||||
#include "io_util_md.h"
|
||||
|
||||
#include <Mswsock.h> // Requires Mswsock.lib
|
||||
|
||||
|
@ -392,6 +394,75 @@ Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
|
|||
return (jlong)size.QuadPart;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_FileDispatcherImpl_available0(JNIEnv *env, jobject this, jobject fdo)
|
||||
{
|
||||
HANDLE handle = (HANDLE)(handleval(env, fdo));
|
||||
DWORD type = GetFileType(handle);
|
||||
jlong available = 0;
|
||||
|
||||
// Calculate the number of bytes available for a regular file,
|
||||
// and return the default (zero) for other types.
|
||||
if (type == FILE_TYPE_DISK) {
|
||||
jlong current, end;
|
||||
LARGE_INTEGER distance, pos, filesize;
|
||||
distance.QuadPart = 0;
|
||||
if (SetFilePointerEx(handle, distance, &pos, FILE_CURRENT) == 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Available failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
current = (jlong)pos.QuadPart;
|
||||
if (GetFileSizeEx(handle, &filesize) == 0) {
|
||||
JNU_ThrowIOExceptionWithLastError(env, "Available failed");
|
||||
return IOS_THROWN;
|
||||
}
|
||||
end = (jlong)filesize.QuadPart;
|
||||
available = end - current;
|
||||
if (available > java_lang_Integer_MAX_VALUE) {
|
||||
available = java_lang_Integer_MAX_VALUE;
|
||||
} else if (available < 0) {
|
||||
available = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (jint)available;
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_sun_nio_ch_FileDispatcherImpl_isOther0(JNIEnv *env, jobject this, jobject fdo)
|
||||
{
|
||||
HANDLE handle = (HANDLE)(handleval(env, fdo));
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION finfo;
|
||||
if (!GetFileInformationByHandle(handle, &finfo))
|
||||
JNU_ThrowIOExceptionWithLastError(env, "isOther failed");
|
||||
DWORD fattr = finfo.dwFileAttributes;
|
||||
|
||||
if ((fattr & FILE_ATTRIBUTE_DEVICE) != 0)
|
||||
return (jboolean)JNI_TRUE;
|
||||
|
||||
if ((fattr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
|
||||
int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
|
||||
void* lpOutBuffer = (void*)malloc(size*sizeof(char));
|
||||
if (lpOutBuffer == NULL)
|
||||
JNU_ThrowOutOfMemoryError(env, "isOther failed");
|
||||
|
||||
DWORD bytesReturned;
|
||||
if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0,
|
||||
lpOutBuffer, (DWORD)size, &bytesReturned, NULL)) {
|
||||
free(lpOutBuffer);
|
||||
JNU_ThrowIOExceptionWithLastError(env, "isOther failed");
|
||||
}
|
||||
ULONG reparseTag = (*((PULONG)lpOutBuffer));
|
||||
free(lpOutBuffer);
|
||||
return reparseTag == IO_REPARSE_TAG_SYMLINK ?
|
||||
(jboolean)JNI_FALSE : (jboolean)JNI_TRUE;
|
||||
}
|
||||
|
||||
return (jboolean)JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
|
||||
jboolean block, jlong pos, jlong size,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue