Skip to content

Commit e5d8792

Browse files
[release/7.0] Change some exception types thrown in Tar APIs (#74893)
* Throw ArgumentException on unsupported tar entry type * Adjust tests * Also change exception type for internal TarEntry conversion constructor called by all other public conversion constructors. Add missing test gap. * LinkName setter null check. * Internal constructors SeekableSubReadStream and SubReadStream unseekable exception should be ArgumentException. * DataStream setter for regular file should throw ArgumentException if passed an unreadable stream. * TarFile CreateFromDirectory unwritable destination change exception to ArgumentException. * Change to ArgumentException when ExtractToDirectory is an unreadable stream. Add missing exception docs. * Add some missing exception docs for TarEntry. * Change TarReader constructor exception if unreadable stream. Close test gap. * Change TarWriter exception for unwritable stream to ArgumentException, adjust docs and tests. * Add missing documentation for exceptions in constructors. * Change wording of conversion constructors comment when passing a Pax GEA entry. * Apply suggestions by Jozkee * Add exception to LinkName if the entry type is hard/symlink and the user tries to set an empty string. Add tests. * Convert all FormatException to InvalidDataException * Address more suggestions Co-authored-by: carlossanlop <[email protected]>
1 parent 734f981 commit e5d8792

35 files changed

+338
-138
lines changed

src/libraries/System.Formats.Tar/src/System/Formats/Tar/GnuTarEntry.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@ internal GnuTarEntry(TarHeader header, TarReader readerOfOrigin)
2020
/// </summary>
2121
/// <param name="entryType">The type of the entry.</param>
2222
/// <param name="entryName">A string with the path and file name of this entry.</param>
23-
/// <exception cref="ArgumentException"><paramref name="entryName"/> is null or empty.</exception>
24-
/// <exception cref="InvalidOperationException">The entry type is not supported for creating an entry.</exception>
2523
/// <remarks>When creating an instance using the <see cref="GnuTarEntry(TarEntryType, string)"/> constructor, only the following entry types are supported:
2624
/// <list type="bullet">
2725
/// <item>In all platforms: <see cref="TarEntryType.Directory"/>, <see cref="TarEntryType.HardLink"/>, <see cref="TarEntryType.SymbolicLink"/>, <see cref="TarEntryType.RegularFile"/>.</item>
2826
/// <item>In Unix platforms only: <see cref="TarEntryType.BlockDevice"/>, <see cref="TarEntryType.CharacterDevice"/> and <see cref="TarEntryType.Fifo"/>.</item>
2927
/// </list>
3028
/// </remarks>
29+
/// <exception cref="ArgumentNullException"><paramref name="entryName"/> is <see langword="null"/>.</exception>
30+
/// <exception cref="ArgumentException"><para><paramref name="entryName"/> is empty.</para>
31+
/// <para>-or-</para>
32+
/// <para><paramref name="entryType"/> is not supported in the specified format.</para></exception>
3133
public GnuTarEntry(TarEntryType entryType, string entryName)
3234
: base(entryType, entryName, TarEntryFormat.Gnu, isGea: false)
3335
{
@@ -38,6 +40,9 @@ public GnuTarEntry(TarEntryType entryType, string entryName)
3840
/// <summary>
3941
/// Initializes a new <see cref="GnuTarEntry"/> instance by converting the specified <paramref name="other"/> entry into the GNU format.
4042
/// </summary>
43+
/// <exception cref="ArgumentException"><para><paramref name="other"/> is a <see cref="PaxGlobalExtendedAttributesTarEntry"/> and cannot be converted.</para>
44+
/// <para>-or-</para>
45+
/// <para>The entry type of <paramref name="other"/> is not supported for conversion to the GNU format.</para></exception>
4146
public GnuTarEntry(TarEntry other)
4247
: base(other, TarEntryFormat.Gnu)
4348
{

src/libraries/System.Formats.Tar/src/System/Formats/Tar/PaxTarEntry.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ internal PaxTarEntry(TarHeader header, TarReader readerOfOrigin)
2525
/// </summary>
2626
/// <param name="entryType">The type of the entry.</param>
2727
/// <param name="entryName">A string with the path and file name of this entry.</param>
28-
/// <exception cref="ArgumentException"><paramref name="entryName"/> is null or empty.</exception>
29-
/// <exception cref="InvalidOperationException">The entry type is not supported for creating an entry.</exception>
3028
/// <remarks><para>When creating an instance using the <see cref="PaxTarEntry(TarEntryType, string)"/> constructor, only the following entry types are supported:</para>
3129
/// <list type="bullet">
3230
/// <item>In all platforms: <see cref="TarEntryType.Directory"/>, <see cref="TarEntryType.HardLink"/>, <see cref="TarEntryType.SymbolicLink"/>, <see cref="TarEntryType.RegularFile"/>.</item>
@@ -47,6 +45,10 @@ internal PaxTarEntry(TarHeader header, TarReader readerOfOrigin)
4745
/// <item>File length, under the name <c>size</c>, as an <see cref="int"/>, if the string representation of the number is larger than 12 bytes.</item>
4846
/// </list>
4947
/// </remarks>
48+
/// <exception cref="ArgumentNullException"><paramref name="entryName"/> is <see langword="null"/>.</exception>
49+
/// <exception cref="ArgumentException"><para><paramref name="entryName"/> is empty.</para>
50+
/// <para>-or-</para>
51+
/// <para><paramref name="entryType"/> is not supported in the specified format.</para></exception>
5052
public PaxTarEntry(TarEntryType entryType, string entryName)
5153
: base(entryType, entryName, TarEntryFormat.Pax, isGea: false)
5254
{
@@ -62,9 +64,6 @@ public PaxTarEntry(TarEntryType entryType, string entryName)
6264
/// <param name="entryType">The type of the entry.</param>
6365
/// <param name="entryName">A string with the path and file name of this entry.</param>
6466
/// <param name="extendedAttributes">An enumeration of string key-value pairs that represents the metadata to include in the Extended Attributes entry that precedes the current entry.</param>
65-
/// <exception cref="ArgumentNullException"><paramref name="extendedAttributes"/> is <see langword="null"/>.</exception>
66-
/// <exception cref="ArgumentException"><paramref name="entryName"/> is null or empty.</exception>
67-
/// <exception cref="InvalidOperationException">The entry type is not supported for creating an entry.</exception>
6867
/// <remarks>When creating an instance using the <see cref="PaxTarEntry(TarEntryType, string)"/> constructor, only the following entry types are supported:
6968
/// <list type="bullet">
7069
/// <item>In all platforms: <see cref="TarEntryType.Directory"/>, <see cref="TarEntryType.HardLink"/>, <see cref="TarEntryType.SymbolicLink"/>, <see cref="TarEntryType.RegularFile"/>.</item>
@@ -85,6 +84,10 @@ public PaxTarEntry(TarEntryType entryType, string entryName)
8584
/// <item>File length, under the name <c>size</c>, as an <see cref="int"/>, if the string representation of the number is larger than 12 bytes.</item>
8685
/// </list>
8786
/// </remarks>
87+
/// <exception cref="ArgumentNullException"><paramref name="extendedAttributes"/> or <paramref name="entryName"/> is <see langword="null"/>.</exception>
88+
/// <exception cref="ArgumentException"><para><paramref name="entryName"/> is empty.</para>
89+
/// <para>-or-</para>
90+
/// <para><paramref name="entryType"/> is not supported in the specified format.</para></exception>
8891
public PaxTarEntry(TarEntryType entryType, string entryName, IEnumerable<KeyValuePair<string, string>> extendedAttributes)
8992
: base(entryType, entryName, TarEntryFormat.Pax, isGea: false)
9093
{
@@ -100,6 +103,9 @@ public PaxTarEntry(TarEntryType entryType, string entryName, IEnumerable<KeyValu
100103
/// <summary>
101104
/// Initializes a new <see cref="PaxTarEntry"/> instance by converting the specified <paramref name="other"/> entry into the PAX format.
102105
/// </summary>
106+
/// <exception cref="ArgumentException"><para><paramref name="other"/> is a <see cref="PaxGlobalExtendedAttributesTarEntry"/> and cannot be converted.</para>
107+
/// <para>-or-</para>
108+
/// <para>The entry type of <paramref name="other"/> is not supported for conversion to the PAX format.</para></exception>
103109
public PaxTarEntry(TarEntry other)
104110
: base(other, TarEntryFormat.Pax)
105111
{

src/libraries/System.Formats.Tar/src/System/Formats/Tar/SeekableSubReadStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public SeekableSubReadStream(Stream superStream, long startPosition, long maxLen
1818
{
1919
if (!superStream.CanSeek)
2020
{
21-
throw new InvalidOperationException(SR.IO_NotSupported_UnseekableStream);
21+
throw new ArgumentException(SR.IO_NotSupported_UnseekableStream, nameof(superStream));
2222
}
2323
}
2424

src/libraries/System.Formats.Tar/src/System/Formats/Tar/SubReadStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public SubReadStream(Stream superStream, long startPosition, long maxLength)
2525
{
2626
if (!superStream.CanRead)
2727
{
28-
throw new InvalidOperationException(SR.IO_NotSupported_UnreadableStream);
28+
throw new ArgumentException(SR.IO_NotSupported_UnreadableStream, nameof(superStream));
2929
}
3030
_startInSuperStream = startPosition;
3131
_positionInSuperStream = startPosition;

src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ internal TarEntry(TarEntry other, TarEntryFormat format)
5151
{
5252
if (other is PaxGlobalExtendedAttributesTarEntry)
5353
{
54-
throw new InvalidOperationException(SR.TarCannotConvertPaxGlobalExtendedAttributesEntry);
54+
throw new ArgumentException(SR.TarCannotConvertPaxGlobalExtendedAttributesEntry, nameof(other));
5555
}
5656

5757
TarEntryType compatibleEntryType = TarHelpers.GetCorrectTypeFlagForFormat(format, other.EntryType);
5858

59-
TarHelpers.ThrowIfEntryTypeNotSupported(compatibleEntryType, format);
59+
TarHelpers.ThrowIfEntryTypeNotSupported(compatibleEntryType, format, nameof(other));
6060

6161
_readerOfOrigin = other._readerOfOrigin;
6262

@@ -92,6 +92,7 @@ public int Gid
9292
/// A timestamps that represents the last time the contents of the file represented by this entry were modified.
9393
/// </summary>
9494
/// <remarks>In Unix platforms, this timestamp is commonly known as <c>mtime</c>.</remarks>
95+
/// <exception cref="ArgumentOutOfRangeException">The specified value is larger than <see cref="DateTimeOffset.UnixEpoch"/>.</exception>
9596
public DateTimeOffset ModificationTime
9697
{
9798
get => _header._mTime;
@@ -114,7 +115,9 @@ public DateTimeOffset ModificationTime
114115
/// <summary>
115116
/// When the <see cref="EntryType"/> indicates a <see cref="TarEntryType.SymbolicLink"/> or a <see cref="TarEntryType.HardLink"/>, this property returns the link target path of such link.
116117
/// </summary>
117-
/// <exception cref="InvalidOperationException">Cannot set the link name if the entry type is not <see cref="TarEntryType.HardLink"/> or <see cref="TarEntryType.SymbolicLink"/>.</exception>
118+
/// <exception cref="InvalidOperationException">The entry type is not <see cref="TarEntryType.HardLink"/> or <see cref="TarEntryType.SymbolicLink"/>.</exception>
119+
/// <exception cref="ArgumentNullException">The specified value is <see langword="null"/>.</exception>
120+
/// <exception cref="ArgumentException">The specified value is empty.</exception>
118121
public string LinkName
119122
{
120123
get => _header._linkName ?? string.Empty;
@@ -124,6 +127,7 @@ public string LinkName
124127
{
125128
throw new InvalidOperationException(SR.TarEntryHardLinkOrSymLinkExpected);
126129
}
130+
ArgumentException.ThrowIfNullOrEmpty(value);
127131
_header._linkName = value;
128132
}
129133
}
@@ -177,7 +181,8 @@ public int Uid
177181
/// <para>Elevation is required to extract a <see cref="TarEntryType.BlockDevice"/> or <see cref="TarEntryType.CharacterDevice"/> to disk.</para>
178182
/// <para>Symbolic links can be recreated using <see cref="File.CreateSymbolicLink(string, string)"/>, <see cref="Directory.CreateSymbolicLink(string, string)"/> or <see cref="FileSystemInfo.CreateAsSymbolicLink(string)"/>.</para>
179183
/// <para>Hard links can only be extracted when using <see cref="TarFile.ExtractToDirectory(Stream, string, bool)"/> or <see cref="TarFile.ExtractToDirectory(string, string, bool)"/>.</para></remarks>
180-
/// <exception cref="ArgumentException"><paramref name="destinationFileName"/> is <see langword="null"/> or empty.</exception>
184+
/// <exception cref="ArgumentNullException"><paramref name="destinationFileName"/> is <see langword="null"/>.</exception>
185+
/// <exception cref="ArgumentException"><paramref name="destinationFileName"/> is empty.</exception>
181186
/// <exception cref="IOException"><para>The parent directory of <paramref name="destinationFileName"/> does not exist.</para>
182187
/// <para>-or-</para>
183188
/// <para><paramref name="overwrite"/> is <see langword="false"/> and a file already exists in <paramref name="destinationFileName"/>.</para>
@@ -206,7 +211,8 @@ public void ExtractToFile(string destinationFileName, bool overwrite)
206211
/// <returns>A task that represents the asynchronous extraction operation.</returns>
207212
/// <remarks><para>Files of type <see cref="TarEntryType.BlockDevice"/>, <see cref="TarEntryType.CharacterDevice"/> or <see cref="TarEntryType.Fifo"/> can only be extracted in Unix platforms.</para>
208213
/// <para>Elevation is required to extract a <see cref="TarEntryType.BlockDevice"/> or <see cref="TarEntryType.CharacterDevice"/> to disk.</para></remarks>
209-
/// <exception cref="ArgumentException"><paramref name="destinationFileName"/> is <see langword="null"/> or empty.</exception>
214+
/// <exception cref="ArgumentNullException"><paramref name="destinationFileName"/> is <see langword="null"/>.</exception>
215+
/// <exception cref="ArgumentException"><paramref name="destinationFileName"/> is empty.</exception>
210216
/// <exception cref="IOException"><para>The parent directory of <paramref name="destinationFileName"/> does not exist.</para>
211217
/// <para>-or-</para>
212218
/// <para><paramref name="overwrite"/> is <see langword="false"/> and a file already exists in <paramref name="destinationFileName"/>.</para>
@@ -237,9 +243,8 @@ public Task ExtractToFileAsync(string destinationFileName, bool overwrite, Cance
237243
/// <para>Sets a new stream that represents the data section, if it makes sense for the <see cref="EntryType"/> to contain data; if a stream already existed, the old stream gets disposed before substituting it with the new stream. Setting a <see langword="null"/> stream is allowed.</para></value>
238244
/// <remarks>If you write data to this data stream, make sure to rewind it to the desired start position before writing this entry into an archive using <see cref="TarWriter.WriteEntry(TarEntry)"/>.</remarks>
239245
/// <exception cref="InvalidOperationException">Setting a data section is not supported because the <see cref="EntryType"/> is not <see cref="TarEntryType.RegularFile"/> (or <see cref="TarEntryType.V7RegularFile"/> for an archive of <see cref="TarEntryFormat.V7"/> format).</exception>
240-
/// <exception cref="IOException"><para>Cannot set an unreadable stream.</para>
241-
/// <para>-or-</para>
242-
/// <para>An I/O problem occurred.</para></exception>
246+
/// <exception cref="ArgumentException">Cannot set an unreadable stream.</exception>
247+
/// <exception cref="IOException">An I/O problem occurred.</exception>
243248
public Stream? DataStream
244249
{
245250
get => _header._dataStream;
@@ -252,7 +257,7 @@ public Stream? DataStream
252257

253258
if (value != null && !value.CanRead)
254259
{
255-
throw new IOException(SR.IO_NotSupported_UnreadableStream);
260+
throw new ArgumentException(SR.IO_NotSupported_UnreadableStream, nameof(value));
256261
}
257262

258263
if (_readerOfOrigin != null)
@@ -339,7 +344,7 @@ internal Task ExtractRelativeToDirectoryAsync(string destinationDirectoryPath, b
339344
{
340345
if (string.IsNullOrEmpty(LinkName))
341346
{
342-
throw new FormatException(SR.TarEntryHardLinkOrSymlinkLinkNameEmpty);
347+
throw new InvalidDataException(SR.TarEntryHardLinkOrSymlinkLinkNameEmpty);
343348
}
344349

345350
linkTargetPath = GetSanitizedFullPath(destinationDirectoryPath, LinkName);
@@ -511,7 +516,7 @@ private void VerifyPathsForEntryType(string filePath, string? linkTargetPath, bo
511516
}
512517
else
513518
{
514-
throw new FormatException(SR.TarEntryHardLinkOrSymlinkLinkNameEmpty);
519+
throw new InvalidDataException(SR.TarEntryHardLinkOrSymlinkLinkNameEmpty);
515520
}
516521
}
517522
}

0 commit comments

Comments
 (0)