Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.IO.IOException: 'Entries cannot be opened multiple times in Update mode.' #24962

Closed
faikozgur opened this issue Feb 8, 2018 · 8 comments · Fixed by dotnet/corefx#28478
Labels
area-System.IO.Compression bug tenet-compatibility Incompatibility with previous versions or .NET Framework
Milestone

Comments

@faikozgur
Copy link

I am moving an application from .net to core. When I run core version I got System.IO.IOException: 'Entries cannot be opened multiple times in Update mode.'

I use System.IO.Packaging library to create packages.

 Package package = Package.Open(packageFile, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite);

AddFile(package, folder, filePath1, mimeType1, id1, reletionType);

AddProperties(package);

AddCoreAndHash(package);


package.Close();

Here is the AddProperties function:

private static void AddProperties(Package package)
{
            package.PackageProperties.Subject = "Subject";
            package.PackageProperties.Creator = "Creator";
}

After this I call the AddCoreAndHash function:

private static void AddCoreAndHash(Package package)
{
            package.Flush(); // serialize core properties

            var coreRelations = package.GetRelationshipsByType("http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties");
            if (coreRelations == null || coreRelations.Count() == 0)
            {
                throw new ApplicationException("Missing core relations.");
            }
            var corePart = package.GetPart(coreRelations.First().TargetUri);
            var stream = corePart.GetStream();
            stream.Position = 0;
            using (var memoryStream = new MemoryStream())
            {
                Tools.CopyStream(stream, memoryStream);
                memoryStream.Position = 0;
                byte[] hash = Tools.CalculateHash(memoryStream);
                //... will add hash to package later
            }
}

I get error while accessing the stream of corePart.
I have attached sample files to reproduce the issue

Files.zip

@twilker
Copy link
Contributor

twilker commented Feb 28, 2018

I have the same issue. After investigation I have found the problem. It seems, that in .net core the implementation of the XmlTextWriter was changed in a way that Close() of the XmlTextWriter does not close the underlying TextWriter anymore. In the sources of System.IO.Packaging one can see, that the PackageProperties are using a XmlTextWriter .https://referencesource.microsoft.com/#WindowsBase/Base/MS/Internal/IO/Packaging/PartBasedPackageProperties.cs,360.
So as soon as one sets any value in the PackageProperties, one has a still opened stream in the end. At the latest when the package is closed this exception is thrown. I do not see any good workaround for that.

@pjanotti
Copy link
Contributor

/cc @ianhays @ViktorHofer this is more related to compression.

@joshfree
Copy link
Member

@pjanotti this should go to the System.IO.Packaging owner(s) or to System.Xml.XmlTextWriter, per the debugging notes from @Luciferius

/cc @krwq

@pjanotti
Copy link
Contributor

pjanotti commented Mar 20, 2018

@Luciferius the code for XmlTextWriter.Close() disposes the text writer both in CoreFX and .NET Framework. I think what you are referring to is the subtle difference in PartBasedPackageProperties.Flush() which in CoreFX always closes the underlying stream and in .NET Framework doesn't (see CoreFX here and .NET Framework here). This subtle difference or others related to InStreamingCreation (example) are likely the root cause of this issue, likely making the ZipArchiveEntry being opened in update mode while it is already open in write mode (this triggers the exception on System.IO.Compression.ZipArchiveEntry.OpenInUpdateMode().

@joshfree System.IO.Packaging is related to compression not to System.IO (in general files, paths, pipes, etc). We should make it explicit on the area ownership table (I will wait a bit before making the change so if anyone feels that it is not correct they can react).

@twilker
Copy link
Contributor

twilker commented Mar 20, 2018

@pjanotti My fault. It was only a guess, that this is the root cause. I did not check with the sources. The cause you found seems logical too.

@joshfree
Copy link
Member

Including callstacks for future reference

https://github.com/dotnet/corefx/blob/a3e4e241c7b7c33750258082969287b9cf45d757/src/System.IO.Compression/src/System/IO/Compression/ZipArchiveEntry.cs#L679-L682

System.IO.IOException: 'Entries cannot be opened multiple times in Update mode.'

 	System.IO.Compression.dll!System.IO.Compression.ZipArchiveEntry.OpenInUpdateMode() Line 696	C#
 	System.IO.Compression.dll!System.IO.Compression.ZipArchiveEntry.Open() Line 307	C#
 	System.IO.Packaging.dll!System.IO.Packaging.ZipStreamManager.Open(System.IO.Compression.ZipArchiveEntry zipArchiveEntry, System.IO.FileMode streamFileMode, System.IO.FileAccess streamFileAccess) Line 80	C#
 	System.IO.Packaging.dll!System.IO.Packaging.ZipPackagePart.GetStreamCore(System.IO.FileMode streamFileMode, System.IO.FileAccess streamFileAccess) Line 41	C#
 	System.IO.Packaging.dll!System.IO.Packaging.PackagePart.GetStream(System.IO.FileMode mode, System.IO.FileAccess access) Line 323	C#
>	ConsoleApp3.dll!Core.Program.AddCoreAndHash(System.IO.Packaging.Package package) Line 38	C#
 	ConsoleApp3.dll!Core.Program.Main(string[] args) Line 25	C#

@pjanotti yes, this should get routed to the System.IO.Packaging owner to investigate why Flush was changed as part of the original port-to-core;
https://github.com/dotnet/corefx/blob/a1e7009bd3c94c3999bfd471a08e5d647c571e52/src/System.IO.Packaging/src/System/IO/Packaging/PartBasedPackageProperties.cs#L314-L323

@joshfree
Copy link
Member

@bartonjs could you load balance this one please? thanks

@bartonjs
Copy link
Member

The change in PartBasedPackageProperties.Flush() looks correct. If you trace backward far enough you find that Package._isStreaming was always false. So the other branch wasn't executed. Still looking for the divergent behavior.

@bartonjs bartonjs removed their assignment Nov 23, 2018
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 31, 2020
@dotnet dotnet locked as resolved and limited conversation to collaborators Dec 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.IO.Compression bug tenet-compatibility Incompatibility with previous versions or .NET Framework
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants