From 8fbfe9c034d681b2754d8db1ea19340ed6fd010e Mon Sep 17 00:00:00 2001 From: Anastasia Iakimova <94782753+Nastya828@users.noreply.github.com> Date: Mon, 20 Nov 2023 20:05:13 +0300 Subject: [PATCH] IGNITE-20867 Fixed server nodes crashing if the cache directory contains illegal chars (#11047) --- .../processors/cache/ClusterCachesInfo.java | 24 ++++ .../distributed/CacheDirectoryNameTest.java | 118 ++++++++++++++++++ .../testsuites/IgniteCacheTestSuite4.java | 3 + 3 files changed, 145 insertions(+) create mode 100644 modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDirectoryNameTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java index 97202caedaf58..fa9833e20b570 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java @@ -18,6 +18,8 @@ package org.apache.ignite.internal.processors.cache; import java.io.Serializable; +import java.nio.file.InvalidPathException; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -95,6 +97,7 @@ import static org.apache.ignite.internal.GridComponent.DiscoveryDataExchangeType.CACHE_PROC; import static org.apache.ignite.internal.processors.cache.GridCacheProcessor.CLUSTER_READ_ONLY_MODE_ERROR_MSG_FORMAT; import static org.apache.ignite.internal.processors.cache.GridLocalConfigManager.validateIncomingConfiguration; +import static org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.cacheDirName; import static org.apache.ignite.internal.processors.cache.persistence.snapshot.IgniteSnapshotManager.SNP_IN_PROGRESS_ERR_MSG; /** @@ -1131,6 +1134,12 @@ else if (encMgr.masterKeyDigest() != null && } } + if (containsInvalidFileNameChars(ccfg)) { + err = new IgniteCheckedException("Cache start failed. Cache or group name contains the characters " + + "that are not allowed in file names [cache= + cacheName " + + (ccfg.getGroupName() == null ? "" : ", group=" + ccfg.getGroupName()) + ']'); + } + if (err != null) { if (persistedCfgs) res.errs.add(err); @@ -1196,6 +1205,21 @@ else if (encMgr.masterKeyDigest() != null && return true; } + /** @return {@code True} if cache directory contains the characters that are not allowed in file names. */ + private boolean containsInvalidFileNameChars(CacheConfiguration ccfg) { + if (!CU.isPersistentCache(ccfg, ctx.config().getDataStorageConfiguration())) + return false; + + String expDir = cacheDirName(ccfg); + + try { + return !expDir.equals(Paths.get(expDir).toFile().getName()); + } + catch (InvalidPathException ignored) { + return true; + } + } + /** * Validate correcteness of new cache start request. * diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDirectoryNameTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDirectoryNameTest.java new file mode 100644 index 0000000000000..079786957e2aa --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDirectoryNameTest.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.cache.distributed; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cluster.ClusterState; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.DataRegionConfiguration; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.apache.ignite.internal.util.lang.GridFunc.asList; +import static org.apache.ignite.testframework.GridTestUtils.assertThrows; +import static org.apache.ignite.testframework.GridTestUtils.cartesianProduct; + +/** + * Test cache directory name validation. + */ +@RunWith(Parameterized.class) +public class CacheDirectoryNameTest extends GridCommonAbstractTest { + /** */ + @Parameterized.Parameter + public boolean persistenceEnabled; + + /** */ + @Parameterized.Parameter(1) + public boolean checkGroup; + + /** @return Test parameters. */ + @Parameterized.Parameters(name = "persistenceEnabled={0}, isGroupName={1}") + public static Collection parameters() { + return cartesianProduct( + asList(false, true), asList(false, true) + ); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + return super.getConfiguration(igniteInstanceName) + .setDataStorageConfiguration(new DataStorageConfiguration() + .setDefaultDataRegionConfiguration(new DataRegionConfiguration() + .setPersistenceEnabled(persistenceEnabled))); + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + cleanPersistenceDir(); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + cleanPersistenceDir(); + } + + /** */ + @Test + public void testCacheDirectoryContainsInvalidFileNameChars() throws Exception { + IgniteEx srv = startGrid(); + + srv.cluster().state(ClusterState.ACTIVE); + + List illegalNames = new ArrayList<>(); + + illegalNames.add("/"); + illegalNames.add("a/b"); + + if (U.isWindows()) { + illegalNames.add("a>b"); + illegalNames.add("a\\b"); + } + + for (String name : illegalNames) { + CacheConfiguration cfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME); + + if (checkGroup) + cfg.setGroupName(name); + else + cfg.setName(name); + + if (persistenceEnabled) { + assertThrows(log, () -> srv.createCache(cfg), IgniteCheckedException.class, + "Cache start failed. Cache or group name contains the characters that are not allowed in file names"); + } + else { + srv.createCache(cfg); + srv.destroyCache(cfg.getName()); + } + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java index 3e7450275cb6e..7a225e4890ca2 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java @@ -96,6 +96,7 @@ import org.apache.ignite.internal.processors.cache.IgniteSystemCacheOnClientTest; import org.apache.ignite.internal.processors.cache.MarshallerCacheJobRunNodeRestartTest; import org.apache.ignite.internal.processors.cache.distributed.CacheAffinityEarlyTest; +import org.apache.ignite.internal.processors.cache.distributed.CacheDirectoryNameTest; import org.apache.ignite.internal.processors.cache.distributed.CacheDiscoveryDataConcurrentJoinTest; import org.apache.ignite.internal.processors.cache.distributed.CacheGetFutureHangsSelfTest; import org.apache.ignite.internal.processors.cache.distributed.CacheGroupsPreloadTest; @@ -329,6 +330,8 @@ public static List> suite(Collection ignoredTests) { GridTestUtils.addTestIfNeeded(suite, GridCacheProcessorActiveTxTest.class, ignoredTests); + GridTestUtils.addTestIfNeeded(suite, CacheDirectoryNameTest.class, ignoredTests); + return suite; } }