diff --git a/docs/core/compatibility/11.md b/docs/core/compatibility/11.md index 8654a6a8b2d52..7f2b92f0f4233 100644 --- a/docs/core/compatibility/11.md +++ b/docs/core/compatibility/11.md @@ -29,6 +29,7 @@ See [Breaking changes in ASP.NET Core 10](/aspnet/core/breaking-changes/10/overv | [Environment.TickCount made consistent with Windows timeout behavior](core-libraries/11/environment-tickcount-windows-behavior.md) | Behavioral change | | [MemoryStream maximum capacity updated and exception behavior changed](core-libraries/11/memorystream-max-capacity.md) | Behavioral change | | [TAR-reading APIs verify header checksums when reading](core-libraries/11/tar-checksum-validation.md) | Behavioral change | +| [TarWriter uses HardLink entries for hard-linked files](core-libraries/11/tarwriter-hardlink-entries.md) | Behavioral change | | [ZipArchive.CreateAsync eagerly loads ZIP archive entries](core-libraries/11/ziparchive-createasync-eager-load.md) | Behavioral change | ## Cryptography diff --git a/docs/core/compatibility/core-libraries/11/tarwriter-hardlink-entries.md b/docs/core/compatibility/core-libraries/11/tarwriter-hardlink-entries.md new file mode 100644 index 0000000000000..085d25ead9234 --- /dev/null +++ b/docs/core/compatibility/core-libraries/11/tarwriter-hardlink-entries.md @@ -0,0 +1,89 @@ +--- +title: "Breaking change: TarWriter uses HardLink entries for hard-linked files" +description: "Learn about the breaking change in .NET 11 where TarWriter writes HardLink entries for files that share the same inode instead of duplicating the file content." +ms.date: 04/03/2026 +ai-usage: ai-assisted +--- + +# TarWriter uses HardLink entries for hard-linked files + + now detects when multiple files are hard-linked to the same inode. It writes a `HardLink` entry for subsequent files instead of duplicating the file content. + +## Version introduced + +.NET 11 Preview 3 + +## Previous behavior + +Previously, when creating a tar archive with `TarWriter`, files that were hard-linked to the same inode were treated as separate, independent files. The full file content was duplicated in the archive for each hard-linked file. + +```csharp +using System.Formats.Tar; +using System.IO; + +string filePath1 = "file1.txt"; +string filePath2 = "file2.txt"; + +// Create two hard-linked files. +File.WriteAllText(filePath1, "Hello, world!"); +File.CreateHardLink(filePath2, filePath1); + +using (var stream = File.Create("archive.tar")) +using (var writer = new TarWriter(stream, TarEntryFormat.Pax, leaveOpen: false)) +{ + writer.WriteEntry(filePath1, "file1.txt"); + writer.WriteEntry(filePath2, "file2.txt"); +} +``` + +In the resulting `archive.tar`, both `file1.txt` and `file2.txt` had separate file entries, each containing the full file content. + +## New behavior + +Starting in .NET 11, detects when multiple files are hard-linked to the same inode and writes a entry for subsequent files instead of duplicating the file content. + +Using the same code as shown in the [Previous behavior](#previous-behavior) section, the resulting `archive.tar` now contains a full file entry for `file1.txt`, while `file2.txt` has a `HardLink` entry pointing to `file1.txt`. + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +This change improves the efficiency of tar archives created by the library. By using entries for files that share the same inode, the size of the resulting archive is reduced and the hard-link relationships between files are preserved. This behavior is consistent with GNU tar and other widely used tar implementations. + +## Recommended action + +If your application depends on duplicating file content for hard-linked files, you can restore the previous behavior. Set the property to in a new instance: + +```csharp +using System.Formats.Tar; +using System.IO; + +string filePath1 = "file1.txt"; +string filePath2 = "file2.txt"; + +// Create two hard-linked files. +File.WriteAllText(filePath1, "Hello, world!"); +File.CreateHardLink(filePath2, filePath1); + +var options = new TarWriterOptions +{ + HardLinkMode = TarHardLinkMode.CopyContents +}; + +using (var stream = File.Create("archive.tar")) +using (var writer = new TarWriter(stream, options, leaveOpen: false)) +{ + writer.WriteEntry(filePath1, "file1.txt"); + writer.WriteEntry(filePath2, "file2.txt"); +} +``` + +Extracting a tar archive that contains `HardLink` entries to a file system without hard link support throws an . Use the new class to specify whether to extract hard links as hard links or copy them as separate files. This enables extraction to file systems without hard link support. + +## Affected APIs + +- +- +- diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index 8dcf0e709440b..ec9f86ad5eda3 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -20,6 +20,8 @@ items: href: core-libraries/11/memorystream-max-capacity.md - name: TAR-reading APIs verify header checksums when reading href: core-libraries/11/tar-checksum-validation.md + - name: TarWriter uses HardLink entries for hard-linked files + href: core-libraries/11/tarwriter-hardlink-entries.md - name: ZipArchive.CreateAsync eagerly loads ZIP archive entries href: core-libraries/11/ziparchive-createasync-eager-load.md - name: Cryptography