Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 23 additions & 3 deletions src/ByteSync.Client/Services/Inventories/InventoryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,24 @@ private void AddInaccessibleDirectoryAndLog(InventoryPart inventoryPart, Directo
AddFileSystemDescription(inventoryPart, subDirectoryDescription);
_logger.LogWarning(ex, message, directoryInfo.FullName);
}

private bool IsRootPath(InventoryPart inventoryPart, FileSystemInfo fileSystemInfo)
{
var rootPath = NormalizePath(inventoryPart.RootPath);
var currentPath = NormalizePath(fileSystemInfo.FullName);
var comparison = OSPlatform == OSPlatforms.Windows
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;

return string.Equals(rootPath, currentPath, comparison);
}

private static string NormalizePath(string path)
{
var fullPath = Path.GetFullPath(path);

return Path.TrimEndingDirectorySeparator(fullPath);
}

private bool ShouldIgnoreHiddenDirectory(DirectoryInfo directoryInfo)
{
Expand Down Expand Up @@ -339,12 +357,14 @@ private bool ShouldIgnoreHiddenDirectory(DirectoryInfo directoryInfo)

try
{
if (ShouldIgnoreHiddenFile(fileInfo))
var isRoot = IsRootPath(inventoryPart, fileInfo);

if (!isRoot && ShouldIgnoreHiddenFile(fileInfo))
{
return;
}

if (ShouldIgnoreSystemFile(fileInfo))
if (!isRoot && ShouldIgnoreSystemFile(fileInfo))
{
return;
}
Expand Down Expand Up @@ -397,7 +417,7 @@ private void DoAnalyze(InventoryPart inventoryPart, DirectoryInfo directoryInfo,
return;
}

if (ShouldIgnoreHiddenDirectory(directoryInfo))
if (!IsRootPath(inventoryPart, directoryInfo) && ShouldIgnoreHiddenDirectory(directoryInfo))
{
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,93 @@ public async Task Test_HiddenFiles_Windows(bool excludeHiddenFiles, int expected
inventory.InventoryParts[0].FileDescriptions.Count.Should().Be(2 + expectedHiddenFiles);
}

[Test]
[Platform(Exclude = "Linux")]
public async Task Test_HiddenRootDirectory_Windows()
{
InventoryBuilder inventoryBuilder;
Inventory inventory;

DirectoryInfo sourceA, unzipDir;
FileInfo fileInfo;

sourceA = new DirectoryInfo(IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, "sourceA"));
sourceA.Create();
var rootAttributes = File.GetAttributes(sourceA.FullName);
File.SetAttributes(sourceA.FullName, rootAttributes | FileAttributes.Hidden);

fileInfo = new FileInfo(_testDirectoryService.CreateFileInDirectory(sourceA.FullName, "fileA.txt", "file1Content").FullName);
fileInfo = new FileInfo(_testDirectoryService.CreateFileInDirectory(sourceA.FullName, "fileA_hidden.txt", "file1Content").FullName);
File.SetAttributes(fileInfo.FullName, FileAttributes.Hidden);

var inventoryAFilePath = IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, $"inventoryA.zip");

var sessionSettings = SessionSettings.BuildDefault();
sessionSettings.ExcludeHiddenFiles = true;

inventoryBuilder = BuildInventoryBuilder(sessionSettings);
inventoryBuilder.AddInventoryPart(sourceA.FullName);
await inventoryBuilder.BuildBaseInventoryAsync(inventoryAFilePath);

File.Exists(inventoryAFilePath).Should().BeTrue();

unzipDir = new DirectoryInfo(IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, "unzip"));
unzipDir.Create();

var fastZip = new FastZip();
fastZip.ExtractZip(inventoryAFilePath, unzipDir.FullName, null);

unzipDir.GetFiles("*", SearchOption.AllDirectories).Length.Should().Be(1);
File.Exists(IOUtils.Combine(unzipDir.FullName, $"inventory.json")).Should().BeTrue();

inventory = inventoryBuilder.Inventory!;
inventory.InventoryParts.Count.Should().Be(1);
inventory.InventoryParts[0].FileDescriptions.Count.Should().Be(1);
inventory.InventoryParts[0].FileDescriptions[0].Name.Should().Be("fileA.txt");
}

[Test]
[Platform(Include = "Linux,MacOsX")]
public async Task Test_HiddenRootDirectory_Linux_Mac()
{
InventoryBuilder inventoryBuilder;
Inventory inventory;

DirectoryInfo sourceA, unzipDir;
FileInfo fileInfo;

sourceA = new DirectoryInfo(IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, ".sourceA"));
sourceA.Create();

fileInfo = new FileInfo(_testDirectoryService.CreateFileInDirectory(sourceA.FullName, "fileA.txt", "file1Content").FullName);
fileInfo = new FileInfo(_testDirectoryService.CreateFileInDirectory(sourceA.FullName, ".fileA_hidden.txt", "file1Content").FullName);

var inventoryAFilePath = IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, $"inventoryA.zip");

