Skip to content

Commit 5bb26db

Browse files
authored
Merge pull request ClickHouse#90181 from ClickHouse/backport/25.8/90079
Backport ClickHouse#90079 to 25.8: Allow files starting with dots in user_files
2 parents f7fa063 + da22de9 commit 5bb26db

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

src/Common/filesystemHelpers.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,17 @@ String getFilesystemName([[maybe_unused]] const String & mount_point)
219219
bool pathStartsWith(const std::filesystem::path & path, const std::filesystem::path & prefix_path)
220220
{
221221
auto rel = fs::relative(path, prefix_path);
222-
return (!rel.empty() && (rel.native() == "." || rel.native()[0] != '.'));
222+
if (rel.empty() || rel == "..")
223+
return false;
224+
225+
while (rel.has_relative_path())
226+
{
227+
rel = rel.parent_path();
228+
if (rel == "..")
229+
return false;
230+
}
231+
232+
return true;
223233
}
224234

225235
static bool fileOrSymlinkPathStartsWith(const std::filesystem::path & path, const std::filesystem::path & prefix_path)
@@ -230,7 +240,18 @@ static bool fileOrSymlinkPathStartsWith(const std::filesystem::path & path, cons
230240
/// not be a path of a symlink itself.
231241

232242
auto rel = fs::absolute(path).lexically_normal().lexically_relative(fs::absolute(prefix_path).lexically_normal());
233-
return (!rel.empty() && (rel.native() == "." || rel.native()[0] != '.'));
243+
244+
if (rel.empty() || rel == "..")
245+
return false;
246+
247+
while (rel.has_relative_path())
248+
{
249+
rel = rel.parent_path();
250+
if (rel == "..")
251+
return false;
252+
}
253+
254+
return true;
234255
}
235256

236257
bool pathStartsWith(const String & path, const String & prefix_path)

tests/queries/0_stateless/03624_proper_path_starts_with.sh

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,20 @@ BAD_PATH_PARENT=$(echo "${USER_FILES_PATH}" | sed 's:/*$::')/../BAD
99
BAD_PATH_EXTRA=$(echo "${USER_FILES_PATH}" | sed 's:/*$::')_BAD
1010

1111
$CLICKHOUSE_CLIENT --query "CREATE TABLE t (a UInt64) ENGINE=File('CSV', '${BAD_PATH_PARENT}') -- { serverError DATABASE_ACCESS_DENIED }"
12-
$CLICKHOUSE_CLIENT --query "CREATE TABLE t (a UInt64) ENGINE=File('CSV', '${BAD_PATH_EXTRA}') -- { serverError DATABASE_ACCESS_DENIED }"
12+
$CLICKHOUSE_CLIENT --query "CREATE TABLE t (a UInt64) ENGINE=File('CSV', '${BAD_PATH_EXTRA}') -- { serverError DATABASE_ACCESS_DENIED }"
13+
14+
# Check the behaviour with dots in the path
15+
# We allow paths like ./file or .file or ..file or a/../s.csv
16+
# But not paths that go to the parent directory like ../BAD or dir/../../BAD
17+
18+
GOOD_PATH_WITH_DOT=$(echo "${USER_FILES_PATH}/.file_that_does_not_exist_but_is_in_a_valid_path.csv")
19+
GOOD_PATH_WITH_DOTS=$(echo "${USER_FILES_PATH}/..file_that_does_not_exist_but_is_in_a_valid_path.csv")
20+
GOOD_PATH_WITH_DOTS_BUT_INSIDE=$(echo "${USER_FILES_PATH}/..a/../s.csv")
21+
BAD_PATH_PARENT_AFTER_SOME_DOTS=$(echo "${USER_FILES_PATH}" | sed 's:/*$::')/.DIR/../../BAD
22+
23+
$CLICKHOUSE_CLIENT --query "DROP TABLE IF EXISTS tdot, tdotdot, tdotdotin"
24+
25+
$CLICKHOUSE_CLIENT --query "CREATE TABLE tdot (a UInt64) ENGINE=File('CSV', '${GOOD_PATH_WITH_DOT}')"
26+
$CLICKHOUSE_CLIENT --query "CREATE TABLE tdotdot (a UInt64) ENGINE=File('CSV', '${GOOD_PATH_WITH_DOTS}')"
27+
$CLICKHOUSE_CLIENT --query "CREATE TABLE tdotdotin (a UInt64) ENGINE=File('CSV', '${GOOD_PATH_WITH_DOTS_BUT_INSIDE}')"
28+
$CLICKHOUSE_CLIENT --query "CREATE TABLE t (a UInt64) ENGINE=File('CSV', '${BAD_PATH_PARENT_AFTER_SOME_DOTS}') -- { serverError DATABASE_ACCESS_DENIED }"

0 commit comments

Comments
 (0)