This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-3311-f2409e9f5eaff1c643985013d927e17fdf16e6ec in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
commit 78fafa99fa77903545dfd3301c8db716f3482b2a Author: Yuhao Su <[email protected]> AuthorDate: Tue Oct 6 23:11:47 2026 +0000 fix(storage-azdls): drop the leading slash from relative paths (#3311) ADLS relative paths kept the leading `/` of the URL path, unlike the other backends. OpenDAL's Deleter passes paths to the service without normalizing them, so FileIO::delete_stream sent `DELETE <filesystem>//dir/file`, which ADLS rejects with 400 InvalidUri. Co-authored-by: Claude Opus 5.5 <[email protected]> --- crates/storage/opendal/src/azdls.rs | 28 +++++++++++++++++++++++----- crates/storage/opendal/src/lib.rs | 5 ++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/crates/storage/opendal/src/azdls.rs b/crates/storage/opendal/src/azdls.rs index 6d39320df..88a197fea 100644 --- a/crates/storage/opendal/src/azdls.rs +++ b/crates/storage/opendal/src/azdls.rs @@ -101,8 +101,7 @@ pub(crate) fn azdls_create_operator<'a>( // including their filesystem and account name. // OpenDAL's operator methods expect only the relative path, so we split it // off and save it for later use. - let relative_path_len = path.path.len(); - let (_, relative_path) = absolute_path.split_at(absolute_path.len() - relative_path_len); + let relative_path = path.relative_path(absolute_path); Ok((op, relative_path)) } @@ -237,6 +236,13 @@ impl AzureStoragePath { self.endpoint_suffix ) } + + /// The part of `absolute_path` below the filesystem, without a leading `/`, + /// like the relative paths of the other backends. + pub(crate) fn relative_path<'a>(&self, absolute_path: &'a str) -> &'a str { + let path = &absolute_path[absolute_path.len() - self.path.len()..]; + path.strip_prefix('/').unwrap_or(path) + } } impl FromStr for AzureStoragePath { @@ -395,7 +401,19 @@ mod tests { ..Default::default() }, ), - Some(("myfs", "/path/to/file.parquet")), + Some(("myfs", "path/to/file.parquet")), + ), + ( + "filesystem root", + ( + "abfss://[email protected]/", + AzdlsConfig { + account_name: Some("myaccount".to_string()), + endpoint: Some("https://myaccount.dfs.core.windows.net".to_string()), + ..Default::default() + }, + ), + Some(("myfs", "")), ), ( "different account", @@ -445,7 +463,7 @@ mod tests { ..Default::default() }, ), - Some(("myfs", "/path/to/file.parquet")), + Some(("myfs", "path/to/file.parquet")), ), ( "scheme differs from a previously-configured one is accepted", @@ -459,7 +477,7 @@ mod tests { ..Default::default() }, ), - Some(("myfs", "/path/to/file.parquet")), + Some(("myfs", "path/to/file.parquet")), ), ]; diff --git a/crates/storage/opendal/src/lib.rs b/crates/storage/opendal/src/lib.rs index f58d6f534..9e0155201 100644 --- a/crates/storage/opendal/src/lib.rs +++ b/crates/storage/opendal/src/lib.rs @@ -603,8 +603,7 @@ impl OpenDalStorage { OpenDalStorage::Azdls { config, .. } => { let azure_path = path.parse::<AzureStoragePath>()?; match_path_with_config(&azure_path, config)?; - let relative_path_len = azure_path.path.len(); - Ok(&path[path.len() - relative_path_len..]) + Ok(azure_path.relative_path(path)) } #[cfg(feature = "opendal-hf")] OpenDalStorage::Hf { .. } => { @@ -1176,7 +1175,7 @@ mod tests { storage .relativize_path("abfss://[email protected]/path/to/file.parquet") .unwrap(), - "/path/to/file.parquet" + "path/to/file.parquet" ); } }
