-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Expand file tree
/
Copy pathWindowsStorageDeviceWatcher.cs
More file actions
168 lines (143 loc) · 5 KB
/
Copy pathWindowsStorageDeviceWatcher.cs
File metadata and controls
168 lines (143 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// Copyright (c) Files Community
// Licensed under the MIT License.
using Microsoft.Extensions.Logging;
using System.IO;
using System.Runtime.InteropServices;
using Windows.Devices.Enumeration;
using Windows.Devices.Portable;
using Windows.Storage;
namespace Files.App.Utils
{
public sealed class WindowsStorageDeviceWatcher : IStorageDeviceWatcher
{
public event EventHandler<IFolder>? DeviceAdded;
public event EventHandler<string>? DeviceRemoved;
public event EventHandler? EnumerationCompleted;
public event EventHandler<string>? DeviceModified;
private DeviceWatcher watcher;
public bool CanBeStarted => watcher.Status is DeviceWatcherStatus.Created or DeviceWatcherStatus.Stopped or DeviceWatcherStatus.Aborted;
public WindowsStorageDeviceWatcher()
{
watcher = DeviceInformation.CreateWatcher(StorageDevice.GetDeviceSelector());
watcher.Added += Watcher_Added;
watcher.Removed += Watcher_Removed;
watcher.EnumerationCompleted += Watcher_EnumerationCompleted;
SetupWin32Watcher();
}
private void SetupWin32Watcher()
{
WindowsDriveManager.Default.DeviceAdded += Win32_OnDeviceAdded;
WindowsDriveManager.Default.DeviceRemoved += Win32_OnDeviceRemoved;
WindowsDriveManager.Default.DeviceInserted += Win32_OnDeviceEjectedOrInserted;
WindowsDriveManager.Default.DeviceEjected += Win32_OnDeviceEjectedOrInserted;
}
private void Win32_OnDeviceEjectedOrInserted(object? sender, DeviceEventArgs e)
{
DeviceModified?.Invoke(this, e.DeviceId);
}
private void Win32_OnDeviceRemoved(object? sender, DeviceEventArgs e)
{
DeviceRemoved?.Invoke(this, e.DeviceId);
}
private async void Win32_OnDeviceAdded(object? sender, DeviceEventArgs e)
{
var driveAdded = new DriveInfo(e.DeviceId);
if (!driveAdded.IsReady && !IsUnauthorizedDrive(driveAdded))
return;
var rootResult = await FilesystemTasks.Wrap(() => StorageFolder.GetFolderFromPathAsync(e.DeviceId).AsTask());
if (rootResult.Result is not { } rootAdded)
{
App.Logger.LogWarning($"{rootResult.ErrorCode}: Attempting to add the device, {e.DeviceId},"
+ " failed at the StorageFolder initialization step. This device will be ignored.");
return;
}
var type = DriveHelpers.GetDriveType(driveAdded);
var label = DriveHelpers.GetExtendedDriveLabel(driveAdded);
DriveItem driveItem = await DriveItem.CreateFromPropertiesAsync(rootAdded, e.DeviceId, label, type);
DeviceAdded?.Invoke(this, driveItem);
}
private void Watcher_EnumerationCompleted(DeviceWatcher sender, object args)
{
EnumerationCompleted?.Invoke(this, EventArgs.Empty);
}
private void Watcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
DeviceRemoved?.Invoke(this, args.Id);
}
private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
string deviceId = args.Id;
StorageFolder root;
try
{
root = StorageDevice.FromId(deviceId);
}
catch (Exception ex) when (ex is ArgumentException or UnauthorizedAccessException or COMException)
{
App.Logger.LogWarning($"{ex.GetType()}: Attempting to add the device, {LogPathHelper.RedactPath(args.Name)},"
+ $" failed at the StorageFolder initialization step. This device will be ignored. Device ID: {deviceId}");
return;
}
Data.Items.DriveType type;
string label;
try
{
// Check if this drive is associated with a drive letter
var driveAdded = new DriveInfo(root.Path);
if (!driveAdded.IsReady && !IsUnauthorizedDrive(driveAdded))
return;
type = DriveHelpers.GetDriveType(driveAdded);
label = DriveHelpers.GetExtendedDriveLabel(driveAdded);
}
catch (ArgumentException)
{
type = Data.Items.DriveType.Removable;
label = string.Empty;
}
var driveItem = await DriveItem.CreateFromPropertiesAsync(root, deviceId, label, type);
DeviceAdded?.Invoke(this, driveItem);
}
public void Start()
{
WindowsDriveManager.Default.Start();
watcher.Start();
}
public void Stop()
{
if (watcher.Status is DeviceWatcherStatus.Started or DeviceWatcherStatus.EnumerationCompleted)
{
watcher.Stop();
}
watcher.Added -= Watcher_Added;
watcher.Removed -= Watcher_Removed;
watcher.EnumerationCompleted -= Watcher_EnumerationCompleted;
WindowsDriveManager.Default.DeviceAdded -= Win32_OnDeviceAdded;
WindowsDriveManager.Default.DeviceRemoved -= Win32_OnDeviceRemoved;
WindowsDriveManager.Default.DeviceInserted -= Win32_OnDeviceEjectedOrInserted;
WindowsDriveManager.Default.DeviceEjected -= Win32_OnDeviceEjectedOrInserted;
WindowsDriveManager.Default.Stop();
}
private bool IsUnauthorizedDrive(DriveInfo driveInfo)
{
try
{
_ = Directory.EnumerateFileSystemEntries(driveInfo.Name).FirstOrDefault();
return false;
}
catch (UnauthorizedAccessException)
{
// probably BitLocker locked drive.
return true;
}
catch (IOException ex) when (ex.HResult == unchecked((int)0x80310000)) // FVE_E_LOCKED_VOLUME
{
// BitLocker locked drive.
return true;
}
catch
{
return false;
}
}
}
}