5
5
using System . Runtime . CompilerServices ;
6
6
using System . Security ;
7
7
using Windows . ApplicationModel ;
8
+ using Files . Shared . Helpers ;
8
9
using static Files . App . Helpers . RegistryHelpers ;
9
10
using static Files . App . Utils . FileTags . TaggedFileRegistry ;
10
11
using JsonSerializer = System . Text . Json . JsonSerializer ;
@@ -15,13 +16,14 @@ public sealed class FileTagsDatabase
15
16
{
16
17
private static string ? _FileTagsKey ;
17
18
private string ? FileTagsKey => _FileTagsKey ??= SafetyExtensions . IgnoreExceptions ( ( ) => @$ "Software\Files Community\{ Package . Current . Id . Name } \v1\FileTags") ;
19
+ private readonly static string MigrationMarkerKey = "MigrationCompleted" ;
18
20
19
21
public void SetTags ( string filePath , ulong ? frn , string [ ] tags )
20
22
{
21
23
if ( FileTagsKey is null )
22
24
return ;
23
25
24
- using var filePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , filePath ) ) ;
26
+ using var filePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , ChecksumHelpers . CreateSHA256 ( filePath ) ) ) ;
25
27
26
28
if ( tags is [ ] )
27
29
{
@@ -57,7 +59,7 @@ public void SetTags(string filePath, ulong? frn, string[] tags)
57
59
58
60
if ( filePath is not null )
59
61
{
60
- using var filePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , filePath ) ) ;
62
+ using var filePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , ChecksumHelpers . CreateSHA256 ( filePath ) ) ) ;
61
63
if ( filePathKey . ValueCount > 0 )
62
64
{
63
65
var tag = new TaggedFile ( ) ;
@@ -99,7 +101,7 @@ public void UpdateTag(string oldFilePath, ulong? frn, string? newFilePath)
99
101
return ;
100
102
101
103
var tag = FindTag ( oldFilePath , null ) ;
102
- using var filePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , oldFilePath ) ) ;
104
+ using var filePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , ChecksumHelpers . CreateSHA256 ( oldFilePath ) ) ) ;
103
105
SaveValues ( filePathKey , null ) ;
104
106
105
107
if ( tag is not null )
@@ -115,7 +117,7 @@ public void UpdateTag(string oldFilePath, ulong? frn, string? newFilePath)
115
117
116
118
if ( newFilePath is not null )
117
119
{
118
- using var newFilePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , newFilePath ) ) ;
120
+ using var newFilePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , ChecksumHelpers . CreateSHA256 ( newFilePath ) ) ) ;
119
121
SaveValues ( newFilePathKey , tag ) ;
120
122
}
121
123
}
@@ -143,14 +145,15 @@ public void UpdateTag(ulong oldFrn, ulong? frn, string? newFilePath)
143
145
144
146
if ( newFilePath is not null )
145
147
{
146
- using var newFilePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , newFilePath ) ) ;
148
+ using var newFilePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , ChecksumHelpers . CreateSHA256 ( newFilePath ) ) ) ;
147
149
SaveValues ( newFilePathKey , tag ) ;
148
150
}
149
151
}
150
152
}
151
153
152
154
public string [ ] GetTags ( string ? filePath , ulong ? frn )
153
155
{
156
+ MigrateExistingKeys ( ) ;
154
157
return FindTag ( filePath , frn ) ? . Tags ?? [ ] ;
155
158
}
156
159
@@ -182,7 +185,7 @@ public IEnumerable<TaggedFile> GetAllUnderPath(string folderPath)
182
185
{
183
186
try
184
187
{
185
- IterateKeys ( list , CombineKeys ( FileTagsKey , folderPath ) , 0 ) ;
188
+ IterateKeys ( list , CombineKeys ( FileTagsKey , ChecksumHelpers . CreateSHA256 ( folderPath ) ) , 0 ) ;
186
189
}
187
190
catch ( SecurityException )
188
191
{
@@ -207,7 +210,7 @@ public void Import(string json)
207
210
}
208
211
foreach ( var tag in tags )
209
212
{
210
- using var filePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , tag . FilePath ) ) ;
213
+ using var filePathKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , ChecksumHelpers . CreateSHA256 ( tag . FilePath ) ) ) ;
211
214
SaveValues ( filePathKey , tag ) ;
212
215
if ( tag . Frn is not null )
213
216
{
@@ -249,5 +252,70 @@ private void IterateKeys(List<TaggedFile> list, string path, int depth)
249
252
IterateKeys ( list , CombineKeys ( path , subKey ) , depth + 1 ) ;
250
253
}
251
254
}
255
+
256
+ private void MigrateExistingKeys ( )
257
+ {
258
+ if ( FileTagsKey is null )
259
+ return ;
260
+
261
+ using var baseKey = Registry . CurrentUser . OpenSubKey ( FileTagsKey ) ;
262
+ if ( baseKey is null )
263
+ return ;
264
+
265
+ // Check if migration is already completed
266
+ if ( baseKey . GetValue ( MigrationMarkerKey ) is not null )
267
+ return ;
268
+
269
+ var keysToMigrate = new List < ( string oldKey , TaggedFile tag ) > ( ) ;
270
+
271
+ // Collect all keys that need migration (excluding FRN and migration marker)
272
+ foreach ( var subKeyName in baseKey . GetSubKeyNames ( ) )
273
+ {
274
+ if ( subKeyName == "FRN" || subKeyName == MigrationMarkerKey )
275
+ continue ;
276
+
277
+ // Check if this is a hash key (64 characters hex)
278
+ if ( subKeyName . Length == 64 && IsHexString ( subKeyName ) )
279
+ continue ; // Already migrated
280
+
281
+ using var subKey = baseKey . OpenSubKey ( subKeyName ) ;
282
+ if ( subKey ? . ValueCount > 0 )
283
+ {
284
+ var tag = new TaggedFile ( ) ;
285
+ BindValues ( subKey , tag ) ;
286
+ keysToMigrate . Add ( ( subKeyName , tag ) ) ;
287
+ }
288
+ }
289
+
290
+ // Migrate collected keys
291
+ using var writerKey = Registry . CurrentUser . CreateSubKey ( FileTagsKey ) ;
292
+ foreach ( var ( oldKey , tag ) in keysToMigrate )
293
+ {
294
+ if ( ! string . IsNullOrEmpty ( tag . FilePath ) )
295
+ {
296
+ // Create new hashed key
297
+ using var newKey = Registry . CurrentUser . CreateSubKey ( CombineKeys ( FileTagsKey , ChecksumHelpers . CreateSHA256 ( tag . FilePath ) ) ) ;
298
+ SaveValues ( newKey , tag ) ;
299
+ }
300
+
301
+ // Delete old key
302
+ try
303
+ {
304
+ writerKey . DeleteSubKeyTree ( oldKey ) ;
305
+ }
306
+ catch
307
+ {
308
+ // Ignore deletion errors
309
+ }
310
+ }
311
+
312
+ // Mark migration as completed
313
+ writerKey . SetValue ( MigrationMarkerKey , "1" , RegistryValueKind . String ) ;
314
+ }
315
+
316
+ private static bool IsHexString ( string value )
317
+ {
318
+ return value . All ( c => c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F' ) ;
319
+ }
252
320
}
253
321
}
0 commit comments