Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

fixing ZipPackagePart.GetStreamCore crashes with NotSupportedException #40355

Merged
merged 1 commit into from
Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ protected override Stream GetStreamCore(FileMode streamFileMode, FileAccess stre
{
if (_zipArchiveEntry != null)
{
if (streamFileMode == FileMode.Create)
// Reset the stream when FileMode.Create is specified. Since ZipArchiveEntry only
// ever supports opening once when the backing archive is in Create mode, we'll avoid
// calling SetLength since the stream returned won't be seekable. You could still open
// an archive in Update mode then call part.GetStream(FileMode.Create), in which case
// we'll want this call to SetLength.
if (streamFileMode == FileMode.Create && _zipArchiveEntry.Archive.Mode != ZipArchiveMode.Create)
{
using (var tempStream = _zipStreamManager.Open(_zipArchiveEntry, streamFileMode, streamFileAccess))
{
Expand Down
104 changes: 81 additions & 23 deletions src/System.IO.Packaging/tests/Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3644,53 +3644,111 @@ public void SetEmptyPropertyToNull()
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Desktop doesn't support Package.Open with FileAccess.Write")]
public void CreateWithFileAccessWrite()
{
string[] fileNames = new [] { "file1.txt", "file2.txt", "file3.txt" };
const string RelationshipType = "http://schemas.microsoft.com/relationships/contains";
const string PartRelationshipType = "http://schemas.microsoft.com/relationships/self";

using (Stream stream = new MemoryStream())
{
using (Package package = Package.Open(stream, FileMode.Create, FileAccess.Write))
{
foreach (string fileName in fileNames)
ForEachPartWithFileName(package, (part, fileName) =>
{
Uri partUri = PackUriHelper.CreatePartUri(new Uri(fileName, UriKind.Relative));
PackagePart part = package.CreatePart(partUri,
System.Net.Mime.MediaTypeNames.Text.Plain,
CompressionOption.Fast);
using (StreamWriter writer = new StreamWriter(part.GetStream(), Encoding.ASCII))
{
// just write the filename as content
writer.Write(fileName);
}
part.CreateRelationship(part.Uri, TargetMode.Internal, PartRelationshipType);
package.CreateRelationship(part.Uri, TargetMode.Internal, RelationshipType);
}
});
}

// reopen for read and validate the content
stream.Seek(0, SeekOrigin.Begin);
using (Package readPackage = Package.Open(stream))
{
PackageRelationshipCollection packageRelationships = readPackage.GetRelationships();
Assert.All(packageRelationships, relationship => Assert.Equal(RelationshipType, relationship.RelationshipType));
foreach (string fileName in fileNames)
ForEachPartWithFileName(readPackage, (part, fileName) =>
{
PackagePart part = readPackage.GetPart(PackUriHelper.CreatePartUri(new Uri(fileName, UriKind.Relative)));

using (Stream partStream = part.GetStream())
using (StreamReader reader = new StreamReader(partStream, Encoding.ASCII))
{
Assert.Equal(fileName.Length, partStream.Length);
Assert.Equal(fileName, reader.ReadToEnd());
}
PackageRelationshipCollection partRelationships = part.GetRelationshipsByType(PartRelationshipType);
Assert.Single(partRelationships);
Assert.All(partRelationships, relationship => Assert.Equal(PartRelationshipType, relationship.RelationshipType));
});
}
}
}

Assert.Single(packageRelationships, relationship => relationship.TargetUri == part.Uri);
[Fact]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Desktop doesn't support Package.Open with FileAccess.Write")]
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "Can't write to FileSystem in UAP")]
public void ZipPackage_CreateWithFileAccessWrite()
{
string packageName = "test.zip";

using (Package package = Package.Open(packageName, FileMode.Create, FileAccess.Write))
{
ForEachPartWithFileName(package, (part, fileName) =>
{
using (StreamWriter writer = new StreamWriter(part.GetStream(FileMode.Create), Encoding.ASCII))
{
// just write the filename as content
writer.Write(fileName);
}
});
}

// reopen for read and validate the content
using (Package readPackage = Package.Open(packageName))
{
ForEachPartWithFileName(readPackage, (part, fileName) =>
{
using (Stream partStream = part.GetStream())
using (StreamReader reader = new StreamReader(partStream, Encoding.ASCII))
{
Assert.Equal(fileName.Length, partStream.Length);
Assert.Equal(fileName, reader.ReadToEnd());
}

using (Stream partStream = part.GetStream(FileMode.Create))
{
// Assert that the stream was reset because we opened the stream in Create mode
Assert.Equal(0, partStream.Length);
}
});
}
}

// Helper method for performing an action on every part in the package. All parts are simple
// text files. If the part didn't exist, it will be created before invoking the action,
// otherwise the existing part is retrieved and passed to the action.
private void ForEachPartWithFileName(Package package, Action<PackagePart, string> action)
{
string[] fileNames = new[] { "file1.txt", "file2.txt", "file3.txt" };

const string RelationshipType = "http://schemas.microsoft.com/relationships/contains";
const string PartRelationshipType = "http://schemas.microsoft.com/relationships/self";
foreach (string fileName in fileNames)
{
Uri partUri = PackUriHelper.CreatePartUri(new Uri(fileName, UriKind.Relative));
PackagePart part = package.PartExists(partUri) ?
package.GetPart(partUri) :
package.CreatePart(partUri, System.Net.Mime.MediaTypeNames.Text.Plain);
action(part, fileName);

// Part didn't exist previously so create relationships
if (package.FileOpenAccess == FileAccess.Write)
{
part.CreateRelationship(part.Uri, TargetMode.Internal, PartRelationshipType);
package.CreateRelationship(part.Uri, TargetMode.Internal, RelationshipType);
}
else
{
// Validate the relationship
PackageRelationshipCollection packageRelationships = package.GetRelationships();
Assert.All(packageRelationships, relationship => Assert.Equal(RelationshipType, relationship.RelationshipType));

PackageRelationshipCollection partRelationships = part.GetRelationshipsByType(PartRelationshipType);
Assert.Single(partRelationships);
Assert.All(partRelationships, relationship => Assert.Equal(PartRelationshipType, relationship.RelationshipType));

Assert.Single(packageRelationships, relationship => relationship.TargetUri == part.Uri);
}
}
}
Expand Down Expand Up @@ -3892,7 +3950,7 @@ public void ComparePackUriDifferentPack()
}

[Fact]
void CreatePackUriWithFragment()
public void CreatePackUriWithFragment()
{
Uri partUri = new Uri("/idontexist.xml", UriKind.Relative);
Uri packageUri = new Uri("application://");
Expand Down