This is an automated email from the ASF dual-hosted git repository.
julianhyde pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 32ef284f88 [CALCITE-7496] OS-adapter usability
32ef284f88 is described below
commit 32ef284f88e5ca57d0ba8719751188b5fdfd596b
Author: Julian Hyde <[email protected]>
AuthorDate: Tue Apr 28 19:06:30 2026 -0700
[CALCITE-7496] OS-adapter usability
---
.../calcite/adapter/os/FilesTableFunction.java | 38 ++++++++++++++--------
.../apache/calcite/adapter/os/OsAdapterTest.java | 16 +++++++++
2 files changed, 41 insertions(+), 13 deletions(-)
diff --git
a/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java
b/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java
index 8c7b3cc815..3df9498c35 100644
--- a/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java
+++ b/plus/src/main/java/org/apache/calcite/adapter/os/FilesTableFunction.java
@@ -44,8 +44,7 @@
public class FilesTableFunction {
private static final BigDecimal THOUSAND = BigDecimal.valueOf(1000L);
- private static final String SINGLE_QUOTE =
- "Path with single quote characters are not supported";
+
private FilesTableFunction() {
}
@@ -87,9 +86,28 @@ public static ScannableTable eval(final String path) {
// %p file name (including argument)
}
+ /** Wraps {@code path} in single quotes for use in a shell command,
+ * throwing if it contains a single quote. */
+ private String quotePath() {
+ return "'" + validatePath(path) + "'";
+ }
+
+ /** Checks that {@code path} is valid and will not cause mischief. */
+ private String validatePath(String path) {
+ if (path.contains("'")) {
+ throw new IllegalArgumentException(
+ "Path with single quote characters is not supported");
+ }
+ if (path.startsWith("-")) {
+ throw new IllegalArgumentException(
+ "Path with leading dash character is not supported");
+ }
+ return path;
+ }
+
private Enumerable<String> sourceLinux() {
final String[] args = {
- "find", path, "-printf", ""
+ "find", "--", validatePath(path), "-printf", ""
+ "%A@\\0" // access_time
+ "%b\\0" // block_count
+ "%C@\\0" // change_time
@@ -115,12 +133,9 @@ private Enumerable<String> sourceLinux() {
}
private Enumerable<String> sourceMacOs() {
- if (path.contains("'")) {
- throw new IllegalArgumentException(SINGLE_QUOTE);
- }
// BSD stat format specifiers:
https://man.freebsd.org/cgi/man.cgi?query=stat
- final String[] args = {"/bin/sh", "-c", "find '" + path
- + "' | xargs stat -f "
+ final String[] args = {"/bin/sh", "-c", "find -- " + quotePath()
+ + " -print0 | xargs -0 stat -f "
+ "%a%n" // access_time
+ "%b%n" // block_count
+ "%c%n" // change_time
@@ -146,14 +161,11 @@ private Enumerable<String> sourceMacOs() {
}
private Enumerable<String> sourceGnuStat() {
- if (path.contains("'")) {
- throw new IllegalArgumentException(SINGLE_QUOTE);
- }
// GNU stat format specifiers:
//
https://www.gnu.org/software/coreutils/manual/html_node/stat-invocation.html
// format string must have exactly 20 lines per file to match the
schema
- final String[] args = {"/bin/sh", "-c", "find '" + path
- + "' | xargs stat -c '"
+ final String[] args = {"/bin/sh", "-c", "find -- " + quotePath()
+ + " -print0 | xargs -0 stat -c '"
+ "%X\n" // access_time
+ "%b\n" // block_count
+ "%Z\n" // change_time
diff --git
a/plus/src/test/java/org/apache/calcite/adapter/os/OsAdapterTest.java
b/plus/src/test/java/org/apache/calcite/adapter/os/OsAdapterTest.java
index e1158d5aa6..602c613038 100644
--- a/plus/src/test/java/org/apache/calcite/adapter/os/OsAdapterTest.java
+++ b/plus/src/test/java/org/apache/calcite/adapter/os/OsAdapterTest.java
@@ -149,6 +149,22 @@ private static boolean checkProcessExists(String command) {
"type=f");
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7496">[CALCITE-7496]
+ * The 'files(path)' table function should not allow paths with a leading
+ * dash</a>.
+ *
+ * <p>GNU {@code find} treats an argument beginning with '{@code -}' as an
+ * expression primary rather than a filesystem path. This can cause mischief.
+ * This test verifies that leading-dash paths are rejected using the harmless
+ * {@code -name} expression.
+ */
+ @Test void testFilesLeadingDashPath() {
+ assumeFalse(Util.isWindows(), "Skip: the 'files' table does not work on
Windows");
+ sql("select * from files('-name')")
+ .throws_("Path with leading dash character is not supported");
+ }
+
@Test void testPs() {
assumeFalse(Util.isWindows(), "Skip: the 'ps' table does not work on
Windows");
assumeToolExists("ps");