mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-19 05:45:01 -04:00
fix(locations): canonicalize paths and register watcher on location add
Two upstream bugs fixed: 1. LocationManager::add_location() stored paths as-is without canonicalization. Relative paths (e.g. from cwd-dependent contexts) broke the watcher, volume manager, and indexer pipelines. Now calls tokio::fs::canonicalize() on local physical paths before storing, with UNC prefix stripping on Windows. 2. LocationAddAction::execute() never registered new locations with the FsWatcherService. The watcher only discovered locations at startup via load_library_locations(). Any location added at runtime had no filesystem monitoring — creates, deletes, and renames went undetected. Now calls fs_watcher.watch_location() after successful creation.
This commit is contained in:
@@ -46,6 +46,40 @@ impl LocationManager {
|
||||
job_policies: Option<String>,
|
||||
volume_manager: &crate::volume::VolumeManager,
|
||||
) -> LocationResult<(Uuid, String)> {
|
||||
// Canonicalize local physical paths to absolute form before storing.
|
||||
// Relative paths break the watcher, volume resolution, and indexer.
|
||||
// Only for local device — remote paths can't be resolved locally.
|
||||
let sd_path = if sd_path.is_local() {
|
||||
if let crate::domain::addressing::SdPath::Physical { device_slug, path } = sd_path {
|
||||
let canonical = tokio::fs::canonicalize(&path).await.map_err(|e| {
|
||||
LocationError::InvalidPath(format!(
|
||||
"Failed to resolve path {}: {}",
|
||||
path.display(),
|
||||
e
|
||||
))
|
||||
})?;
|
||||
// On Windows, canonicalize() returns UNC paths (\\?\C:\...) which break
|
||||
// starts_with() matching throughout the codebase. Strip the prefix.
|
||||
#[cfg(windows)]
|
||||
let canonical = {
|
||||
let s = canonical.to_string_lossy();
|
||||
if let Some(stripped) = s.strip_prefix(r"\\?\") {
|
||||
std::path::PathBuf::from(stripped)
|
||||
} else {
|
||||
canonical
|
||||
}
|
||||
};
|
||||
crate::domain::addressing::SdPath::Physical {
|
||||
device_slug,
|
||||
path: canonical,
|
||||
}
|
||||
} else {
|
||||
sd_path
|
||||
}
|
||||
} else {
|
||||
sd_path
|
||||
};
|
||||
|
||||
info!("Adding location: {}", sd_path);
|
||||
|
||||
// Validate the path based on type
|
||||
|
||||
@@ -102,6 +102,31 @@ impl LibraryAction for LocationAddAction {
|
||||
.await
|
||||
.map_err(|e| ActionError::Internal(e.to_string()))?;
|
||||
|
||||
// Register the new location with the filesystem watcher so changes
|
||||
// (creates, deletes, renames) are detected in real-time.
|
||||
// Without this, the watcher only learns about locations at startup.
|
||||
if let Some(local_path) = self.input.path.as_local_path() {
|
||||
if let Some(fs_watcher) = context.get_fs_watcher().await {
|
||||
use crate::ops::indexing::handlers::LocationMeta;
|
||||
use crate::ops::indexing::RuleToggles;
|
||||
|
||||
// Use canonical path to match what add_location stored in DB
|
||||
let root_path = tokio::fs::canonicalize(local_path)
|
||||
.await
|
||||
.unwrap_or_else(|_| local_path.to_path_buf());
|
||||
|
||||
let meta = LocationMeta {
|
||||
id: location_id,
|
||||
library_id: library.id(),
|
||||
root_path,
|
||||
rule_toggles: RuleToggles::default(),
|
||||
};
|
||||
if let Err(e) = fs_watcher.watch_location(meta).await {
|
||||
tracing::warn!("Failed to register location with watcher: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the job ID from the string returned by add_location
|
||||
let job_id = if !job_id_string.is_empty() {
|
||||
Some(
|
||||
|
||||
Reference in New Issue
Block a user