Skip to content

Commit dc6774c

Browse files
Refactor: Migrate LayoutPreferences and FileTags keys to SHA256 hash
1 parent 223ecce commit dc6774c

File tree

3 files changed

+151
-10
lines changed

3 files changed

+151
-10
lines changed

src/Files.App/Helpers/Layout/LayoutPreferencesDatabase.cs

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Microsoft.Win32;
55
using System.Runtime.CompilerServices;
66
using Windows.ApplicationModel;
7+
using Files.Shared.Helpers;
78
using static Files.App.Helpers.LayoutPreferencesDatabaseItemRegistry;
89
using static Files.App.Helpers.RegistryHelpers;
910
using JsonSerializer = System.Text.Json.JsonSerializer;
@@ -13,9 +14,11 @@ namespace Files.App.Helpers
1314
public sealed class LayoutPreferencesDatabase
1415
{
1516
private readonly static string LayoutSettingsKey = @$"Software\Files Community\{Package.Current.Id.Name}\v1\LayoutPreferences";
17+
private readonly static string MigrationMarkerKey = "MigrationCompleted";
1618

1719
public LayoutPreferencesItem? GetPreferences(string filePath, ulong? frn)
1820
{
21+
MigrateExistingKeys();
1922
return FindPreferences(filePath, frn)?.LayoutPreferencesManager;
2023
}
2124

@@ -58,7 +61,7 @@ void UpdateValues(LayoutPreferencesDatabaseItem? preferences)
5861
{
5962
if (filePath is not null)
6063
{
61-
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(LayoutSettingsKey, filePath));
64+
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(LayoutSettingsKey, ChecksumHelpers.CreateSHA256(filePath)));
6265
SaveValues(filePathKey, preferences);
6366
}
6467

@@ -91,7 +94,7 @@ private static void ImportCore(LayoutPreferencesDatabaseItem[]? preferences)
9194
}
9295
foreach (var preference in preferences)
9396
{
94-
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(LayoutSettingsKey, preference.FilePath));
97+
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(LayoutSettingsKey, ChecksumHelpers.CreateSHA256(preference.FilePath)));
9598
SaveValues(filePathKey, preference);
9699
if (preference.Frn is not null)
97100
{
@@ -139,7 +142,7 @@ private void IterateKeys(List<LayoutPreferencesDatabaseItem> list, string path,
139142
{
140143
if (filePath is not null)
141144
{
142-
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(LayoutSettingsKey, filePath));
145+
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(LayoutSettingsKey, ChecksumHelpers.CreateSHA256(filePath)));
143146
if (filePathKey.ValueCount > 0)
144147
{
145148
var preference = new LayoutPreferencesDatabaseItem();
@@ -174,5 +177,67 @@ private void IterateKeys(List<LayoutPreferencesDatabaseItem> list, string path,
174177

175178
return null;
176179
}
180+
181+
private void MigrateExistingKeys()
182+
{
183+
using var baseKey = Registry.CurrentUser.OpenSubKey(LayoutSettingsKey);
184+
if (baseKey is null)
185+
return;
186+
187+
// Check if migration is already completed
188+
if (baseKey.GetValue(MigrationMarkerKey) is not null)
189+
return;
190+
191+
var keysToMigrate = new List<(string oldKey, LayoutPreferencesDatabaseItem preference)>();
192+
193+
// Collect all keys that need migration (excluding FRN and migration marker)
194+
foreach (var subKeyName in baseKey.GetSubKeyNames())
195+
{
196+
if (subKeyName == "FRN" || subKeyName == MigrationMarkerKey)
197+
continue;
198+
199+
// Check if this is a hash key (64 characters hex)
200+
if (subKeyName.Length == 64 && IsHexString(subKeyName))
201+
continue; // Already migrated
202+
203+
using var subKey = baseKey.OpenSubKey(subKeyName);
204+
if (subKey?.ValueCount > 0)
205+
{
206+
var preference = new LayoutPreferencesDatabaseItem();
207+
BindValues(subKey, preference);
208+
keysToMigrate.Add((subKeyName, preference));
209+
}
210+
}
211+
212+
// Migrate collected keys
213+
using var writerKey = Registry.CurrentUser.CreateSubKey(LayoutSettingsKey);
214+
foreach (var (oldKey, preference) in keysToMigrate)
215+
{
216+
if (!string.IsNullOrEmpty(preference.FilePath))
217+
{
218+
// Create new hashed key
219+
using var newKey = Registry.CurrentUser.CreateSubKey(CombineKeys(LayoutSettingsKey, ChecksumHelpers.CreateSHA256(preference.FilePath)));
220+
SaveValues(newKey, preference);
221+
}
222+
223+
// Delete old key
224+
try
225+
{
226+
writerKey.DeleteSubKeyTree(oldKey);
227+
}
228+
catch
229+
{
230+
// Ignore deletion errors
231+
}
232+
}
233+
234+
// Mark migration as completed
235+
writerKey.SetValue(MigrationMarkerKey, "1", RegistryValueKind.String);
236+
}
237+
238+
private static bool IsHexString(string value)
239+
{
240+
return value.All(c => c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F');
241+
}
177242
}
178243
}

src/Files.App/Utils/FileTags/FileTagsDatabase.cs

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Runtime.CompilerServices;
66
using System.Security;
77
using Windows.ApplicationModel;
8+
using Files.Shared.Helpers;
89
using static Files.App.Helpers.RegistryHelpers;
910
using static Files.App.Utils.FileTags.TaggedFileRegistry;
1011
using JsonSerializer = System.Text.Json.JsonSerializer;
@@ -15,13 +16,14 @@ public sealed class FileTagsDatabase
1516
{
1617
private static string? _FileTagsKey;
1718
private string? FileTagsKey => _FileTagsKey ??= SafetyExtensions.IgnoreExceptions(() => @$"Software\Files Community\{Package.Current.Id.Name}\v1\FileTags");
19+
private readonly static string MigrationMarkerKey = "MigrationCompleted";
1820

1921
public void SetTags(string filePath, ulong? frn, string[] tags)
2022
{
2123
if (FileTagsKey is null)
2224
return;
2325

24-
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, filePath));
26+
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, ChecksumHelpers.CreateSHA256(filePath)));
2527

