From 2beac185d9d7bf323d5da75fd5329b37d59da57d Mon Sep 17 00:00:00 2001 From: Paul Fresquet Date: Tue, 3 Feb 2026 16:06:43 +0100 Subject: [PATCH 1/5] Skip POSIX special files without marking incomplete --- .../Services/Inventories/InventoryBuilder.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs b/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs index 948fbe4f..e722d7b4 100644 --- a/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs +++ b/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs @@ -610,13 +610,6 @@ private void AddInaccessibleFileAndLog(InventoryPart inventoryPart, FileInfo fil private void AddPosixSpecialFileAndLog(InventoryPart inventoryPart, FileInfo fileInfo, FileSystemEntryKind entryKind) { - inventoryPart.IsIncompleteDueToAccess = true; - var relativePath = BuildRelativePath(inventoryPart, fileInfo); - var fileDescription = new FileDescription(inventoryPart, relativePath) - { - IsAccessible = false - }; - AddFileSystemDescription(inventoryPart, fileDescription); RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.SpecialPosixFile, entryKind); _logger.LogWarning("File {File} is a POSIX special file ({EntryKind}) and will be skipped", fileInfo.FullName, entryKind); } From c18ba68c2905abf5ae5a86e9c08ac8275f8e9969 Mon Sep 17 00:00:00 2001 From: Paul Fresquet Date: Tue, 3 Feb 2026 16:07:01 +0100 Subject: [PATCH 2/5] Update POSIX special file inventory tests --- .../Services/Inventories/TestInventoryBuilder.cs | 13 +++++++------ .../Inventories/InventoryBuilderInspectorTests.cs | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/ByteSync.Client.IntegrationTests/Services/Inventories/TestInventoryBuilder.cs b/tests/ByteSync.Client.IntegrationTests/Services/Inventories/TestInventoryBuilder.cs index 854fafbb..90897655 100644 --- a/tests/ByteSync.Client.IntegrationTests/Services/Inventories/TestInventoryBuilder.cs +++ b/tests/ByteSync.Client.IntegrationTests/Services/Inventories/TestInventoryBuilder.cs @@ -747,7 +747,8 @@ public async Task Test_PosixFifo_IsSkipped() var sessionSettings = SessionSettings.BuildDefault(); var osPlatform = OperatingSystem.IsMacOS() ? OSPlatforms.MacOs : OSPlatforms.Linux; - inventoryBuilder = BuildInventoryBuilder(sessionSettings, null, null, osPlatform); + var inventoryProcessData = new InventoryProcessData(); + inventoryBuilder = BuildInventoryBuilder(sessionSettings, inventoryProcessData, null, osPlatform); inventoryBuilder.AddInventoryPart(sourceA.FullName); await inventoryBuilder.BuildBaseInventoryAsync(inventoryAFilePath); @@ -765,11 +766,11 @@ public async Task Test_PosixFifo_IsSkipped() inventory = inventoryBuilder.Inventory!; inventory.InventoryParts.Count.Should().Be(1); inventory.InventoryParts[0].DirectoryDescriptions.Count.Should().Be(0); - inventory.InventoryParts[0].FileDescriptions.Count.Should().Be(2); - - var fifoDescription = inventory.InventoryParts[0].FileDescriptions.Single(fd => fd.Name.Equals("pipeA")); - fifoDescription.IsAccessible.Should().BeFalse(); - inventory.InventoryParts[0].IsIncompleteDueToAccess.Should().BeTrue(); + inventory.InventoryParts[0].FileDescriptions.Count.Should().Be(1); + inventory.InventoryParts[0].FileDescriptions.Single().Name.Should().Be("fileA.txt"); + inventory.InventoryParts[0].IsIncompleteDueToAccess.Should().BeFalse(); + inventoryProcessData.SkippedEntries.Should() + .ContainSingle(entry => entry.Name == "pipeA" && entry.Reason == SkipReason.SpecialPosixFile); } [Test] diff --git a/tests/ByteSync.Client.UnitTests/Services/Inventories/InventoryBuilderInspectorTests.cs b/tests/ByteSync.Client.UnitTests/Services/Inventories/InventoryBuilderInspectorTests.cs index 9a2710b1..8f14aaff 100644 --- a/tests/ByteSync.Client.UnitTests/Services/Inventories/InventoryBuilderInspectorTests.cs +++ b/tests/ByteSync.Client.UnitTests/Services/Inventories/InventoryBuilderInspectorTests.cs @@ -339,7 +339,8 @@ public async Task Posix_Special_File_Is_Recorded() await builder.BuildBaseInventoryAsync(invPath); var part = builder.Inventory.InventoryParts.Single(); - part.FileDescriptions.Should().ContainSingle(fd => !fd.IsAccessible); + part.FileDescriptions.Should().BeEmpty(); + part.IsIncompleteDueToAccess.Should().BeFalse(); processData.SkippedEntries.Should() .ContainSingle(e => e.Name == "posix_special.txt" && e.Reason == SkipReason.SpecialPosixFile); } From 607fa4e3f5a92099a12ecf6036d7c699a4a949d7 Mon Sep 17 00:00:00 2001 From: Paul Fresquet Date: Tue, 3 Feb 2026 16:22:14 +0100 Subject: [PATCH 3/5] feat: improve logging --- src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs b/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs index e722d7b4..367e25bd 100644 --- a/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs +++ b/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs @@ -271,6 +271,7 @@ private void ProcessSubDirectories(InventoryPart inventoryPart, DirectoryInfo di if (IsReparsePoint(subDirectory)) { RecordSkippedEntry(inventoryPart, subDirectory, SkipReason.Symlink, FileSystemEntryKind.Symlink); + continue; } } @@ -480,6 +481,8 @@ private void DoAnalyze(InventoryPart inventoryPart, DirectoryInfo directoryInfo, if (IsPosixSpecialFile(entryKind)) { RecordSkippedEntry(inventoryPart, directoryInfo, SkipReason.SpecialPosixFile, entryKind); + _logger.LogWarning("Directory {Directory} is a POSIX special file ({EntryKind}) and will be skipped", + directoryInfo.FullName, entryKind); return; } @@ -735,4 +738,4 @@ private void AddFileSystemDescription(InventoryPart inventoryPart, FileSystemDes } } } -} +} \ No newline at end of file From 10bbd67d8b2e9f37ebb2c46971126ff5e480ee6b Mon Sep 17 00:00:00 2001 From: Paul Fresquet Date: Tue, 3 Feb 2026 16:58:42 +0100 Subject: [PATCH 4/5] test: improve test covering --- .../InventoryBuilderInspectorTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/ByteSync.Client.UnitTests/Services/Inventories/InventoryBuilderInspectorTests.cs b/tests/ByteSync.Client.UnitTests/Services/Inventories/InventoryBuilderInspectorTests.cs index 8f14aaff..d6d7e941 100644 --- a/tests/ByteSync.Client.UnitTests/Services/Inventories/InventoryBuilderInspectorTests.cs +++ b/tests/ByteSync.Client.UnitTests/Services/Inventories/InventoryBuilderInspectorTests.cs @@ -364,6 +364,28 @@ public async Task Posix_Symlink_Directory_Is_Recorded() processData.SkippedEntries.Should() .ContainSingle(e => e.Name == "root_posix_symlink" && e.Reason == SkipReason.Symlink); } + + [Test] + public async Task Posix_Special_Directory_Is_Recorded() + { + var insp = new Mock(MockBehavior.Strict); + var posix = new Mock(MockBehavior.Strict); + posix.Setup(p => p.ClassifyPosixEntry(It.IsAny())).Returns(FileSystemEntryKind.BlockDevice); + var (builder, processData) = CreateBuilderWithData(insp.Object, posix.Object); + + var root = Directory.CreateDirectory(Path.Combine(TestDirectory.FullName, "root_posix_special")); + + builder.AddInventoryPart(root.FullName); + var invPath = Path.Combine(TestDirectory.FullName, "inv_posix_special_dir.zip"); + await builder.BuildBaseInventoryAsync(invPath); + + var part = builder.Inventory.InventoryParts.Single(); + part.DirectoryDescriptions.Should().BeEmpty(); + part.FileDescriptions.Should().BeEmpty(); + part.IsIncompleteDueToAccess.Should().BeFalse(); + processData.SkippedEntries.Should() + .ContainSingle(e => e.Name == "root_posix_special" && e.Reason == SkipReason.SpecialPosixFile); + } [Test] public async Task Reparse_File_Is_Ignored() From b3282820016385c7ed40ad6911763c343850018b Mon Sep 17 00:00:00 2001 From: Paul Fresquet Date: Tue, 3 Feb 2026 17:23:38 +0100 Subject: [PATCH 5/5] refactor: improve maintanability --- .../Services/Inventories/InventoryBuilder.cs | 110 ++++++++++-------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs b/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs index 367e25bd..83e04c88 100644 --- a/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs +++ b/src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs @@ -378,57 +378,8 @@ private bool ShouldIgnoreHiddenDirectory(DirectoryInfo directoryInfo) { var isRoot = IsRootPath(inventoryPart, fileInfo); - var entryKind = PosixFileTypeClassifier.ClassifyPosixEntry(fileInfo.FullName); - if (entryKind == FileSystemEntryKind.Symlink) + if (TryHandleFileSkip(inventoryPart, fileInfo, isRoot)) { - RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.Symlink, FileSystemEntryKind.Symlink); - - return; - } - - if (IsPosixSpecialFile(entryKind)) - { - AddPosixSpecialFileAndLog(inventoryPart, fileInfo, entryKind); - - return; - } - - if (!isRoot && ShouldIgnoreHiddenFile(fileInfo)) - { - RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.Hidden, FileSystemEntryKind.RegularFile); - - return; - } - - if (!isRoot) - { - var systemSkipReason = GetSystemSkipReason(fileInfo); - if (systemSkipReason.HasValue) - { - RecordSkippedEntry(inventoryPart, fileInfo, systemSkipReason.Value, FileSystemEntryKind.RegularFile); - - return; - } - } - - if (IsReparsePoint(fileInfo)) - { - RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.Symlink, FileSystemEntryKind.Symlink); - - return; - } - - if (!FileSystemInspector.Exists(fileInfo)) - { - RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.NotFound); - - return; - } - - if (FileSystemInspector.IsOffline(fileInfo) || IsRecallOnDataAccess(fileInfo)) - { - RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.Offline, FileSystemEntryKind.RegularFile); - return; } @@ -455,6 +406,65 @@ private bool ShouldIgnoreHiddenDirectory(DirectoryInfo directoryInfo) } } + private bool TryHandleFileSkip(InventoryPart inventoryPart, FileInfo fileInfo, bool isRoot) + { + var entryKind = PosixFileTypeClassifier.ClassifyPosixEntry(fileInfo.FullName); + if (entryKind == FileSystemEntryKind.Symlink) + { + RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.Symlink, FileSystemEntryKind.Symlink); + + return true; + } + + if (IsPosixSpecialFile(entryKind)) + { + AddPosixSpecialFileAndLog(inventoryPart, fileInfo, entryKind); + + return true; + } + + if (!isRoot && ShouldIgnoreHiddenFile(fileInfo)) + { + RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.Hidden, FileSystemEntryKind.RegularFile); + + return true; + } + + if (!isRoot) + { + var systemSkipReason = GetSystemSkipReason(fileInfo); + if (systemSkipReason.HasValue) + { + RecordSkippedEntry(inventoryPart, fileInfo, systemSkipReason.Value, FileSystemEntryKind.RegularFile); + + return true; + } + } + + if (IsReparsePoint(fileInfo)) + { + RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.Symlink, FileSystemEntryKind.Symlink); + + return true; + } + + if (!FileSystemInspector.Exists(fileInfo)) + { + RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.NotFound); + + return true; + } + + if (FileSystemInspector.IsOffline(fileInfo) || IsRecallOnDataAccess(fileInfo)) + { + RecordSkippedEntry(inventoryPart, fileInfo, SkipReason.Offline, FileSystemEntryKind.RegularFile); + + return true; + } + + return false; + } + private void DoAnalyze(InventoryPart inventoryPart, DirectoryInfo directoryInfo, CancellationToken cancellationToken) {