mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-08 01:21:42 +01:00
Before this commit there was a race condition: `sun.nio.fs.ExtendedOptions.InternalOption.register(java.nio.file.OpenOption)` could register only one option. There have been two similar options: * `sun.nio.fs.ExtendedOptions.NOSHARE_DELETE` * `java.io.JbExtendedOpenOptions.NOSHARE_DELETE` This led to the following failure: ``` Caused by: java.lang.UnsupportedOperationException at java.base/sun.nio.fs.WindowsChannelFactory$Flags.toFlags(WindowsChannelFactory.java:131) at java.base/sun.nio.fs.WindowsChannelFactory.newFileChannel(WindowsChannelFactory.java:151) at java.base/sun.nio.fs.WindowsFileSystemProvider.newFileChannel(WindowsFileSystemProvider.java:114) at java.base/java.io.IoOverNioFileSystem.initializeStreamsUsingNio0(IoOverNioFileSystem.java:294) at java.base/java.io.IoOverNioFileSystem.initializeStreamUsingNio(IoOverNioFileSystem.java:279) at java.base/java.io.RandomAccessFile.<init>(RandomAccessFile.java:332) ``` This commit fixes the issue, now both options are supported.
297 lines
11 KiB
Java
297 lines
11 KiB
Java
/*
|
|
* Copyright 2025 JetBrains s.r.o.
|
|
* 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 java.io.RandomAccessFileTest uses java.nio.file inside.
|
|
* @library testNio
|
|
* @run junit/othervm
|
|
* -Djava.nio.file.spi.DefaultFileSystemProvider=testNio.ManglingFileSystemProvider
|
|
* -Djbr.java.io.use.nio=true
|
|
* --add-opens jdk.unsupported/com.sun.nio.file=ALL-UNNAMED
|
|
* --add-opens java.base/java.io=ALL-UNNAMED
|
|
* RandomAccessFileTest
|
|
*/
|
|
|
|
import com.sun.nio.file.ExtendedOpenOption;
|
|
import org.junit.After;
|
|
import org.junit.Assume;
|
|
import org.junit.Before;
|
|
import org.junit.BeforeClass;
|
|
import org.junit.Rule;
|
|
import org.junit.Test;
|
|
import org.junit.rules.TemporaryFolder;
|
|
import testNio.ManglingFileSystemProvider;
|
|
|
|
import java.io.EOFException;
|
|
import java.io.File;
|
|
import java.io.RandomAccessFile;
|
|
import java.lang.reflect.Field;
|
|
import java.nio.channels.FileChannel;
|
|
import java.nio.channels.FileLock;
|
|
import java.nio.file.FileSystems;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.OpenOption;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.EnumSet;
|
|
import java.util.Objects;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertFalse;
|
|
import static org.junit.Assert.assertTrue;
|
|
import static org.junit.Assert.fail;
|
|
|
|
|
|
public class RandomAccessFileTest {
|
|
@Rule
|
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
|
|
|
@BeforeClass
|
|
public static void checkSystemProperties() {
|
|
Objects.requireNonNull(System.getProperty("java.nio.file.spi.DefaultFileSystemProvider"));
|
|
}
|
|
|
|
private static void assumeNotWindows() {
|
|
Assume.assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win"));
|
|
}
|
|
|
|
@Before
|
|
@After
|
|
public void resetFs() {
|
|
ManglingFileSystemProvider.resetTricks();
|
|
}
|
|
|
|
@Test
|
|
public void usesNioForNonExistingFiles() throws Exception {
|
|
File nonExistingFile = new File(temporaryFolder.getRoot(), "non-existing-file");
|
|
assertFalse(Files.exists(nonExistingFile.toPath()));
|
|
ManglingFileSystemProvider.mangleFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(nonExistingFile, "rw")) {
|
|
byte[] buffer = "hello".getBytes();
|
|
rac.write(buffer);
|
|
rac.seek(0);
|
|
rac.readFully(buffer);
|
|
assertEquals("h3110", new String(buffer));
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void getChannel() throws Exception {
|
|
File file = temporaryFolder.newFile();
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "r")) {
|
|
FileChannel channel = rac.getChannel();
|
|
assertTrue(channel.getClass().getName(), channel instanceof testNio.ManglingFileChannel);
|
|
}
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "rw")) {
|
|
FileChannel channel = rac.getChannel();
|
|
assertTrue(channel.getClass().getName(), channel instanceof testNio.ManglingFileChannel);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void getFilePointer() throws Exception {
|
|
File file = temporaryFolder.newFile();
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "r")) {
|
|
assertEquals(0, rac.getFilePointer());
|
|
}
|
|
|
|
ManglingFileSystemProvider.readExtraFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "r")) {
|
|
rac.readLine();
|
|
assertEquals(ManglingFileSystemProvider.extraContent.length(), rac.getFilePointer());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void length() throws Exception {
|
|
File file = temporaryFolder.newFile();
|
|
String content = "hello";
|
|
Files.writeString(file.toPath(), content);
|
|
ManglingFileSystemProvider.readExtraFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "r")) {
|
|
assertEquals(content.length() + ManglingFileSystemProvider.extraContent.length(), rac.length());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void read() throws Exception {
|
|
File file = temporaryFolder.newFile();
|
|
|
|
ManglingFileSystemProvider.readExtraFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "r")) {
|
|
String extraContent = ManglingFileSystemProvider.extraContent;
|
|
for (int i = 0; i < extraContent.length(); i++) {
|
|
assertEquals((int) extraContent.charAt(i), rac.read());
|
|
}
|
|
assertEquals(-1, rac.read());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void readFully() throws Exception {
|
|
File file = temporaryFolder.newFile();
|
|
Files.writeString(file.toPath(), "adapters everywhere");
|
|
|
|
ManglingFileSystemProvider.mangleFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "r")) {
|
|
byte[] data = new byte[10];
|
|
rac.readFully(data);
|
|
assertEquals("4d4p73r5 3", new String(data));
|
|
|
|
Arrays.fill(data, (byte)' ');
|
|
try {
|
|
rac.readFully(data);
|
|
fail("An error should have been thrown but wasn't");
|
|
} catch (EOFException _) {
|
|
// Nothing.
|
|
}
|
|
assertEquals("v3rywh3r3 ", new String(data));
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void seek() throws Exception {
|
|
File file = temporaryFolder.newFile();
|
|
|
|
ManglingFileSystemProvider.readExtraFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "r")) {
|
|
String extraContent = ManglingFileSystemProvider.extraContent;
|
|
for (int i = extraContent.length() - 1; i >= 0; i--) {
|
|
rac.seek(i);
|
|
assertEquals(extraContent.charAt(i), (char) rac.readByte());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void setLength() throws Exception {
|
|
String extraContent = ManglingFileSystemProvider.extraContent;
|
|
assertTrue(extraContent.length() > 2);
|
|
assertTrue(extraContent.length() < 11);
|
|
|
|
File file = temporaryFolder.newFile();
|
|
String content = "hello";
|
|
Files.writeString(file.toPath(), content);
|
|
|
|
ManglingFileSystemProvider.mangleFileContent = true;
|
|
ManglingFileSystemProvider.readExtraFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "rw")) {
|
|
assertEquals(content.length() + extraContent.length(), rac.length());
|
|
rac.setLength(content.length() + 2);
|
|
assertEquals(content.length() + 2, rac.length());
|
|
rac.seek(0);
|
|
assertEquals("h3110" + extraContent.substring(0, 2), rac.readLine());
|
|
}
|
|
|
|
ManglingFileSystemProvider.readExtraFileContent = false;
|
|
Files.writeString(file.toPath(), content);
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "rw")) {
|
|
assertEquals(content.length(), rac.length());
|
|
rac.setLength(11);
|
|
assertEquals(11, rac.length());
|
|
|
|
rac.seek(0);
|
|
byte[] buffer = new byte[1234];
|
|
try {
|
|
rac.readFully(buffer);
|
|
fail("EOFException wasn't thrown");
|
|
} catch (EOFException ignored) {
|
|
// Expected behavior.
|
|
}
|
|
assertEquals("h3110\0\0\0\0\0\0", new String(buffer, 0, 11));
|
|
|
|
// setLength should keep the offset.
|
|
rac.seek(0);
|
|
assertEquals('h', rac.readByte());
|
|
rac.setLength(17);
|
|
assertEquals('3', rac.readByte());
|
|
rac.setLength(3);
|
|
assertEquals('1', rac.readByte());
|
|
try {
|
|
rac.readByte();
|
|
fail("EOFException wasn't thrown");
|
|
} catch (EOFException ignored) {
|
|
// Expected behavior.
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void writeSingleByte() throws Exception {
|
|
File file = temporaryFolder.newFile();
|
|
|
|
ManglingFileSystemProvider.mangleFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "rw")) {
|
|
rac.write('f');
|
|
rac.write('o');
|
|
rac.write('o');
|
|
rac.write('b');
|
|
rac.write('a');
|
|
rac.write('r');
|
|
}
|
|
|
|
ManglingFileSystemProvider.mangleFileContent = false;
|
|
assertEquals("f00b4r", Files.readString(file.toPath()));
|
|
}
|
|
|
|
@Test
|
|
public void writeBytes() throws Exception {
|
|
File file = temporaryFolder.newFile();
|
|
|
|
ManglingFileSystemProvider.mangleFileContent = true;
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "rw")) {
|
|
rac.writeBytes("herpderp");
|
|
}
|
|
|
|
ManglingFileSystemProvider.mangleFileContent = false;
|
|
assertEquals("h3rpd3rp", Files.readString(file.toPath()));
|
|
}
|
|
|
|
@Test
|
|
public void testDeletionOfLockedFile() throws Exception {
|
|
Assume.assumeTrue("Windows-only test", System.getProperty("os.name").toLowerCase().startsWith("win"));
|
|
File file = temporaryFolder.newFile();
|
|
try (RandomAccessFile rac = new RandomAccessFile(file, "rw");
|
|
FileLock ignored = rac.getChannel().lock()) {
|
|
assertFalse(file.delete());
|
|
}
|
|
}
|
|
|
|
/** JBR-9260 */
|
|
@Test
|
|
public void testNoShareDelete() throws Exception {
|
|
// This code should throw no exceptions.
|
|
File file = temporaryFolder.newFile();
|
|
|
|
FileSystems.getDefault().provider().newFileChannel(file.toPath(), EnumSet.of(ExtendedOpenOption.NOSHARE_DELETE)).close();
|
|
|
|
{
|
|
Class<?> cls = RandomAccessFileTest.class.getClassLoader().loadClass("java.io.JbExtendedOpenOptions");
|
|
Field field = cls.getDeclaredField("NOSHARE_DELETE");
|
|
field.setAccessible(true);
|
|
OpenOption option = (OpenOption) field.get(null);
|
|
FileSystems.getDefault().provider().newFileChannel(file.toPath(), Collections.singleton(option)).close();
|
|
}
|
|
}
|
|
}
|