Exemplo n.º 1
0
    /// <summary>
    ///   Test a local header against that provided from the central directory
    /// </summary>
    /// <param name="entry">
    ///   The entry to test against
    /// </param>
    /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
    /// <returns>The offset of the entries data in the file</returns>
    private long TestLocalHeader(ZipEntry entry, HeaderTest tests)
    {
      lock (baseStream_)
      {
        var testHeader = (tests & HeaderTest.Header) != 0;
        var testData = (tests & HeaderTest.Extract) != 0;

        baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
        if ((int) ReadLEUint() != ZipConstants.LocalHeaderSignature)
        {
          throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset));
        }

        var extractVersion = (short) ReadLEUshort();
        var localFlags = (short) ReadLEUshort();
        var compressionMethod = (short) ReadLEUshort();
        var fileTime = (short) ReadLEUshort();
        var fileDate = (short) ReadLEUshort();
        var crcValue = ReadLEUint();
        long compressedSize = ReadLEUint();
        long size = ReadLEUint();
        int storedNameLength = ReadLEUshort();
        int extraDataLength = ReadLEUshort();

        var nameData = new byte[storedNameLength];
        StreamUtils.ReadFully(baseStream_, nameData);

        var extraData = new byte[extraDataLength];
        StreamUtils.ReadFully(baseStream_, extraData);

        var localExtraData = new ZipExtraData(extraData);

        // Extra data / zip64 checks
        if (localExtraData.Find(1))
        {
          // TODO Check for tag values being distinct..  Multiple zip64 tags means what?

          // Zip64 extra data but 'extract version' is too low
          if (extractVersion < ZipConstants.VersionZip64)
          {
            throw new ZipException(
              string.Format("Extra data contains Zip64 information but version {0}.{1} is not high enough",
                            extractVersion/10, extractVersion%10));
          }

          // Zip64 extra data but size fields dont indicate its required.
          if (((uint) size != uint.MaxValue) && ((uint) compressedSize != uint.MaxValue))
          {
            throw new ZipException("Entry sizes not correct for Zip64");
          }

          size = localExtraData.ReadLong();
          compressedSize = localExtraData.ReadLong();

          if ((localFlags & (int) GeneralBitFlags.Descriptor) != 0)
          {
            // These may be valid if patched later
            if ((size != -1) && (size != entry.Size))
            {
              throw new ZipException("Size invalid for descriptor");
            }

            if ((compressedSize != -1) && (compressedSize != entry.CompressedSize))
            {
              throw new ZipException("Compressed size invalid for descriptor");
            }
          }
        }
        else
        {
          // No zip64 extra data but entry requires it.
          if ((extractVersion >= ZipConstants.VersionZip64) &&
              (((uint) size == uint.MaxValue) || ((uint) compressedSize == uint.MaxValue)))
          {
            throw new ZipException("Required Zip64 extended information missing");
          }
        }

        if (testData)
        {
          if (entry.IsFile)
          {
            if (!entry.IsCompressionMethodSupported())
            {
              throw new ZipException("Compression method not supported");
            }

            if ((extractVersion > ZipConstants.VersionMadeBy)
                || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)))
            {
              throw new ZipException(string.Format("Version required to extract this entry not supported ({0})",
                                                   extractVersion));
            }

            if ((localFlags &
                 (int)
                   (GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress |
                    GeneralBitFlags.HeaderMasked)) != 0)
            {
              throw new ZipException("The library does not support the zip version required to extract this entry");
            }
          }
        }

        if (testHeader)
        {
          if ((extractVersion <= 63) && // Ignore later versions as we dont know about them..
              (extractVersion != 10) &&
              (extractVersion != 11) &&
              (extractVersion != 20) &&
              (extractVersion != 21) &&
              (extractVersion != 25) &&
              (extractVersion != 27) &&
              (extractVersion != 45) &&
              (extractVersion != 46) &&
              (extractVersion != 50) &&
              (extractVersion != 51) &&
              (extractVersion != 52) &&
              (extractVersion != 61) &&
              (extractVersion != 62) &&
              (extractVersion != 63)
            )
          {
            throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})",
                                                 extractVersion));
          }

          // Local entry flags dont have reserved bit set on.
          if ((localFlags &
               (int)
                 (GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15)) !=
              0)
          {
            throw new ZipException("Reserved bit flags cannot be set.");
          }

          // Encryption requires extract version >= 20
          if (((localFlags & (int) GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))
          {
            throw new ZipException(
              string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
          }

          // Strong encryption requires encryption flag to be set and extract version >= 50.
          if ((localFlags & (int) GeneralBitFlags.StrongEncryption) != 0)
          {
            if ((localFlags & (int) GeneralBitFlags.Encrypted) == 0)
            {
              throw new ZipException("Strong encryption flag set but encryption flag is not set");
            }

            if (extractVersion < 50)
            {
              throw new ZipException(
                string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
            }
          }

          // Patched entries require extract version >= 27
          if (((localFlags & (int) GeneralBitFlags.Patched) != 0) && (extractVersion < 27))
          {
            throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
          }

          // Central header flags match local entry flags.
          if (localFlags != entry.Flags)
          {
            throw new ZipException("Central header/local header flags mismatch");
          }

          // Central header compression method matches local entry
          if (entry.CompressionMethod != (CompressionMethod) compressionMethod)
          {
            throw new ZipException("Central header/local header compression method mismatch");
          }

          if (entry.Version != extractVersion)
          {
            throw new ZipException("Extract version mismatch");
          }

          // Strong encryption and extract version match
          if ((localFlags & (int) GeneralBitFlags.StrongEncryption) != 0)
          {
            if (extractVersion < 62)
            {
              throw new ZipException("Strong encryption flag set but version not high enough");
            }
          }

          if ((localFlags & (int) GeneralBitFlags.HeaderMasked) != 0)
          {
            if ((fileTime != 0) || (fileDate != 0))
            {
              throw new ZipException("Header masked set but date/time values non-zero");
            }
          }

          if ((localFlags & (int) GeneralBitFlags.Descriptor) == 0)
          {
            if (crcValue != (uint) entry.Crc)
            {
              throw new ZipException("Central header/local header crc mismatch");
            }
          }

          // Crc valid for empty entry.
          // This will also apply to streamed entries where size isnt known and the header cant be patched
          if ((size == 0) && (compressedSize == 0))
          {
            if (crcValue != 0)
            {
              throw new ZipException("Invalid CRC for empty entry");
            }
          }

          // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS strings
          // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
          if (entry.Name.Length > storedNameLength)
          {
            throw new ZipException("File name length mismatch");
          }

          // Name data has already been read convert it and compare.
          var localName = ZipConstants.ConvertToStringExt(localFlags, nameData);

          // Central directory and local entry name match
          if (localName != entry.Name)
          {
            throw new ZipException("Central header and local header file name mismatch");
          }

          // Directories have zero actual size but can have compressed size
          if (entry.IsDirectory)
          {
            if (size > 0)
            {
              throw new ZipException("Directory cannot have size");
            }

            // There may be other cases where the compressed size can be greater than this?
            // If so until details are known we will be strict.
            if (compressedSize > 2)
            {
              // When not compressed the directory size can validly be 2 bytes
              // if the true size wasnt known when data was originally being written.
              // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
              throw new ZipException("Directory compressed size invalid");
            }
          }

          if (!ZipNameTransform.IsValidName(localName, true))
          {
            throw new ZipException("Name is invalid");
          }
        }

        // Tests that apply to both data and header.

        // Size can be verified only if it is known in the local header.
        // it will always be known in the central header.
        if (((localFlags & (int) GeneralBitFlags.Descriptor) == 0) ||
            ((size > 0) || (compressedSize > 0)))
        {
          if (size != entry.Size)
          {
            throw new ZipException(
              string.Format("Size mismatch between central header({0}) and local header({1})",
                            entry.Size, size));
          }

          if (compressedSize != entry.CompressedSize)
          {
            throw new ZipException(
              string.Format("Compressed size mismatch between central header({0}) and local header({1})",
                            entry.CompressedSize, compressedSize));
          }
        }

        var extraLength = storedNameLength + extraDataLength;
        return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
      }
    }
