Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions docs/core/compatibility/11.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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

<xref:System.Formats.Tar.TarWriter> 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, `TarWriter` detects when multiple files are hard-linked to the same inode and writes a `HardLink` 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 `System.Formats.Tar` library. By using `HardLink` 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 `HardLinkMode` property to `TarHardLinkMode.CopyContents` in a new `TarWriterOptions` 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(TarEntryFormat.Pax)
{
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 <xref:System.IO.IOException>. Use the new `TarExtractOptions` 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

- <xref:System.Formats.Tar.TarWriter?displayProperty=fullName>
- <xref:System.Formats.Tar.TarWriter.WriteEntry(System.String,System.String)?displayProperty=fullName>
- <xref:System.Formats.Tar.TarWriter.WriteEntryAsync(System.String,System.String,System.Threading.CancellationToken)?displayProperty=fullName>
2 changes: 2 additions & 0 deletions docs/core/compatibility/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading