示例#1
0
        private List <TarEntry> _internal_ListOrExtract(string archive, bool wantExtract, string path)
        {
            var entryList = new List <TarEntry>();

            byte[]   block                = new byte[512];
            int      n                    = 0;
            int      blocksToMunch        = 0;
            int      remainingBytes       = 0;
            Stream   output               = null;
            DateTime mtime                = DateTime.Now;
            string   name                 = null;
            TarEntry entry                = null;
            var      deferredDirTimestamp = new Dictionary <String, DateTime>();

            if (!File.Exists(archive))
            {
                throw new InvalidOperationException("The specified file does not exist.");
            }

            using (Stream fs = _internal_GetInputStream(archive))
            {
                while ((n = fs.Read(block, 0, block.Length)) > 0)
                {
                    if (blocksToMunch > 0)
                    {
                        if (output != null)
                        {
                            int bytesToWrite = (block.Length < remainingBytes)
                                ? block.Length
                                : remainingBytes;

                            output.Write(block, 0, bytesToWrite);
                            remainingBytes -= bytesToWrite;
                        }

                        blocksToMunch--;

                        if (blocksToMunch == 0)
                        {
                            if (output != null)
                            {
                                if (output is MemoryStream)
                                {
                                    entry.Name = name = System.Text.Encoding.ASCII.GetString((output as MemoryStream).ToArray()).TrimNull();
                                }

                                output.Close();
                                output.Dispose();

                                if (output is FileStream && !TarOptions.DoNotSetTime)
                                {
                                    File.SetLastWriteTimeUtc(name, mtime);
                                }

                                output = null;
                            }
                        }
                        continue;
                    }

                    HeaderBlock hb = serializer.RawDeserialize(block);

                    if (!hb.VerifyChksum())
                    {
                        throw new Exception("header checksum is invalid.");
                    }

                    if (entry == null || entry.Type != TarEntryType.GnuLongName)
                    {
                        name = hb.GetName();
                    }

                    if (name == null || name.Length == 0)
                    {
                        break;
                    }
                    mtime          = hb.GetMtime();
                    remainingBytes = hb.GetSize();

                    if (hb.typeflag == 0)
                    {
                        hb.typeflag = (byte)'0';
                    }

                    entry = new TarEntry()
                    {
                        Name = name, Mtime = mtime, Size = remainingBytes, @Type = (TarEntryType)hb.typeflag
                    };

                    if (entry.Type != TarEntryType.GnuLongName)
                    {
                        entryList.Add(entry);
                    }

                    blocksToMunch = (remainingBytes > 0)
                        ? ((remainingBytes - 1) / 512) + 1
                        : 0;

                    if (entry.Type == TarEntryType.GnuLongName)
                    {
                        if (name != "././@LongLink")
                        {
                            if (wantExtract)
                            {
                                throw new Exception(String.Format("unexpected name for type 'L' (expected '././@LongLink', got '{0}')", name));
                            }
                        }
                        output = new MemoryStream();
                        continue;
                    }

                    if (wantExtract)
                    {
                        name = path + name;
                        switch (entry.Type)
                        {
                        case TarEntryType.Directory:
                            if (!Directory.Exists(name))
                            {
                                Directory.CreateDirectory(name);
                                if (!TarOptions.DoNotSetTime)
                                {
                                    deferredDirTimestamp.Add(name.TrimSlash(), mtime);
                                }
                            }
                            else if (TarOptions.Overwrite)
                            {
                                if (!TarOptions.DoNotSetTime)
                                {
                                    deferredDirTimestamp.Add(name.TrimSlash(), mtime);
                                }
                            }
                            break;

                        case TarEntryType.File_Old:
                        case TarEntryType.File:
                        case TarEntryType.File_Contiguous:
                            string p = Path.GetDirectoryName(name);
                            if (!String.IsNullOrEmpty(p))
                            {
                                if (!Directory.Exists(p))
                                {
                                    Directory.CreateDirectory(p);
                                }
                            }
                            output = _internal_GetExtractOutputStream(name);
                            break;

                        case TarEntryType.GnuVolumeHeader:
                        case TarEntryType.CharSpecial:
                        case TarEntryType.BlockSpecial:
                            break;

                        case TarEntryType.SymbolicLink:
                            break;


                        default:
                            throw new Exception(String.Format("unsupported entry type ({0})", hb.typeflag));
                        }
                    }
                }
            }

            if (deferredDirTimestamp.Count > 0)
            {
                foreach (var s in deferredDirTimestamp.Keys)
                {
                    Directory.SetLastWriteTimeUtc(s, deferredDirTimestamp[s]);
                }
            }

            return(entryList);
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>   Gets extracted streams. </summary>
        ///
        /// <param name="archive">  The archive. </param>
        ///
        /// <returns>   The extracted streams. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////

        public static Dictionary <string, byte[]> GetExtractedStreams(string archive)
        {
            Dictionary <string, byte[]> result = new Dictionary <string, byte[]>();

            byte[] block = new byte[512];
            RawSerializer <HeaderBlock> serializer = new RawSerializer <HeaderBlock>();
            int blocksToMunch  = 0;
            int remainingBytes = 0;

            bool   outputFlg = false;
            string name      = String.Empty;

            List <byte> output = new List <byte>();

            using (Stream fs = new GZipStream(File.Open(archive, FileMode.Open, FileAccess.Read), CompressionMode.Decompress, false))
            {
                while (fs.Read(block, 0, block.Length) > 0)
                {
                    if (blocksToMunch > 0)
                    {
                        if (outputFlg)
                        {
                            int bytesToWrite = block.Length < remainingBytes ? block.Length : remainingBytes;

                            byte[] tmpArray = new byte[bytesToWrite];
                            Array.Copy(block, 0, tmpArray, 0, bytesToWrite);

                            output.AddRange(tmpArray);

                            remainingBytes -= bytesToWrite;
                        }

                        blocksToMunch--;

                        if (blocksToMunch == 0)
                        {
                            outputFlg = false;
                        }

                        continue;
                    }

                    if (name != string.Empty)
                    {
                        result.Add(name, output.ToArray());
                        output.Clear();
                    }

                    HeaderBlock hb = serializer.RawDeserialize(block);


                    if (name == String.Empty || (TarEntryType)hb.typeflag != TarEntryType.GnuLongName)
                    {
                        name = hb.GetName();
                    }

                    if (name == String.Empty)
                    {
                        break;
                    }
                    remainingBytes = hb.GetSize();

                    if (hb.typeflag == 0)
                    {
                        hb.typeflag = (byte)'0';
                    }

                    blocksToMunch = remainingBytes > 0 ? (remainingBytes - 1) / 512 + 1 : 0;

                    if ((TarEntryType)hb.typeflag == TarEntryType.File_Old ||
                        (TarEntryType)hb.typeflag == TarEntryType.File ||
                        (TarEntryType)hb.typeflag == TarEntryType.File_Contiguous)
                    {
                        outputFlg = true;
                    }
                }
            }

            return(result);
        }
示例#3
0
        private List <TarEntry> listOrExtract(Stream file, string extractDirectory)
        {
            bool wantExtract = extractDirectory != null;

            var entryList = new List <TarEntry>();

            byte[]   block                = new byte[512];
            int      n                    = 0;
            int      blocksToMunch        = 0;
            int      remainingBytes       = 0;
            Stream   output               = null;
            DateTime mtime                = DateTime.Now;
            string   name                 = null;
            TarEntry entry                = null;
            var      deferredDirTimestamp = new Dictionary <String, DateTime>();

            while ((n = file.Read(block, 0, block.Length)) > 0)
            {
                if (blocksToMunch > 0)
                {
                    if (output != null)
                    {
                        int bytesToWrite = (block.Length < remainingBytes)
                            ? block.Length
                            : remainingBytes;

                        output.Write(block, 0, bytesToWrite);
                        remainingBytes -= bytesToWrite;
                    }

                    blocksToMunch--;

                    //System.Diagnostics.Debugger.Break();

                    if (blocksToMunch == 0)
                    {
                        if (output != null)
                        {
                            if (output is MemoryStream)
                            {
                                entry.Name = name = System.Text.Encoding.ASCII.GetString((output as MemoryStream).ToArray()).TrimNull();
                            }

                            output.Close();
                            output.Dispose();

                            if (output is FileStream)
                            {
                                File.SetLastWriteTimeUtc(Path.Combine(extractDirectory, name), mtime);
                            }

                            output = null;
                        }
                    }
                    continue;
                }

                HeaderBlock hb = serializer.RawDeserialize(block);

                //System.Diagnostics.Debugger.Break();

                if (!hb.VerifyChksum())
                {
                    throw new Exception("header checksum is invalid.");
                }

                // if this is the first entry, or if the prior entry is not a GnuLongName
                if (entry == null || entry.Type != TarEntryType.GnuLongName)
                {
                    name = hb.GetName();
                }

                if (name == null || name.Length == 0)
                {
                    break;                                   // EOF
                }
                mtime          = hb.GetMtime();
                remainingBytes = hb.GetSize();

                if (hb.typeflag == 0)
                {
                    hb.typeflag = (byte)'0';                   // coerce old-style GNU type to posix tar type
                }
                entry = new TarEntry()
                {
                    Name = name, Mtime = mtime, Size = remainingBytes, @Type = (TarEntryType)hb.typeflag
                };

                if (entry.Type != TarEntryType.GnuLongName)
                {
                    entryList.Add(entry);
                }

                blocksToMunch = (remainingBytes > 0)
                    ? ((remainingBytes - 1) / 512) + 1
                    : 0;

                if (entry.Type == TarEntryType.GnuLongName)
                {
                    if (name != "././@LongLink")
                    {
                        if (wantExtract)
                        {
                            throw new Exception(String.Format("unexpected name for type 'L' (expected '././@LongLink', got '{0}')", name));
                        }
                    }
                    // for GNU long names, we extract the long name info into a memory stream
                    output = new MemoryStream();
                    continue;
                }

                if (wantExtract)
                {
                    var extractPath = Path.Combine(extractDirectory, name);
                    switch (entry.Type)
                    {
                    case TarEntryType.Directory:
                        if (!Directory.Exists(extractPath))
                        {
                            Directory.CreateDirectory(extractPath);
                            // cannot set the time on the directory now, or it will be updated
                            // by future file writes.  Defer until after all file writes are done.
                            deferredDirTimestamp.Add(extractPath.TrimSlash(), mtime);
                        }
                        else
                        {
                            deferredDirTimestamp.Add(extractPath.TrimSlash(), mtime);
                        }
                        break;

                    case TarEntryType.File_Old:
                    case TarEntryType.File:
                    case TarEntryType.File_Contiguous:
                        string p = Path.GetDirectoryName(extractPath);
                        if (!String.IsNullOrEmpty(p))
                        {
                            if (!Directory.Exists(p))
                            {
                                Directory.CreateDirectory(p);
                            }
                        }
                        output = getOutputStream(extractPath);
                        break;

                    case TarEntryType.GnuVolumeHeader:
                    case TarEntryType.CharSpecial:
                    case TarEntryType.BlockSpecial:
                        // do nothing on extract
                        break;

                    case TarEntryType.SymbolicLink:
                        break;
                    // can support other types here - links, etc


                    default:
                        throw new Exception(String.Format("unsupported entry type ({0})", hb.typeflag));
                    }
                }
            }


            // apply the deferred timestamps on the directories
            if (deferredDirTimestamp.Count > 0)
            {
                foreach (var s in deferredDirTimestamp.Keys)
                {
                    Directory.SetLastWriteTimeUtc(s, deferredDirTimestamp[s]);
                }
            }

            return(entryList);
        }