Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
ac4d898
ref: Conversion constructors
carlossanlop Jun 1, 2022
9899220
src: Conversion constructors
carlossanlop Jun 7, 2022
476bec1
tests: Conversion constructors
carlossanlop Jun 7, 2022
4484202
src: Conversion constructor should call this instead of base
carlossanlop Jun 7, 2022
45d87a0
tests: Verify unseekable stream data can be read after conversion
carlossanlop Jun 7, 2022
adf074e
Adjust _readerOfOrigin nullability in constructors.
carlossanlop Jun 7, 2022
c9002d1
Move most constructor work to the base class.
carlossanlop Jun 7, 2022
42a000d
ref: Move TarFormat from TarReader to TarEntry
carlossanlop Jun 7, 2022
ac7ff62
ref: Move Format property from TarReader to TarEntry
carlossanlop Jun 7, 2022
a0a2d88
src: Move Format property from TarReader to TarEntry
carlossanlop Jun 7, 2022
0a54727
tests: Move Format property from TarReader to TarEntry
carlossanlop Jun 7, 2022
6de8f40
nit - Remove extra spacing in tests
carlossanlop Jun 7, 2022
b6f75cb
src: When converting, only transfer fields available in the new format.
carlossanlop Jun 9, 2022
2daa87e
tests: Verify only supported fields are transferred when converting.
carlossanlop Jun 9, 2022
247af82
Revert internal->private for magic and version
carlossanlop Jun 9, 2022
270403c
Add boolean arg to PaxTarEntry method that adds atime and ctime
carlossanlop Jun 9, 2022
d405d4e
Make sure back and forth tests create firstt timestamp with a slight …
carlossanlop Jun 9, 2022
7e79e57
Make _readerOfOrigin private again
carlossanlop Jun 9, 2022
ba4d394
src: Use UtcNow, not Now
carlossanlop Jun 9, 2022
e37c645
tests: Use UtcNow, not Now. Compare converted DateTimeOffset from dou…
carlossanlop Jun 9, 2022
f987f77
Address feedback for comments.
carlossanlop Jun 11, 2022
cd66da4
Add asserts that verify mtime has a non-default value when it is expe…
carlossanlop Jun 11, 2022
c61ce71
Adress feedback for setting field values in PosixTarEntry and TarEntr…
carlossanlop Jun 11, 2022
0a39b22
Remove code that reads atime and ctime from extended attributes and s…
carlossanlop Jun 11, 2022
948b3d7
Make sure that extended attributes always have an atime and a ctime w…
carlossanlop Jun 11, 2022
131608f
Address feedback around timestamps in tests.
carlossanlop Jun 11, 2022
1b82298
Add more tests for expected values in extended attributes after writi…
carlossanlop Jun 11, 2022
ed5ec9a
Reuse code for conversion tests.
carlossanlop Jun 13, 2022
c82f766
Change test comparisons of Assert.True with ">=" to use AssertExtensi…
carlossanlop Jun 13, 2022
98e6191
Reduce number of dictionary newing, only do it when the contents are …
carlossanlop Jun 13, 2022
b7c1c83
Avoid returning dateTimeOffset != default, instead return true on suc…
carlossanlop Jun 13, 2022
83888ba
Remove redundant assignment of format to header.
carlossanlop Jun 13, 2022
e958afd
Pass Dictionary<string,string> directly to make use of non-virtual Tr…
carlossanlop Jun 13, 2022
81376fe
Add tests that verify the default writer format is utilized when call…
carlossanlop Jun 13, 2022
b865bf4
Add overload that takes long for converting number of seconds to Date…
carlossanlop Jun 13, 2022
c37e9e7
Address latest suggestions by eerhardt
carlossanlop Jun 15, 2022
526b55a
Make sure dictionary is initialized once in PaxTarEntry constructor.
carlossanlop Jun 16, 2022
2b3dff3
Reuse code for single conversion construction tests and back-n-forth …
carlossanlop Jun 16, 2022
f10d0bf
Invert verification of default case and TarEntryFormat.Unknown in swi…
carlossanlop Jun 20, 2022
a363c3f
Change "if dictionary is not null" to "Debug.Assert "dictionary is no…
carlossanlop Jun 20, 2022
cedf1a2
Conversion tests should also check expected values of ATime and CTime…
carlossanlop Jun 20, 2022
30261f3
Chop long comment, remove another 'preferred default'.
carlossanlop Jun 20, 2022
f23d244
Make unseekable conversion tests theories to verify all writer formats.
carlossanlop Jun 20, 2022
4e3e4a3
Set _prefix to Empty if other is not ustar or pax
carlossanlop Jun 20, 2022
2d503fc
Rename TarWriter archiveFormat parameter to format
carlossanlop Jun 20, 2022
411aefa
Compare datetime offsets only up to seconds
carlossanlop Jun 20, 2022
767a5e8
Increase fixed point format specifier precision, use test comparison …
carlossanlop Jun 20, 2022
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
Prev Previous commit
Next Next commit
src: Move Format property from TarReader to TarEntry
  • Loading branch information
