Skip to content

Commit e2dead6

Browse files
committed
Optimize AbstractRecycleBinHelpers
1 parent bfb9713 commit e2dead6

2 files changed

Lines changed: 36 additions & 28 deletions

File tree

src/Core/SecureFolderFS.Core.FileSystem/Helpers/RecycleBin/Abstract/AbstractRecycleBinHelpers.Operational.cs

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -127,29 +127,33 @@ public static async Task DeleteOrRecycleAsync(
127127

128128
if (!specifics.Options.IsRecycleBinEnabled() || deleteImmediately)
129129
{
130-
await ciphertextSourceFolder.DeleteAsync(ciphertextItem, cancellationToken);
130+
await DeleteImmediatelyAsync(ciphertextSourceFolder, ciphertextItem, cancellationToken);
131131
return;
132132
}
133133

134+
// Allocate Directory ID for later use
135+
var directoryId = AbstractPathHelpers.AllocateDirectoryId(specifics.Security, ciphertextSourceFolder.Id);
136+
137+
// Decrypt the plaintext name
138+
var plaintextName = await AbstractPathHelpers.DecryptNameAsync(ciphertextItem.Name, ciphertextSourceFolder, specifics, cancellationToken) ?? string.Empty;
139+
if (plaintextName is null)
140+
throw new FormatException("Could not decrypt name for recycle bin configuration file.");
141+
142+
// Check for wildcard file names
134143
if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst())
135144
{
136-
var parentFolder = await ciphertextItem.GetParentAsync(cancellationToken);
137-
if (parentFolder is not null)
145+
if (plaintextName == ".DS_Store" || plaintextName.StartsWith("._", StringComparison.Ordinal))
138146
{
139-
var plaintextName = await AbstractPathHelpers.DecryptNameAsync(ciphertextItem.Name, parentFolder, specifics, cancellationToken) ?? string.Empty;
140-
if (plaintextName == ".DS_Store" || plaintextName.StartsWith("._", StringComparison.Ordinal))
141-
{
142-
// .DS_Store and Apple Double files are not supported by the recycle bin, delete immediately
143-
await ciphertextSourceFolder.DeleteAsync(ciphertextItem, cancellationToken);
144-
return;
145-
}
147+
// .DS_Store and Apple Double files are unsupported by the recycle bin, delete immediately
148+
await DeleteImmediatelyAsync(ciphertextSourceFolder, ciphertextItem, cancellationToken);
149+
return;
146150
}
147151

148152
// Check if the file was recently created (likely part of a copy operation)
149153
// On macOS, Finder creates files and immediately deletes them during copy operations
150154
if (await IsRecentlyCreatedAsync(ciphertextItem, cancellationToken))
151155
{
152-
await ciphertextSourceFolder.DeleteAsync(ciphertextItem, cancellationToken);
156+
await DeleteImmediatelyAsync(ciphertextSourceFolder, ciphertextItem, cancellationToken);
153157
return;
154158
}
155159
}
@@ -172,15 +176,11 @@ public static async Task DeleteOrRecycleAsync(
172176
var availableSize = specifics.Options.RecycleBinSize - occupiedSize;
173177
if (availableSize < sizeHint)
174178
{
175-
await ciphertextSourceFolder.DeleteAsync(ciphertextItem, cancellationToken);
179+
await DeleteImmediatelyAsync(ciphertextSourceFolder, ciphertextItem, cancellationToken);
176180
return;
177181
}
178182
}
179183

