2
2
// Licensed under the MIT License. See the LICENSE.
3
3
4
4
using Microsoft . Data . Sqlite ;
5
- using Microsoft . Extensions . Logging ;
6
- using Microsoft . Win32 ;
7
5
using System . IO ;
8
6
using Windows . Storage ;
9
- using Vanara . Windows . Shell ;
10
7
11
8
namespace Files . App . Utils . Cloud
12
9
{
13
10
/// <summary>
14
- /// Provides a utility for Google Drive Cloud detection.
11
+ /// Provides an utility for Google Drive Cloud detection.
15
12
/// </summary>
16
13
public sealed class GoogleDriveCloudDetector : AbstractCloudDetector
17
14
{
18
- private static readonly ILogger _logger = Ioc . Default . GetRequiredService < ILogger < App > > ( ) ;
19
-
20
- private const string _googleDriveRegKeyName = @"Software\Google\DriveFS" ;
21
- private const string _googleDriveRegValName = "PerAccountPreferences" ;
22
- private const string _googleDriveRegValPropName = "value" ;
23
- private const string _googleDriveRegValPropPropName = "mount_point_path" ;
24
-
25
15
protected override async IAsyncEnumerable < ICloudProvider > GetProviders ( )
26
16
{
27
17
// Google Drive's sync database can be in a couple different locations. Go find it.
@@ -66,8 +56,7 @@ await FilesystemTasks.Wrap(() => StorageFile.GetFileFromPathAsync(Path.Combine(a
66
56
var folder = await StorageFolder . GetFolderFromPathAsync ( path ) ;
67
57
string title = reader [ "title" ] ? . ToString ( ) ?? folder . Name ;
68
58
69
- Debug . WriteLine ( "YIELD RETURNING from `GoogleDriveCloudDetector.GetProviders()` (roots): " ) ;
70
- Debug . WriteLine ( $ "Name: Google Drive ({ title } ); SyncFolder: { path } ") ;
59
+ App . AppModel . GoogleDrivePath = path ;
71
60
72
61
yield return new CloudProvider ( CloudProviders . GoogleDrive )
73
62
{
@@ -76,7 +65,6 @@ await FilesystemTasks.Wrap(() => StorageFile.GetFileFromPathAsync(Path.Combine(a
76
65
} ;
77
66
}
78
67
79
- var iconFile = await GetGoogleDriveIconFileAsync ( ) ;
80
68
// Google virtual drive
81
69
reader = cmdMedia . ExecuteReader ( ) ;
82
70
@@ -86,14 +74,13 @@ await FilesystemTasks.Wrap(() => StorageFile.GetFileFromPathAsync(Path.Combine(a
86
74
if ( string . IsNullOrWhiteSpace ( path ) )
87
75
continue ;
88
76
89
- if ( ! AddMyDriveToPathAndValidate ( ref path ) )
90
- continue ;
91
-
92
77
var folder = await StorageFolder . GetFolderFromPathAsync ( path ) ;
93
78
string title = reader [ "name" ] ? . ToString ( ) ?? folder . Name ;
79
+ string iconPath = Path . Combine ( Environment . GetEnvironmentVariable ( "ProgramFiles" ) , "Google" , "Drive File Stream" , "drive_fs.ico" ) ;
80
+
81
+ App . AppModel . GoogleDrivePath = path ;
94
82
95
- Debug . WriteLine ( "YIELD RETURNING from `GoogleDriveCloudDetector.GetProviders` (media): " ) ;
96
- Debug . WriteLine ( $ "Name: { title } ; SyncFolder: { path } ") ;
83
+ StorageFile iconFile = await FilesystemTasks . Wrap ( ( ) => StorageFile . GetFileFromPathAsync ( iconPath ) . AsTask ( ) ) ;
97
84
98
85
yield return new CloudProvider ( CloudProviders . GoogleDrive )
99
86
{
@@ -102,190 +89,6 @@ await FilesystemTasks.Wrap(() => StorageFile.GetFileFromPathAsync(Path.Combine(a
102
89
IconData = iconFile is not null ? await iconFile . ToByteArrayAsync ( ) : null ,
103
90
} ;
104
91
}
105
-
106
- await Inspect ( database , "SELECT * FROM roots" , "root_preferences db, roots table" ) ;
107
- await Inspect ( database , "SELECT * FROM media" , "root_preferences db, media table" ) ;
108
- await Inspect ( database , "SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY 1" , "root_preferences db, all tables" ) ;
109
-
110
- var registryPath = App . AppModel . GoogleDrivePath ;
111
- if ( ! AddMyDriveToPathAndValidate ( ref registryPath ) )
112
- yield break ;
113
- yield return new CloudProvider ( CloudProviders . GoogleDrive )
114
- {
115
- Name = "Google Drive" ,
116
- SyncFolder = registryPath ,
117
- IconData = iconFile is not null ? await iconFile . ToByteArrayAsync ( ) : null
118
- } ;
119
- }
120
-
121
- private static async Task Inspect ( SqliteConnection database , string sqlCommand , string targetDescription )
122
- {
123
- await using var cmdTablesAll = new SqliteCommand ( sqlCommand , database ) ;
124
- var reader = await cmdTablesAll . ExecuteReaderAsync ( ) ;
125
- var colNamesList = Enumerable . Range ( 0 , reader . FieldCount ) . Select ( i => reader . GetName ( i ) ) . ToList ( ) ;
126
-
127
- Debug . WriteLine ( $ "BEGIN LOGGING of { targetDescription } ") ;
128
-
129
- for ( int rowIdx = 0 ; reader . Read ( ) is not false ; rowIdx ++ )
130
- {
131
- var colVals = new object [ reader . FieldCount ] ;
132
- reader . GetValues ( colVals ) ;
133
-
134
- colVals . Select ( ( val , colIdx ) => $ "row { rowIdx } : column { colIdx } : { colNamesList [ colIdx ] } : { val } ")
135
- . ToList ( ) . ForEach ( s => Debug . WriteLine ( s ) ) ;
136
- }
137
-
138
- Debug . WriteLine ( $ "END LOGGING of { targetDescription } contents") ;
139
- }
140
-
141
- private static JsonDocument ? GetGoogleDriveRegValJson ( )
142
- {
143
- // This will be null if the key name is not found.
144
- using var googleDriveRegKey = Registry . CurrentUser . OpenSubKey ( _googleDriveRegKeyName ) ;
145
-
146
- if ( googleDriveRegKey is null )
147
- {
148
- _logger . LogWarning ( $ "Google Drive registry key for key name '{ _googleDriveRegKeyName } ' not found.") ;
149
- return null ;
150
- }
151
-
152
- var googleDriveRegVal = googleDriveRegKey . GetValue ( _googleDriveRegValName ) ;
153
-
154
- if ( googleDriveRegVal is null )
155
- {
156
- _logger . LogWarning ( $ "Google Drive registry value for value name '{ _googleDriveRegValName } ' not found.") ;
157
- return null ;
158
- }
159
-
160
- JsonDocument ? googleDriveRegValueJson = null ;
161
- try
162
- {
163
- googleDriveRegValueJson = JsonDocument . Parse ( googleDriveRegVal . ToString ( ) ?? "" ) ;
164
- }
165
- catch ( JsonException je )
166
- {
167
- _logger . LogWarning ( je , $ "Google Drive registry value for value name '{ _googleDriveRegValName } ' could not be parsed as a JsonDocument.") ;
168
- }
169
-
170
- return googleDriveRegValueJson ;
171
- }
172
-
173
- public static string ? GetRegistryBasePath ( )
174
- {
175
- var googleDriveRegValJson = GetGoogleDriveRegValJson ( ) ;
176
-
177
- if ( googleDriveRegValJson is null )
178
- return null ;
179
-
180
- var googleDriveRegValJsonProperty = googleDriveRegValJson
181
- . RootElement . EnumerateObject ( )
182
- . FirstOrDefault ( ) ;
183
-
184
- // A default JsonProperty struct has an "Undefined" Value#ValueKind and throws an
185
- // error if you try to call EnumerateArray on its Value.
186
- if ( googleDriveRegValJsonProperty . Value . ValueKind == JsonValueKind . Undefined )
187
- {
188
- _logger . LogWarning ( $ "Root element of Google Drive registry value for value name '{ _googleDriveRegValName } ' was empty.") ;
189
- return null ;
190
- }
191
-
192
- Debug . WriteLine ( "REGISTRY LOGGING" ) ;
193
- Debug . WriteLine ( googleDriveRegValJsonProperty . ToString ( ) ) ;
194
-
195
- var item = googleDriveRegValJsonProperty . Value . EnumerateArray ( ) . FirstOrDefault ( ) ;
196
- if ( item . ValueKind == JsonValueKind . Undefined )
197
- {
198
- _logger . LogWarning ( $ "Array in the root element of Google Drive registry value for value name '{ _googleDriveRegValName } ' was empty.") ;
199
- return null ;
200
- }
201
-
202
- if ( ! item . TryGetProperty ( _googleDriveRegValPropName , out var googleDriveRegValProp ) )
203
- {
204
- _logger . LogWarning ( $ "First element in the Google Drive Registry Root Array did not have property named { _googleDriveRegValPropName } ") ;
205
- return null ;
206
- }
207
-
208
- if ( ! googleDriveRegValProp . TryGetProperty ( _googleDriveRegValPropPropName , out var googleDriveRegValPropProp ) )
209
- {
210
- _logger . LogWarning ( $ "Value from { _googleDriveRegValPropName } did not have property named { _googleDriveRegValPropPropName } ") ;
211
- return null ;
212
- }
213
-
214
- var path = googleDriveRegValPropProp . GetString ( ) ;
215
- if ( path is not null )
216
- return ConvertDriveLetterToPathAndValidate ( ref path ) ? path : null ;
217
-
218
- _logger . LogWarning ( $ "Could not get string from value from { _googleDriveRegValPropPropName } ") ;
219
- return null ;
220
- }
221
-
222
- /// <summary>
223
- /// If Google Drive is mounted as a drive, then the path found in the registry will be
224
- /// *just* the drive letter (e.g. just "G" as opposed to "G:\"), and therefore must be
225
- /// reformatted as a valid path.
226
- /// </summary>
227
- private static bool ConvertDriveLetterToPathAndValidate ( ref string path )
228
- {
229
- if ( path . Length > 1 )
230
- return ValidatePath ( path ) ;
231
-
232
- DriveInfo driveInfo ;
233
- try
234
- {
235
- driveInfo = new DriveInfo ( path ) ;
236
- }
237
- catch ( ArgumentException e )
238
- {
239
- _logger . LogWarning ( e , $ "Could not resolve drive letter '{ path } ' to a valid drive.") ;
240
- return false ;
241
- }
242
-
243
- path = driveInfo . RootDirectory . Name ;
244
- return true ;
245
- }
246
-
247
- private static bool ValidatePath ( string path )
248
- {
249
- if ( Directory . Exists ( path ) )
250
- return true ;
251
- _logger . LogWarning ( $ "Invalid path: { path } ") ;
252
- return false ;
253
- }
254
-
255
- private static async Task < StorageFile ? > GetGoogleDriveIconFileAsync ( )
256
- {
257
- var programFilesEnvVar = Environment . GetEnvironmentVariable ( "ProgramFiles" ) ;
258
-
259
- if ( programFilesEnvVar is null )
260
- return null ;
261
-
262
- var iconPath = Path . Combine ( programFilesEnvVar , "Google" , "Drive File Stream" , "drive_fs.ico" ) ;
263
-
264
- return await FilesystemTasks . Wrap ( ( ) => StorageFile . GetFileFromPathAsync ( iconPath ) . AsTask ( ) ) ;
265
- }
266
-
267
- private static bool AddMyDriveToPathAndValidate ( ref string path )
268
- {
269
- // If `path` contains a shortcut named "My Drive", store its target in `shellFolderBaseFirst`.
270
- // This happens when "My Drive syncing options" is set to "Mirror files".
271
- // TODO: Avoid to use Vanara (#15000)
272
- using var rootFolder = ShellFolderExtensions . GetShellItemFromPathOrPIDL ( path ) as ShellFolder ;
273
- var myDriveFolder = Environment . ExpandEnvironmentVariables ( (
274
- rootFolder ? . FirstOrDefault ( si =>
275
- si . Name ? . Equals ( "My Drive" ) ?? false ) as ShellLink ) ? . TargetPath
276
- ?? string . Empty ) ;
277
-
278
- Debug . WriteLine ( "SHELL FOLDER LOGGING" ) ;
279
- rootFolder ? . ForEach ( si => Debug . WriteLine ( si . Name ) ) ;
280
-
281
- if ( ! string . IsNullOrEmpty ( myDriveFolder ) )
282
- {
283
- path = myDriveFolder ;
284
- return true ;
285
- }
286
-
287
- path = Path . Combine ( path , "My Drive" ) ;
288
- return ValidatePath ( path ) ;
289
92
}
290
93
}
291
94
}
0 commit comments