Exemplo n.º 1
0
        private static void ExplodeAndVerifyCab(string cabinetFilename, int fileCount)
        {
            Console.WriteLine("Files in " + cabinetFilename + ":");

            bool   errors = false;
            string outDir = OutDir(cabinetFilename);

            try
            {
                Assert.True(File.Exists(cabinetFilename));

                using (var cab = new MSCabinet(cabinetFilename))
                {
                    ExplodeCab(cab, outDir);
                }
            }
            catch (Exception e)
            {
                errors = true;
                Console.WriteLine("ERROR! " + e.Message);
            }

            Assert.False(errors);

            Assert.True(Directory.Exists(outDir));

            var outputFiles = Directory.GetFiles(outDir, "*", SearchOption.AllDirectories);

            Assert.Equal(fileCount, outputFiles.Count());

            Directory.Delete(outDir, true);

            Console.WriteLine("");
            Console.WriteLine("");
        }
Exemplo n.º 2
0
 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);
     }
 }
Exemplo n.º 3
0
        /// <summary>
        /// Allocates a decompressor for each cab and merges any cabs that need merged.
        /// </summary>
        /// <param name="cabinets"></param>
        /// <returns></returns>
        private static IEnumerable <MSCabinet> MergeCabs(IList <CabInfo> cabInfos)
        {
            /* Sometimes cab files are part of a set. We must merge those into their set before we leave here.
             * Otherwise extracting a file that extends beyond the bounds of one cab in the set will fail. This happens in VBRuntime.msi
             *
             * It can be determined if a cabinet has further parts to load by examining the mscabd_cabinet::flags field:
             * if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a predecessor cabinet to open() and prepend(). Its MS-DOS case-insensitive filename is mscabd_cabinet::prevname
             * if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a successor cabinet to open() and append(). Its MS-DOS case-insensitive filename is mscabd_cabinet::nextname
             */
            var decompressors = new List <MSCabinet>();

            for (int i = 0; i < cabInfos.Count; i++)
            {
                CabInfo   cab   = cabInfos[i];
                MSCabinet msCab = null;
                try
                {
                    msCab = new MSCabinet(cab.LocalCabFile); // NOTE: Deliberately not disposing. Caller must cleanup.
                }
                catch (Exception)
                {
                    // As seen in https://github.com/activescott/lessmsi/issues/104, sometimes bogus cabs are inside of a msi but they're not needed to extract any files from. So we should attempt to ignore this failure here:
                    Debug.Fail(
                        string.Format("Cab name \"{0}\" could not be read by cab reader. Will attempt to ignore...", cab.CabSourceName)
                        );
                    continue;
                }

                if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_NEXTCAB) != 0)
                {
                    Debug.Assert(!string.IsNullOrEmpty(msCab.NextName), "Header indcates next cab but new cab not found.");
                    // load the cab found in NextName:
                    // Append it to msCab
                    Debug.Print("Found cabinet set. Nextname: " + msCab.NextName);
                    var nextCab   = FindCabAndRemoveFromList(cabInfos, msCab.NextName);
                    var msCabNext = new MSCabinet(nextCab.LocalCabFile);
                    msCab.Append(msCabNext);
                    decompressors.Add(msCab);
                }
                else if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_PREVCAB) != 0)
                {
                    Debug.Assert(!string.IsNullOrEmpty(msCab.PrevName), "Header indcates prev cab but new cab not found.");
                    Debug.Print("Found cabinet set. PrevName: " + msCab.PrevName);
                    var prevCabInfo = FindCabAndRemoveFromList(cabInfos, msCab.PrevName);
                    var msCabPrev   = new MSCabinet(prevCabInfo.LocalCabFile);
                    msCabPrev.Append(msCab);
                    decompressors.Add(msCabPrev);
                }
                else
                {                       // just a simple standalone cab
                    decompressors.Add(msCab);
                }
            }
            return(decompressors);
        }
Exemplo n.º 4
0
        public void CabinetSet()
        {
            //NO WORKY!
            var root         = Path.Combine(AppPath, "cabinetset");
            var cabFilename1 = Path.Combine(root, "Disk1.CAB");
            var cabFilename2 = Path.Combine(root, "Disk2.CAB");

            using (var cab1 = new MSCabinet(cabFilename1))
                using (var cab2 = new MSCabinet(cabFilename2))
                {
                    cab1.Append(cab2);
                    ExplodeCab(cab1, OutDir(cabFilename1));
                }
            Console.ReadLine();
        }
Exemplo n.º 5
0
        public void CabinetSet()
        {
            string root         = Path.Combine(AppContext.BaseDirectory, "test_files", "cabinetset");
            string cabFilename1 = Path.Combine(root, "Disk1.CAB");
            string cabFilename2 = Path.Combine(root, "Disk2.CAB");

            Assert.True(File.Exists(cabFilename1));
            Assert.True(File.Exists(cabFilename2));

            using (var cab1 = new MSCabinet(cabFilename1))
                using (var cab2 = new MSCabinet(cabFilename2))
                {
                    cab1.Append(cab2);
                    ExplodeCab(cab1, OutDir(cabFilename1));
                }
        }
Exemplo n.º 6
0
 private static void ExplodeCab(string cabinetFilename)
 {
     Console.WriteLine("Files in " + cabinetFilename + ":");
     try
     {
         using (var cab = new MSCabinet(cabinetFilename))
         {
             var outDir = OutDir(cabinetFilename);
             ExplodeCab(cab, outDir);
         }
     }
     catch (Exception e)
     {
         Console.WriteLine("ERROR! " + e.Message);
     }
     Console.WriteLine("");
     Console.WriteLine("");
 }
