private static void ExplodeCab(MSCabinet cab, string outDir) { Directory.CreateDirectory(outDir); foreach (var file in cab.GetFiles()) { var extractPath = Path.Combine(outDir, file.Filename); Console.WriteLine(" Extracting {0} to {1}.", file.Filename, extractPath); file.ExtractTo(extractPath); } }
// TODO: Add stream opening support /// <inheritdoc/> public ConcurrentDictionary <string, ConcurrentQueue <string> > Scan(Scanner scanner, Stream stream, string file) { // If the cab file itself fails try { string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempPath); using (MSCabinet cabfile = new MSCabinet(file)) { foreach (var sub in cabfile.GetFiles()) { // If an individual entry fails try { // The trim here is for some very odd and stubborn files string tempFile = Path.Combine(tempPath, sub.Filename.TrimEnd('.')); sub.ExtractTo(tempFile); } catch { } } } // Collect and format all found protections var protections = scanner.GetProtections(tempPath); // If temp directory cleanup fails try { Directory.Delete(tempPath, true); } catch { } // Remove temporary path references Utilities.StripFromKeys(protections, tempPath); return(protections); } catch { } return(null); }
/// <summary> /// Extracts the compressed files from the specified MSI file to the specified output directory. /// If specified, the list of <paramref name="filesToExtract"/> objects are the only files extracted. /// </summary> /// <param name="filesToExtract">The files to extract or null or empty to extract all files.</param> /// <param name="progressCallback">Will be called during during the operation with progress information, and upon completion. The argument will be of type <see cref="ExtractionProgress"/>.</param> public static void ExtractFiles(FileInfo msi, DirectoryInfo outputDir, MsiFile[] filesToExtract, AsyncCallback progressCallback) { if (msi == null) throw new ArgumentNullException("msi"); if (outputDir == null) throw new ArgumentNullException("outputDir"); int filesExtractedSoFar = 0; ExtractionProgress progress = null; Database msidb = new Database(msi.FullName, OpenDatabase.ReadOnly); try { if (filesToExtract == null || filesToExtract.Length < 1) filesToExtract = MsiFile.CreateMsiFilesFromMSI(msidb); progress = new ExtractionProgress(progressCallback, filesToExtract.Length); if (!msi.Exists) { Trace.WriteLine("File \'" + msi.FullName + "\' not found."); progress.ReportProgress(ExtractionActivity.Complete, "", filesExtractedSoFar); return; } progress.ReportProgress(ExtractionActivity.Initializing, "", filesExtractedSoFar); outputDir.Create(); //map short file names to the msi file entry var fileEntryMap = new Dictionary<string, MsiFile>(filesToExtract.Length, StringComparer.InvariantCulture); foreach (var fileEntry in filesToExtract) { MsiFile existingFile = null; if (fileEntryMap.TryGetValue(fileEntry.File, out existingFile)) { //NOTE: This used to be triggered when we ignored case of file, but now we don't ignore case so this is unlikely to occur. // Differing only by case is not compliant with the msi specification but some installers do it (e.g. python, see issue 28). Debug.Print("!!Found duplicate file using key {0}. The existing key was {1}", fileEntry.File, existingFile.File); } else { fileEntryMap.Add(fileEntry.File, fileEntry); } } Debug.Assert(fileEntryMap.Count == filesToExtract.Length, "Duplicate files must have caused some files to not be in the map."); var cabinets = CabsFromMsiToDisk(msidb, outputDir); foreach (CabInfo cabinfo in cabinets) { using (var cabDecompressor = new MSCabinet(cabinfo.LocalCabFile)) { foreach (var compressedFile in cabDecompressor.GetFiles()) { var entry = fileEntryMap[compressedFile.Filename]; progress.ReportProgress(ExtractionActivity.ExtractingFile, entry.LongFileName, filesExtractedSoFar); DirectoryInfo targetDirectoryForFile = GetTargetDirectory(outputDir, entry.Directory); string destName = Path.Combine(targetDirectoryForFile.FullName, entry.LongFileName); if (File.Exists(destName)) { Debug.Fail("output file already exists. We'll make it unique, but this is probably a strange msi or a bug in this program."); //make unique // ReSharper disable HeuristicUnreachableCode Trace.WriteLine(string.Concat("Duplicate file found \'", destName, "\'")); int duplicateCount = 0; string uniqueName; do { uniqueName = string.Concat(destName, ".", "duplicate", ++duplicateCount); } while (File.Exists(uniqueName)); destName = uniqueName; // ReSharper restore HeuristicUnreachableCode } Trace.WriteLine(string.Concat("Extracting File \'", compressedFile.Filename, "\' to \'", destName, "\'")); compressedFile.ExtractTo(destName); filesExtractedSoFar++; } } //del local cab: File.Delete(cabinfo.LocalCabFile); } } finally { if (msidb != null) msidb.Close(); if (progress != null) progress.ReportProgress(ExtractionActivity.Complete, "", filesExtractedSoFar); } }