X-Git-Url: https://deadsoftware.ru/gitweb?p=d2df-sdl.git;a=blobdiff_plain;f=src%2Fshared%2Ffhashdb.pas;h=09797e8b27fb07cd22d489f2a00006753fa4fbe9;hp=7e45c10b461eb68706b0ca5b5d57596960accdcc;hb=93f620df25ad634372657a64d609dcaf44e718bd;hpb=28bbe4d9b49c66e9dab264b037c426a7b38ce962 diff --git a/src/shared/fhashdb.pas b/src/shared/fhashdb.pas index 7e45c10..09797e8 100644 --- a/src/shared/fhashdb.pas +++ b/src/shared/fhashdb.pas @@ -36,9 +36,11 @@ type TFileHashDB = class private + type TStrDynArray = array of AnsiString; + type TFileInfo = record - name: AnsiString; // names are relative to `mBasePath` + name: AnsiString; // name includes `mBasePath`, if necessary hash: TMD5Digest; size: LongWord; age: LongInt; @@ -48,7 +50,8 @@ type end; private - mBasePath: AnsiString; // ends with '/' + mBasePath: AnsiString; // ends with '/', or empty string + mPathList: TStrDynArray; mHash2List: THashMD5Int; // hash -> list index mFile2List: THashStrCIInt; // file name -> list index mFileList: array of TFileInfo; @@ -60,10 +63,18 @@ type procedure scanDir (path: AnsiString; var changed: Boolean); + procedure appendOneDir (dir: AnsiString); + + procedure setup (aBasePath: AnsiString; const aPathList: TStrDynArray); + public - constructor Create (aBasePath: AnsiString); + constructor Create (aBasePath: AnsiString; const aPathList: TStrDynArray); + constructor Create (aBasePath: AnsiString; const aPathList: SSArray); destructor Destroy (); override; + // doesn't automatically rescans + procedure appendMoreDirs (const aPathList: SSArray); + // doesn't clear base path procedure clear (); @@ -81,7 +92,7 @@ type function findByHash (const md5: TMD5Digest): AnsiString; // returns `true` if something was changed // name is relative to base - function addWithHash (relname: AnsiString; const md5: TMD5Digest): Boolean; + function addWithHash (fdiskname: AnsiString; const md5: TMD5Digest): Boolean; end; @@ -116,10 +127,42 @@ end; //========================================================================== // -// TFileHashDB.Create +// TFileHashDB.appendOneDir // //========================================================================== -constructor TFileHashDB.Create (aBasePath: AnsiString); +procedure TFileHashDB.appendOneDir (dir: AnsiString); +var + mps: AnsiString; + found: Boolean; +begin + if (length(dir) = 0) then exit; + if not findFileCI(dir, true) then exit; + dir := fixSlashes(dir, true); + if (mBasePath <> '') and (dir[1] <> '/') then + begin + dir := mBasePath+dir; + if not findFileCI(dir, true) then exit; + dir := fixSlashes(dir, true); + end; + if (dir = '/') then exit; + found := false; + for mps in mPathList do if (dir = mps) then begin found := true; break; end; + if not found then + begin + SetLength(mPathList, length(mPathList)+1); + mPathList[High(mPathList)] := dir; + end; +end; + + +//========================================================================== +// +// TFileHashDB.setup +// +//========================================================================== +procedure TFileHashDB.setup (aBasePath: AnsiString; const aPathList: TStrDynArray); +var + s: AnsiString; begin mBasePath := aBasePath; if (length(aBasePath) <> 0) then @@ -127,6 +170,8 @@ begin if not findFileCI(mBasePath, true) then mBasePath := aBasePath; end; mBasePath := fixSlashes(mBasePath, true); + SetLength(mPathList, 0); + for s in aPathList do appendOneDir(s); mHash2List := THashMD5Int.Create(); mFile2List := THashStrCIInt.Create(); SetLength(mFileList, 0); @@ -134,6 +179,46 @@ begin end; +//========================================================================== +// +// TFileHashDB.Create +// +//========================================================================== +constructor TFileHashDB.Create (aBasePath: AnsiString; const aPathList: TStrDynArray); +begin + setup(aBasePath, aPathList); +end; + + +//========================================================================== +// +// TFileHashDB.Create +// +//========================================================================== +constructor TFileHashDB.Create (aBasePath: AnsiString; const aPathList: SSArray); +var + f: Integer; + pl: TStrDynArray = nil; +begin + SetLength(pl, length(aPathList)); + for f := Low(pl) to High(pl) do pl[f] := aPathList[f-Low(pl)+Low(aPathList)]; + setup(aBasePath, pl); +end; + + +//========================================================================== +// +// TFileHashDB.appendMoreDirs +// +//========================================================================== +procedure TFileHashDB.appendMoreDirs (const aPathList: SSArray); +var + f: Integer; +begin + for f := Low(aPathList) to High(aPathList) do appendOneDir(aPathList[f]); +end; + + //========================================================================== // // TFileHashDB.Destroy @@ -145,6 +230,7 @@ begin mHash2List.Free; mFile2List.Free; SetLength(mFileList, 0); + SetLength(mPathList, 0); mFreeHead := -1; end; @@ -161,6 +247,7 @@ begin mHash2List.clear(); mFile2List.clear(); SetLength(mFileList, 0); + //SetLength(mPathList, 0); mFreeHead := -1; end; @@ -177,7 +264,7 @@ var begin sign := 'FHDB'; st.WriteBuffer(sign, 4); - st.WriteWord(0); // version + st.WriteWord(1); // version st.WriteDWord(LongWord(mFile2List.count)); for f := Low(mFileList) to High(mFileList) do begin @@ -207,7 +294,7 @@ begin st.ReadBuffer(sign, 4); if (sign <> 'FHDB') then raise Exception.Create('invalid database signature'); count := st.ReadWord(); - if (count <> 0) then raise Exception.Create('invalid database version'); + if (count <> 1) then raise Exception.Create('invalid database version'); count := Integer(st.ReadDWord()); if (count < 0) or (count > 1024*1024) then raise Exception.Create('invalid database file count'); while (count > 0) do @@ -285,7 +372,13 @@ var age: LongInt; needUpdate: Boolean; begin - if (FindFirst(path+'*', faAnyFile, sr) <> 0) then exit; + //writeln('TFileHashDB.scanDir(000): [', path, ']'); + if (FindFirst(path+'*', faAnyFile, sr) <> 0) then + begin + FindClose(sr); + exit; + end; + //writeln('TFileHashDB.scanDir(001): [', path, ']'); try repeat if ((sr.Attr and faDirectory) <> 0) then @@ -299,7 +392,7 @@ begin dfn := fixSlashes(path+sr.Name, false); // build internal file name hfn := dfn; - Delete(hfn, 1, length(mBasePath)); // remove prefix + //Delete(hfn, 1, length(mBasePath)); // remove prefix // find file in hash if not mFile2List.get(hfn, idx) then idx := -1; // check if we already have this file @@ -395,7 +488,9 @@ var begin result := false; for f := Low(mFileList) to High(mFileList) do mFileList[f].wasSeen := false; - scanDir(mBasePath, result); + //scanDir(mBasePath, result); + //writeln('TFileHashDB.scanFiles: dll=', length(mPathList)); + for f := Low(mPathList) to High(mPathList) do scanDir(mPathList[f], result); // remove all unseen files f := High(mFileList); while (f >= 0) do @@ -427,10 +522,10 @@ end; // TFileHashDB.addWithHash // // returns `true` if something was changed -// name is relative to base +// name is *NOT* relative to base // //========================================================================== -function TFileHashDB.addWithHash (relname: AnsiString; const md5: TMD5Digest): Boolean; +function TFileHashDB.addWithHash (fdiskname: AnsiString; const md5: TMD5Digest): Boolean; var age: LongInt; size: LongInt; @@ -439,9 +534,10 @@ var idx: Integer; begin result := false; - if (length(relname) > length(mBasePath)) and strEquCI1251(mBasePath, Copy(relname, 1, length(mBasePath))) then Delete(relname, 1, Length(mBasePath)); - if (length(relname) = 0) then exit; - fn := mBasePath+relname; + //if (length(fdiskname) > length(mBasePath)) and strEquCI1251(mBasePath, Copy(fdiskname, 1, length(mBasePath))) then Delete(fdiskname, 1, Length(mBasePath)); + if (length(fdiskname) = 0) then exit; + //fn := mBasePath+fdiskname; + fn := fdiskname; if not findFileCI(fn) then exit; // get age age := FileAge(fn); @@ -453,7 +549,7 @@ begin FileClose(handle); if (size = -1) then exit; // find old file, if any - Delete(fn, 1, length(mBasePath)); + //Delete(fn, 1, length(mBasePath)); if not mFile2List.get(fn, idx) then idx := -1; // check for changes if (idx >= 0) then