var sessionSettings = SessionSettings.BuildDefault();
sessionSettings.ExcludeHiddenFiles = true;

inventoryBuilder = BuildInventoryBuilder(sessionSettings);
inventoryBuilder.AddInventoryPart(sourceA.FullName);
await inventoryBuilder.BuildBaseInventoryAsync(inventoryAFilePath);

File.Exists(inventoryAFilePath).Should().BeTrue();

unzipDir = new DirectoryInfo(IOUtils.Combine(_testDirectoryService.TestDirectory.FullName, "unzip"));
unzipDir.Create();

var fastZip = new FastZip();
fastZip.ExtractZip(inventoryAFilePath, unzipDir.FullName, null);

unzipDir.GetFiles("*", SearchOption.AllDirectories).Length.Should().Be(1);
File.Exists(IOUtils.Combine(unzipDir.FullName, $"inventory.json")).Should().BeTrue();

inventory = inventoryBuilder.Inventory!;
inventory.InventoryParts.Count.Should().Be(1);
inventory.InventoryParts[0].FileDescriptions.Count.Should().Be(1);
inventory.InventoryParts[0].FileDescriptions[0].Name.Should().Be("fileA.txt");
}

[Test]
[Platform(Exclude = "Win")]
[TestCase(true, 0)]
Expand Down Expand Up @@ -786,4 +873,4 @@ private InventoryBuilder BuildInventoryBuilder(SessionSettings? sessionSettings
saver,
new InventoryIndexer());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,15 @@ private InventoryBuilder CreateBuilder(IFileSystemInspector inspector)
}

[Test]
public async Task Hidden_File_Is_Ignored()
public async Task Hidden_Root_File_Is_Analyzed()
{
var insp = new Mock<IFileSystemInspector>(MockBehavior.Strict);
insp.Setup(i => i.IsHidden(It.IsAny<FileSystemInfo>(), It.IsAny<OSPlatforms>())).Returns(true);
insp.Setup(i => i.IsSystem(It.IsAny<FileInfo>())).Returns(false);
insp.Setup(i => i.IsReparsePoint(It.IsAny<FileSystemInfo>())).Returns(false);
insp.Setup(i => i.Exists(It.IsAny<FileInfo>())).Returns(true);
insp.Setup(i => i.IsOffline(It.IsAny<FileInfo>())).Returns(false);
insp.Setup(i => i.IsRecallOnDataAccess(It.IsAny<FileInfo>())).Returns(false);
var builder = CreateBuilder(insp.Object);

var filePath = Path.Combine(TestDirectory.FullName, "a.txt");
Expand All @@ -89,15 +94,19 @@ public async Task Hidden_File_Is_Ignored()
await builder.BuildBaseInventoryAsync(invPath);

var part = builder.Inventory.InventoryParts.Single();
part.FileDescriptions.Should().BeEmpty();
part.FileDescriptions.Should().ContainSingle();
}

[Test]
public async Task System_File_Is_Ignored()
public async Task System_Root_File_Is_Analyzed()
{
var insp = new Mock<IFileSystemInspector>(MockBehavior.Strict);
insp.Setup(i => i.IsHidden(It.IsAny<FileSystemInfo>(), It.IsAny<OSPlatforms>())).Returns(false);
insp.Setup(i => i.IsSystem(It.IsAny<FileInfo>())).Returns(true);
insp.Setup(i => i.IsReparsePoint(It.IsAny<FileSystemInfo>())).Returns(false);
insp.Setup(i => i.Exists(It.IsAny<FileInfo>())).Returns(true);
insp.Setup(i => i.IsOffline(It.IsAny<FileInfo>())).Returns(false);
insp.Setup(i => i.IsRecallOnDataAccess(It.IsAny<FileInfo>())).Returns(false);
var builder = CreateBuilder(insp.Object);

var filePath = Path.Combine(TestDirectory.FullName, "b.txt");
Expand All @@ -108,7 +117,91 @@ public async Task System_File_Is_Ignored()
await builder.BuildBaseInventoryAsync(invPath);

var part = builder.Inventory.InventoryParts.Single();
part.FileDescriptions.Should().BeEmpty();
part.FileDescriptions.Should().ContainSingle();
}

