Skip to content

SOLR-16903: Make java.io.File a forbidden API #3321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion gradle/validation/forbidden-apis/defaults.all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,7 @@ java.util.Locale#<init>(**)
java.nio.file.Paths#get(**)

@defaultMessage You probably meant to call String.startsWith
java.nio.file.Path#startsWith(java.lang.String)
java.nio.file.Path#startsWith(java.lang.String)

@defaultMessage Use NIO Path instead of File
java.io.File
48 changes: 44 additions & 4 deletions solr/core/src/java/org/apache/solr/core/CoreContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import jakarta.inject.Singleton;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Arrays;
Expand Down Expand Up @@ -988,28 +989,67 @@ private void loadInternal() {
Path dataHome =
cfg.getSolrDataHome() != null ? cfg.getSolrDataHome() : cfg.getCoreRootDirectory();
solrMetricsContext.gauge(
() -> dataHome.toFile().getTotalSpace(),
() -> {
try {
return Files.getFileStore(dataHome).getTotalSpace();
} catch (IOException e) {
throw new SolrException(
ErrorCode.SERVER_ERROR,
"Error retrieving total space for data home directory" + dataHome,
e);
}
},
true,
"totalSpace",
SolrInfoBean.Category.CONTAINER.toString(),
"fs");

solrMetricsContext.gauge(
() -> dataHome.toFile().getUsableSpace(),
() -> {
try {
return Files.getFileStore(dataHome).getUsableSpace();
} catch (IOException e) {
throw new SolrException(
ErrorCode.SERVER_ERROR,
"Error retrieving usable space for data home directory" + dataHome,
e);
}
},
true,
"usableSpace",
SolrInfoBean.Category.CONTAINER.toString(),
"fs");
solrMetricsContext.gauge(
dataHome::toString, true, "path", SolrInfoBean.Category.CONTAINER.toString(), "fs");
solrMetricsContext.gauge(
() -> cfg.getCoreRootDirectory().toFile().getTotalSpace(),
() -> {
try {
return Files.getFileStore(cfg.getCoreRootDirectory()).getTotalSpace();
} catch (IOException e) {
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR,
"Error retrieving total space for core root directory: "
+ cfg.getCoreRootDirectory(),
e);
}
},
true,
"totalSpace",
SolrInfoBean.Category.CONTAINER.toString(),
"fs",
"coreRoot");
solrMetricsContext.gauge(
() -> cfg.getCoreRootDirectory().toFile().getUsableSpace(),
() -> {
try {
return Files.getFileStore(cfg.getCoreRootDirectory()).getUsableSpace();
} catch (IOException e) {
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR,
"Error retrieving usable space for core root directory: "
+ cfg.getCoreRootDirectory(),
e);
}
},
true,
"usableSpace",
SolrInfoBean.Category.CONTAINER.toString(),
Expand Down
14 changes: 12 additions & 2 deletions solr/core/src/java/org/apache/solr/filestore/DistribFileStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,12 @@ public MetaData getMetaData() {

@Override
public Date getTimeStamp() {
return new Date(realPath().toFile().lastModified());
try {
return new Date(Files.getLastModifiedTime(realPath()).toMillis());
} catch (IOException e) {
throw new SolrException(
SERVER_ERROR, "Failed to retrieve the last modified time for: " + realPath(), e);
}
}

@Override
Expand All @@ -295,7 +300,12 @@ public boolean isDir() {

@Override
public long size() {
return realPath().toFile().length();
try {
return Files.size(realPath());
} catch (IOException e) {
throw new SolrException(
SERVER_ERROR, "Failed to retrieve the file size for: " + realPath(), e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.file.PathUtils;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.slf4j.Logger;
Expand Down Expand Up @@ -80,7 +81,7 @@ public boolean hasPackage(String packageName) {
@Override
public Path download(String artifactName) throws SolrException, IOException {
Path tmpDirectory = Files.createTempDirectory("solr-packages");
tmpDirectory.toFile().deleteOnExit();
PathUtils.deleteOnExit(tmpDirectory);
URL url = getRepoUri().resolve(artifactName).toURL();
String fileName = FilenameUtils.getName(url.getPath());
Path destination = tmpDirectory.resolve(fileName);
Expand Down
3 changes: 2 additions & 1 deletion solr/core/src/java/org/apache/solr/update/UpdateLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
import org.apache.commons.io.file.PathUtils;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.apache.solr.common.SolrDocumentBase;
Expand Down Expand Up @@ -2439,7 +2440,7 @@ public static void deleteFile(Path file) {

if (!success) {
try {
file.toFile().deleteOnExit();
PathUtils.deleteOnExit(file);
} catch (Exception e) {
log.error("Error deleting file on exit: {}", file, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ public void testDownconfig() throws Exception {
verifyZkLocalPathsMatch(tmp.resolve("conf"), "/configs/downconfig2");
// And insure the empty file is a text file
Path destEmpty = tmp2.resolve("conf").resolve("stopwords").resolve("emptyfile");
assertTrue("Empty files should NOT be copied down as directories", destEmpty.toFile().isFile());
assertTrue(
"Empty files should NOT be copied down as directories", Files.isRegularFile(destEmpty));
}

@Test
Expand Down Expand Up @@ -326,7 +327,7 @@ public void testCp() throws Exception {

// Next, copy cp7 down and verify that zknode.data exists for cp7
Path zData = tmp.resolve("conf/stopwords/zknode.data");
assertTrue("znode.data should have been copied down", zData.toFile().exists());
assertTrue("znode.data should have been copied down", Files.exists(zData));

// Finally, copy up to cp8 and verify that the data is up there.
args = new String[] {"cp", "--recursive", "--zk-host", zkAddr, "file:" + tmp, "zk:/cp9"};
Expand Down Expand Up @@ -385,7 +386,8 @@ public void testCp() throws Exception {
assertEquals("Copy should have succeeded.", 0, res);

Path locEmpty = tmp2.resolve("stopwords/emptyfile");
assertTrue("Empty files should NOT be copied down as directories", locEmpty.toFile().isFile());
assertTrue(
"Empty files should NOT be copied down as directories", Files.isRegularFile(locEmpty));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ public static void beforeClass() throws Exception {
long processHttpsValue = isWindows ? processHttps.getKey() : processHttps.getValue().pid();
SolrProcessManager.enableTestingMode = true;
System.setProperty("jetty.port", Integer.toString(processHttp.getKey()));
Path pidDir = Files.createTempDirectory("solr-pid-dir").toAbsolutePath();
pidDir.toFile().deleteOnExit();
Path pidDir = createTempDir("solr-pid-dir");
System.setProperty("solr.pid.dir", pidDir.toString());
Files.writeString(
pidDir.resolve("solr-" + processHttpValue + PID_SUFFIX), Long.toString(processHttpValue));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ private void doCustomSharding() throws Exception {
Files.createDirectories(jettyDir);
setupJettySolrHome(jettyDir);
JettySolrRunner j =
createJetty(
jettyDir, createTempDir().toFile().getAbsolutePath(), "shardA", "solrconfig.xml", null);
createJetty(jettyDir, createTempDir().toString(), "shardA", "solrconfig.xml", null);
j.start();
assertEquals(
0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ private void setupBaseConfigSet(String baseConfigSetName, Map<String, String> ol
throws Exception {
final Path configDir = getFile("solr").resolve("configsets/configset-2/conf");
final Path tmpConfigDir = createTempDir();
tmpConfigDir.toFile().deleteOnExit();
PathUtils.copyDirectory(configDir, tmpConfigDir);
if (oldProps != null) {
Files.writeString(
Expand Down Expand Up @@ -1565,7 +1564,6 @@ public void testDeleteErrors() throws Exception {
final SolrClient solrClient = getHttpSolrClient(baseUrl);
final Path configDir = getFile("solr").resolve("configsets/configset-2/conf");
final Path tmpConfigDir = createTempDir();
tmpConfigDir.toFile().deleteOnExit();
// Ensure ConfigSet is immutable
PathUtils.copyDirectory(configDir, tmpConfigDir);
Files.writeString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ private void setupBaseConfigSet(String baseConfigSetName, Map<String, String> ol
throws Exception {
final Path configDir = getFile("solr").resolve("configsets/configset-2/conf");
final Path tmpConfigDir = createTempDir();
tmpConfigDir.toFile().deleteOnExit();
PathUtils.copyDirectory(configDir, tmpConfigDir);
if (oldProps != null) {
Files.writeString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public void reorderingTest() throws Exception {
df.release(a);
assertTrue(
"The path " + pathA + " should exist because it has subdirs that prevent removal",
pathA.toFile().exists()); // we know there are subdirs that should prevent removal
Files.exists(pathA)); // we know there are subdirs that should prevent removal
Collections.shuffle(Arrays.asList(subdirs), r);
for (Map.Entry<String, Directory> e : subdirs) {
boolean after = removeAfter.getAsBoolean();
Expand Down Expand Up @@ -126,7 +126,7 @@ public void reorderingTest() throws Exception {
} else {
assertTrue(
"There are subdirs to wait on, so the parent directory should still exist",
pathA.toFile().exists()); // parent must still be present
Files.exists(pathA)); // parent must still be present
for (Map.Entry<String, Directory> e : subdirs) {
Path path = Path.of(e.getKey());
boolean exists = Files.exists(path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public void testSnapshots() throws Exception {
BackupRestoreUtils.verifyDocs(0, solrClient, collectionName);
}

String backupLocation = createTempDir().toFile().getAbsolutePath();
String backupLocation = createTempDir().toString();
String backupName = "mytestbackup";
String restoreCollectionName = collectionName + "_restored";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public void testBackupRestore() throws Exception {
CollectionAdminRequest.createCollection(collectionName, "conf1", 1, 1);
create.process(solrClient);

String location = createTempDir().toFile().getAbsolutePath();
String location = createTempDir().toString();
int nDocs = BackupRestoreUtils.indexDocs(cluster.getSolrClient(), collectionName, docsSeed);

DocCollection collectionState = solrClient.getClusterState().getCollection(collectionName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public void testSimpleRestore() throws Exception {

// Use the default backup location or an externally provided location.
if (random().nextBoolean()) {
location = createTempDir().toFile().getAbsolutePath();
location = createTempDir().toString();
leaderJetty
.getCoreContainer()
.getAllowPaths()
Expand Down Expand Up @@ -182,8 +182,7 @@ public void testSimpleRestore() throws Exception {

public void testBackupFailsMissingAllowPaths() throws Exception {
final String params =
"&location="
+ URLEncoder.encode(createTempDir().toFile().getAbsolutePath(), StandardCharsets.UTF_8);
"&location=" + URLEncoder.encode(createTempDir().toString(), StandardCharsets.UTF_8);
Throwable t =
expectThrows(
IOException.class,
Expand All @@ -199,7 +198,7 @@ public void testBackupFailsMissingAllowPaths() throws Exception {
public void testFailedRestore() throws Exception {
int nDocs = BackupRestoreUtils.indexDocs(leaderClient, "collection1", docsSeed);

String location = createTempDir().toFile().getAbsolutePath();
String location = createTempDir().toString();
leaderJetty.getCoreContainer().getAllowPaths().add(Path.of(location));
String snapshotName = TestUtil.randomSimpleString(random(), 1, 5);
String params =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public void testCollectionsApi() throws Exception {
assertEquals(
"/collections/collection1/get",
Utils.getObjectByPath(result, true, "/spec[0]/url/paths[0]"));
String tempDir = createTempDir().toFile().getPath();
String tempDir = createTempDir().toString();
Map<String, Object> backupParams = new HashMap<>();
backupParams.put("location", tempDir);
cluster
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ public static void beforeClass() throws Exception {
pemFilePath = JWT_TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem");
wrongPemFilePath = JWT_TEST_PATH().resolve("security").resolve("jwt_plugin_idp_wrongcert.pem");

Path tempDir = Files.createTempDirectory(JWTAuthPluginIntegrationTest.class.getSimpleName());
tempDir.toFile().deleteOnExit();

Path tempDir = createTempDir(JWTAuthPluginIntegrationTest.class.getSimpleName());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createTempDir already incorporates the test class name

Path modifiedP12Cert = tempDir.resolve(p12Cert.getFileName());
new KeystoreGenerator()
.generateKeystore(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ protected static void setupTest(
protected static void initFolders(boolean isPersistent) throws Exception {
tmpSolrHome = createTempDir();
tmpConfDir = tmpSolrHome.resolve(CONF_DIR);
tmpConfDir.toFile().deleteOnExit();
PathUtils.copyDirectory(TEST_PATH(), tmpSolrHome.toAbsolutePath());

final Path modelStore = tmpConfDir.resolve(MODEL_FILE_NAME);

if (isPersistent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ protected static void setupTestInit(String solrconfig, String schema, boolean is
throws Exception {
tmpSolrHome = createTempDir();
tmpConfDir = tmpSolrHome.resolve(CONF_DIR);
tmpConfDir.toFile().deleteOnExit();
PathUtils.copyDirectory(TEST_PATH(), tmpSolrHome);

final Path fstore = tmpConfDir.resolve(FEATURE_FILE_NAME);
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this suite, can we just use createTempDir?

Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@
import org.apache.solr.cloud.api.collections.AbstractBackupRepositoryTest;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.backup.repository.BackupRepository;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
Expand All @@ -51,12 +50,18 @@ public class S3BackupRepositoryTest extends AbstractBackupRepositoryTest {

private static final String BUCKET_NAME = S3BackupRepositoryTest.class.getSimpleName();

@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
public Path temporaryFolder;

@ClassRule
public static final S3MockRule S3_MOCK_RULE =
S3MockRule.builder().withInitialBuckets(BUCKET_NAME).withSecureConnection(false).build();

@Before
public void setUp() throws Exception {
super.setUp();
temporaryFolder = createTempDir("junit");
}

/**
* Sent by {@link org.apache.solr.handler.ReplicationHandler}, ensure we don't choke on the bare
* URI.
Expand Down Expand Up @@ -175,7 +180,7 @@ private void doTestCopyFileFrom(String content) throws Exception {
try (S3BackupRepository repo = getRepository()) {

// A file on the local disk
Path tmp = temporaryFolder.newFolder().toPath();
Path tmp = Files.createTempDirectory(temporaryFolder, "junit");
try (OutputStream os = PathUtils.newOutputStream(tmp.resolve("from-file"), false);
IndexOutput indexOutput = new OutputStreamIndexOutput("", "", os, content.length())) {
byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
Expand Down Expand Up @@ -205,7 +210,7 @@ private void doTestCopyFileTo(String content) throws Exception {
try (S3BackupRepository repo = getRepository()) {

// Local folder for destination
Path tmp = temporaryFolder.newFolder().toPath();
Path tmp = Files.createTempDirectory(temporaryFolder, "junit");

// Directly create a file on S3
pushObject("from-file", content);
Expand Down Expand Up @@ -335,7 +340,7 @@ private void pushObject(String path, String content) {

private Path pullObject(String path) throws IOException {
try (S3Client s3 = S3_MOCK_RULE.createS3ClientV2()) {
Path file = temporaryFolder.newFile().toPath();
Path file = Files.createTempFile(temporaryFolder, "junit", null);
InputStream input = s3.getObject(b -> b.bucket(BUCKET_NAME).key(path));
Files.copy(input, file, StandardCopyOption.REPLACE_EXISTING);
return file;
Expand Down
Loading
Loading