浏览代码

FIX: #36 Bug Reading of tar archives with files larger than 4 and 8GiB fails

Alexander Koblov 4 年之前
父节点
当前提交
21b34f4890
共有 2 个文件被更改,包括 198 次插入32 次删除
  1. 53 6
      plugins/wcx/zip/src/fparchive/abtartyp.pas
  2. 145 26
      plugins/wcx/zip/src/fparchive/doublecmd.diff

+ 53 - 6
plugins/wcx/zip/src/fparchive/abtartyp.pas

@@ -468,20 +468,67 @@ uses
 { ****************** Helper functions Not from Classes Above ***************** }
 function OctalToInt(const Oct : PAnsiChar; aLen : integer): Int64;
 var
+  r : UInt64;
   i : integer;
+  c, sign : Byte;
 begin
   Result := 0;
   if (aLen = 0 ) then
    Exit;
    
   { detect binary number format }
-  if ((Ord(Oct[0]) and $80) <> 0) then begin
-    i := 1;
-    while (i < aLen) do begin
-      Result := (Result * 256) + Ord(Oct[i]);
-      inc(i);
+  if ((Ord(Oct[0]) and $80) <> 0) then
+  begin
+    c:= Ord(Oct[0]);
+
+    if (c and $40 <> 0) then
+    begin
+      sign := $FF;
+      r := High(UInt64);
+    end
+    else begin
+      r := 0;
+      sign := 0;
+      c := c and $7F;
     end;
-    Exit;
+
+    i:= 1;
+    while (aLen > SizeOf(Int64)) do
+    begin
+      if (c <> sign) then
+      begin
+        if (sign <> 0) then
+          Result:= Low(Int64)
+        else begin
+          Result:= High(Int64);
+        end;
+        Exit;
+      end;
+      c := Ord(Oct[i]);
+      Dec(aLen);
+      Inc(i);
+    end;
+
+    if ((c xor sign) and $80 <> 0) then
+    begin
+      if (sign <> 0) then
+        Result:= Low(Int64)
+      else begin
+        Result:= High(Int64);
+      end;
+      Exit;
+    end;
+
+    while (aLen > 1) do
+    begin
+      r := (r shl 8) or c;
+      c:= Ord(Oct[i]);
+      Dec(aLen);
+      Inc(i);
+    end;
+    r := (r shl 8) or c;
+
+    Exit(Int64(r));
   end;
 
   i := 0;

+ 145 - 26
plugins/wcx/zip/src/fparchive/doublecmd.diff

@@ -1460,7 +1460,7 @@ Index: AbTarTyp.pas
  function VerifyTar(Strm : TStream) : TAbArchiveType;
 
 
-@@ -454,10 +462,8 @@
+@@ -454,18 +462,75 @@
  implementation
 
  uses
@@ -1473,7 +1473,74 @@ Index: AbTarTyp.pas
 
  { ****************** Helper functions Not from Classes Above ***************** }
  function OctalToInt(const Oct : PAnsiChar; aLen : integer): Int64;
-@@ -566,7 +572,58 @@
+ var
++  r : UInt64;
+   i : integer;
++  c, sign : Byte;
+ begin
+   Result := 0;
++  if (aLen = 0 ) then
++   Exit;
++
++  { detect binary number format }
++  if ((Ord(Oct[0]) and $80) <> 0) then
++  begin
++    c:= Ord(Oct[0]);
+
++    if (c and $40 <> 0) then
++    begin
++      sign := $FF;
++      r := High(UInt64);
++    end
++    else begin
++      r := 0;
++      sign := 0;
++      c := c and $7F;
++    end;
++
++    i:= 1;
++    while (aLen > SizeOf(Int64)) do
++    begin
++      if (c <> sign) then
++      begin
++        if (sign <> 0) then
++          Result:= Low(Int64)
++        else begin
++          Result:= High(Int64);
++        end;
++        Exit;
++      end;
++      c := Ord(Oct[i]);
++      Dec(aLen);
++      Inc(i);
++    end;
++
++    if ((c xor sign) and $80 <> 0) then
++    begin
++      if (sign <> 0) then
++        Result:= Low(Int64)
++      else begin
++        Result:= High(Int64);
++      end;
++      Exit;
++    end;
++
++    while (aLen > 1) do
++    begin
++      r := (r shl 8) or c;
++      c:= Ord(Oct[i]);
++      Dec(aLen);
++      Inc(i);
++    end;
++    r := (r shl 8) or c;
++
++    Exit(Int64(r));
++  end;
++
+   i := 0;
+   while (i < aLen) and (Oct[i] = ' ') do
+     inc(i);
+@@ -566,7 +631,58 @@
               not (AB_TAR_RECORDSIZE - 1);
  end;
 
