diff --git a/Cargo.lock b/Cargo.lock index ee3fcd1e..59c9e400 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -1405,6 +1405,12 @@ dependencies = [ "digest", ] +[[package]] +name = "md5" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" + [[package]] name = "memchr" version = "2.7.5" @@ -1549,6 +1555,7 @@ dependencies = [ "futures", "http-auth-basic", "log", + "md5", "miette", "mini-redis", "nextcloud-config-parser", diff --git a/Cargo.toml b/Cargo.toml index 7553144b..f05f66c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ nextcloud-config-parser = "0.14.1" url = "2.5.4" clap = { version = "4.5.43", features = ["derive"] } sd-notify = { version = "0.4.5", optional = true } +md5 = "0.8.0" [dev-dependencies] mini-redis = "0.4.1" diff --git a/src/storage_mapping.rs b/src/storage_mapping.rs index c094e565..532dc68e 100644 --- a/src/storage_mapping.rs +++ b/src/storage_mapping.rs @@ -2,7 +2,6 @@ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ - use crate::error::DatabaseError; use crate::metrics::METRICS; use crate::{Result, UserId}; @@ -10,9 +9,11 @@ use ahash::RandomState; use dashmap::mapref::one::Ref; use dashmap::DashMap; use log::debug; +use md5; use rand::{thread_rng, Rng}; use sqlx::any::AnyConnectOptions; use sqlx::{query_as, Any, AnyPool, FromRow}; +use std::collections::HashMap; use std::time::Instant; use tokio::time::Duration; @@ -20,8 +21,8 @@ use tokio::time::Duration; pub struct UserStorageAccess { #[sqlx(rename = "user_id")] user: UserId, - #[sqlx(rename = "path")] - root: String, + #[sqlx(rename = "path_hash")] + root_hash: String, } struct CachedAccess { @@ -86,12 +87,25 @@ impl StorageMapping { storage: u32, path: &str, ) -> Result, DatabaseError> { + let mut parents: HashMap = HashMap::new(); + parents.insert(format!("{:x}", md5::compute("")), ()); + + let mut current_path = "".to_string(); + for name in path.split("/") { + if current_path.is_empty() { + current_path = name.to_string(); + } else { + current_path = format!("{}/{}", current_path.clone(), name); + } + parents.insert(format!("{:x}", md5::compute(¤t_path)), ()); + } + let cached = self.get_storage_mapping(storage).await?; Ok(cached .access .iter() .filter_map(move |access| { - if path.starts_with(&access.root) { + if parents.contains_key(&access.root_hash) { Some(access.user.clone()) } else { None @@ -108,7 +122,7 @@ impl StorageMapping { debug!("querying storage mapping for {storage}"); let users = query_as::(&format!( "\ - SELECT user_id, path \ + SELECT user_id, path_hash \ FROM {prefix}mounts \ INNER JOIN {prefix}filecache ON root_id = fileid \ WHERE storage_id = {storage}", diff --git a/tests/integration.rs b/tests/integration.rs index 6e8d78f2..ae3a69d2 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -82,7 +82,7 @@ impl Services { .await .expect("Failed to connect sqlite database"); - sqlx::query("CREATE TABLE oc_filecache(fileid BIGINT, path TEXT)") + sqlx::query("CREATE TABLE oc_filecache(fileid BIGINT, path_hash TEXT)") .execute(&db) .await .unwrap(); @@ -237,9 +237,9 @@ impl Services { } async fn add_filecache_item(&self, fileid: u32, path: &str) { - sqlx::query("INSERT INTO oc_filecache(fileid, path) VALUES(?, ?)") + sqlx::query("INSERT INTO oc_filecache(fileid, path_hash) VALUES(?, ?)") .bind(fileid as i64) - .bind(path) + .bind(format!("{:x}", md5::compute(path))) .execute(&self.db) .await .unwrap();