Skip to content

Commit 7d05d18

Browse files
Fix builds on windows (#2864)
* Fix builds on windows * Fix rust compile issues * Autoformat * Fix windows volumes compile again --------- Co-authored-by: Arnab Chakraborty <[email protected]>
1 parent 193a693 commit 7d05d18

File tree

8 files changed

+109
-81
lines changed

8 files changed

+109
-81
lines changed

.github/workflows/release.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,6 @@ jobs:
100100
with:
101101
token: ${{ secrets.GITHUB_TOKEN }}
102102

103-
- name: Run pnpm prep
104-
run: |
105-
pnpm prep
106-
107103
- name: Build
108104
run: |
109105
pnpm tauri build --ci -v --target ${{ matrix.settings.target }} --bundles ${{ matrix.settings.bundles }}

apps/desktop/src/commands.ts

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/Cargo.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ http-range = "0.1.5"
9595
hyper-util = { version = "0.1.9", features = ["tokio"] }
9696
int-enum = "0.5" # Update blocked due to API breaking changes
9797
mini-moka = "0.10.3"
98+
once_cell = "1.19.0"
9899
serde-hashkey = "0.4.5"
99100
serde_repr = "0.1.19"
100101
serde_with = "3.8"
@@ -104,7 +105,6 @@ tar = "0.4.41"
104105
tower-service = "0.3.2"
105106
tracing-appender = "0.2.3"
106107
whoami = "1.5.2"
107-
once_cell = "1.19.0"
108108

109109
[dependencies.tokio]
110110
features = ["io-util", "macros", "process", "rt-multi-thread", "sync", "time"]
@@ -130,12 +130,17 @@ plist = "1.6"
130130
trash = "5.1"
131131

132132
[target.'cfg(target_os = "linux")'.dependencies]
133-
trash = "5.1"
134133
inotify = "0.11.0"
134+
trash = "5.1"
135135

136136
[target.'cfg(target_os = "windows")'.dependencies]
137-
trash = "5.1"
138-
windows = { features = ["Win32_Storage_FileSystem"], version = "0.58" }
137+
trash = "5.1"
138+
windows = { features = [
139+
"Win32_Storage_FileSystem",
140+
"Win32_System_IO",
141+
"Win32_System_Ioctl",
142+
"Win32_System_WindowsProgramming"
143+
], version = "0.58" }
139144

140145
[target.'cfg(target_os = "ios")'.dependencies]
141146
icrate = { version = "0.1.2", features = [

core/crates/cloud-services/src/client.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use quic_rpc::{transport::quinn::QuinnConnector, RpcClient, RpcMessage};
1010
use quinn::{crypto::rustls::QuicClientConfig, ClientConfig, Endpoint};
1111
use reqwest::{IntoUrl, Url};
1212
use reqwest_middleware::{reqwest, ClientBuilder, ClientWithMiddleware};
13-
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
1413
use tokio::sync::{Mutex, RwLock};
1514
use tracing::warn;
1615

core/src/library/statistics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ pub async fn update_library_statistics(
3939

4040
if total_capacity == 0 && available_capacity == 0 {
4141
// Failed to fetch volume statistics from database, so we compute from local volumes
42+
#[cfg(any(target_os = "linux", target_os = "macos"))]
4243
let volumes = crate::volume::get_volumes().await?;
4344

45+
#[cfg(target_os = "windows")]
46+
let volumes = crate::volume::get_volumes().await;
47+
4448
let mut local_total_capacity: u64 = 0;
4549
let mut local_available_capacity: u64 = 0;
4650
for volume in volumes {

core/src/volume/os.rs

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ mod common {
2727
pub fn parse_size(size_str: &str) -> u64 {
2828
size_str
2929
.chars()
30-
.filter(|c| c.is_digit(10))
30+
.filter(|c| c.is_ascii_digit())
3131
.collect::<String>()
3232
.parse()
3333
.unwrap_or(0)
@@ -315,19 +315,23 @@ pub mod linux {
315315
pub mod windows {
316316
use super::*;
317317
use std::ffi::OsString;
318-
use std::os::windows::ffi::OsStringExt;
319-
use windows::Win32::Storage::FileSystem::{
320-
GetDiskFreeSpaceExW, GetDriveTypeW, GetVolumeInformationW, DRIVE_FIXED, DRIVE_REMOTE,
321-
DRIVE_REMOVABLE,
318+
use std::path::PathBuf;
319+
320+
use ::windows::core::PCWSTR;
321+
use ::windows::Win32::Storage::FileSystem::{
322+
GetDiskFreeSpaceExW, GetDriveTypeW, GetVolumeInformationW,
323+
};
324+
use ::windows::Win32::System::WindowsProgramming::{
325+
DRIVE_FIXED, DRIVE_REMOTE, DRIVE_REMOVABLE,
322326
};
323-
use windows::Win32::System::Ioctl::STORAGE_PROPERTY_QUERY;
327+
use std::os::windows::ffi::OsStrExt;
324328

325329
pub async fn get_volumes() -> Vec<Volume> {
326330
task::spawn_blocking(|| {
327331
let mut volumes = Vec::new();
328332

329333
// Get available drives
330-
let drives = unsafe { windows::Win32::Storage::FileSystem::GetLogicalDrives() };
334+
let drives = unsafe { ::windows::Win32::Storage::FileSystem::GetLogicalDrives() };
331335

332336
for i in 0..26 {
333337
if (drives & (1 << i)) != 0 {
@@ -338,7 +342,7 @@ pub mod windows {
338342
.chain(std::iter::once(0))
339343
.collect();
340344

341-
let drive_type = unsafe { GetDriveTypeW(wide_path.as_ptr()) };
345+
let drive_type = unsafe { GetDriveTypeW(PCWSTR(wide_path.as_ptr())) };
342346

343347
// Skip CD-ROM drives and other unsupported types
344348
if drive_type == DRIVE_FIXED
@@ -379,29 +383,25 @@ pub mod windows {
379383

380384
unsafe {
381385
let success = GetVolumeInformationW(
382-
wide_path.as_ptr(),
383-
name_buf.as_mut_ptr(),
384-
name_buf.len() as u32,
385-
&mut serial_number,
386-
&mut max_component_length,
387-
&mut flags,
388-
fs_name_buf.as_mut_ptr(),
389-
fs_name_buf.len() as u32,
386+
PCWSTR(wide_path.as_ptr()),
387+
Some(name_buf.as_mut_slice()),
388+
Some(&mut serial_number),
389+
Some(&mut max_component_length),
390+
Some(&mut flags),
391+
Some(&mut fs_name_buf),
390392
);
391393

392-
if success.as_bool() {
394+
if let Ok(_) = success {
393395
let mut total_bytes = 0;
394396
let mut free_bytes = 0;
395397
let mut available_bytes = 0;
396398

397-
if GetDiskFreeSpaceExW(
398-
wide_path.as_ptr(),
399-
&mut available_bytes,
400-
&mut total_bytes,
401-
&mut free_bytes,
402-
)
403-
.as_bool()
404-
{
399+
if let Ok(_) = GetDiskFreeSpaceExW(
400+
PCWSTR(wide_path.as_ptr()),
401+
Some(&mut available_bytes),
402+
Some(&mut total_bytes),
403+
Some(&mut free_bytes),
404+
) {
405405
let mount_type = match drive_type {
406406
DRIVE_FIXED => MountType::System,
407407
DRIVE_REMOVABLE => MountType::External,
@@ -425,10 +425,12 @@ pub mod windows {
425425
},
426426
mount_type,
427427
PathBuf::from(path),
428+
vec![PathBuf::from(path)],
428429
detect_disk_type(path),
429430
FileSystem::from_string(&fs_name),
430-
total_bytes as u64,
431-
available_bytes as u64,
431+
total_bytes,
432+
available_bytes,
433+
false,
432434
))
433435
} else {
434436
None
@@ -440,37 +442,39 @@ pub mod windows {
440442
}
441443

442444
pub async fn unmount_volume(path: &std::path::Path) -> Result<(), VolumeError> {
443-
use std::ffi::OsStr;
444-
use std::os::windows::ffi::OsStrExt;
445-
use windows::core::PWSTR;
446-
use windows::Win32::Storage::FileSystem::{
445+
use ::windows::core::PWSTR;
446+
use ::windows::Win32::Storage::FileSystem::{
447447
DeleteVolumeMountPointW, GetVolumeNameForVolumeMountPointW,
448448
};
449+
use std::ffi::OsStr;
450+
use std::os::windows::ffi::OsStrExt;
449451

450452
// Convert path to wide string for Windows API
451-
let wide_path: Vec<u16> = OsStr::new(path)
453+
let mut wide_path: Vec<u16> = OsStr::new(path)
452454
.encode_wide()
453455
.chain(std::iter::once(0))
454456
.collect();
455457

458+
let wide_path_ptr = PWSTR(wide_path.as_mut_ptr());
459+
456460
unsafe {
457461
// Buffer for volume name
458462
let mut volume_name = [0u16; 50];
459-
let mut volume_name_ptr = PWSTR(volume_name.as_mut_ptr());
460463

461464
// Get the volume name for the mount point
462-
let result = GetVolumeNameForVolumeMountPointW(wide_path.as_ptr(), volume_name_ptr);
465+
let result =
466+
GetVolumeNameForVolumeMountPointW(wide_path_ptr, volume_name.as_mut_slice());
463467

464-
if !result.as_bool() {
468+
if result.is_err() {
465469
return Err(VolumeError::Platform(
466470
"Failed to get volume name".to_string(),
467471
));
468472
}
469473

470474
// Delete the mount point
471-
let result = DeleteVolumeMountPointW(wide_path.as_ptr());
475+
let result = DeleteVolumeMountPointW(wide_path_ptr);
472476

473-
if result.as_bool() {
477+
if let Ok(_) = result {
474478
Ok(())
475479
} else {
476480
Err(VolumeError::Platform(

core/src/volume/state.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
library::Library,
33
volume::{
44
speed::SpeedTest,
5-
types::{LibraryId, Volume, VolumeEvent, VolumeFingerprint, VolumePubId},
5+
types::{Volume, VolumeEvent, VolumeFingerprint},
66
},
77
};
88

@@ -84,7 +84,12 @@ impl VolumeManagerState {
8484
}
8585

8686
pub async fn scan_volumes(&mut self) -> Result<(), VolumeError> {
87+
#[cfg(any(target_os = "linux", target_os = "macos"))]
8788
let detected_volumes = super::os::get_volumes().await?;
89+
90+
#[cfg(target_os = "windows")]
91+
let detected_volumes = super::os::get_volumes().await;
92+
8893
let mut registry = self.registry.write().await;
8994

9095
// Track existing volumes for removal detection
@@ -192,7 +197,7 @@ impl VolumeManagerState {
192197
for (fingerprint, volume) in registry.volumes() {
193198
let mut volume = volume.clone();
194199

195-
if let Some(db_volume) = db_volumes.get(&fingerprint) {
200+
if let Some(db_volume) = db_volumes.get(fingerprint) {
196201
volume = Volume::merge_with_db(&volume, db_volume);
197202
}
198203

core/src/volume/watcher.rs

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use tokio::{
1010
sync::{broadcast, mpsc, RwLock},
1111
time::{sleep, Instant},
1212
};
13-
use tracing::{debug, error, warn};
13+
use tracing::{debug, error};
1414

1515
const DEBOUNCE_MS: u64 = 100;
1616

@@ -58,35 +58,40 @@ impl VolumeWatcher {
5858
}
5959
last_check = Instant::now();
6060

61-
match super::os::get_volumes().await {
62-
Ok(discovered_volumes) => {
63-
let actor = actor.lock().await;
61+
#[cfg(any(target_os = "linux", target_os = "macos"))]
62+
let discovered_volumes = match super::os::get_volumes().await {
63+
Ok(volumes) => volumes,
64+
Err(e) => {
65+
error!("Failed to get volumes: {}", e);
66+
// Return empty volumes to avoid sending events
67+
vec![]
68+
}
69+
};
6470

65-
// Find new volumes
66-
for volume in &discovered_volumes {
67-
let fingerprint = VolumeFingerprint::new(&device_id, volume);
71+
#[cfg(target_os = "windows")]
72+
let discovered_volumes = super::os::get_volumes().await;
6873

69-
let volume_exists = actor.volume_exists(fingerprint.clone()).await;
70-
// if the volume doesn't exist in the actor state, we need to send an event
71-
if !volume_exists {
72-
let _ = event_tx.send(VolumeEvent::VolumeAdded(volume.clone()));
73-
}
74-
}
74+
let actor = actor.lock().await;
7575

76-
// Find removed volumes and send an event
77-
for volume in &actor.get_volumes().await {
78-
let fingerprint = VolumeFingerprint::new(&device_id, volume);
79-
if !discovered_volumes
80-
.iter()
81-
.any(|v| VolumeFingerprint::new(&device_id, v) == fingerprint)
82-
{
83-
let _ =
84-
event_tx.send(VolumeEvent::VolumeRemoved(volume.clone()));
85-
}
86-
}
76+
// Find new volumes
77+
for volume in &discovered_volumes {
78+
let fingerprint = VolumeFingerprint::new(&device_id, volume);
79+
80+
let volume_exists = actor.volume_exists(fingerprint.clone()).await;
81+
// if the volume doesn't exist in the actor state, we need to send an event
82+
if !volume_exists {
83+
let _ = event_tx.send(VolumeEvent::VolumeAdded(volume.clone()));
8784
}
88-
Err(e) => {
89-
warn!("Failed to get volumes during watch: {}", e);
85+
}
86+
87+
// Find removed volumes and send an event
88+
for volume in &actor.get_volumes().await {
89+
let fingerprint = VolumeFingerprint::new(&device_id, volume);
90+
if !discovered_volumes
91+
.iter()
92+
.any(|v| VolumeFingerprint::new(&device_id, v) == fingerprint)
93+
{
94+
let _ = event_tx.send(VolumeEvent::VolumeRemoved(volume.clone()));
9095
}
9196
}
9297
}
@@ -183,24 +188,31 @@ impl VolumeWatcher {
183188

184189
#[cfg(target_os = "windows")]
185190
{
186-
use windows::Win32::Storage::FileSystem::{
187-
FindFirstVolumeW, FindNextVolumeW, FindVolumeClose, ReadDirectoryChangesW,
188-
FILE_NOTIFY_CHANGE_DIR_NAME,
189-
};
191+
use ::windows::Win32::Storage::FileSystem::{FindFirstVolumeW, FindVolumeClose};
190192

191193
let check_tx = check_tx.clone();
192194
tokio::spawn(async move {
193195
while *running.read().await {
194196
// Watch for volume arrival/removal
195197
unsafe {
196198
let mut volume_name = [0u16; 260];
197-
let handle = FindFirstVolumeW(volume_name.as_mut_ptr());
198-
if !handle.is_invalid() {
199+
let mut volume_change_detected = false;
200+
match FindFirstVolumeW(volume_name.as_mut_slice()) {
201+
Ok(handle) => {
202+
if !handle.is_invalid() {
203+
volume_change_detected = true;
204+
FindVolumeClose(handle);
205+
}
206+
}
207+
Err(e) => {
208+
error!("Failed to get a volume handle: {}", e);
209+
}
210+
}
211+
if volume_change_detected {
199212
// Volume change detected
200213
if let Err(e) = check_tx.send(()).await {
201214
error!("Failed to trigger volume check: {}", e);
202215
}
203-
FindVolumeClose(handle);
204216
}
205217
}
206218
sleep(Duration::from_millis(100)).await;

0 commit comments

Comments
 (0)