Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a47b7eb
Update RecycleBinItemCreatedAtProperty.cs
d2dyno1 Jul 12, 2026
737b024
Prevent leaving unrecoverable folders in FUSE
d2dyno1 Jul 12, 2026
4ec932a
Don't abandon size calculation if one item fails
d2dyno1 Jul 12, 2026
ff49d68
Fixed size maximum calculation in recycle bin overlay
d2dyno1 Jul 12, 2026
6b03996
Update IRecycleBinFolder.cs
d2dyno1 Jul 12, 2026
776c24a
Update Resources.resx
d2dyno1 Jul 12, 2026
0264c8a
Added SemaphoreSlim to FileSystemSpecifics
d2dyno1 Jul 13, 2026
083b692
Improved recycle and restore reliability
d2dyno1 Jul 13, 2026
4973bb9
Fixed Linux build
d2dyno1 Jul 13, 2026
d2b4e68
Implemented folding for recycled folders on WebDav
d2dyno1 Jul 13, 2026
ddbae28
Avoid preventing access to the recycle bin after subscription has exp…
d2dyno1 Jul 13, 2026
167d85c
Added more recycle bin tests
d2dyno1 Jul 13, 2026
cc520f7
Delete config files on revocation
d2dyno1 Jul 13, 2026
c4e5223
Warn before overwriting YubiKey slots
d2dyno1 Jul 13, 2026
fc5afb3
Adjust MacOSBiometricsViewModel
d2dyno1 Jul 13, 2026
7005a88
Added window buttons and fixed compile-time constants
d2dyno1 Jul 14, 2026
70b386e
Improved caption button styles
d2dyno1 Jul 14, 2026
c25d794
Fixed drag regions on X11
d2dyno1 Jul 14, 2026
d70858c
Merge branch 'master' into recycle_bin_reliability
d2dyno1 Jul 17, 2026
c9f2024
Added a new glass effect to EncryptedFileSlide
d2dyno1 Jul 18, 2026
4ac4634
Adjusted onboarding reveal animation
d2dyno1 Jul 18, 2026
31c5c48
Update EncryptedFileSlide.xaml.cs
d2dyno1 Jul 18, 2026
acb4bf1
Added resizable window support to X11
d2dyno1 Jul 18, 2026
15ee23d
Minor fixes for WinUI
d2dyno1 Jul 18, 2026
679f4e2
Moved to partial GPU rendering on Windows
d2dyno1 Jul 18, 2026
1d7a9cb
Revert EncryptedFileSlide
d2dyno1 Jul 18, 2026
4600624
Merge branch 'master' into recycle_bin_reliability
d2dyno1 Jul 19, 2026
5dd29bb
Upgraded to Uno 6.6
d2dyno1 Jul 19, 2026
cbfc164
Update SkiaVaultFileSystemService.cs
d2dyno1 Jul 20, 2026
729bba5
Added macOS system toolbar icon support
d2dyno1 Jul 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"msbuild-sdks": {
"Uno.Sdk": "6.5.31"
"Uno.Sdk": "6.6.29"
}
}
12 changes: 11 additions & 1 deletion src/Core/SecureFolderFS.Core.Dokany/Callbacks/OnDeviceDokany.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,10 @@ public override void Cleanup(string fileName, IDokanFileInfo info)
NativeRecycleBinHelpers.DeleteOrRecycle(ciphertextPath, specifics, StorableType.File);
}
}
catch (UnauthorizedAccessException)
catch (Exception)
{
// An exception must never escape into the driver callback. Concurrent deletes
// can surface IOException (sharing violations) besides UnauthorizedAccessException.
}
}
}
Expand Down Expand Up @@ -492,6 +494,10 @@ public override NtStatus DeleteFile(string fileName, IDokanFileInfo info)
if (ciphertextPath is null)
return Trace(NtStatus.ObjectPathInvalid, fileName, info);

// Protect core files from deletion
if (PathHelpers.IsCoreName(Path.GetFileName(ciphertextPath)))
return Trace(DokanResult.AccessDenied, fileName, info);

// Perform checks
if (Directory.Exists(ciphertextPath))
return Trace(DokanResult.AccessDenied, fileName, info);
Expand All @@ -516,6 +522,10 @@ public override NtStatus DeleteDirectory(string fileName, IDokanFileInfo info)
if (ciphertextPath is null)
return Trace(NtStatus.ObjectPathInvalid, fileName, info);

// Protect core folders from deletion
if (PathHelpers.IsCoreName(Path.GetFileName(ciphertextPath)))
return Trace(DokanResult.AccessDenied, fileName, info);