Exemplo n.º 7
0
        /// <summary>
        /// Allocates a decompressor for each cab and merges any cabs that need merged.
        /// </summary>
        /// <param name="cabinets"></param>
        /// <returns></returns>
        private static IEnumerable <MSCabinet> MergeCabs(IList <CabInfo> cabInfos)
        {
            /* Sometimes cab files are part of a set. We must merge those into their set before we leave here.
             * Otherwise extracting a file that extends beyond the bounds of one cab in the set will fail. This happens in VBRuntime.msi
             *
             * It can be determined if a cabinet has further parts to load by examining the mscabd_cabinet::flags field:
             * if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a predecessor cabinet to open() and prepend(). Its MS-DOS case-insensitive filename is mscabd_cabinet::prevname
             * if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a successor cabinet to open() and append(). Its MS-DOS case-insensitive filename is mscabd_cabinet::nextname
             */
            var decompressors = new List <MSCabinet>();

            for (int i = 0; i < cabInfos.Count; i++)
            {
                CabInfo cab   = cabInfos[i];
                var     msCab = new MSCabinet(cab.LocalCabFile);            //NOTE: Deliberately not disposing. Caller must cleanup.

                if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_NEXTCAB) != 0)
                {
                    Debug.Assert(!string.IsNullOrEmpty(msCab.NextName), "Header indcates next cab but new cab not found.");
                    // load the cab found in NextName:
                    // Append it to msCab
                    Debug.Print("Found cabinet set. Nextname: " + msCab.NextName);
                    var nextCab   = FindCabAndRemoveFromList(cabInfos, msCab.NextName);
                    var msCabNext = new MSCabinet(nextCab.LocalCabFile);
                    msCab.Append(msCabNext);
                    decompressors.Add(msCab);
                }
                else if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_PREVCAB) != 0)
                {
                    Debug.Assert(!string.IsNullOrEmpty(msCab.PrevName), "Header indcates prev cab but new cab not found.");
                    Debug.Print("Found cabinet set. PrevName: " + msCab.PrevName);
                    var prevCabInfo = FindCabAndRemoveFromList(cabInfos, msCab.PrevName);
                    var msCabPrev   = new MSCabinet(prevCabInfo.LocalCabFile);
                    msCabPrev.Append(msCab);
                    decompressors.Add(msCabPrev);
                }
                else
                {                       // just a simple standalone cab
                    decompressors.Add(msCab);
                }
            }
            return(decompressors);
        }
Exemplo n.º 8
0
        // 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);
        }
Exemplo n.º 9
0
        static void Main()
        {
            IEnumerable <string> files = Directory.GetFiles(AppPath, "*.cab");

            foreach (var f in files)
            {
                ExplodeCab(f);
            }

            //NO WORKY!
            var root         = Path.Combine(AppPath, "cabinetset");
            var cabFilename1 = Path.Combine(root, "Disk1.CAB");
            var cabFilename2 = Path.Combine(root, "Disk2.CAB");

            using (var cab1 = new MSCabinet(cabFilename1))
                using (var cab2 = new MSCabinet(cabFilename2))
                {
                    cab1.Append(cab2);
                    ExplodeCab(cab1, OutDir(cabFilename1));
                }
            Console.ReadLine();
        }
Exemplo n.º 10
0
        /// <summary>
        /// Allocates a decompressor for each cab and merges any cabs that need merged.
        /// </summary>
        /// <param name="cabinets"></param>
        /// <returns></returns>
        private static IEnumerable<MSCabinet> MergeCabs(IList<CabInfo> cabInfos)
        {
            /* Sometimes cab files are part of a set. We must merge those into their set before we leave here.
             * Otherwise extracting a file that extends beyond the bounds of one cab in the set will fail. This happens in VBRuntime.msi
             *
             * It can be determined if a cabinet has further parts to load by examining the mscabd_cabinet::flags field:
             * if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a predecessor cabinet to open() and prepend(). Its MS-DOS case-insensitive filename is mscabd_cabinet::prevname
             * if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a successor cabinet to open() and append(). Its MS-DOS case-insensitive filename is mscabd_cabinet::nextname
             */
            var decompressors = new List<MSCabinet>();
            for (int i=0; i < cabInfos.Count; i++)
            {
                CabInfo cab = cabInfos[i];
                var msCab = new MSCabinet(cab.LocalCabFile);//NOTE: Deliberately not disposing. Caller must cleanup.

                if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_NEXTCAB) != 0)
                {
                    Debug.Assert(!string.IsNullOrEmpty(msCab.NextName), "Header indcates next cab but new cab not found.");
                    // load the cab found in NextName:
                    // Append it to msCab
                    Debug.Print("Found cabinet set. Nextname: " + msCab.NextName);
                    var nextCab = FindCabAndRemoveFromList(cabInfos, msCab.NextName);
                    var msCabNext = new MSCabinet(nextCab.LocalCabFile);
                    msCab.Append(msCabNext);
                    decompressors.Add(msCab);
                }
                else if ((msCab.Flags & MSCabinetFlags.MSCAB_HDR_PREVCAB) != 0)
                {
                    Debug.Assert(!string.IsNullOrEmpty(msCab.PrevName), "Header indcates prev cab but new cab not found.");
                    Debug.Print("Found cabinet set. PrevName: " + msCab.PrevName);
                    var prevCabInfo = FindCabAndRemoveFromList(cabInfos, msCab.PrevName);
                    var msCabPrev = new MSCabinet(prevCabInfo.LocalCabFile);
                    msCabPrev.Append(msCab);
                    decompressors.Add(msCabPrev);
                }
                else
                {	// just a simple standalone cab
                    decompressors.Add(msCab);
                }
            }
            return decompressors;
        }
Exemplo n.º 11
0
        /// <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);
            }
        }