Exemplo n.º 2
0
        /// <summary>
        ///   Process extra data fields updating the entry based on the contents.
        /// </summary>
        /// <param name="localHeader">
        ///   True if the extra data fields should be handled
        ///   for a local header, rather than for a central header.
        /// </param>
        internal void ProcessExtraData(bool localHeader)
        {
            var extraData = new ZipExtraData(extra);

            if (extraData.Find(0x0001))
            {
                if ((versionToExtract & 0xff) < ZipConstants.VersionZip64)
                {
                    throw new ZipException("Zip64 Extended information found but version is not valid");
                }

                // The recorded size will change but remember that this is zip64.
                forceZip64_ = true;

                if (extraData.ValueLength < 4)
                {
                    throw new ZipException("Extra data extended Zip64 information length is invalid");
                }

                if (localHeader || (size == uint.MaxValue))
                {
                    size = (ulong)extraData.ReadLong();
                }

                if (localHeader || (compressedSize == uint.MaxValue))
                {
                    compressedSize = (ulong)extraData.ReadLong();
                }

                if (!localHeader && (offset == uint.MaxValue))
                {
                    offset = extraData.ReadLong();
                }
            }
            else
            {
                if (
                    ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
                    ((size == uint.MaxValue) || (compressedSize == uint.MaxValue))
                    )
                {
                    throw new ZipException("Zip64 Extended information required but is missing.");
                }
            }

            if (extraData.Find(10))
            {
                // No room for any tags.
                if (extraData.ValueLength < 8)
                {
                    throw new ZipException("NTFS Extra data invalid");
                }

                extraData.ReadInt(); // Reserved

                while (extraData.UnreadCount >= 4)
                {
                    var ntfsTag    = extraData.ReadShort();
                    var ntfsLength = extraData.ReadShort();
                    if (ntfsTag == 1)
                    {
                        if (ntfsLength >= 24)
                        {
                            var lastModification = extraData.ReadLong();
                            //long lastAccess = extraData.ReadLong();
                            //long createTime = extraData.ReadLong();
                            extraData.Skip(16);

                            DateTime = DateTime.FromFileTime(lastModification);
                        }
                        break;
                    }
                    // An unknown NTFS tag so simply skip it.
                    extraData.Skip(ntfsLength);
                }
            }
            else if (extraData.Find(0x5455))
            {
                var length = extraData.ValueLength;
                var flags  = extraData.ReadByte();

                // Can include other times but these are ignored.  Length of data should
                // actually be 1 + 4 * no of bits in flags.
                if (((flags & 1) != 0) && (length >= 5))
                {
                    var iTime = extraData.ReadInt();

                    DateTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
                                new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
                }
            }
        }