[Test]
public async Task Hidden_Root_Directory_Is_Analyzed()
{
var insp = new Mock<IFileSystemInspector>(MockBehavior.Strict);
insp.Setup(i => i.IsHidden(It.IsAny<DirectoryInfo>(), It.IsAny<OSPlatforms>())).Returns(true);
insp.Setup(i => i.IsHidden(It.IsAny<FileInfo>(), It.IsAny<OSPlatforms>())).Returns(false);
insp.Setup(i => i.IsSystem(It.IsAny<FileInfo>())).Returns(false);
insp.Setup(i => i.IsReparsePoint(It.IsAny<FileSystemInfo>())).Returns(false);
insp.Setup(i => i.Exists(It.IsAny<FileInfo>())).Returns(true);
insp.Setup(i => i.IsOffline(It.IsAny<FileInfo>())).Returns(false);
insp.Setup(i => i.IsRecallOnDataAccess(It.IsAny<FileInfo>())).Returns(false);
var builder = CreateBuilder(insp.Object);

var root = Directory.CreateDirectory(Path.Combine(TestDirectory.FullName, "root_hidden"));
var filePath = Path.Combine(root.FullName, "f.txt");
await File.WriteAllTextAsync(filePath, "x");

builder.AddInventoryPart(root.FullName);
var invPath = Path.Combine(TestDirectory.FullName, "inv_hidden_root.zip");
await builder.BuildBaseInventoryAsync(invPath);

var part = builder.Inventory.InventoryParts.Single();
part.FileDescriptions.Should().ContainSingle();
part.FileDescriptions[0].RelativePath.Should().Be("/f.txt");
}

[Test]
public async Task Hidden_Child_File_Is_Ignored()
{
var insp = new Mock<IFileSystemInspector>(MockBehavior.Strict);
insp.Setup(i => i.IsHidden(It.IsAny<DirectoryInfo>(), It.IsAny<OSPlatforms>())).Returns(false);
insp.Setup(i => i.IsHidden(It.Is<FileInfo>(fi => fi.Name == "hidden.txt"), It.IsAny<OSPlatforms>()))
.Returns(true);
insp.Setup(i => i.IsHidden(It.Is<FileInfo>(fi => fi.Name != "hidden.txt"), It.IsAny<OSPlatforms>()))
.Returns(false);
insp.Setup(i => i.IsSystem(It.IsAny<FileInfo>())).Returns(false);
insp.Setup(i => i.IsReparsePoint(It.IsAny<FileSystemInfo>())).Returns(false);
insp.Setup(i => i.Exists(It.IsAny<FileInfo>())).Returns(true);
insp.Setup(i => i.IsOffline(It.IsAny<FileInfo>())).Returns(false);
insp.Setup(i => i.IsRecallOnDataAccess(It.IsAny<FileInfo>())).Returns(false);
var builder = CreateBuilder(insp.Object);

var root = Directory.CreateDirectory(Path.Combine(TestDirectory.FullName, "root_hidden_child"));
var visiblePath = Path.Combine(root.FullName, "visible.txt");
var hiddenPath = Path.Combine(root.FullName, "hidden.txt");
await File.WriteAllTextAsync(visiblePath, "x");
await File.WriteAllTextAsync(hiddenPath, "x");

builder.AddInventoryPart(root.FullName);
var invPath = Path.Combine(TestDirectory.FullName, "inv_hidden_child.zip");
await builder.BuildBaseInventoryAsync(invPath);

var part = builder.Inventory.InventoryParts.Single();
part.FileDescriptions.Should().ContainSingle(fd => fd.Name == "visible.txt");
}

[Test]
public async Task System_Child_File_Is_Ignored()
{
var insp = new Mock<IFileSystemInspector>(MockBehavior.Strict);
insp.Setup(i => i.IsHidden(It.IsAny<DirectoryInfo>(), It.IsAny<OSPlatforms>())).Returns(false);
insp.Setup(i => i.IsHidden(It.IsAny<FileInfo>(), It.IsAny<OSPlatforms>())).Returns(false);
insp.Setup(i => i.IsSystem(It.Is<FileInfo>(fi => fi.Name == "system.txt"))).Returns(true);
insp.Setup(i => i.IsSystem(It.Is<FileInfo>(fi => fi.Name != "system.txt"))).Returns(false);
insp.Setup(i => i.IsReparsePoint(It.IsAny<FileSystemInfo>())).Returns(false);
insp.Setup(i => i.Exists(It.IsAny<FileInfo>())).Returns(true);
insp.Setup(i => i.IsOffline(It.IsAny<FileInfo>())).Returns(false);
insp.Setup(i => i.IsRecallOnDataAccess(It.IsAny<FileInfo>())).Returns(false);
var builder = CreateBuilder(insp.Object);

var root = Directory.CreateDirectory(Path.Combine(TestDirectory.FullName, "root_system_child"));
var visiblePath = Path.Combine(root.FullName, "visible.txt");
var systemPath = Path.Combine(root.FullName, "system.txt");
await File.WriteAllTextAsync(visiblePath, "x");
await File.WriteAllTextAsync(systemPath, "x");

builder.AddInventoryPart(root.FullName);
var invPath = Path.Combine(TestDirectory.FullName, "inv_system_child.zip");
await builder.BuildBaseInventoryAsync(invPath);

var part = builder.Inventory.InventoryParts.Single();
part.FileDescriptions.Should().ContainSingle(fd => fd.Name == "visible.txt");
}

[Test]
Expand Down Expand Up @@ -320,4 +413,4 @@ public async Task Directory_ReparsePoint_Is_Skipped()
part.FileDescriptions.Should().ContainSingle();
part.FileDescriptions[0].RelativePath.Should().Be("/ok.txt");
}
}
}
Loading