Skip to main content

cli/data/
path.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Shared path helpers for export/import data files.
16
17use crate::data::export_v2::schema::{DDL_DIR, SCHEMA_DIR};
18
19pub(crate) fn ddl_path_for_schema(schema: &str) -> String {
20    format!(
21        "{}/{}/{}.sql",
22        SCHEMA_DIR,
23        DDL_DIR,
24        encode_path_segment(schema)
25    )
26}
27
28pub(crate) fn encode_path_segment(value: &str) -> String {
29    let mut encoded = String::with_capacity(value.len());
30    for byte in value.bytes() {
31        match byte {
32            b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' => {
33                encoded.push(byte as char);
34            }
35            _ => {
36                encoded.push('%');
37                encoded.push(hex_char(byte >> 4));
38                encoded.push(hex_char(byte & 0x0F));
39            }
40        }
41    }
42    encoded
43}
44
45fn hex_char(nibble: u8) -> char {
46    match nibble {
47        0..=9 => (b'0' + nibble) as char,
48        10..=15 => (b'A' + (nibble - 10)) as char,
49        _ => unreachable!("nibble must be in 0..=15"),
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_encode_path_segment_preserves_safe_ascii() {
59        assert_eq!(encode_path_segment("test_db"), "test_db");
60    }
61
62    #[test]
63    fn test_encode_path_segment_escapes_path_traversal_chars() {
64        assert_eq!(encode_path_segment("../evil"), "%2E%2E%2Fevil");
65        assert_eq!(encode_path_segment(r"..\\evil"), "%2E%2E%5C%5Cevil");
66    }
67
68    #[test]
69    fn test_ddl_path_for_schema_encodes_schema_segment() {
70        assert_eq!(ddl_path_for_schema("public"), "schema/ddl/public.sql");
71        assert_eq!(
72            ddl_path_for_schema("../evil"),
73            "schema/ddl/%2E%2E%2Fevil.sql"
74        );
75    }
76}