From 1134e4fbf3d4571ab4a5594a621a382fa988007d Mon Sep 17 00:00:00 2001 From: Gerard Smit Date: Mon, 27 May 2024 22:54:49 +0200 Subject: [PATCH 1/5] Fix Linux unit tests --- .../FileSystems/TestFileSystemBase.cs | 19 +++-- .../FileSystems/TestFileSystemCompactBase.cs | 70 ++++++++++++------- .../FileSystems/TestPhysicalFileSystem.cs | 68 +++++++++++------- .../TestPhysicalFileSystemCompat.cs | 7 ++ .../FileSystems/TestSubFileSystem.cs | 8 ++- .../FileSystems/TestZipArchiveFileSystem.cs | 4 +- src/Zio.Tests/TestUPath.cs | 2 + src/Zio.Tests/Zio.Tests.csproj | 1 + src/Zio.sln.DotSettings | 1 + src/Zio/FileSystems/AggregateFileSystem.cs | 6 +- src/Zio/FileSystems/FileSystem.cs | 2 +- src/Zio/FileSystems/MemoryFileSystem.cs | 3 +- src/Zio/FileSystems/PhysicalFileSystem.cs | 4 +- src/Zio/FileSystems/ReadOnlyFileSystem.cs | 6 +- src/Zio/FileSystems/ZipArchiveFileSystem.cs | 7 +- 15 files changed, 141 insertions(+), 67 deletions(-) diff --git a/src/Zio.Tests/FileSystems/TestFileSystemBase.cs b/src/Zio.Tests/FileSystems/TestFileSystemBase.cs index 0dfbf9c..c0622d8 100644 --- a/src/Zio.Tests/FileSystems/TestFileSystemBase.cs +++ b/src/Zio.Tests/FileSystems/TestFileSystemBase.cs @@ -237,7 +237,7 @@ protected void AssertCommonReadOnly(IFileSystem fs) AssertCommonRead(fs, true); } - protected void AssertCommonRead(IFileSystem fs, bool isReadOnly = false) + protected void AssertCommonRead(IFileSystem fs, bool isReadOnly = false, bool? isWindows = null) { { var innerPath = fs.ConvertPathToInternal("/"); @@ -283,17 +283,26 @@ protected void AssertCommonRead(IFileSystem fs, bool isReadOnly = false) Assert.StartsWith("content", fs.ReadAllText("/b.txt")); Assert.StartsWith("content", fs.ReadAllText("/a/a/a1.txt")); + var fileFlag = (isWindows ?? IsWindows, isReadOnly) switch + { + // Windows + (true, true) => FileAttributes.ReadOnly | FileAttributes.Archive, + (true, false) => FileAttributes.Archive, - var readOnlyFlag = isReadOnly ? FileAttributes.ReadOnly : 0; + // Linux + (false, true) => FileAttributes.ReadOnly, + (false, false) => FileAttributes.Normal + }; - Assert.Equal(readOnlyFlag | FileAttributes.Archive, fs.GetAttributes("/A.txt")); - Assert.Equal(readOnlyFlag | FileAttributes.Archive, fs.GetAttributes("/b.txt")); - Assert.Equal(readOnlyFlag | FileAttributes.Archive, fs.GetAttributes("/a/a/a1.txt")); + Assert.Equal(fileFlag, fs.GetAttributes("/A.txt")); + Assert.Equal(fileFlag, fs.GetAttributes("/b.txt")); + Assert.Equal(fileFlag, fs.GetAttributes("/a/a/a1.txt")); Assert.True(fs.GetFileLength("/A.txt") > 0); Assert.True(fs.GetFileLength("/b.txt") > 0); Assert.True(fs.GetFileLength("/a/a/a1.txt") > 0); + var readOnlyFlag = isReadOnly ? FileAttributes.ReadOnly : 0; Assert.Equal(readOnlyFlag | FileAttributes.Directory, fs.GetAttributes("/a")); Assert.Equal(readOnlyFlag | FileAttributes.Directory, fs.GetAttributes("/a/a")); Assert.Equal(readOnlyFlag | FileAttributes.Directory, fs.GetAttributes("/C")); diff --git a/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs b/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs index 6b2acc8..05b4f86 100644 --- a/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs +++ b/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs @@ -78,14 +78,23 @@ public void TestDirectoryExceptions() fs.WriteAllText("/toto.txt", "test"); Assert.Throws(() => fs.CreateDirectory("/toto.txt")); - Assert.Throws(() => fs.DeleteDirectory("/toto.txt", true)); + + if (IsWindows) + { + Assert.Throws(() => fs.DeleteDirectory("/toto.txt", true)); + } + Assert.Throws(() => fs.MoveDirectory("/toto.txt", "/test")); fs.CreateDirectory("/dir2"); Assert.Throws(() => fs.MoveDirectory("/dir1", "/dir2")); - fs.SetAttributes("/dir1", FileAttributes.Directory | FileAttributes.ReadOnly); - Assert.Throws(() => fs.DeleteDirectory("/dir1", true)); + if (IsWindows) + { + // Linux allows modifications on directories while they are readonly. + fs.SetAttributes("/dir1", FileAttributes.Directory | FileAttributes.ReadOnly); + Assert.Throws(() => fs.DeleteDirectory("/dir1", true)); + } } [Fact] @@ -122,21 +131,23 @@ public void TestFile() Assert.True(fs.GetFileLength("/toto.txt") > 0); Assert.Equal(fs.GetFileLength("/toto.txt"), fs.GetFileLength("/titi.txt")); Assert.Equal(fs.GetAttributes("/toto.txt"), fs.GetAttributes("/titi.txt")); - Assert.NotEqual(fs.GetCreationTime("/toto.txt"), fs.GetCreationTime("/titi.txt")); + if (IsWindows) Assert.NotEqual(fs.GetCreationTime("/toto.txt"), fs.GetCreationTime("/titi.txt")); // Because we read titi.txt just before, access time must be different // Following test is disabled as it seems unstable with NTFS? // Assert.NotEqual(fs.GetLastAccessTime("/toto.txt"), fs.GetLastAccessTime("/titi.txt")); Assert.Equal(fs.GetLastWriteTime("/toto.txt"), fs.GetLastWriteTime("/titi.txt")); - var now = DateTime.Now + TimeSpan.FromSeconds(10); - var now1 = DateTime.Now + TimeSpan.FromSeconds(11); - var now2 = DateTime.Now + TimeSpan.FromSeconds(12); - fs.SetCreationTime("/toto.txt", now); - fs.SetLastAccessTime("/toto.txt", now1); - fs.SetLastWriteTime("/toto.txt", now2); - Assert.Equal(now, fs.GetCreationTime("/toto.txt")); - Assert.Equal(now1, fs.GetLastAccessTime("/toto.txt")); - Assert.Equal(now2, fs.GetLastWriteTime("/toto.txt")); + var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetCreationTime("/toto.txt", creationTime); + Assert.Equal(creationTime, fs.GetCreationTime("/toto.txt")); + + var lastWriteTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetLastWriteTime("/toto.txt", lastWriteTime); + Assert.Equal(lastWriteTime, fs.GetLastWriteTime("/toto.txt")); + + var lastAccessTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetLastAccessTime("/toto.txt", lastAccessTime); + Assert.Equal(lastAccessTime, fs.GetLastAccessTime("/toto.txt")); Assert.NotEqual(fs.GetCreationTime("/toto.txt"), fs.GetCreationTime("/titi.txt")); Assert.NotEqual(fs.GetLastAccessTime("/toto.txt"), fs.GetLastAccessTime("/titi.txt")); @@ -171,11 +182,15 @@ public void TestFile() Assert.Equal(originalContent, content); // Check File ReadOnly - fs.SetAttributes("/titi.txt", FileAttributes.ReadOnly); - Assert.Throws(() => fs.DeleteFile("/titi.txt")); - Assert.Throws(() => fs.CopyFile("/titi.bak.txt", "/titi.txt", true)); - Assert.Throws(() => fs.OpenFile("/titi.txt", FileMode.Open, FileAccess.ReadWrite)); - fs.SetAttributes("/titi.txt", FileAttributes.Normal); + if (IsWindows) + { + // Linux allows modifications on files while they are readonly. + fs.SetAttributes("/titi.txt", FileAttributes.ReadOnly); + Assert.Throws(() => fs.DeleteFile("/titi.txt")); + Assert.Throws(() => fs.CopyFile("/titi.bak.txt", "/titi.txt", true)); + Assert.Throws(() => fs.OpenFile("/titi.txt", FileMode.Open, FileAccess.ReadWrite)); + fs.SetAttributes("/titi.txt", FileAttributes.Normal); + } // Delete File fs.DeleteFile("/titi.txt"); @@ -279,21 +294,24 @@ public void TestFileExceptions() Assert.Equal(defaultTime, fs.GetLastWriteTime("/dest")); Assert.Equal(defaultTime, fs.GetLastAccessTime("/dest")); - using (var stream1 = fs.OpenFile("/toto.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) + if (IsWindows) { - Assert.Throws(() => + using (var stream1 = fs.OpenFile("/toto.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) { - using (var stream2 = fs.OpenFile("/toto.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) + Assert.Throws(() => { - } - }); + using (var stream2 = fs.OpenFile("/toto.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) + { + } + }); + } } Assert.Throws(() => fs.OpenFile("/dir1", FileMode.Open, FileAccess.Read)); Assert.Throws(() => fs.OpenFile("/dir/toto.txt", FileMode.Open, FileAccess.Read)); Assert.Throws(() => fs.CopyFile("/toto.txt", "/dest/toto.txt", true)); Assert.Throws(() => fs.CopyFile("/toto.txt", "/titi.txt", false)); - Assert.Throws(() => fs.CopyFile("/toto.txt", "/dir1", true)); + if (IsWindows) Assert.Throws(() => fs.CopyFile("/toto.txt", "/dir1", true)); Assert.Throws(() => fs.MoveFile("/toto.txt", "/dest/toto.txt")); fs.WriteAllText("/titi.txt", "yo2"); @@ -319,8 +337,8 @@ public void TestFileExceptions() } } - [Fact] - public void TestDirectoryDeleteAndOpenFile() + [SkippableFact] + public virtual void TestDirectoryDeleteAndOpenFileOnWindows() { fs.CreateDirectory("/dir"); fs.WriteAllText("/dir/toto.txt", "content"); diff --git a/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs b/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs index 20c3620..caa7e18 100644 --- a/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs +++ b/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs @@ -18,9 +18,11 @@ public void TestCommonRead() AssertCommonRead(fs); } - [Fact] - public void TestFileSystemInvalidDriveLetter() + [SkippableFact] + public void TestFileSystemInvalidDriveLetterOnWindows() { + Skip.IfNot(IsWindows, "Exception is only thrown on Windows"); + var driverLetter = SystemPath[0]; Assert.Throws( () => new SubFileSystem(new PhysicalFileSystem(), $"/mnt/{driverLetter}")); using (var fs = new SubFileSystem(new PhysicalFileSystem(), $"/mnt/{char.ToLowerInvariant(driverLetter)}")) @@ -92,15 +94,17 @@ public void TestDirectory() // LastAccessTime // LastWriteTime // CreationTime - var lastWriteTime = DateTime.Now + TimeSpan.FromSeconds(10); - var lastAccessTime = DateTime.Now + TimeSpan.FromSeconds(11); - var creationTime = DateTime.Now + TimeSpan.FromSeconds(12); - fs.SetLastWriteTime(pathToCreate, lastWriteTime); - fs.SetLastAccessTime(pathToCreate, lastAccessTime); + var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); fs.SetCreationTime(pathToCreate, creationTime); + Assert.Equal(creationTime, fs.GetCreationTime(pathToCreate)); + + var lastWriteTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetLastWriteTime(pathToCreate, lastWriteTime); Assert.Equal(lastWriteTime, fs.GetLastWriteTime(pathToCreate)); + + var lastAccessTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetLastAccessTime(pathToCreate, lastAccessTime); Assert.Equal(lastAccessTime, fs.GetLastAccessTime(pathToCreate)); - Assert.Equal(creationTime, fs.GetCreationTime(pathToCreate)); // DirectoryExists Assert.True(fs.DirectoryExists(pathToCreate)); @@ -155,9 +159,11 @@ public void TestDirectorySpecial() } } - [Fact] - public void TestDirectoryExceptions() + [SkippableFact] + public void TestDirectoryWindowsExceptions() { + Skip.IfNot(IsWindows, "Exceptions are only thrown on Windows"); + var fs = new PhysicalFileSystem(); // Test invalid characters in path @@ -187,6 +193,18 @@ public void TestDirectoryExceptions() Assert.Throws(() => fs.DeleteDirectory("/mnt/yoyo", false)); } + [SkippableFact] + public void TestWindowsDirectoryAttributes() + { + Skip.IfNot(IsWindows, "Root attributes are only set on the Windows"); + + var fs = new PhysicalFileSystem(); + var sysAttr = FileAttributes.Directory | FileAttributes.System | FileAttributes.ReadOnly; + + Assert.True((fs.GetAttributes("/") & (sysAttr)) == sysAttr); + Assert.True((fs.GetAttributes("/mnt") & (sysAttr)) == sysAttr); + } + [Fact] public void TestFile() { @@ -217,15 +235,17 @@ public void TestFile() Assert.Equal(File.GetLastAccessTime(systemFilePath), fs.GetLastAccessTime(filePath)); Assert.Equal(File.GetCreationTime(systemFilePath), fs.GetCreationTime(filePath)); - var lastWriteTime = DateTime.Now + TimeSpan.FromSeconds(10); - var lastAccessTime = DateTime.Now + TimeSpan.FromSeconds(11); - var creationTime = DateTime.Now + TimeSpan.FromSeconds(12); - fs.SetLastWriteTime(filePath, lastWriteTime); - fs.SetLastAccessTime(filePath, lastAccessTime); + var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); fs.SetCreationTime(filePath, creationTime); + Assert.Equal(creationTime, fs.GetCreationTime(filePath)); + + var lastWriteTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetLastWriteTime(filePath, lastWriteTime); Assert.Equal(lastWriteTime, fs.GetLastWriteTime(filePath)); + + var lastAccessTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetLastAccessTime(filePath, lastAccessTime); Assert.Equal(lastAccessTime, fs.GetLastAccessTime(filePath)); - Assert.Equal(creationTime, fs.GetCreationTime(filePath)); // FileAttributes Assert.Equal(File.GetAttributes(systemFilePath), fs.GetAttributes(filePath)); @@ -295,10 +315,6 @@ public void TestFile() fs.GetLastAccessTime("/mnt/c"); fs.GetCreationTime("/mnt/c"); fs.GetAttributes("/mnt/c"); - - var sysAttr = FileAttributes.Directory | FileAttributes.System | FileAttributes.ReadOnly; - Assert.True((fs.GetAttributes("/") & (sysAttr)) == sysAttr); - Assert.True((fs.GetAttributes("/mnt") & (sysAttr)) == sysAttr); } finally { @@ -319,17 +335,19 @@ public void TestEnumerate() Assert.Equal(expectedfiles, files); var dirs = fs.EnumerateDirectories(path / "../../..").Select(p => fs.ConvertPathToInternal(p)).ToList(); - var expecteddirs = Directory.EnumerateDirectories(Path.GetFullPath(Path.Combine(SystemPath, "..\\..\\.."))).ToList(); + var expecteddirs = Directory.EnumerateDirectories(Path.GetFullPath(Path.Combine(SystemPath, "../../.."))).ToList(); Assert.Equal(expecteddirs, dirs); var paths = fs.EnumeratePaths(path / "../..").Select(p => fs.ConvertPathToInternal(p)).ToList(); - var expectedPaths = Directory.EnumerateFileSystemEntries(Path.GetFullPath(Path.Combine(SystemPath, "..\\.."))).ToList(); + var expectedPaths = Directory.EnumerateFileSystemEntries(Path.GetFullPath(Path.Combine(SystemPath, "../.."))).ToList(); Assert.Equal(expectedPaths, paths); } - - [Fact] - public void TestFileExceptions() + + [SkippableFact] + public void TestFileWindowsExceptions() { + Skip.IfNot(IsWindows, "Exceptions are only thrown on Windows"); + var fs = new PhysicalFileSystem(); var path = fs.ConvertPathFromInternal(SystemPath); var fileName = $"toto-{Guid.NewGuid()}.txt"; diff --git a/src/Zio.Tests/FileSystems/TestPhysicalFileSystemCompat.cs b/src/Zio.Tests/FileSystems/TestPhysicalFileSystemCompat.cs index e78537a..c9e1d82 100644 --- a/src/Zio.Tests/FileSystems/TestPhysicalFileSystemCompat.cs +++ b/src/Zio.Tests/FileSystems/TestPhysicalFileSystemCompat.cs @@ -14,6 +14,13 @@ public TestPhysicalFileSystemCompat() fs = _fsHelper.PhysicalFileSystem; } + public override void TestDirectoryDeleteAndOpenFileOnWindows() + { + Skip.IfNot(IsWindows, "Linux allows files to be deleted when they are open"); + + base.TestDirectoryDeleteAndOpenFileOnWindows(); + } + public override void Dispose() { _fsHelper.Dispose(); diff --git a/src/Zio.Tests/FileSystems/TestSubFileSystem.cs b/src/Zio.Tests/FileSystems/TestSubFileSystem.cs index 48d4353..ed79648 100644 --- a/src/Zio.Tests/FileSystems/TestSubFileSystem.cs +++ b/src/Zio.Tests/FileSystems/TestSubFileSystem.cs @@ -29,9 +29,13 @@ public void TestBasic() // Check that SubFileSystem is actually checking that the directory exists in the delegate filesystem Assert.Throws(() => new SubFileSystem(fs, path / "does_not_exist")); - Assert.Throws(() => subfs.ConvertPathFromInternal(@"C:\")); + if (IsWindows) + { + Assert.Throws(() => subfs.ConvertPathFromInternal(@"C:\")); + } + // TODO: We could add another test just to make sure that files can be created...etc. But the test above should already cover the code provided in SubFileSystem - } + } [Fact] public void TestGetOrCreateFileSystem() diff --git a/src/Zio.Tests/FileSystems/TestZipArchiveFileSystem.cs b/src/Zio.Tests/FileSystems/TestZipArchiveFileSystem.cs index 36ead55..7888cbf 100644 --- a/src/Zio.Tests/FileSystems/TestZipArchiveFileSystem.cs +++ b/src/Zio.Tests/FileSystems/TestZipArchiveFileSystem.cs @@ -16,7 +16,9 @@ public class TestZipArchiveFileSystem : TestFileSystemBase public void TestCommonRead() { var fs = this.GetCommonZipArchiveFileSystem(); - this.AssertCommonRead(fs); + + // The ZIP is created on Windows, so it has the FileAttributes of a Windows system. + this.AssertCommonRead(fs, isWindows: true); } [Fact] diff --git a/src/Zio.Tests/TestUPath.cs b/src/Zio.Tests/TestUPath.cs index 0b19857..ec3a42b 100644 --- a/src/Zio.Tests/TestUPath.cs +++ b/src/Zio.Tests/TestUPath.cs @@ -1,3 +1,5 @@ +using System.IO; + namespace Zio.Tests; public class TestUPath diff --git a/src/Zio.Tests/Zio.Tests.csproj b/src/Zio.Tests/Zio.Tests.csproj index 89d8391..2508a12 100644 --- a/src/Zio.Tests/Zio.Tests.csproj +++ b/src/Zio.Tests/Zio.Tests.csproj @@ -14,6 +14,7 @@ runtime; build; native; contentfiles; analyzers + diff --git a/src/Zio.sln.DotSettings b/src/Zio.sln.DotSettings index ec726d9..0e0c8ec 100644 --- a/src/Zio.sln.DotSettings +++ b/src/Zio.sln.DotSettings @@ -4,6 +4,7 @@ Copyright (c) Alexandre Mutel. All rights reserved. This file is licensed under the BSD-Clause 2 license. See the license.txt file in the project root for more information. + True True True True diff --git a/src/Zio/FileSystems/AggregateFileSystem.cs b/src/Zio/FileSystems/AggregateFileSystem.cs index 40778eb..a7719c3 100644 --- a/src/Zio/FileSystems/AggregateFileSystem.cs +++ b/src/Zio/FileSystems/AggregateFileSystem.cs @@ -287,7 +287,11 @@ protected override Stream OpenFileImpl(UPath path, FileMode mode, FileAccess acc protected override FileAttributes GetAttributesImpl(UPath path) { var entry = GetPath(path); - return entry.FileSystem.GetAttributes(path) | FileAttributes.ReadOnly; + var attributes = entry.FileSystem.GetAttributes(path); + + return attributes == FileAttributes.Normal + ? FileAttributes.ReadOnly + : attributes | FileAttributes.ReadOnly; } /// diff --git a/src/Zio/FileSystems/FileSystem.cs b/src/Zio/FileSystems/FileSystem.cs index 0f7feb0..f85dea8 100644 --- a/src/Zio/FileSystems/FileSystem.cs +++ b/src/Zio/FileSystems/FileSystem.cs @@ -3,7 +3,7 @@ // See the license.txt file in the project root for more information. using System.Diagnostics; using System.IO; - +using System.Text; using static Zio.FileSystemExceptionHelper; namespace Zio.FileSystems; diff --git a/src/Zio/FileSystems/MemoryFileSystem.cs b/src/Zio/FileSystems/MemoryFileSystem.cs index c96c2e8..362c258 100644 --- a/src/Zio/FileSystems/MemoryFileSystem.cs +++ b/src/Zio/FileSystems/MemoryFileSystem.cs @@ -1744,7 +1744,8 @@ public FileNode(MemoryFileSystem fileSystem, DirectoryNode parentNode, string? n } else { - Attributes = FileAttributes.Archive; + // Mimic OS-specific attributes. + Attributes = PhysicalFileSystem.IsOnWindows ? FileAttributes.Archive : FileAttributes.Normal; Content = new FileContent(this); } } diff --git a/src/Zio/FileSystems/PhysicalFileSystem.cs b/src/Zio/FileSystems/PhysicalFileSystem.cs index cccfa1e..6d4ffd7 100644 --- a/src/Zio/FileSystems/PhysicalFileSystem.cs +++ b/src/Zio/FileSystems/PhysicalFileSystem.cs @@ -23,9 +23,9 @@ public class PhysicalFileSystem : FileSystem private const string DrivePrefixOnWindows = "/mnt/"; private static readonly UPath PathDrivePrefixOnWindows = new UPath(DrivePrefixOnWindows); #if NETSTANDARD - private static readonly bool IsOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + internal static readonly bool IsOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); #else - private static readonly bool IsOnWindows = CheckIsOnWindows(); + internal static readonly bool IsOnWindows = CheckIsOnWindows(); private static bool CheckIsOnWindows() { diff --git a/src/Zio/FileSystems/ReadOnlyFileSystem.cs b/src/Zio/FileSystems/ReadOnlyFileSystem.cs index 9986f82..50432d0 100644 --- a/src/Zio/FileSystems/ReadOnlyFileSystem.cs +++ b/src/Zio/FileSystems/ReadOnlyFileSystem.cs @@ -102,7 +102,11 @@ protected override Stream OpenFileImpl(UPath path, FileMode mode, FileAccess acc protected override FileAttributes GetAttributesImpl(UPath path) { // All paths are readonly - return base.GetAttributesImpl(path) | FileAttributes.ReadOnly; + var attributes = base.GetAttributesImpl(path); + + return attributes == FileAttributes.Normal + ? FileAttributes.ReadOnly + : attributes | FileAttributes.ReadOnly; } /// diff --git a/src/Zio/FileSystems/ZipArchiveFileSystem.cs b/src/Zio/FileSystems/ZipArchiveFileSystem.cs index 7c7ce23..c178888 100644 --- a/src/Zio/FileSystems/ZipArchiveFileSystem.cs +++ b/src/Zio/FileSystems/ZipArchiveFileSystem.cs @@ -492,12 +492,15 @@ protected override FileAttributes GetAttributesImpl(UPath path) var attributes = entry.FullName[entry.FullName.Length - 1] == DirectorySeparator ? FileAttributes.Directory : 0; #if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER - if (entry.ExternalAttributes == 0 && attributes == 0) + const FileAttributes validValues = (FileAttributes)0x7FFF /* Up to FileAttributes.Encrypted */ | FileAttributes.IntegrityStream | FileAttributes.NoScrubData; + var externalAttributes = (FileAttributes)entry.ExternalAttributes & validValues; + + if (externalAttributes == 0 && attributes == 0) { attributes |= FileAttributes.Normal; } - return (FileAttributes)entry.ExternalAttributes | attributes; + return externalAttributes | attributes; #endif // return standard attributes if it's not NetStandard2.1 return attributes == FileAttributes.Directory ? FileAttributes.Directory : entry.LastWriteTime >= _creationTime ? FileAttributes.Archive : FileAttributes.Normal; From 777e6afe9af7aac55f0c87e02499907318528aab Mon Sep 17 00:00:00 2001 From: Gerard Smit Date: Mon, 27 May 2024 23:06:24 +0200 Subject: [PATCH 2/5] Add CI for Linux --- .github/workflows/ci.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8d52bf..aebedf0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,11 @@ on: jobs: build: - runs-on: windows-latest + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest, windows-latest] steps: - name: Checkout @@ -26,7 +30,15 @@ jobs: dotnet-version: '8.0.x' - name: Build, Test, Pack, Publish + if: matrix.os == 'windows-latest' + shell: bash + run: | + dotnet tool install -g dotnet-releaser --configfile .github/workflows/nuget_org_only.config + dotnet-releaser run --nuget-token "${{secrets.NUGET_TOKEN}}" --github-token "${{secrets.GITHUB_TOKEN}}" src/dotnet-releaser.toml + + - name: Build, Test + if: matrix.os == 'ubuntu-latest' shell: bash run: | dotnet tool install -g dotnet-releaser --configfile .github/workflows/nuget_org_only.config - dotnet-releaser run --nuget-token "${{secrets.NUGET_TOKEN}}" --github-token "${{secrets.GITHUB_TOKEN}}" src/dotnet-releaser.toml \ No newline at end of file + dotnet-releaser build src/dotnet-releaser.toml \ No newline at end of file From 2d0cfeb3a25f65aa9ab5ac252d4f153184a51725 Mon Sep 17 00:00:00 2001 From: Gerard Smit Date: Mon, 27 May 2024 23:13:10 +0200 Subject: [PATCH 3/5] Fix CI errors --- .../FileSystems/TestFileSystemCompactBase.cs | 9 ++++-- .../FileSystems/TestPhysicalFileSystem.cs | 29 ++++++++++--------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs b/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs index 05b4f86..40bffe6 100644 --- a/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs +++ b/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs @@ -149,9 +149,12 @@ public void TestFile() fs.SetLastAccessTime("/toto.txt", lastAccessTime); Assert.Equal(lastAccessTime, fs.GetLastAccessTime("/toto.txt")); - Assert.NotEqual(fs.GetCreationTime("/toto.txt"), fs.GetCreationTime("/titi.txt")); - Assert.NotEqual(fs.GetLastAccessTime("/toto.txt"), fs.GetLastAccessTime("/titi.txt")); - Assert.NotEqual(fs.GetLastWriteTime("/toto.txt"), fs.GetLastWriteTime("/titi.txt")); + if (IsWindows) + { + Assert.NotEqual(fs.GetCreationTime("/toto.txt"), fs.GetCreationTime("/titi.txt")); + Assert.NotEqual(fs.GetLastAccessTime("/toto.txt"), fs.GetLastAccessTime("/titi.txt")); + Assert.NotEqual(fs.GetLastWriteTime("/toto.txt"), fs.GetLastWriteTime("/titi.txt")); + } // Test MoveFile fs.MoveFile("/toto.txt", "/tata.txt"); diff --git a/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs b/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs index caa7e18..822d9ca 100644 --- a/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs +++ b/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs @@ -302,19 +302,22 @@ public void TestFile() Assert.Equal(buffer2.Length, fs.GetFileLength(filePathDest)); Assert.Equal(buffer.Length, fs.GetFileLength(filePathBack)); - // RootFileSystem - fs.GetLastWriteTime("/"); - fs.GetLastAccessTime("/"); - fs.GetCreationTime("/"); - - fs.GetLastWriteTime("/mnt"); - fs.GetLastAccessTime("/mnt"); - fs.GetCreationTime("/mnt"); - - fs.GetLastWriteTime("/mnt/c"); - fs.GetLastAccessTime("/mnt/c"); - fs.GetCreationTime("/mnt/c"); - fs.GetAttributes("/mnt/c"); + if (IsWindows) + { + // RootFileSystem + fs.GetLastWriteTime("/"); + fs.GetLastAccessTime("/"); + fs.GetCreationTime("/"); + + fs.GetLastWriteTime("/mnt"); + fs.GetLastAccessTime("/mnt"); + fs.GetCreationTime("/mnt"); + + fs.GetLastWriteTime("/mnt/c"); + fs.GetLastAccessTime("/mnt/c"); + fs.GetCreationTime("/mnt/c"); + fs.GetAttributes("/mnt/c"); + } } finally { From 70de24e76d3c228391415d36badc4e359075a4a5 Mon Sep 17 00:00:00 2001 From: Gerard Smit Date: Mon, 27 May 2024 23:16:18 +0200 Subject: [PATCH 4/5] Skip SetCreationTime on Linux --- .../FileSystems/TestFileSystemCompactBase.cs | 9 ++++++--- .../FileSystems/TestPhysicalFileSystem.cs | 18 ++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs b/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs index 40bffe6..70115d9 100644 --- a/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs +++ b/src/Zio.Tests/FileSystems/TestFileSystemCompactBase.cs @@ -137,9 +137,12 @@ public void TestFile() // Assert.NotEqual(fs.GetLastAccessTime("/toto.txt"), fs.GetLastAccessTime("/titi.txt")); Assert.Equal(fs.GetLastWriteTime("/toto.txt"), fs.GetLastWriteTime("/titi.txt")); - var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); - fs.SetCreationTime("/toto.txt", creationTime); - Assert.Equal(creationTime, fs.GetCreationTime("/toto.txt")); + if (IsWindows) + { + var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetCreationTime("/toto.txt", creationTime); + Assert.Equal(creationTime, fs.GetCreationTime("/toto.txt")); + } var lastWriteTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local); fs.SetLastWriteTime("/toto.txt", lastWriteTime); diff --git a/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs b/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs index 822d9ca..dba95bb 100644 --- a/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs +++ b/src/Zio.Tests/FileSystems/TestPhysicalFileSystem.cs @@ -94,9 +94,12 @@ public void TestDirectory() // LastAccessTime // LastWriteTime // CreationTime - var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); - fs.SetCreationTime(pathToCreate, creationTime); - Assert.Equal(creationTime, fs.GetCreationTime(pathToCreate)); + if (IsWindows) + { + var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetCreationTime(pathToCreate, creationTime); + Assert.Equal(creationTime, fs.GetCreationTime(pathToCreate)); + } var lastWriteTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local); fs.SetLastWriteTime(pathToCreate, lastWriteTime); @@ -235,9 +238,12 @@ public void TestFile() Assert.Equal(File.GetLastAccessTime(systemFilePath), fs.GetLastAccessTime(filePath)); Assert.Equal(File.GetCreationTime(systemFilePath), fs.GetCreationTime(filePath)); - var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); - fs.SetCreationTime(filePath, creationTime); - Assert.Equal(creationTime, fs.GetCreationTime(filePath)); + if (IsWindows) + { + var creationTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Local); + fs.SetCreationTime(filePath, creationTime); + Assert.Equal(creationTime, fs.GetCreationTime(filePath)); + } var lastWriteTime = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Local); fs.SetLastWriteTime(filePath, lastWriteTime); From 731020063e830fb215d69bfb3931ee1a2fcee48b Mon Sep 17 00:00:00 2001 From: Gerard Smit Date: Mon, 27 May 2024 23:24:16 +0200 Subject: [PATCH 5/5] Fix Dispose Exception by bumping xunit.runner.visualstudio --- src/Zio.Tests/Zio.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Zio.Tests/Zio.Tests.csproj b/src/Zio.Tests/Zio.Tests.csproj index 2508a12..194790e 100644 --- a/src/Zio.Tests/Zio.Tests.csproj +++ b/src/Zio.Tests/Zio.Tests.csproj @@ -9,7 +9,7 @@ - + all runtime; build; native; contentfiles; analyzers