docs/core/volumes.mdx
Spacedrive detects and tracks storage volumes across all platforms, including local drives and cloud storage. The volume system enables intelligent file operations by understanding where data lives and how to move it efficiently.
The volume system operates in two modes:
When you connect a drive or add cloud storage, Spacedrive detects it immediately. If you choose to track that volume, it remembers your preferences and recognizes it when reconnected.
Spacedrive supports two types of storage backends:
Each volume gets a unique fingerprint based on hardware identifiers, capacity, and filesystem type:
let volume = volume_manager.volume_for_path(&path).await;
println!("Volume: {} ({})", volume.name, volume.fingerprint);
This fingerprint remains stable even when mount points change.
Volumes serve as the ownership anchor for the sync system. Entries and locations reference a volume, inheriting ownership from the volume's device. This indirection enables portable storage: when you plug an external drive into a different machine, updating the volume's device reference transfers ownership of all associated files instantly. No bulk updates needed.
<Info> See [Library Sync](/docs/core/library-sync) for details on how ownership flows through volumes and enables seamless device transfers. </Info>Spacedrive uses service-native URIs for cloud volumes that match industry tools:
s3://my-bucket/photos/vacation.jpg ← Amazon S3
gdrive://My Drive/Documents/report.pdf ← Google Drive
onedrive://Documents/budget.xlsx ← OneDrive
azblob://container/data/export.csv ← Azure Blob
gcs://bucket/logs/app.log ← Google Cloud Storage
These URIs work identically to local volume paths and enable seamless operations across all storage backends. See Unified Addressing for complete details.
Spacedrive recognizes major filesystems including APFS, NTFS, Ext4, Btrfs, ZFS, FAT32, and ExFAT.
Supports 40+ cloud services via OpenDAL:
// Find volume for a path
let volume = volume_manager.volume_for_path("/Users/data").await;
// List all volumes
let volumes = volume_manager.get_all_volumes().await;
// Check available space
let available = volume.total_bytes_available;
Convert a runtime-detected volume into a tracked volume:
volume_manager.track_volume(
&volume.fingerprint,
&library_context,
Some("My Backup Drive".to_string())
).await?;
Tracked volumes persist across sessions and can have custom names, colors, and icons.
Add cloud storage as a tracked volume:
use sd_core::ops::volumes::add_cloud::{CloudStorageConfig, VolumeAddCloudInput};
// Add S3 bucket via action
let input = VolumeAddCloudInput {
service: CloudServiceType::S3,
display_name: "My S3 Bucket".to_string(),
config: CloudStorageConfig::S3 {
bucket: "my-bucket".to_string(),
region: "us-west-2".to_string(),
access_key_id: "AKIAXXXX".to_string(),
secret_access_key: "secret".to_string(),
endpoint: None, // Optional: for S3-compatible services
},
};
let output = action_manager.execute(input, library, context).await?;
Add cloud volumes from the command line:
# Amazon S3
sd volume add-cloud "My S3 Bucket" \
--service s3 \
--bucket my-bucket \
--region us-west-2 \
--access-key-id AKIAXXXX \
--secret-access-key secret123
# Cloudflare R2
sd volume add-cloud "R2 Storage" \
--service s3 \
--bucket my-r2-bucket \
--region auto \
--access-key-id xxx \
--secret-access-key yyy \
--endpoint https://account.r2.cloudflarestorage.com
# MinIO (self-hosted)
sd volume add-cloud "MinIO Local" \
--service s3 \
--bucket test \
--region us-east-1 \
--access-key-id minioadmin \
--secret-access-key minioadmin \
--endpoint http://localhost:9000
# Remove cloud volume
sd volume remove-cloud <fingerprint> -y
Cloud volumes work identically to local volumes for indexing, searching, and file operations.
Monitor volume state changes:
let mut events = event_bus.subscribe();
while let Ok(event) = events.recv().await {
match event {
Event::VolumeAdded(volume) => {
// New volume connected
}
Event::VolumeRemoved { fingerprint } => {
// Volume disconnected
}
_ => {}
}
}
Spacedrive uses optimal copy strategies based on the storage backend:
if volume.supports_cow() {
// Use fast COW copy (APFS, Btrfs, ZFS, ReFS)
perform_cow_copy(&src, &dst).await?;
} else if volume.supports_server_side_copy() {
// Cloud server-side copy (S3, GCS, Azure)
perform_server_side_copy(&src, &dst).await?;
} else {
// Standard streaming copy
perform_regular_copy(&src, &dst).await?;
}
Volume awareness enables optimal file operations:
// Check if paths are on same volume
let same_volume = volume_manager.same_volume(&src, &dst).await;
if same_volume {
// Fast move operation (local) or server-side rename (cloud)
fs::rename(&src, &dst).await?;
} else {
// Cross-volume copy required
copy_cross_volume(&src, &dst).await?;
}
Cloud volumes automatically use efficient operations:
Test volume read/write speeds:
let (read_mbps, write_mbps) = volume_manager
.run_speed_test(&fingerprint).await?;
Uses diskutil and df to detect APFS volumes and identify SSD/HDD types.
Parses /sys/block/ and df output for filesystem and disk type information.
Uses PowerShell cmdlets for volume enumeration (implementation pending).
Uses OpenDAL for unified cloud service integration. Credentials are encrypted with library keys and stored securely in the OS keyring.
Fully integrated and tested:
Implemented with OpenDAL backend:
Note: OAuth flow for consumer cloud services (Google Drive, Dropbox, OneDrive) requires manual credential setup. Native OAuth integration coming soon.
Cloud credentials are:
let config = VolumeDetectionConfig {
include_system: false, // Skip system volumes
include_virtual: false, // Skip virtual filesystems
refresh_interval_secs: 30, // Monitor interval
};
let volume_manager = VolumeManager::new(device_id, config, event_bus);
Cloud volumes require service-specific configuration:
// S3-compatible services
CloudStorageConfig::S3 {
bucket: "bucket-name".to_string(),
region: "us-west-2".to_string(),
access_key_id: "key".to_string(),
secret_access_key: "secret".to_string(),
endpoint: Some("https://custom-endpoint.com".to_string()), // Optional
}
The endpoint parameter enables use of S3-compatible services:
https://<account>.r2.cloudflarestorage.comhttp://localhost:9000 or your server URLhttps://s3.<region>.wasabisys.comhttps://s3.<region>.backblazeb2.comhttps://<region>.digitaloceanspaces.commatch volume_manager.track_volume(&library, &fingerprint, None).await {
Ok(tracked) => {
println!("Volume tracked: {}", tracked.display_name.unwrap_or_default());
}
Err(VolumeError::NotFound(fp)) => {
// Volume no longer available
}
Err(VolumeError::Platform(msg)) => {
// Platform-specific error
}
Err(VolumeError::Database(msg)) => {
// Database operation failed
}
}
Cloud volumes may encounter additional error conditions:
use sd_core::crypto::cloud_credentials::CloudCredentialError;
match credential_manager.get_credential(library_id, &fingerprint) {
Ok(cred) => { /* Use credentials */ }
Err(CloudCredentialError::NotFound(lib_id, fp)) => {
// Credentials not found - volume may have been removed
}
Err(CloudCredentialError::Keyring(e)) => {
// OS keyring access failed
}
Err(CloudCredentialError::Decryption(e)) => {
// Credential decryption failed - may need re-authentication
}
}
When users add a location, suggest tracking its volume:
if let Some(volume) = volume_manager.volume_for_path(&location_path).await {
if !volume_manager.is_volume_tracked(&volume.fingerprint).await? {
// Prompt: "Track this volume for better performance?"
}
}
Before large operations:
let required_bytes = calculate_operation_size();
let volumes = volume_manager.volumes_with_space(required_bytes).await;
if volumes.is_empty() {
return Err("Insufficient space on any volume");
}
Tracked volumes maintain statistics:
These help users understand their storage usage and performance characteristics.
Spacedrive uses consistent content hashing across all storage backends:
// Same file gets same content hash regardless of location
let local_hash = hash_file("/local/photo.jpg").await?;
let cloud_hash = hash_file("s3://bucket/photo.jpg").await?;
assert_eq!(local_hash, cloud_hash); // Same content = same hash
This enables true cross-storage deduplication: