diff --git a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs index 7263af221ad657..9c2f0553eb39bf 100644 --- a/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs +++ b/src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs @@ -529,7 +529,7 @@ private void ExtractAsRegularFile(string destinationFileName) DataStream?.CopyTo(fs); } - ArchivingUtils.AttemptSetLastWriteTime(destinationFileName, ModificationTime); + AttemptSetLastWriteTime(destinationFileName, ModificationTime); } // Asynchronously extracts the current entry as a regular file into the specified destination. @@ -551,7 +551,19 @@ private async Task ExtractAsRegularFileAsync(string destinationFileName, Cancell } } - ArchivingUtils.AttemptSetLastWriteTime(destinationFileName, ModificationTime); + AttemptSetLastWriteTime(destinationFileName, ModificationTime); + } + + private static void AttemptSetLastWriteTime(string destinationFileName, DateTimeOffset lastWriteTime) + { + try + { + File.SetLastWriteTime(destinationFileName, lastWriteTime.LocalDateTime); // SetLastWriteTime expects local time + } + catch + { + // Some OSes like Android might not support setting the last write time, the extraction should not fail because of that + } } private FileStreamOptions CreateFileStreamOptions(bool isAsync) diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Tests.cs index 388e9639bd2956..308a9b68ba4def 100644 --- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectory.File.Tests.cs @@ -194,7 +194,7 @@ public void IncludeAllSegmentsOfPath(bool includeBaseDirectory) Assert.Null(reader.GetNextEntry()); } - [Fact] + [ConditionalFact(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))] public void SkipRecursionIntoDirectorySymlinks() { using TempDirectory root = new TempDirectory(); @@ -225,7 +225,7 @@ public void SkipRecursionIntoDirectorySymlinks() Assert.Null(reader.GetNextEntry()); // file.txt should not be found } - [Fact] + [ConditionalFact(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))] public void SkipRecursionIntoBaseDirectorySymlink() { using TempDirectory root = new TempDirectory(); diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectoryAsync.File.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectoryAsync.File.Tests.cs index bb1d8ff7cc0cc3..78b051ae33b08e 100644 --- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectoryAsync.File.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.CreateFromDirectoryAsync.File.Tests.cs @@ -238,7 +238,7 @@ public async Task IncludeAllSegmentsOfPath_Async(bool includeBaseDirectory) } } - [Fact] + [ConditionalFact(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))] public async Task SkipRecursionIntoDirectorySymlinksAsync() { using TempDirectory root = new TempDirectory(); @@ -269,7 +269,7 @@ public async Task SkipRecursionIntoDirectorySymlinksAsync() Assert.Null(await reader.GetNextEntryAsync()); // file.txt should not be found } - [Fact] + [ConditionalFact(typeof(MountHelper), nameof(MountHelper.CanCreateSymbolicLinks))] public async Task SkipRecursionIntoBaseDirectorySymlinkAsync() { using TempDirectory root = new TempDirectory(); diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.cs index ee00ccfaf6ccb8..90c5eba6b9ff97 100644 --- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.cs @@ -44,6 +44,33 @@ public void NonExistentDirectory_Throws() Assert.Throws(() => TarFile.ExtractToDirectory(sourceFileName: filePath, destinationDirectoryName: dirPath, overwriteFiles: false)); } + [Fact] + public void SetsLastModifiedTimeOnExtractedFiles() + { + using TempDirectory root = new TempDirectory(); + + string inDir = Path.Join(root.Path, "indir"); + string inFile = Path.Join(inDir, "file"); + + string tarFile = Path.Join(root.Path, "file.tar"); + + string outDir = Path.Join(root.Path, "outdir"); + string outFile = Path.Join(outDir, "file"); + + Directory.CreateDirectory(inDir); + File.Create(inFile).Dispose(); + var dt = new DateTime(2001, 1, 2, 3, 4, 5, DateTimeKind.Local); + File.SetLastWriteTime(inFile, dt); + + TarFile.CreateFromDirectory(sourceDirectoryName: inDir, destinationFileName: tarFile, includeBaseDirectory: false); + + Directory.CreateDirectory(outDir); + TarFile.ExtractToDirectory(sourceFileName: tarFile, destinationDirectoryName: outDir, overwriteFiles: false); + + Assert.True(File.Exists(outFile)); + Assert.InRange(File.GetLastWriteTime(outFile).Ticks, dt.AddSeconds(-3).Ticks, dt.AddSeconds(3).Ticks); // include some slop for filesystem granularity + } + [Theory] [InlineData(TestTarFormat.v7)] [InlineData(TestTarFormat.ustar)] diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.File.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.File.Tests.cs index 905e9b61bfb8e2..19a28d7f59ce39 100644 --- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.File.Tests.cs +++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.File.Tests.cs @@ -56,6 +56,33 @@ public async Task NonExistentDirectory_Throws_Async() } } + [Fact] + public async Task SetsLastModifiedTimeOnExtractedFiles() + { + using TempDirectory root = new TempDirectory(); + + string inDir = Path.Join(root.Path, "indir"); + string inFile = Path.Join(inDir, "file"); + + string tarFile = Path.Join(root.Path, "file.tar"); + + string outDir = Path.Join(root.Path, "outdir"); + string outFile = Path.Join(outDir, "file"); + + Directory.CreateDirectory(inDir); + File.Create(inFile).Dispose(); + var dt = new DateTime(2001, 1, 2, 3, 4, 5, DateTimeKind.Local); + File.SetLastWriteTime(inFile, dt); + + await TarFile.CreateFromDirectoryAsync(sourceDirectoryName: inDir, destinationFileName: tarFile, includeBaseDirectory: false); + + Directory.CreateDirectory(outDir); + await TarFile.ExtractToDirectoryAsync(sourceFileName: tarFile, destinationDirectoryName: outDir, overwriteFiles: false); + + Assert.True(File.Exists(outFile)); + Assert.InRange(File.GetLastWriteTime(outFile).Ticks, dt.AddSeconds(-3).Ticks, dt.AddSeconds(3).Ticks); // include some slop for filesystem granularity + } + [Theory] [InlineData(TestTarFormat.v7)] [InlineData(TestTarFormat.ustar)]