mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-24 09:10:08 +00:00
8000330: (fc) FileChannel.truncate issues when given size > file size
8002180: (fc) FileChannel.map does not throw NPE if MapMode specified as null Reviewed-by: chegar
This commit is contained in:
parent
430592a30e
commit
f2aa8d9df9
@ -302,12 +302,10 @@ public class FileChannelImpl
|
||||
}
|
||||
}
|
||||
|
||||
public FileChannel truncate(long size) throws IOException {
|
||||
public FileChannel truncate(long newSize) throws IOException {
|
||||
ensureOpen();
|
||||
if (size < 0)
|
||||
throw new IllegalArgumentException();
|
||||
if (size > size())
|
||||
return this;
|
||||
if (newSize < 0)
|
||||
throw new IllegalArgumentException("Negative size");
|
||||
if (!writable)
|
||||
throw new NonWritableChannelException();
|
||||
synchronized (positionLock) {
|
||||
@ -320,6 +318,14 @@ public class FileChannelImpl
|
||||
if (!isOpen())
|
||||
return null;
|
||||
|
||||
// get current size
|
||||
long size;
|
||||
do {
|
||||
size = nd.size(fd);
|
||||
} while ((size == IOStatus.INTERRUPTED) && isOpen());
|
||||
if (!isOpen())
|
||||
return null;
|
||||
|
||||
// get current position
|
||||
do {
|
||||
p = position0(fd, -1);
|
||||
@ -328,16 +334,18 @@ public class FileChannelImpl
|
||||
return null;
|
||||
assert p >= 0;
|
||||
|
||||
// truncate file
|
||||
do {
|
||||
rv = nd.truncate(fd, size);
|
||||
} while ((rv == IOStatus.INTERRUPTED) && isOpen());
|
||||
if (!isOpen())
|
||||
return null;
|
||||
// truncate file if given size is less than the current size
|
||||
if (newSize < size) {
|
||||
do {
|
||||
rv = nd.truncate(fd, newSize);
|
||||
} while ((rv == IOStatus.INTERRUPTED) && isOpen());
|
||||
if (!isOpen())
|
||||
return null;
|
||||
}
|
||||
|
||||
// set position to size if greater than size
|
||||
if (p > size)
|
||||
p = size;
|
||||
// if position is beyond new size then adjust it
|
||||
if (p > newSize)
|
||||
p = newSize;
|
||||
do {
|
||||
rv = (int)position0(fd, p);
|
||||
} while ((rv == IOStatus.INTERRUPTED) && isOpen());
|
||||
@ -779,6 +787,8 @@ public class FileChannelImpl
|
||||
throws IOException
|
||||
{
|
||||
ensureOpen();
|
||||
if (mode == null)
|
||||
throw new NullPointerException("Mode is null");
|
||||
if (position < 0L)
|
||||
throw new IllegalArgumentException("Negative position");
|
||||
if (size < 0L)
|
||||
@ -787,6 +797,7 @@ public class FileChannelImpl
|
||||
throw new IllegalArgumentException("Position + size overflow");
|
||||
if (size > Integer.MAX_VALUE)
|
||||
throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE");
|
||||
|
||||
int imode = -1;
|
||||
if (mode == MapMode.READ_ONLY)
|
||||
imode = MAP_RO;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2012, 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
|
||||
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 4429043 8002180
|
||||
* @summary Test file mapping with FileChannel
|
||||
* @run main/othervm MapTest
|
||||
*/
|
||||
@ -29,7 +30,10 @@
|
||||
import java.io.*;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileChannel.MapMode;
|
||||
import java.nio.file.Files;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import static java.nio.charset.StandardCharsets.*;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
@ -39,6 +43,7 @@ import java.util.Random;
|
||||
|
||||
public class MapTest {
|
||||
|
||||
private static PrintStream out = System.out;
|
||||
private static PrintStream err = System.err;
|
||||
|
||||
private static Random generator = new Random();
|
||||
@ -51,15 +56,21 @@ public class MapTest {
|
||||
blah = File.createTempFile("blah", null);
|
||||
blah.deleteOnExit();
|
||||
initTestFile(blah);
|
||||
err.println("Test file " + blah + " initialized");
|
||||
testZero();
|
||||
err.println("Zero size: OK");
|
||||
testRead();
|
||||
err.println("Read: OK");
|
||||
testWrite();
|
||||
err.println("Write: OK");
|
||||
testHighOffset();
|
||||
err.println("High offset: OK");
|
||||
try {
|
||||
out.println("Test file " + blah + " initialized");
|
||||
testZero();
|
||||
out.println("Zero size: OK");
|
||||
testRead();
|
||||
out.println("Read: OK");
|
||||
testWrite();
|
||||
out.println("Write: OK");
|
||||
testHighOffset();
|
||||
out.println("High offset: OK");
|
||||
testExceptions();
|
||||
out.println("Exceptions: OK");
|
||||
} finally {
|
||||
blah.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,30 +88,25 @@ public class MapTest {
|
||||
* ability to index into a file of multiple pages is tested.
|
||||
*/
|
||||
private static void initTestFile(File blah) throws Exception {
|
||||
FileOutputStream fos = new FileOutputStream(blah);
|
||||
BufferedWriter awriter
|
||||
= new BufferedWriter(new OutputStreamWriter(fos, "8859_1"));
|
||||
|
||||
for(int i=0; i<4000; i++) {
|
||||
String number = new Integer(i).toString();
|
||||
for (int h=0; h<4-number.length(); h++)
|
||||
awriter.write("0");
|
||||
awriter.write(""+i);
|
||||
awriter.newLine();
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(blah.toPath(), ISO_8859_1)) {
|
||||
for (int i=0; i<4000; i++) {
|
||||
String number = new Integer(i).toString();
|
||||
for (int h=0; h<4-number.length(); h++)
|
||||
writer.write("0");
|
||||
writer.write(""+i);
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
awriter.flush();
|
||||
awriter.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests zero size file mapping
|
||||
*/
|
||||
private static void testZero() throws Exception {
|
||||
FileInputStream fis = new FileInputStream(blah);
|
||||
FileChannel c = fis.getChannel();
|
||||
MappedByteBuffer b = c.map(FileChannel.MapMode.READ_ONLY, 0, 0);
|
||||
c.close();
|
||||
fis.close();
|
||||
try (FileInputStream fis = new FileInputStream(blah)) {
|
||||
FileChannel fc = fis.getChannel();
|
||||
MappedByteBuffer b = fc.map(MapMode.READ_ONLY, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,33 +114,32 @@ public class MapTest {
|
||||
* from the ByteBuffer gets the right line number
|
||||
*/
|
||||
private static void testRead() throws Exception {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.setLength(4);
|
||||
|
||||
for (int x=0; x<1000; x++) {
|
||||
FileInputStream fis = new FileInputStream(blah);
|
||||
FileChannel c = fis.getChannel();
|
||||
try (FileInputStream fis = new FileInputStream(blah)) {
|
||||
FileChannel fc = fis.getChannel();
|
||||
|
||||
long offset = generator.nextInt(10000);
|
||||
long expectedResult = offset / CHARS_PER_LINE;
|
||||
offset = expectedResult * CHARS_PER_LINE;
|
||||
long offset = generator.nextInt(10000);
|
||||
long expectedResult = offset / CHARS_PER_LINE;
|
||||
offset = expectedResult * CHARS_PER_LINE;
|
||||
|
||||
MappedByteBuffer b = c.map(FileChannel.MapMode.READ_ONLY,
|
||||
offset, 100);
|
||||
MappedByteBuffer b = fc.map(MapMode.READ_ONLY,
|
||||
offset, 100);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
byte aByte = b.get(i);
|
||||
sb.setCharAt(i, (char)aByte);
|
||||
for (int i=0; i<4; i++) {
|
||||
byte aByte = b.get(i);
|
||||
sb.setCharAt(i, (char)aByte);
|
||||
}
|
||||
|
||||
int result = Integer.parseInt(sb.toString());
|
||||
if (result != expectedResult) {
|
||||
err.println("I expected "+expectedResult);
|
||||
err.println("I got "+result);
|
||||
throw new Exception("Read test failed");
|
||||
}
|
||||
}
|
||||
|
||||
int result = Integer.parseInt(sb.toString());
|
||||
if (result != expectedResult) {
|
||||
err.println("I expected "+expectedResult);
|
||||
err.println("I got "+result);
|
||||
throw new Exception("Read test failed");
|
||||
}
|
||||
c.close();
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,46 +148,159 @@ public class MapTest {
|
||||
* written out to the file can be read back in
|
||||
*/
|
||||
private static void testWrite() throws Exception {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.setLength(4);
|
||||
|
||||
for (int x=0; x<1000; x++) {
|
||||
RandomAccessFile raf = new RandomAccessFile(blah, "rw");
|
||||
FileChannel c = raf.getChannel();
|
||||
try (RandomAccessFile raf = new RandomAccessFile(blah, "rw")) {
|
||||
FileChannel fc = raf.getChannel();
|
||||
|
||||
long offset = generator.nextInt(1000);
|
||||
MappedByteBuffer b = c.map(FileChannel.MapMode.READ_WRITE,
|
||||
offset, 100);
|
||||
long offset = generator.nextInt(1000);
|
||||
MappedByteBuffer b = fc.map(MapMode.READ_WRITE,
|
||||
offset, 100);
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
b.put(i, (byte)('0' + i));
|
||||
for (int i=0; i<4; i++) {
|
||||
b.put(i, (byte)('0' + i));
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
byte aByte = b.get(i);
|
||||
sb.setCharAt(i, (char)aByte);
|
||||
}
|
||||
if (!sb.toString().equals("0123"))
|
||||
throw new Exception("Write test failed");
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
byte aByte = b.get(i);
|
||||
sb.setCharAt(i, (char)aByte);
|
||||
}
|
||||
if (!sb.toString().equals("0123"))
|
||||
throw new Exception("Write test failed");
|
||||
c.close();
|
||||
raf.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void testHighOffset() throws Exception {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.setLength(4);
|
||||
|
||||
for (int x=0; x<1000; x++) {
|
||||
RandomAccessFile raf = new RandomAccessFile(blah, "rw");
|
||||
FileChannel fc = raf.getChannel();
|
||||
long offset = 66000;
|
||||
MappedByteBuffer b = fc.map(FileChannel.MapMode.READ_WRITE,
|
||||
offset, 100);
|
||||
|
||||
fc.close();
|
||||
raf.close();
|
||||
try (RandomAccessFile raf = new RandomAccessFile(blah, "rw")) {
|
||||
FileChannel fc = raf.getChannel();
|
||||
long offset = 66000;
|
||||
MappedByteBuffer b = fc.map(MapMode.READ_WRITE,
|
||||
offset, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exceptions specified by map method
|
||||
*/
|
||||
private static void testExceptions() throws Exception {
|
||||
// check exceptions when channel opened for read access
|
||||
try (FileChannel fc = FileChannel.open(blah.toPath(), READ)) {
|
||||
testExceptions(fc);
|
||||
|
||||
checkException(fc, MapMode.READ_WRITE, 0L, fc.size(),
|
||||
NonWritableChannelException.class);
|
||||
|
||||
checkException(fc, MapMode.READ_WRITE, -1L, fc.size(),
|
||||
NonWritableChannelException.class, IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, MapMode.READ_WRITE, 0L, -1L,
|
||||
NonWritableChannelException.class, IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, MapMode.PRIVATE, 0L, fc.size(),
|
||||
NonWritableChannelException.class);
|
||||
|
||||
checkException(fc, MapMode.PRIVATE, -1L, fc.size(),
|
||||
NonWritableChannelException.class, IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, MapMode.PRIVATE, 0L, -1L,
|
||||
NonWritableChannelException.class, IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
// check exceptions when channel opened for write access
|
||||
try (FileChannel fc = FileChannel.open(blah.toPath(), WRITE)) {
|
||||
testExceptions(fc);
|
||||
|
||||
checkException(fc, MapMode.READ_ONLY, 0L, fc.size(),
|
||||
NonReadableChannelException.class);
|
||||
|
||||
checkException(fc, MapMode.READ_ONLY, -1L, fc.size(),
|
||||
NonReadableChannelException.class, IllegalArgumentException.class);
|
||||
|
||||
/*
|
||||
* implementation/spec mismatch, these tests disabled for now
|
||||
*/
|
||||
//checkException(fc, MapMode.READ_WRITE, 0L, fc.size(),
|
||||
// NonWritableChannelException.class);
|
||||
//checkException(fc, MapMode.PRIVATE, 0L, fc.size(),
|
||||
// NonWritableChannelException.class);
|
||||
}
|
||||
|
||||
// check exceptions when channel opened for read and write access
|
||||
try (FileChannel fc = FileChannel.open(blah.toPath(), READ, WRITE)) {
|
||||
testExceptions(fc);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testExceptions(FileChannel fc) throws IOException {
|
||||
checkException(fc, null, 0L, fc.size(),
|
||||
NullPointerException.class);
|
||||
|
||||
checkException(fc, MapMode.READ_ONLY, -1L, fc.size(),
|
||||
IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, null, -1L, fc.size(),
|
||||
IllegalArgumentException.class, NullPointerException.class);
|
||||
|
||||
checkException(fc, MapMode.READ_ONLY, 0L, -1L,
|
||||
IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, null, 0L, -1L,
|
||||
IllegalArgumentException.class, NullPointerException.class);
|
||||
|
||||
checkException(fc, MapMode.READ_ONLY, 0L, Integer.MAX_VALUE + 1L,
|
||||
IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, null, 0L, Integer.MAX_VALUE + 1L,
|
||||
IllegalArgumentException.class, NullPointerException.class);
|
||||
|
||||
checkException(fc, MapMode.READ_ONLY, Long.MAX_VALUE, 1L,
|
||||
IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, null, Long.MAX_VALUE, 1L,
|
||||
IllegalArgumentException.class, NullPointerException.class);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that FileChannel map throws one of the expected exceptions
|
||||
* when invoked with the given inputs.
|
||||
*/
|
||||
private static void checkException(FileChannel fc,
|
||||
MapMode mode,
|
||||
long position,
|
||||
long size,
|
||||
Class<?>... expected)
|
||||
throws IOException
|
||||
{
|
||||
Exception exc = null;
|
||||
try {
|
||||
fc.map(mode, position, size);
|
||||
} catch (Exception actual) {
|
||||
exc = actual;
|
||||
}
|
||||
if (exc != null) {
|
||||
for (Class<?> clazz: expected) {
|
||||
if (clazz.isInstance(exc)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.err.println("Expected one of");
|
||||
for (Class<?> clazz: expected) {
|
||||
System.out.println(clazz);
|
||||
}
|
||||
if (exc == null) {
|
||||
throw new RuntimeException("No expection thrown");
|
||||
} else {
|
||||
throw new RuntimeException("Unexpected exception thrown", exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2012, 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
|
||||
@ -22,14 +22,16 @@
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 6191269 6709457
|
||||
* @bug 6191269 6709457 8000330
|
||||
* @summary Test truncate method of FileChannel
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.file.Files;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import static java.nio.charset.StandardCharsets.*;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
@ -46,6 +48,7 @@ public class Truncate {
|
||||
try {
|
||||
basicTest(blah);
|
||||
appendTest(blah);
|
||||
exceptionTests(blah);
|
||||
} finally {
|
||||
blah.delete();
|
||||
}
|
||||
@ -66,15 +69,22 @@ public class Truncate {
|
||||
if (fc.size() != testSize)
|
||||
throw new RuntimeException("Size failed");
|
||||
|
||||
long position = generator.nextInt((int)testSize);
|
||||
long position = generator.nextInt((int)testSize*2);
|
||||
fc.position(position);
|
||||
|
||||
long newSize = generator.nextInt((int)testSize);
|
||||
long newSize = generator.nextInt((int)testSize*2);
|
||||
fc.truncate(newSize);
|
||||
|
||||
if (fc.size() != newSize)
|
||||
throw new RuntimeException("Truncate failed");
|
||||
// check new size
|
||||
if (newSize > testSize) {
|
||||
if (fc.size() != testSize)
|
||||
throw new RuntimeException("Attempt to expand file changed size");
|
||||
} else {
|
||||
if (fc.size() != newSize)
|
||||
throw new RuntimeException("Unexpected size after truncate");
|
||||
}
|
||||
|
||||
// check new position
|
||||
if (position > newSize) {
|
||||
if (fc.position() != newSize)
|
||||
throw new RuntimeException("Position greater than size");
|
||||
@ -114,21 +124,91 @@ public class Truncate {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test exceptions specified by truncate method
|
||||
*/
|
||||
static void exceptionTests(File blah) throws Exception {
|
||||
// check exceptions when channel opened for read access
|
||||
try (FileChannel fc = FileChannel.open(blah.toPath(), READ)) {
|
||||
long size = fc.size();
|
||||
|
||||
// open channel
|
||||
checkException(fc, 0L, NonWritableChannelException.class);
|
||||
|
||||
checkException(fc, -1L, NonWritableChannelException.class,
|
||||
IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, size+1L, NonWritableChannelException.class);
|
||||
|
||||
// closed channel
|
||||
fc.close();
|
||||
|
||||
checkException(fc, 0L, ClosedChannelException.class);
|
||||
|
||||
checkException(fc, -1L, ClosedChannelException.class,
|
||||
IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, size+1L, ClosedChannelException.class);
|
||||
}
|
||||
|
||||
// check exceptions when channel opened for write access
|
||||
try (FileChannel fc = FileChannel.open(blah.toPath(), WRITE)) {
|
||||
long size = fc.size();
|
||||
|
||||
// open channel
|
||||
checkException(fc, -1L, IllegalArgumentException.class);
|
||||
|
||||
// closed channel
|
||||
fc.close();
|
||||
|
||||
checkException(fc, 0L, ClosedChannelException.class);
|
||||
|
||||
checkException(fc, -1L, ClosedChannelException.class,
|
||||
IllegalArgumentException.class);
|
||||
|
||||
checkException(fc, size+1L, ClosedChannelException.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that FileChannel truncate throws one of the expected exceptions
|
||||
* when invoked with the given size.
|
||||
*/
|
||||
private static void checkException(FileChannel fc, long size, Class<?>... expected)
|
||||
throws IOException
|
||||
{
|
||||
Exception exc = null;
|
||||
try {
|
||||
fc.truncate(size);
|
||||
} catch (Exception actual) {
|
||||
exc = actual;
|
||||
}
|
||||
if (exc != null) {
|
||||
for (Class<?> clazz: expected) {
|
||||
if (clazz.isInstance(exc)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.err.println("Expected one of");
|
||||
for (Class<?> clazz: expected) {
|
||||
System.err.println(clazz);
|
||||
}
|
||||
if (exc == null) {
|
||||
throw new RuntimeException("No expection thrown");
|
||||
} else {
|
||||
throw new RuntimeException("Unexpected exception thrown", exc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates file blah of specified size in bytes.
|
||||
*
|
||||
*/
|
||||
private static void initTestFile(File blah, long size) throws Exception {
|
||||
if (blah.exists())
|
||||
blah.delete();
|
||||
FileOutputStream fos = new FileOutputStream(blah);
|
||||
BufferedWriter awriter
|
||||
= new BufferedWriter(new OutputStreamWriter(fos, "8859_1"));
|
||||
|
||||
for(int i=0; i<size; i++) {
|
||||
awriter.write("e");
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(blah.toPath(), ISO_8859_1)) {
|
||||
for(int i=0; i<size; i++) {
|
||||
writer.write("e");
|
||||
}
|
||||
}
|
||||
awriter.flush();
|
||||
awriter.close();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user