2628
if (tags is [])
2729
{
@@ -57,7 +59,7 @@ public void SetTags(string filePath, ulong? frn, string[] tags)
5759

5860
if (filePath is not null)
5961
{
60-
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, filePath));
62+
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, ChecksumHelpers.CreateSHA256(filePath)));
6163
if (filePathKey.ValueCount > 0)
6264
{
6365
var tag = new TaggedFile();
@@ -99,7 +101,7 @@ public void UpdateTag(string oldFilePath, ulong? frn, string? newFilePath)
99101
return;
100102

101103
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)));
103105
SaveValues(filePathKey, null);
104106

105107
if (tag is not null)
@@ -115,7 +117,7 @@ public void UpdateTag(string oldFilePath, ulong? frn, string? newFilePath)
115117

116118
if (newFilePath is not null)
117119
{
118-
using var newFilePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, newFilePath));
120+
using var newFilePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, ChecksumHelpers.CreateSHA256(newFilePath)));
119121
SaveValues(newFilePathKey, tag);
120122
}
121123
}
@@ -143,14 +145,15 @@ public void UpdateTag(ulong oldFrn, ulong? frn, string? newFilePath)
143145

144146
if (newFilePath is not null)
145147
{
146-
using var newFilePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, newFilePath));
148+
using var newFilePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, ChecksumHelpers.CreateSHA256(newFilePath)));
147149
SaveValues(newFilePathKey, tag);
148150
}
149151
}
150152
}
151153

152154
public string[] GetTags(string? filePath, ulong? frn)
153155
{
156+
MigrateExistingKeys();
154157
return FindTag(filePath, frn)?.Tags ?? [];
155158
}
156159

@@ -182,7 +185,7 @@ public IEnumerable<TaggedFile> GetAllUnderPath(string folderPath)
182185
{
183186
try
184187
{
185-
IterateKeys(list, CombineKeys(FileTagsKey, folderPath), 0);
188+
IterateKeys(list, CombineKeys(FileTagsKey, ChecksumHelpers.CreateSHA256(folderPath)), 0);
186189
}
187190
catch (SecurityException)
188191
{
@@ -207,7 +210,7 @@ public void Import(string json)
207210
}
208211
foreach (var tag in tags)
209212
{
210-
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, tag.FilePath));
213+
using var filePathKey = Registry.CurrentUser.CreateSubKey(CombineKeys(FileTagsKey, ChecksumHelpers.CreateSHA256(tag.FilePath)));
211214
SaveValues(filePathKey, tag);
212215
if (tag.Frn is not null)
213216
{
@@ -249,5 +252,70 @@ private void IterateKeys(List<TaggedFile> list, string path, int depth)
249252
IterateKeys(list, CombineKeys(path, subKey), depth + 1);
250253
}
251254
}
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+
}
252320
}
253321
}

src/Files.Shared/Helpers/ChecksumHelpers.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ public static string CalculateChecksumForPath(string path)
2222
return Convert.ToHexString(hash);
2323
}
2424

25+
public static string CreateSHA256(string input)
26+
{
27+
var buffer = Encoding.UTF8.GetBytes(input);
28+
Span<byte> hash = stackalloc byte[SHA256.HashSizeInBytes];
29+
SHA256.HashData(buffer, hash);
30+
return Convert.ToHexString(hash).ToLower();
31+
}
32+
2533
public async static Task<string> CreateCRC32(Stream stream, CancellationToken cancellationToken)
2634
{
2735
var crc32 = new Crc32();

0 commit comments

Comments
 (0)