@@ -1532,7 +1599,7 @@ Index: AbTarTyp.pas
  { ****************************** TAbTarItem ********************************** }
  constructor TAbTarItem.Create;
  begin
-@@ -632,7 +689,7 @@
+@@ -632,7 +748,7 @@
 
  function TAbTarItem.GetExternalFileAttributes: LongWord;
  begin
@@ -1541,7 +1608,7 @@ Index: AbTarTyp.pas
  end;
 
  function TAbTarItem.GetFileName: string;
-@@ -678,6 +735,19 @@
+@@ -678,6 +794,19 @@
    Result := AbUnixTimeToLocalDateTime(FTarItem.ModTime);
  end;
 
@@ -1561,7 +1628,7 @@ Index: AbTarTyp.pas
  function TAbTarItem.GetLinkName: string;
  begin
    Result := FTarItem.LinkName;
-@@ -734,7 +804,7 @@
+@@ -734,7 +863,7 @@
    { GNU_FORMAT is detected by the presence of GNU extended headers. }
 
    { These detections are similar to GNU tar's. }
@@ -1570,7 +1637,7 @@ Index: AbTarTyp.pas
    begin { We have one of three types, STAR_FORMAT, USTAR_FORMAT, POSIX_FORMAT }
      { Detect STAR format.  Leave disabled until explicit STAR support is added. }
      {if (PTarHeader.star.Prefix[130] = #00) and
-@@ -750,7 +820,7 @@
+@@ -750,7 +879,7 @@
      { This can define false positives, Pax headers/ STAR format could be detected as this }
      FTarItem.ArchiveFormat := USTAR_FORMAT;
    end
@@ -1579,7 +1646,7 @@ Index: AbTarTyp.pas
    begin
      FTarItem.ArchiveFormat := OLDGNU_FORMAT;
    end
-@@ -819,7 +889,7 @@
+@@ -819,7 +948,7 @@
        RawFileName := PTarHeader.Name;
    end; { End not FoundName }
 
@@ -1588,7 +1655,7 @@ Index: AbTarTyp.pas
  end;
 
  { Extract the file name from the headers }
-@@ -876,7 +946,7 @@
+@@ -876,7 +1005,7 @@
    if not FoundName then
      RawLinkName := PHeader.LinkName;
 
@@ -1597,7 +1664,7 @@ Index: AbTarTyp.pas
  end;
 
  { Return True if CheckSum passes out. }
-@@ -935,6 +1005,107 @@
+@@ -935,6 +1064,107 @@
    { FTarItem.Dirty; Stuffed upon creaction }
  end;
 
@@ -1705,7 +1772,7 @@ Index: AbTarTyp.pas
  procedure TAbTarItem.LoadTarHeaderFromStream(AStream: TStream);
  var
    NumMHeaders : Integer;
-@@ -968,7 +1139,7 @@
+@@ -968,7 +1198,7 @@
      begin { This Header type is in the Set of un/supported Meta data type headers }
        if PTarHeader.LinkFlag in AB_UNSUPPORTED_MD_HEADERS then
          FTarItem.ItemReadOnly := True; { We don't fully support this meta-data type }
@@ -1714,7 +1781,14 @@ Index: AbTarTyp.pas
          FTarItem.ArchiveFormat := POSIX_FORMAT; { We have a POSIX_FORMAT, has x headers, and Magic matches }
        if PTarHeader.LinkFlag in AB_GNU_MD_HEADERS then
          FTarItem.ArchiveFormat := OLDGNU_FORMAT; { We have a OLDGNU_FORMAT, has L/K headers }
-@@ -1016,9 +1187,10 @@
+@@ -1010,15 +1240,16 @@
+   { PTarHeader points to FTarHeaderList.Items[FTarHeaderList.Count-1]; }
+
+   { Re-wind the Stream back to the begining of this Item inc. all headers }
+-  AStream.Seek(-(FTarHeaderList.Count*AB_TAR_RECORDSIZE), soFromCurrent);
++  AStream.Seek(-(FTarHeaderList.Count*AB_TAR_RECORDSIZE), soCurrent);
+   { AStream.Position := FTarItem.StreamPosition; } { This should be equivalent as above }
+   FTarItem.FileHeaderCount := FTarHeaderList.Count;
    if FTarItem.ItemType <> UNKNOWN_ITEM then
    begin
      ParseTarHeaders; { Update FTarItem values }
@@ -1727,7 +1801,7 @@ Index: AbTarTyp.pas
    end;
    Action := aaNone;
    Tagged := False;
-@@ -1142,14 +1314,21 @@
+@@ -1142,14 +1373,21 @@
  var
    S : AnsiString;
    I: Integer;
@@ -1751,7 +1825,7 @@ Index: AbTarTyp.pas
    FTarItem.Dirty := True;
  end;
 
-@@ -1297,9 +1476,9 @@
+@@ -1297,9 +1535,9 @@
    { Finally we need to stuff the file type Header. }
    { Note: Value.length > AB_TAR_NAMESIZE(100) }
    if LinkFlag = AB_TAR_LF_LONGNAME then
@@ -1763,7 +1837,7 @@ Index: AbTarTyp.pas
  end;
 
  procedure TAbTarItem.SetFileName(const Value: string);
-@@ -1333,7 +1512,7 @@
+@@ -1333,7 +1571,7 @@
           OLD_GNU & GNU: Add N Headers for name, Update name in MD header, update name field in File Headers, min 3 headers
 
        Add headers to length of new Name Length, update name in file header, update name fields }
@@ -1772,7 +1846,7 @@ Index: AbTarTyp.pas
    { In all cases zero out the name fields in the File Header. }
    if Length(RawFileName) > AB_TAR_NAMESIZE then begin { Must be null terminated except at 100 char length }
      { Look for long name meta-data headers already in the archive. }
-@@ -1431,8 +1610,8 @@
+@@ -1431,8 +1669,8 @@
 
    { Update the inherited file names. }
    FFileName := FTarItem.Name;
@@ -1783,7 +1857,7 @@ Index: AbTarTyp.pas
    FTarItem.Dirty := True;
  end;
 
-@@ -1527,7 +1706,7 @@
+@@ -1527,7 +1765,7 @@
        if old was Long,
           OLD_GNU & GNU: Add N Headers for name, Update name in MD header, update name field in File Headers, min 3 headers
        STAR & PAX: And should not yet get here.}
@@ -1792,7 +1866,52 @@ Index: AbTarTyp.pas
    if Length(RawLinkName) > AB_TAR_NAMESIZE then { Must be null terminated except at 100 char length }
    begin
      { Look for long name meta-data headers already in the archive. }
-@@ -1838,16 +2017,19 @@
+@@ -1672,7 +1910,7 @@
+     { copy stored data to output }
+     AStream.CopyFrom(FStream, FCurrItemSize);
+     {reset the stream to the start of the item}
+-    FStream.Seek(-(FCurrItemPreHdrs*AB_TAR_RECORDSIZE+FCurrItemSize), soFromCurrent);
++    FStream.Seek(-(FCurrItemPreHdrs*AB_TAR_RECORDSIZE+FCurrItemSize), soCurrent);
+   end;
+   { else do nothing }
+ end;
+@@ -1699,7 +1937,7 @@
+     begin { We have a un/supported Meta-Data Header }
+       { FoundItem := False } { Value remains False. }
+       SkipHdrs := Ceil(OctalToInt(FTarHeader.Size, SizeOf(FTarHeader.Size))/AB_TAR_RECORDSIZE);
+-      FStream.Seek(SkipHdrs*AB_TAR_RECORDSIZE, soFromCurrent);
++      FStream.Seek(SkipHdrs*AB_TAR_RECORDSIZE, soCurrent);
+       { Tally new Headers: Consumed + Current }
+       FCurrItemPreHdrs := FCurrItemPreHdrs + SkipHdrs + 1;
+       { Read our next header, Loop, and re-parse }
+@@ -1725,7 +1963,7 @@
+   { Rewind to the "The Beginning" of this Item }
+   { Really that means to the first supported Header Type before a supported Item Type }
+   if FoundItem then
+-    FStream.Seek(-(FCurrItemPreHdrs*AB_TAR_RECORDSIZE), soFromCurrent);
++    FStream.Seek(-(FCurrItemPreHdrs*AB_TAR_RECORDSIZE), soCurrent);
+   Result := FoundItem;
+ end;
+
+@@ -1732,7 +1970,7 @@
+ { Should only be used from LoadArchive, as it is slow. }
+ function TAbTarStreamHelper.FindFirstItem: Boolean;
+ begin
+-  FStream.Seek(0, soFromBeginning);
++  FStream.Seek(0, soBeginning);
+   Result := FindItem;
+ end;
+
+@@ -1740,7 +1978,7 @@
+ function TAbTarStreamHelper.FindNextItem: Boolean;
+ begin
+   { Fast Forward Past the current Item }
+-  FStream.Seek((FCurrItemPreHdrs*AB_TAR_RECORDSIZE + RoundToTarBlock(FCurrItemSize)), soFromCurrent);
++  FStream.Seek((FCurrItemPreHdrs*AB_TAR_RECORDSIZE + RoundToTarBlock(FCurrItemSize)), soCurrent);
+   Result := FindItem;
+ end;
+
+@@ -1838,16 +2076,19 @@
    FArchFormat := V7_FORMAT;  // Default for new archives
  end;
 
@@ -1815,7 +1934,7 @@ Index: AbTarTyp.pas
    Item := TAbTarItem.Create;
    try
    //  HeaderFormat = (UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT);
-@@ -1863,7 +2045,7 @@
+@@ -1863,7 +2104,7 @@
        Item.LinkFlag := AB_TAR_LF_NORMAL;
        Item.Magic := AB_TAR_MAGIC_VAL+AB_TAR_MAGIC_VER;
      end
@@ -1824,7 +1943,7 @@ Index: AbTarTyp.pas
        begin { Switch the rep over to GNU so it can have long file names. }
        FArchFormat := OLDGNU_FORMAT;
        Item.ArchiveFormat := OLDGNU_FORMAT;
-@@ -1882,9 +2064,10 @@
+@@ -1882,9 +2123,10 @@
 
      { Most others are initialized in the .Create }
      Item.CRC32 := 0;
@@ -1837,7 +1956,7 @@ Index: AbTarTyp.pas
      Item.Action := aaNone;
    finally
      Result := Item;
-@@ -1894,12 +2077,13 @@
+@@ -1894,12 +2136,13 @@
 
  procedure TAbTarArchive.ExtractItemAt(Index: Integer; const UseName: string);
  var
@@ -1853,7 +1972,7 @@ Index: AbTarTyp.pas
 
    CurItem := TAbTarItem(ItemList[Index]);
 
-@@ -1911,21 +2095,50 @@
+@@ -1911,21 +2154,50 @@
      raise EAbTarBadOp.Create; { Unsupported Type, Cannot Extract }
    { We will allow extractions if the file name/Link name are strickly less than 100 chars }
 
@@ -1916,7 +2035,7 @@ Index: AbTarTyp.pas
      end;
    end;
    AbSetFileTime(UseName, CurItem.LastModTimeAsDateTime);
-@@ -2060,7 +2273,7 @@
+@@ -2060,7 +2332,7 @@
      AbStripDrive( lValue );
 
    { check for a leading slash }
@@ -1925,7 +2044,7 @@ Index: AbTarTyp.pas
      System.Delete( lValue, 1, 1 );
 
    if soStripPath in StoreOptions then
-@@ -2097,7 +2310,6 @@
+@@ -2097,7 +2369,6 @@
    i              : Integer;
    NewStream      : TAbVirtualMemoryStream;
    TempStream     : TStream;
@@ -1933,7 +2052,7 @@ Index: AbTarTyp.pas
    CurItem        : TAbTarItem;
    AttrEx         : TAbAttrExRec;
  begin
-@@ -2145,24 +2357,27 @@
+@@ -2145,24 +2416,27 @@
 
          aaAdd, aaFreshen, aaReplace: begin
            try
@@ -1977,7 +2096,7 @@ Index: AbTarTyp.pas
                    fmOpenRead or fmShareDenyWrite );
                  try { TempStream }
                    CurItem.UncompressedSize := TempStream.Size;
-@@ -2173,9 +2388,13 @@
+@@ -2173,9 +2447,13 @@
                    TempStream.Free;
                  end; { TempStream }
                end;
@@ -1994,7 +2113,7 @@ Index: AbTarTyp.pas
            except
              ItemList[i].Action := aaDelete;
              DoProcessItemFailure(ItemList[i], ptAdd, ecFileOpenError, 0);
-@@ -2200,7 +2419,7 @@
+@@ -2200,7 +2478,7 @@
      else begin
        { need new stream to write }
        FreeAndNil(FStream);