From 40a71ffb604413c41b429dbbe4dfaf4520a03061 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Wed, 23 Oct 2024 21:14:22 +0200 Subject: Sort global filelist in case of a streaming type archive Before this change sorting was done on each panel item separately. Streaming type archives (e.g. tar) needs strict sequential order as indicated by the inode_no and the global filelist to copy needs to be sorted once more. Tested on 7z2301-extra.7z --- UCore.pas | 42 ++++++++++++++++++++++++------------------ UCoreWorkers.pas | 6 ++++++ 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/UCore.pas b/UCore.pas index 79fcd32..9059371 100644 --- a/UCore.pas +++ b/UCore.pas @@ -29,6 +29,7 @@ procedure FindNextSelected(ListView: TGTKListView; DataList: TList; var Item1, I procedure UnselectAll(ListView: TGTKListView; DataList: TList); procedure FillDirFiles(Engine: TPanelEngine; DestList: TList; InputFiles: TStringList; DoNotRecurse: boolean; InaccessiblePaths: TStringList; CancelFlag: Pboolean); +procedure FillDirFiles_sort(FList: TList); function GetFileInfoSL(Engine: TPanelEngine; const APath: string): PDataItemSL; procedure DebugWriteListSL(List: TList); @@ -348,8 +349,7 @@ end; (********************************************************************************************************************************) (********************************************************************************************************************************) -procedure FillDirFiles(Engine: TPanelEngine; DestList: TList; InputFiles: TStringList; DoNotRecurse: boolean; InaccessiblePaths: TStringList; CancelFlag: Pboolean); -var DirStage1List, FilesList, DirStage2List: TList; +procedure FillDirFiles_sort(FList: TList); function FillDirFiles_compare_func(Item1, Item2: Pointer): integer; var DataItem1, DataItem2: PDataItem; @@ -357,12 +357,16 @@ var DirStage1List, FilesList, DirStage2List: TList; DataItem1 := PDataItemSL(Item1)^.DataItem; DataItem2 := PDataItemSL(Item2)^.DataItem; // sort by inode number - // also, we want to have directories at the bottom of the list - if DataItem1^.IsDir and (not DataItem2^.IsDir) then Result := 1 else - if (not DataItem1^.IsDir) and DataItem2^.IsDir then Result := -1 else + // also, we want to have directories at the top of the list + if PDataItemSL(Item1)^.Stage1 and (not PDataItemSL(Item2)^.Stage1) then Result := -1 else + if (not PDataItemSL(Item1)^.Stage1) and PDataItemSL(Item2)^.Stage1 then Result := 1 else + if DataItem1^.IsDir and (not DataItem2^.IsDir) then Result := -1 else + if (not DataItem1^.IsDir) and DataItem2^.IsDir then Result := 1 else if DataItem1^.inode_no > DataItem2^.inode_no then Result := 1 else if DataItem1^.inode_no < DataItem2^.inode_no then Result := -1 else - Result := 0; + // sort by name, in inverse order for Stage2 + if PDataItemSL(Item1)^.Stage1 then Result := strcmp(DataItem1^.FName, DataItem2^.FName) + else Result := -strcmp(DataItem1^.FName, DataItem2^.FName); end; procedure QuickSort(FList: TList; L, R : Longint); @@ -392,18 +396,20 @@ var DirStage1List, FilesList, DirStage2List: TList; until I >= R; end; - procedure FillDirFiles_sort(FList: TList); - var i: integer; - begin - if FList.Count < 2 then Exit; - DebugMsg(['before sorting:']); - for i := 0 to FList.Count - 1 do - DebugMsg([' ', i, ' [', PDataItemSL(FList[i])^.DataItem^.inode_no, '] ', PDataItemSL(FList[i])^.DataItem^.FName]); - QuickSort(Flist, 0, FList.Count - 1); - DebugMsg(['after sorting:']); - for i := 0 to FList.Count - 1 do - DebugMsg([' ', i, ' [', PDataItemSL(FList[i])^.DataItem^.inode_no, '] ', PDataItemSL(FList[i])^.DataItem^.FName]); - end; +var i: integer; +begin + if FList.Count < 2 then Exit; + DebugMsg(['before sorting:']); + for i := 0 to FList.Count - 1 do + DebugMsg([' ', i, ' [', PDataItemSL(FList[i])^.DataItem^.inode_no, '] ', PDataItemSL(FList[i])^.DataItem^.FName]); + QuickSort(Flist, 0, FList.Count - 1); + DebugMsg(['after sorting:']); + for i := 0 to FList.Count - 1 do + DebugMsg([' ', i, ' [', PDataItemSL(FList[i])^.DataItem^.inode_no, '] ', PDataItemSL(FList[i])^.DataItem^.FName]); +end; + +procedure FillDirFiles(Engine: TPanelEngine; DestList: TList; InputFiles: TStringList; DoNotRecurse: boolean; InaccessiblePaths: TStringList; CancelFlag: Pboolean); +var DirStage1List, FilesList, DirStage2List: TList; procedure FillDirFiles_Recurse(const LocalPath: string; ALevel: integer); var LocalList: TList; diff --git a/UCoreWorkers.pas b/UCoreWorkers.pas index 6ea4268..507e2b7 100644 --- a/UCoreWorkers.pas +++ b/UCoreWorkers.pas @@ -1501,6 +1501,12 @@ begin { if DestEngine.ChangeDir(CurrPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour may occur.']); if SrcEngine.ChangeDir(CurrPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour may occur.']); } + + // For streaming type archives the list of files to copy strictly needs to be sorted globally according to inode_no + if (SrcEngine is TVFSEngine) and (SrcEngine as TVFSEngine).ArchiveMode and (SrcEngine as TVFSEngine).ArchiveStreamingType then begin + DebugMsg(['Archive type is streaming, performing global filelist sort...']); + FillDirFiles_sort(List); + end; DebugWriteListSL(List); SkipInaccessible := False; -- cgit v1.2.3