Exemplo n.º 3
0
    /// <summary>
    ///   Process extra data fields updating the entry based on the contents.
    /// </summary>
    /// <param name="localHeader">
    ///   True if the extra data fields should be handled
    ///   for a local header, rather than for a central header.
    /// </param>
    internal void ProcessExtraData(bool localHeader)
    {
      var extraData = new ZipExtraData(extra);

      if (extraData.Find(0x0001))
      {
        if ((versionToExtract & 0xff) < ZipConstants.VersionZip64)
        {
          throw new ZipException("Zip64 Extended information found but version is not valid");
        }

        // The recorded size will change but remember that this is zip64.
        forceZip64_ = true;

        if (extraData.ValueLength < 4)
        {
          throw new ZipException("Extra data extended Zip64 information length is invalid");
        }

        if (localHeader || (size == uint.MaxValue))
        {
          size = (ulong) extraData.ReadLong();
        }

        if (localHeader || (compressedSize == uint.MaxValue))
        {
          compressedSize = (ulong) extraData.ReadLong();
        }

        if (!localHeader && (offset == uint.MaxValue))
        {
          offset = extraData.ReadLong();
        }
      }
      else
      {
        if (
          ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
          ((size == uint.MaxValue) || (compressedSize == uint.MaxValue))
          )
        {
          throw new ZipException("Zip64 Extended information required but is missing.");
        }
      }

      if (extraData.Find(10))
      {
        // No room for any tags.
        if (extraData.ValueLength < 8)
        {
          throw new ZipException("NTFS Extra data invalid");
        }

        extraData.ReadInt(); // Reserved

        while (extraData.UnreadCount >= 4)
        {
          var ntfsTag = extraData.ReadShort();
          var ntfsLength = extraData.ReadShort();
          if (ntfsTag == 1)
          {
            if (ntfsLength >= 24)
            {
              var lastModification = extraData.ReadLong();
              //long lastAccess = extraData.ReadLong();
              //long createTime = extraData.ReadLong();
              extraData.Skip(16);

              DateTime = DateTime.FromFileTime(lastModification);
            }
            break;
          }
          // An unknown NTFS tag so simply skip it.
          extraData.Skip(ntfsLength);
        }
      }
      else if (extraData.Find(0x5455))
      {
        var length = extraData.ValueLength;
        var flags = extraData.ReadByte();

        // Can include other times but these are ignored.  Length of data should
        // actually be 1 + 4 * no of bits in flags.
        if (((flags & 1) != 0) && (length >= 5))
        {
          var iTime = extraData.ReadInt();

          DateTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
                      new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
        }
      }
    }