180-
// Get source Directory ID
181-
var directoryId = AbstractPathHelpers.AllocateDirectoryId(specifics.Security, ciphertextSourceFolder.Id);
182-
var directoryIdResult = await AbstractPathHelpers.GetDirectoryIdAsync(ciphertextSourceFolder, specifics, directoryId, cancellationToken);
183-
184184
// Rename and move item
185185
var guid = Guid.NewGuid().ToString();
186186
_ = await modifiableRecycleBin.MoveStorableFromAsync(ciphertextItem, ciphertextSourceFolder, false, guid, null, cancellationToken);
@@ -189,21 +189,25 @@ public static async Task DeleteOrRecycleAsync(
189189
var configurationFile = await modifiableRecycleBin.CreateFileAsync($"{guid}.json", false, cancellationToken);
190190
await using (var configurationStream = await configurationFile.OpenWriteAsync(cancellationToken))
191191
{
192-
// Decrypt the plaintext name and parent ID
193-
var plaintextName = await AbstractPathHelpers.DecryptNameAsync(ciphertextItem.Name, ciphertextSourceFolder, specifics, cancellationToken) ?? string.Empty;
194-
var plaintextParentId = await AbstractPathHelpers.GetPlaintextPathAsync((IStorableChild)ciphertextSourceFolder, specifics, cancellationToken) ?? string.Empty;
192+
// Decrypt the plaintext parent ID
193+
var plaintextParentId = await AbstractPathHelpers.GetPlaintextPathAsync((IStorableChild)ciphertextSourceFolder, specifics, cancellationToken);
194+
if (plaintextParentId is null)
195+
throw new FormatException("Could not decrypt parent path for the recycle bin configuration file.");
196+
197+
// Determine if Directory ID is present
198+
var isDirectoryIdPresent = directoryId.IsEmpty() || directoryId.IsAllZeros();
195199

196200
// Encrypt the new plaintext name and parent ID
197-
var newCiphertextName = RecycleBinItemDataModel.Encrypt(plaintextName, specifics.Security, directoryIdResult ? directoryId : ReadOnlySpan<byte>.Empty);
198-
var newCiphertextParentId = RecycleBinItemDataModel.Encrypt(plaintextParentId, specifics.Security, directoryIdResult ? directoryId : ReadOnlySpan<byte>.Empty);
201+
var newCiphertextName = RecycleBinItemDataModel.Encrypt(plaintextName, specifics.Security, isDirectoryIdPresent ? directoryId : ReadOnlySpan<byte>.Empty);
202+
var newCiphertextParentId = RecycleBinItemDataModel.Encrypt(plaintextParentId, specifics.Security, isDirectoryIdPresent ? directoryId : ReadOnlySpan<byte>.Empty);
199203

200204
// Serialize configuration data model
201205
await using var serializedStream = await streamSerializer.SerializeAsync(
202206
new RecycleBinItemDataModel()
203207
{
204208
Name = newCiphertextName,
205209
ParentId = newCiphertextParentId,
206-
DirectoryId = directoryIdResult ? directoryId : [],
210+
DirectoryId = isDirectoryIdPresent ? directoryId : [],
207211
DeletionTimestamp = DateTime.Now,
208212
Size = sizeHint
209213
}, cancellationToken);
@@ -220,6 +224,11 @@ public static async Task DeleteOrRecycleAsync(
220224
var newSize = occupiedSize + sizeHint;
221225
await SetOccupiedSizeAsync(modifiableRecycleBin, newSize, cancellationToken);
222226
}
227+
228+
static async Task DeleteImmediatelyAsync(IModifiableFolder ciphertextSourceFolder, IStorableChild ciphertextItem, CancellationToken cancellationToken)
229+
{
230+
await ciphertextSourceFolder.DeleteAsync(ciphertextItem, deleteImmediately: true, cancellationToken: cancellationToken);
231+
}
223232
}
224233

225234
private static async Task<string> GetAvailableDestinationNameAsync(IFolder ciphertextDestinationFolder, string ciphertextName, string plaintextOriginalName, FileSystemSpecifics specifics, CancellationToken cancellationToken)

src/Core/SecureFolderFS.Core.FileSystem/Helpers/RecycleBin/Native/NativeRecycleBinHelpers.Operational.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ public static void DeleteOrRecycle(string ciphertextPath, FileSystemSpecifics sp
3232
var ciphertextParentPath = Path.GetDirectoryName(ciphertextPath);
3333
_ = ciphertextParentPath ?? throw new DirectoryNotFoundException("The parent folder could not be determined.");
3434
var plaintextName = NativePathHelpers.DecryptName(Path.GetFileName(ciphertextPath), ciphertextParentPath, specifics, directoryId);
35+
if (plaintextName is null)
36+
throw new FormatException("Could not decrypt name for recycle bin configuration file.");
3537

38+
// Check for wildcard file names
3639
if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst())
3740
{
3841
if (plaintextName == ".DS_Store" || (plaintextName?.StartsWith("._", StringComparison.Ordinal) ?? false))
@@ -75,14 +78,10 @@ public static void DeleteOrRecycle(string ciphertextPath, FileSystemSpecifics sp
7578
// Create the configuration file
7679
using (var configurationStream = File.Create($"{destinationPath}.json"))
7780
{
78-
var parentCiphertextPath = Path.GetDirectoryName(ciphertextPath);
79-
if (parentCiphertextPath is null)
80-
throw new FileNotFoundException("The parent folder could not be determined.");
81-
8281
// Decrypt the plaintext parent ID
83-
var plaintextParentId = NativePathHelpers.GetPlaintextPath(parentCiphertextPath, specifics);
82+
var plaintextParentId = NativePathHelpers.GetPlaintextPath(ciphertextParentPath, specifics);
8483
if (plaintextParentId is null || plaintextName is null)
85-
throw new FormatException("Could not decrypt paths for recycle bin configuration file.");
84+
throw new FormatException("Could not decrypt parent path for recycle bin configuration file.");
8685

8786
// Determine if Directory ID is present
8887
var isDirectoryIdPresent = directoryId.IsEmpty() || directoryId.IsAllZeros();

0 commit comments

Comments
 (0)