/// <summary> /// Build up the <see cref="ZipData"/> instance for a given zip container. This will also report any consistency /// errors found when examining the zip archive. /// </summary> private bool BuildZipData(FileName zipFileName, out ZipData zipData) { Debug.Assert(zipFileName.IsZipContainer()); Package package = null; try { package = Package.Open(zipFileName.FullPath, FileMode.Open, FileAccess.Read); var packageTempDir = Path.Combine(_pathToContainerUnpackingDirectory, Guid.NewGuid().ToString()); var nestedParts = new List <ZipPart>(); foreach (var part in package.GetParts()) { var relativePath = GetPartRelativeFileName(part); var packagePartTempName = Path.Combine(packageTempDir, relativePath); var packagePartTempDirectory = Path.GetDirectoryName(packagePartTempName); if (!FileName.IsZipContainer(packagePartTempName) && !FileName.IsPEFile(packagePartTempName)) { continue; } Directory.CreateDirectory(packagePartTempDirectory); using (var tempFileStream = File.OpenWrite(packagePartTempName)) { part.GetStream().CopyTo(tempFileStream); tempFileStream.Close(); } var partFileName = TrackFile(packagePartTempName); nestedParts.Add(new ZipPart(relativePath, partFileName, null, partFileName.SignInfo)); } zipData = new ZipData(zipFileName, nestedParts.ToImmutableList()); return(true); } catch (Exception e) { _log.LogErrorFromException(e); zipData = null; return(false); } finally { package?.Close(); } }
/// <summary> /// Repack the VSIX with the signed parts from the binaries directory. /// </summary> private void Repack(ZipData vsixData) { using (var package = Package.Open(vsixData.Name.FullPath, FileMode.Open, FileAccess.ReadWrite)) { foreach (var part in package.GetParts()) { var relativeName = GetPartRelativeFileName(part); var vsixPart = vsixData.FindNestedBinaryPart(relativeName); if (!vsixPart.HasValue) { continue; } using (var stream = File.OpenRead(vsixPart.Value.FileName.FullPath)) using (var partStream = part.GetStream(FileMode.Open, FileAccess.ReadWrite)) { stream.CopyTo(partStream); partStream.SetLength(stream.Length); } } } }
/// <summary> /// Build up the <see cref="ZipData"/> instance for a given zip container. This will also report any consistency /// errors found when examining the zip archive. /// </summary> private bool TryBuildZipData(FileSignInfo zipFileSignInfo, out ZipData zipData) { Debug.Assert(zipFileSignInfo.IsZipContainer()); try { using (var archive = new ZipArchive(File.OpenRead(zipFileSignInfo.FullPath), ZipArchiveMode.Read)) { var nestedParts = new List <ZipPart>(); foreach (ZipArchiveEntry entry in archive.Entries) { string relativePath = entry.FullName; // `entry` might be just a pointer to a folder. We skip those. if (relativePath.EndsWith("/") && entry.Name == "") { continue; } ImmutableArray <byte> contentHash; using (var stream = entry.Open()) { contentHash = ContentUtil.GetContentHash(stream); } var fileUniqueKey = new SignedFileContentKey(contentHash, relativePath); if (!_whichPackagesTheFileIsIn.TryGetValue(fileUniqueKey, out var packages)) { packages = new HashSet <string>(); } packages.Add(zipFileSignInfo.FileName); _whichPackagesTheFileIsIn[fileUniqueKey] = packages; // if we already encountered file that hash the same content we can reuse its signed version when repackaging the container. var fileName = Path.GetFileName(relativePath); if (!_filesByContentKey.TryGetValue(new SignedFileContentKey(contentHash, fileName), out var fileSignInfo)) { string extractPathRoot = _useHashInExtractionPath ? ContentUtil.HashToString(contentHash) : _filesByContentKey.Count().ToString(); string tempPath = Path.Combine(_pathToContainerUnpackingDirectory, extractPathRoot, relativePath); _log.LogMessage($"Extracting file '{fileName}' from '{zipFileSignInfo.FullPath}' to '{tempPath}'."); Directory.CreateDirectory(Path.GetDirectoryName(tempPath)); using (var stream = entry.Open()) using (var tempFileStream = File.OpenWrite(tempPath)) { stream.CopyTo(tempFileStream); } fileSignInfo = TrackFile(tempPath, contentHash, isNested: true); } if (fileSignInfo.SignInfo.ShouldSign || fileSignInfo.ForceRepack) { nestedParts.Add(new ZipPart(relativePath, fileSignInfo)); } } zipData = new ZipData(zipFileSignInfo, nestedParts.ToImmutableArray()); return(true); } } catch (Exception e) { _log.LogErrorFromException(e); zipData = null; return(false); } }
/// <summary> /// Build up the <see cref="ZipData"/> instance for a given zip container. This will also report any consistency /// errors found when examining the zip archive. /// </summary> private bool TryBuildWixData(FileSignInfo msiFileSignInfo, out ZipData zipData) { // Treat msi as an archive where the filename is the name of the msi, but its contents are from the corresponding wixpack return(TryBuildZipData(msiFileSignInfo, out zipData, msiFileSignInfo.WixContentFilePath)); }
/// <summary> /// Build up the <see cref="ZipData"/> instance for a given zip container. This will also report any consistency /// errors found when examining the zip archive. /// </summary> private bool TryBuildZipData(FileSignInfo zipFileSignInfo, out ZipData zipData, string alternativeArchivePath = null) { string archivePath = zipFileSignInfo.FullPath; if (alternativeArchivePath != null) { archivePath = alternativeArchivePath; Debug.Assert(Path.GetExtension(archivePath) == ".zip"); } else { Debug.Assert(zipFileSignInfo.IsZipContainer()); } try { using (var archive = new ZipArchive(File.OpenRead(archivePath), ZipArchiveMode.Read)) { var nestedParts = new Dictionary <string, ZipPart>(); foreach (ZipArchiveEntry entry in archive.Entries) { string relativePath = entry.FullName; // `entry` might be just a pointer to a folder. We skip those. if (relativePath.EndsWith("/") && entry.Name == "") { continue; } using (var entryStream = entry.Open()) using (MemoryStream entryMemoryStream = new MemoryStream((int)entry.Length)) { entryStream.CopyTo(entryMemoryStream); entryMemoryStream.Position = 0; ImmutableArray <byte> contentHash = ContentUtil.GetContentHash(entryMemoryStream); var fileUniqueKey = new SignedFileContentKey(contentHash, Path.GetFileName(relativePath)); if (!_whichPackagesTheFileIsIn.TryGetValue(fileUniqueKey, out var packages)) { packages = new HashSet <string>(); } packages.Add(Path.GetFileName(archivePath)); _whichPackagesTheFileIsIn[fileUniqueKey] = packages; // if we already encountered file that has the same content we can reuse its signed version when repackaging the container. var fileName = Path.GetFileName(relativePath); if (!_filesByContentKey.TryGetValue(fileUniqueKey, out var fileSignInfo)) { string extractPathRoot = _useHashInExtractionPath ? fileUniqueKey.StringHash : _filesByContentKey.Count().ToString(); string tempPath = Path.Combine(_pathToContainerUnpackingDirectory, extractPathRoot, relativePath); _log.LogMessage($"Extracting file '{fileName}' from '{archivePath}' to '{tempPath}'."); Directory.CreateDirectory(Path.GetDirectoryName(tempPath)); entryMemoryStream.Position = 0; using (var tempFileStream = File.OpenWrite(tempPath)) { entryMemoryStream.CopyTo(tempFileStream); } _hashToCollisionIdMap.TryGetValue(fileUniqueKey, out string collisionPriorityId); PathWithHash nestedFile = new PathWithHash(tempPath, contentHash); fileSignInfo = TrackFile(nestedFile, zipFileSignInfo.File, collisionPriorityId); } if (fileSignInfo.ShouldTrack) { nestedParts.Add(relativePath, new ZipPart(relativePath, fileSignInfo)); } } } zipData = new ZipData(zipFileSignInfo, nestedParts.ToImmutableDictionary()); return(true); } } catch (Exception e) { _log.LogErrorFromException(e); zipData = null; return(false); } }
/// <summary> /// Build up the <see cref="ZipData"/> instance for a given zip container. This will also report any consistency /// errors found when examining the zip archive. /// </summary> private bool TryBuildZipData(FileSignInfo zipFileSignInfo, out ZipData zipData) { Debug.Assert(zipFileSignInfo.IsZipContainer()); try { using (var archive = new ZipArchive(File.OpenRead(zipFileSignInfo.FullPath), ZipArchiveMode.Read)) { var nestedParts = new List <ZipPart>(); foreach (ZipArchiveEntry entry in archive.Entries) { string relativePath = entry.FullName; // `entry` might be just a pointer to a folder. We skip those. if (relativePath.EndsWith("/") && entry.Name == "") { continue; } ImmutableArray <byte> contentHash; using (var stream = entry.Open()) { contentHash = ContentUtil.GetContentHash(stream); } // if we already encountered file that hash the same content we can reuse its signed version when repackaging the container. string fileName = Path.GetFileName(relativePath); if (!_filesByContentKey.TryGetValue(new SignedFileContentKey(contentHash, fileName), out var fileSignInfo)) { string tempDir = Path.Combine(_pathToContainerUnpackingDirectory, ContentUtil.HashToString(contentHash)); string tempPath = Path.Combine(tempDir, Path.GetFileName(relativePath)); Directory.CreateDirectory(tempDir); using (var stream = entry.Open()) using (var tempFileStream = File.OpenWrite(tempPath)) { stream.CopyTo(tempFileStream); } fileSignInfo = TrackFile(tempPath, contentHash, isNested: true); } if (fileSignInfo.SignInfo.ShouldSign) { nestedParts.Add(new ZipPart(relativePath, fileSignInfo)); } } zipData = new ZipData(zipFileSignInfo, nestedParts.ToImmutableArray()); return(true); } } catch (Exception e) { _log.LogErrorFromException(e); zipData = null; return(false); } }
/// <summary> /// Build up the <see cref="ZipData"/> instance for a given zip container. This will also report any consistency /// errors found when examining the zip archive. /// </summary> private bool TryBuildZipData(FileSignInfo zipFileSignInfo, out ZipData zipData) { Debug.Assert(zipFileSignInfo.IsZipContainer()); try { using (var archive = new ZipArchive(File.OpenRead(zipFileSignInfo.FullPath), ZipArchiveMode.Read)) { var nestedParts = new List <ZipPart>(); foreach (ZipArchiveEntry entry in archive.Entries) { string relativePath = entry.FullName; string extension = Path.GetExtension(relativePath); if (!FileSignInfo.IsZipContainer(relativePath) && (!_fileExtensionSignInfo.TryGetValue(extension, out var extensionSignInfo) || !extensionSignInfo.ShouldSign)) { var reason = extensionSignInfo.ShouldIgnore ? "configuration tells to ignore this extension" : "its extension isn't on recognizable signing extension list"; _log.LogMessage($"Ignoring this file because {reason} : {relativePath}"); continue; } ImmutableArray <byte> contentHash; using (var stream = entry.Open()) { contentHash = ContentUtil.GetContentHash(stream); } // if we already encountered file that hash the same content we can reuse its signed version when repackaging the container. string fileName = Path.GetFileName(relativePath); if (!_filesByContentKey.TryGetValue(new SignedFileContentKey(contentHash, fileName), out var fileSignInfo)) { string tempDir = Path.Combine(_pathToContainerUnpackingDirectory, ContentUtil.HashToString(contentHash)); string tempPath = Path.Combine(tempDir, Path.GetFileName(relativePath)); Directory.CreateDirectory(tempDir); using (var stream = entry.Open()) using (var tempFileStream = File.OpenWrite(tempPath)) { stream.CopyTo(tempFileStream); } fileSignInfo = TrackFile(tempPath, contentHash, isNested: true); } if (fileSignInfo.SignInfo.ShouldSign) { nestedParts.Add(new ZipPart(relativePath, fileSignInfo)); } } zipData = new ZipData(zipFileSignInfo, nestedParts.ToImmutableArray()); return(true); } } catch (Exception e) { _log.LogErrorFromException(e); zipData = null; return(false); } }