carlossanlop committed Jun 20, 2022
commit a0a2d88cf7cba578a1ccdf4d1f12c18ab06a7e0f
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ internal TarEntry(TarEntryType entryType, TarEntryFormat format, string entryNam
/// </summary>
public TarEntryType EntryType => _header._typeFlag;

/// <summary>
/// The format of the entry.
/// </summary>
public TarEntryFormat Format => _header._format;

/// <summary>
/// The ID of the group that owns the file represented by this entry.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ internal static int SkipBlockAlignmentPadding(Stream archiveStream, long size)

// Throws if the specified entry type is not supported for the specified format.
// If 'invokingFromWriteEntry' is true, an incompatible 'Regular File' entry type is allowed. It will be converted to the compatible version before writing.
internal static void VerifyEntryTypeIsSupported(TarEntryType entryType, TarEntryFormat archiveFormat, bool invokingFromWriteEntry = false)
internal static void VerifyEntryTypeIsSupported(TarEntryType entryType, TarEntryFormat archiveFormat)
{
switch (archiveFormat)
{
Expand All @@ -192,10 +192,6 @@ TarEntryType.V7RegularFile or
{
return;
}
if (invokingFromWriteEntry && entryType is TarEntryType.RegularFile)
{
return;
}
break;

case TarEntryFormat.Ustar:
Expand All @@ -210,10 +206,6 @@ TarEntryType.RegularFile or
{
return;
}
if (invokingFromWriteEntry && entryType is TarEntryType.V7RegularFile)
{
return;
}
break;

case TarEntryFormat.Pax:
Expand All @@ -231,10 +223,6 @@ TarEntryType.RegularFile or
// - GlobalExtendedAttributes
return;
}
if (invokingFromWriteEntry && entryType is TarEntryType.V7RegularFile)
{
return;
}
break;

case TarEntryFormat.Gnu:
Expand All @@ -260,10 +248,6 @@ TarEntryType.RegularFile or
// - LongPath
return;
}
if (invokingFromWriteEntry && entryType is TarEntryType.V7RegularFile)
{
return;
}
break;

case TarEntryFormat.Unknown:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,11 @@ public TarReader(Stream archiveStream, bool leaveOpen = false)

_previouslyReadEntry = null;
GlobalExtendedAttributes = null;
Format = TarEntryFormat.Unknown;
_isDisposed = false;
_readFirstEntry = false;
_reachedEndMarkers = false;
}

/// <summary>
/// The format of the archive. It is initially <see cref="TarEntryFormat.Unknown"/>. The archive format is detected after the first call to <see cref="GetNextEntry(bool)"/>.
/// </summary>
public TarEntryFormat Format { get; private set; }