try
{
using var directoryEnumerator = Directory.EnumerateFileSystemEntries(ciphertextPath).GetEnumerator();
Expand Down
71 changes: 67 additions & 4 deletions src/Core/SecureFolderFS.Core.FUSE/Callbacks/OnDeviceFuse.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System.Text;
using OwlCore.Storage;
using SecureFolderFS.Core.FileSystem;
using SecureFolderFS.Core.FileSystem.Helpers.Paths;
using SecureFolderFS.Core.FileSystem.Helpers.Paths.Abstract;
using SecureFolderFS.Core.FileSystem.Helpers.Paths.Native;
using SecureFolderFS.Core.FileSystem.Helpers.RecycleBin.Native;
using SecureFolderFS.Core.FUSE.OpenHandles;
using SecureFolderFS.Core.FUSE.UnsafeNative;
using SecureFolderFS.Storage.Extensions;
using Tmds.Fuse;
using Tmds.Linux;
using static SecureFolderFS.Core.FUSE.UnsafeNative.UnsafeNativeApis;
Expand Down Expand Up @@ -470,19 +473,58 @@ public override unsafe int RmDir(ReadOnlySpan<byte> path)
if (ciphertextPath is null)
return -ENOENT;

if (Directory.EnumerateFileSystemEntries(ciphertextPath).Any(x => !PathHelpers.IsCoreName(x)))
// Protect core folders from deletion
if (PathHelpers.IsCoreName(Path.GetFileName(Path.TrimEndingDirectorySeparator(ciphertextPath))))
return -EACCES;

if (Directory.EnumerateFileSystemEntries(ciphertextPath).Any(x => !PathHelpers.IsCoreName(Path.GetFileName(x))))
return -ENOTEMPTY;

var directoryIdPath = Path.Combine(ciphertextPath, FileSystem.Constants.Names.DIRECTORY_ID_FILENAME);
specifics.DirectoryIdCache.CacheRemove(directoryIdPath);

if (FuseOptions.IsRecycleBinEnabled())
{
try
{
// The folder is moved into the recycle bin together with its DirectoryID file
NativeRecycleBinHelpers.DeleteOrRecycle(ciphertextPath, specifics, StorableType.Folder);
return 0;
}
catch (UnauthorizedAccessException)
{
return -EACCES;
}
catch (Exception)
{
return -EIO;
}
}

// Remove DirectoryID
// Read the DirectoryID so it can be restored if rmdir fails.
// Deleting it permanently while the folder survives would make its contents undecryptable
var directoryId = File.Exists(directoryIdPath) ? File.ReadAllBytes(directoryIdPath) : null;
File.Delete(directoryIdPath);
specifics.DirectoryIdCache.CacheRemove(directoryIdPath);

fixed (byte *ciphertextPathPtr = Encoding.UTF8.GetBytes(ciphertextPath))
{
if (rmdir(ciphertextPathPtr) == -1)
return -errno;
{
var error = errno;
if (directoryId is null)
return -error;

try
{
File.WriteAllBytes(directoryIdPath, directoryId);
}
catch (Exception)
{
// Best effort - the directory may have been removed concurrently
}

return -error;
}
}

return 0;
Expand Down Expand Up @@ -590,6 +632,27 @@ public override unsafe int Unlink(ReadOnlySpan<byte> path)
if (Directory.Exists(ciphertextPath))
return -EISDIR;

// Protect core files from deletion
if (PathHelpers.IsCoreName(Path.GetFileName(ciphertextPath)))
return -EACCES;

if (FuseOptions.IsRecycleBinEnabled())
{
try
{
NativeRecycleBinHelpers.DeleteOrRecycle(ciphertextPath, specifics, StorableType.File);
return 0;
}
catch (UnauthorizedAccessException)
{
return -EACCES;
}
catch (Exception)
{
return -EIO;
}
}

fixed (byte *ciphertextPathPtr = Encoding.UTF8.GetBytes(ciphertextPath))
{
if (unlink(ciphertextPathPtr) == -1)
Expand Down
10 changes: 10 additions & 0 deletions src/Core/SecureFolderFS.Core.FileSystem/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ public static class Constants
public const string UNC_NAME = "securefolderfs";
public const int FILE_EOF = 0;
public const int DIRECTORY_ID_SIZE = 16;

/// <summary>
/// The time window within which previously recycled items are folded back into a
/// recycled parent folder. OS clients (Finder, Explorer, WebDav/FUSE drivers) delete
/// folder trees member-by-member; when the parent folder finally arrives at the recycle
/// bin, children recycled within this window are reattached to it so the tree appears
/// as a single restorable entry. Membership is proven by Directory ID, so this window
/// only limits how far back unrelated same-folder deletions are pulled in.
/// </summary>
public const long RECYCLE_BIN_FOLD_WINDOW_MS = 60L * 60L * 1000L;
public const ulong INVALID_HANDLE = 0UL;
public const bool OPT_IN_FOR_OPTIONAL_DEBUG_TRACING = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using SecureFolderFS.Shared.Models;
using SecureFolderFS.Storage.VirtualFileSystem;
using System;
using System.Threading;

namespace SecureFolderFS.Core.FileSystem
{
Expand Down Expand Up @@ -48,13 +49,19 @@ public sealed class FileSystemSpecifics : IDisposable
/// </summary>
public required UniversalCache<NameWithDirectoryId, string> PlaintextFileNameCache { get; init; }

/// <summary>
/// Gets the lock that serializes recycle bin quota checks and occupied-size updates.
/// </summary>
public SemaphoreSlim RecycleBinSemaphore { get; } = new(1, 1);

private FileSystemSpecifics()
{
}

/// <inheritdoc/>
public void Dispose()
{
RecycleBinSemaphore.Dispose();
PlaintextFileNameCache.Dispose();
CiphertextFileNameCache.Dispose();
DirectoryIdCache.Dispose();
Expand Down
Loading
Loading