Skip to content

Commit c04c2b7

Browse files
github-actions[bot]sobczykcarlossanlop
authored
[release/9.0] [Tar] Fill in the file size even if the file is empty. (#107633)
* [Tar] Fill in the file size even if the file is empty. This matches standard behavior. * fix tests, set size only when datastream is not null * Add unit tests for size header of an empty file * Scope disposables Co-authored-by: Carlos Sánchez López <[email protected]> * Update test to verify entry can be read after confirming the sequence is correct. Add test to verify that entries created with the malformed size field are still readable after the bug fix. --------- Co-authored-by: Szymon Sobik <[email protected]> Co-authored-by: Carlos Sánchez López <[email protected]>
1 parent 593af2b commit c04c2b7

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarHeader.Write.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ private int WriteCommonFields(Span<byte> buffer, TarEntryType actualEntryType)
629629
checksum += FormatNumeric(_gid, buffer.Slice(FieldLocations.Gid, FieldLengths.Gid));
630630
}
631631

632-
if (_size > 0)
632+
if (_dataStream != null && _size >= 0)
633633
{
634634
checksum += FormatNumeric(_size, buffer.Slice(FieldLocations.Size, FieldLengths.Size));
635635
}

src/libraries/System.Formats.Tar/tests/TarWriter/TarWriter.Tests.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.IO;
5+
using System.Linq;
56
using Xunit;
67

78
namespace System.Formats.Tar.Tests
@@ -144,6 +145,74 @@ public void Verify_Checksum_SymbolicLink_LongLink(TarEntryFormat format) =>
144145
public void Verify_Checksum_SymbolicLink_LongLink_LongPath(TarEntryFormat format) =>
145146
Verify_Checksum_Internal(format, TarEntryType.SymbolicLink, longPath: true, longLink: true);
146147

148+
[Fact]
149+
public void Verify_Size_RegularFile_Empty()
150+
{
151+
using MemoryStream archiveStream = new();
152+
string entryName = "entry.txt";
153+
using (TarWriter archive = new(archiveStream, TarEntryFormat.V7, leaveOpen: true))
154+
{
155+
V7TarEntry e = new(TarEntryType.V7RegularFile, entryName)
156+
{
157+
DataStream = new MemoryStream(0)
158+
};
159+
archive.WriteEntry(e);
160+
}
161+
162+
int sizeLocation = 100 + // Name
163+
8 + // Mode
164+
8 + // Uid
165+
8; // Gid
166+
int sizeLength = 12;
167+
168+
archiveStream.Position = 0;
169+
byte[] actual = archiveStream.GetBuffer()[sizeLocation..(sizeLocation + sizeLength)];
170+
171+
byte[] expected = [0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0];
172+
AssertExtensions.SequenceEqual(expected, actual);
173+
174+
archiveStream.Position = 0;
175+
using TarReader reader = new(archiveStream);
176+
177+
TarEntry? actualEntry = reader.GetNextEntry();
178+
Assert.NotNull(actualEntry);
179+
Assert.Equal(0, actualEntry.Length);
180+
Assert.Null(actualEntry.DataStream); // No stream created when size field's value is 0
181+
}
182+
183+
[Fact]
184+
public void Verify_Compatibility_RegularFile_EmptyFile_NoSizeStored()
185+
{
186+
using MemoryStream archiveStream = new();
187+
string entryName = "entry.txt";
188+
using (TarWriter archive = new(archiveStream, TarEntryFormat.V7, leaveOpen: true))
189+
{
190+
V7TarEntry e = new(TarEntryType.V7RegularFile, entryName)
191+
{
192+
DataStream = new MemoryStream(0)
193+
};
194+
archive.WriteEntry(e);
195+
}
196+
197+
int sizeLocation = 100 + // Name
198+
8 + // Mode
199+
8 + // Uid
200+
8; // Gid
201+
202+
// Fill the size field with 12 zeros as we used to before the bug fix
203+
byte[] replacement = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
204+
archiveStream.Seek(sizeLocation, SeekOrigin.Begin);
205+
archiveStream.Write(replacement);
206+
207+
archiveStream.Position = 0;
208+
using TarReader reader = new(archiveStream);
209+
210+
TarEntry? actualEntry = reader.GetNextEntry(); // Should succeed to read the entry with a malformed size field value
211+
Assert.NotNull(actualEntry);
212+
Assert.Equal(0, actualEntry.Length); // Should succeed to detect the size field's value as zero
213+
Assert.Null(actualEntry.DataStream); // No stream created when size field's value is 0
214+
}
215+
147216
private void Verify_Checksum_Internal(TarEntryFormat format, TarEntryType entryType, bool longPath, bool longLink)
148217
{
149218
using MemoryStream archive = new MemoryStream();

0 commit comments

Comments
 (0)