/// <summary>
/// <para>If the archive format is <see cref="TarEntryFormat.Pax"/>, returns a read-only dictionary containing the string key-value pairs of the Global Extended Attributes in the first entry of the archive.</para>
/// <para>If there is no Global Extended Attributes entry at the beginning of the archive, this returns an empty read-only dictionary.</para>
Expand Down Expand Up @@ -115,16 +109,10 @@ public void Dispose()
{
if (!_readFirstEntry)
{
Debug.Assert(Format == TarEntryFormat.Unknown);
Format = header._format;
_readFirstEntry = true;
}
else if (header._format != Format)
{
throw new FormatException(string.Format(SR.TarEntriesInDifferentFormats, header._format, Format));
}

TarEntry entry = Format switch
TarEntry entry = header._format switch
{
TarEntryFormat.Pax => new PaxTarEntry(header, this),
TarEntryFormat.Gnu => new GnuTarEntry(header, this),
Expand Down Expand Up @@ -227,11 +215,7 @@ private bool TryGetNextEntryHeader(out TarHeader header, bool copyData)
Debug.Assert(!_reachedEndMarkers);

header = default;

// Set the initial format that is expected to be retrieved when calling TarHeader.TryReadAttributes.
// If the archive format is set to unknown here, it means this is the first entry we read and the value will be changed as fields get discovered.
// If the archive format is initially detected as pax, then any subsequent entries detected as ustar will be assumed to be pax.
header._format = Format;
header._format = TarEntryFormat.Unknown;

if (!header.TryGetNextHeader(_archiveStream, copyData))
{
Expand Down Expand Up @@ -261,7 +245,6 @@ private bool TryGetNextEntryHeader(out TarHeader header, bool copyData)
catch (EndOfStreamException)
{
// Edge case: The only entry in the archive was a Global Extended Attributes entry
Format = TarEntryFormat.Pax;
return false;
}
if (header._typeFlag == TarEntryType.GlobalExtendedAttributes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ public sealed partial class TarWriter : IDisposable
private readonly Stream _archiveStream;
private readonly IEnumerable<KeyValuePair<string, string>>? _globalExtendedAttributes;

/// <summary>
/// Initializes a <see cref="TarWriter"/> instance that can write tar entries to the specified stream and closes the <paramref name="archiveStream"/> upon disposal of this instance.
/// </summary>
/// <param name="archiveStream">The stream to write to.</param>
/// <remarks>When using this constructor, <see cref="TarEntryFormat.Pax"/> is used as the default format of the entries written to the archive using the <see cref="WriteEntry(string, string?)"/> method.</remarks>
public TarWriter(Stream archiveStream)
: this(archiveStream, TarEntryFormat.Pax, leaveOpen: false)
{
}

/// <summary>
/// Initializes a <see cref="TarWriter"/> instance that can write tar entries to the specified stream, optionally leave the stream open upon disposal of this instance, and can optionally add a Global Extended Attributes entry at the beginning of the archive. When using this constructor, the format of the resulting archive is <see cref="TarEntryFormat.Pax"/>.
/// </summary>
Expand All @@ -33,17 +43,16 @@ public TarWriter(Stream archiveStream, IEnumerable<KeyValuePair<string, string>>
}

/// <summary>
/// Initializes a <see cref="TarWriter"/> instance that can write tar entries to the specified stream, optionally leave the stream open upon disposal of this instance, and can specify the format of the underlying archive.
/// Initializes a <see cref="TarWriter"/> instance that can write tar entries to the specified stream, optionally leaves the stream open upon disposal of this instance, and can optionally specify the preferred default format when writing entries using the <see cref="WriteEntry(string, string?)"/> method.
/// </summary>
/// <param name="archiveStream">The stream to write to.</param>
/// <param name="archiveFormat">The format of the archive.</param>
/// <param name="leaveOpen"><see langword="false"/> to dispose the <paramref name="archiveStream"/> when this instance is disposed; <see langword="true"/> to leave the stream open.</param>
/// <remarks><para>If the selected <paramref name="archiveFormat"/> is <see cref="TarEntryFormat.Pax"/>, no Global Extended Attributes entry is written. To write a PAX archive with a Global Extended Attributes entry inserted at the beginning of the archive, use the <see cref="TarWriter(Stream, IEnumerable{KeyValuePair{string, string}}?, bool)"/> constructor instead.</para>
/// <para>The recommended format is <see cref="TarEntryFormat.Pax"/> for its flexibility.</para></remarks>
/// <param name="archiveFormat">The preferred default format when writing entries to the archive using the <see cref="WriteEntry(string, string?)"/> method. The default value is <see cref="TarEntryFormat.Pax"/>.</param>
/// <param name="leaveOpen"><see langword="false"/> to dispose the <paramref name="archiveStream"/> when this instance is disposed; <see langword="true"/> to leave the stream open. The default is <see langword="false"/>.</param>
/// <remarks>The recommended format is <see cref="TarEntryFormat.Pax"/> for its flexibility.</remarks>
/// <exception cref="ArgumentNullException"><paramref name="archiveStream"/> is <see langword="null"/>.</exception>
/// <exception cref="IOException"><paramref name="archiveStream"/> is unwritable.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="archiveFormat"/> is either <see cref="TarEntryFormat.Unknown"/>, or not one of the other enum values.</exception>
public TarWriter(Stream archiveStream, TarEntryFormat archiveFormat, bool leaveOpen = false)
public TarWriter(Stream archiveStream, TarEntryFormat archiveFormat = TarEntryFormat.Pax, bool leaveOpen = false)
{
ArgumentNullException.ThrowIfNull(archiveStream);

Expand All @@ -67,7 +76,7 @@ public TarWriter(Stream archiveStream, TarEntryFormat archiveFormat, bool leaveO
}

/// <summary>
/// The format of the archive.
/// The preferred default format of the entries when writing entries to the archive using the <see cref="WriteEntry(string, string?)"/> method.
/// </summary>
public TarEntryFormat Format { get; private set; }

Expand Down Expand Up @@ -165,16 +174,14 @@ public void WriteEntry(TarEntry entry)
{
ThrowIfDisposed();

TarHelpers.VerifyEntryTypeIsSupported(entry.EntryType, Format, invokingFromWriteEntry: true);

WriteGlobalExtendedAttributesEntryIfNeeded();

byte[] rented = ArrayPool<byte>.Shared.Rent(minimumLength: TarHelpers.RecordSize);
Span<byte> buffer = rented.AsSpan(0, TarHelpers.RecordSize); // minimumLength means the array could've been larger
buffer.Clear(); // Rented arrays aren't clean
try
{
switch (Format)
switch (entry.Format)
{
case TarEntryFormat.V7:
entry._header.WriteAsV7(_archiveStream, buffer);
Expand Down