BSOne.SFC/Tocsg.Module/Bs1Flt/MTPMon/MTPControl/FileHandleListUnit.pas

645 lines
14 KiB
Plaintext

unit FileHandleListUnit;
interface
uses
Winapi.Windows, System.SysUtils, System.Generics.Collections, System.Classes,
System.Character, System.StrUtils,
BsoneDebug,
BsoneUtil;
const
MIN_BUFFERSIZE = 40;
HISTORY_FILE_LISTMAX = 30;
type
TFILE_BUFFER = record
buf: array[0..MIN_BUFFERSIZE - 1] of Byte;
size: DWORD;
end;
PFILE_BUFFER = ^TFILE_BUFFER;
TFileHandle = class
public
path: string;
drivetype: DWORD;
h: THandle;
hash: array[0..31] of Byte;
cnt: DWORD;
dwDesiredAccess: DWORD;
dwShareMode: DWORD;
dwCreationDisposition: DWORD;
dwFlagsAndAttributes: DWORD;
dwOffset: DWORD;
lbuf: TList<TFILE_BUFFER>;
constructor Create;
destructor Destroy; override;
procedure Assign(ASource: TFileHandle);
end;
TFileHandleList = class
private
public
lFile: TObjectList<TFileHandle>;
lHisFile: TObjectList<TFileHandle>;
cs, lHcs: TRTLCriticalSection;
state: boolean;
HistoryFileCnt: DWORD;
constructor Create;
destructor Destroy; override;
procedure Lock(var ACS: TRTLCriticalSection);
procedure UnLock(var ACS: TRTLCriticalSection);
function IsHandleOutPath(h: THandle; out sPath: string): BOOL;
function FindHandle(h: THandle): TFileHandle;
function ChangeHandle(h: THandle; const path: string; dwDesiredAccess: DWORD = 0;
dwShareMode: DWORD = 0; dwCreationDisposition: DWORD = 0;
dwFlagsAndAttributes: DWORD = 0): Boolean;
function IsHandle(h: THandle; out HandleInfo: TFileHandle): BOOL;
procedure Cleanup;
procedure ClearHistory;
function InsertHandle(h: THandle; const path: string;
dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes: DWORD): BOOL;
function IsEmptyBuffer(lpBuffer: PByte; size: DWORD): BOOL;
function InsertBufferForHandle(h: THandle; const path: string; buf: PByte; size: DWORD): BOOL;
function InsertBuffer(h: THandle; const path: string; buf: PByte; size: DWORD): BOOL;
function SetHistoryFile(f: TFileHandle): BOOL;
function IsHistoryFileBufferCompare(const path: string; lpBuffer: PByte; size: DWORD;
out fileHandle: TFileHandle): BOOL; overload;
function IsBufferCompare(const path: string; buffer: PByte; size: DWORD;
out fileHandle: TFileHandle; bInterNetWriteFile: BOOL = FALSE): BOOL; overload;
function DelHandle(h: THandle): BOOL;
end;
implementation
constructor TFileHandle.Create;
begin
inherited Create;
lbuf := TList<TFILE_BUFFER>.Create;
FillChar(hash, SizeOf(hash), 0);
end;
destructor TFileHandle.Destroy;
begin
lbuf.Free;
inherited Destroy;
end;
procedure TFileHandle.Assign(ASource: TFileHandle);
begin
if ASource = nil then Exit;
Self.path := ASource.path;
Self.drivetype := ASource.drivetype;
Self.h := ASource.h;
Self.hash := ASource.hash;
Self.cnt := ASource.cnt;
Self.dwDesiredAccess := ASource.dwDesiredAccess;
Self.dwShareMode := ASource.dwShareMode;
Self.dwCreationDisposition := ASource.dwCreationDisposition;
Self.dwFlagsAndAttributes := ASource.dwFlagsAndAttributes;
Self.dwOffset := ASource.dwOffset;
end;
constructor TFileHandleList.Create;
begin
InitializeCriticalSection(cs);
InitializeCriticalSection(lHcs);
lFile := TObjectList<TFileHandle>.Create(True);
lHisFile := TObjectList<TFileHandle>.Create(True);
HistoryFileCnt := 0;
state := true;
end;
destructor TFileHandleList.Destroy;
begin
Cleanup;
inherited Destroy;
end;
procedure TFileHandleList.Lock(var ACS: TRTLCriticalSection);
begin
EnterCriticalSection(ACS);
end;
procedure TFileHandleList.UnLock(var ACS: TRTLCriticalSection);
begin
LeaveCriticalSection(ACS);
end;
function TFileHandleList.FindHandle(h: THandle): TFileHandle;
var
ch: TFileHandle;
begin
Result := nil;
if not state then
Exit;
if lFile.Count = 0 then
Exit;
for ch in lFile do
begin
if ch.h = h then
begin
Result := ch;
Exit;
end;
end;
end;
function TFileHandleList.ChangeHandle(h: THandle; const path: string;
dwDesiredAccess: DWORD; dwShareMode: DWORD; dwCreationDisposition: DWORD;
dwFlagsAndAttributes: DWORD): Boolean;
var
fh: TFileHandle;
begin
Result := False;
if not state then
Exit;
if lFile.Count = 0 then
Exit;
for fh in lFile do
begin
if fh.h = h then
begin
if path = '' then
Break;
if (path <> '') and (not StartsText(path, fh.path)) then
begin
fh.path := path;
fh.dwDesiredAccess := dwDesiredAccess;
fh.dwCreationDisposition := dwCreationDisposition;
fh.dwFlagsAndAttributes := dwFlagsAndAttributes;
fh.dwShareMode := dwShareMode;
fh.lbuf.Clear;
fh.drivetype := UtilGetDriveTypeEx(path);
end;
Result := True;
Exit;
end;
end;
end;
procedure TFileHandleList.Cleanup;
begin
if not state then Exit;
state := false;
Lock(cs);
FreeAndNil(lFile);
UnLock(cs);
Lock(lHcs);
FreeAndNil(lHisFile);
UnLock(lHcs);
DeleteCriticalSection(cs);
DeleteCriticalSection(lHcs);
end;
procedure TFileHandleList.ClearHistory;
begin
Lock(lHcs);
try
lHisFile.Clear;
finally
UnLock(lHcs);
end;
end;
function TFileHandleList.InsertHandle(h: THandle; const path: string;
dwDesiredAccess, dwShareMode, dwCreationDisposition,
dwFlagsAndAttributes: DWORD): BOOL;
var
fh: TFileHandle;
drivetype: DWORD;
isType: Boolean;
begin
isType:= False;
Result := FALSE;
// DVLOG('InsertHandle: state(%d)', [DWORD(state)]);
if not state then
Exit;
Lock(cs);
try
drivetype:= UtilGetDriveTypeEx(path);
case drivetype of
DRIVE_NO_ROOT_DIR,
DRIVE_REMOTE,
DRIVE_FIXED:
isType:= True;
end;
// DVLOG('InsertHandle: drivetype(%d)', [drivetype]);
if not isType then
Exit;
if not ChangeHandle(h, path, dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes) then
begin
fh := TFileHandle.Create;
fh.h := h;
fh.dwDesiredAccess := dwDesiredAccess;
fh.dwCreationDisposition := dwCreationDisposition;
fh.dwFlagsAndAttributes := dwFlagsAndAttributes;
fh.dwShareMode := dwShareMode;
fh.path := path;
fh.drivetype := drivetype;
lFile.Insert(0, fh);
// DVLOG('InsertHandle: (%s)', [path]);
end;
finally
UnLock(cs);
end;
Result := TRUE;
end;
function TFileHandleList.IsEmptyBuffer(lpBuffer: PByte; size: DWORD): BOOL;
var
i: DWORD;
begin
Result := TRUE;
if lpBuffer = nil then Exit;
for i := 0 to size - 1 do
begin
if lpBuffer[i] <> 0 then
begin
Result := FALSE;
Break;
end;
end;
end;
function TFileHandleList.InsertBufferForHandle(h: THandle; const path: string; buf: PByte; size: DWORD): BOOL;
var
fh: TFileHandle;
fbuf: TFILE_BUFFER;
max: Integer;
begin
Result := FALSE;
if not state then
Exit;
if IsEmptyBuffer(buf, 32) then
Exit;
// DVLOG('InsertBufferForHandle: ++',[]);
Lock(cs);
try
fh := FindHandle(h);
// DVLOG('InsertBufferForHandle: fh(%p) ++',[Pointer(fh)]);
if fh = nil then
begin
if path = '' then
Exit;
fh := TFileHandle.Create;
fh.h := h;
fh.path := path;
// DVLOG('InsertBufferForHandle: UtilGetDriveTypeEx ++', []);
fh.drivetype := UtilGetDriveTypeEx(path);
fh.cnt := 0;
if size > 0 then
begin
FillChar(fbuf, SizeOf(fbuf), 0);
if size > SizeOf(fbuf.buf) then
max := SizeOf(fbuf.buf)
else
max := size;
DVLOG('InsertBufferForHandle: New max(%d)', [max]);
Move(buf^, fbuf.buf, max);
fbuf.size := max;
fh.lbuf.Add(fbuf);
end;
// DVLOG('InsertBufferForHandle: Insert++', []);
lFile.Insert(0, fh);
end
else
begin
// DVLOG('InsertBufferForHandle: path(%s)(%s), size(%d)', [PChar(path), PChar(fh.path), size]);
if (path <> '') and (not StartsText(path, fh.path)) then
begin
fh.path := path;
end;
if fh.lbuf.Count <> 0 then
Exit;
// fh.lbuf.Clear;
if size > 0 then
begin
FillChar(fbuf, SizeOf(fbuf), 0);
if size > SizeOf(fbuf.buf) then
max := SizeOf(fbuf.buf)
else
max := size;
DVLOG('InsertBufferForHandle: max(%d)', [max]);
Move(buf^, fbuf.buf, max);
fbuf.size := max;
fh.lbuf.Add(fbuf);
end;
end;
finally
UnLock(cs);
end;
Result := TRUE;
end;
function TFileHandleList.InsertBuffer(h: THandle; const path: string; buf: PByte;
size: DWORD): BOOL;
var
ch: TFileHandle;
fbuf: TFILE_BUFFER;
max: Integer;
begin
Result := FALSE;
if not state then Exit;
if IsEmptyBuffer(buf, 32) then Exit;
Lock(cs);
try
ch := FindHandle(h);
if ch <> nil then
begin
if (path <> '') and (not StartsText(path, ch.path)) then
begin
ch.path := path;
end;
ch.lbuf.Clear;
if (size > 0) and (ch.lbuf.Count = 0) then
begin
FillChar(fbuf, SizeOf(fbuf), 0);
if size > SizeOf(fbuf.buf) then max := SizeOf(fbuf.buf) else max := size;
Move(buf^, fbuf.buf, max);
fbuf.size := max;
ch.lbuf.Insert(0, fbuf);
end;
end;
finally
UnLock(cs);
end;
Result := TRUE;
end;
function TFileHandleList.SetHistoryFile(f: TFileHandle): BOOL;
begin
Result := FALSE;
if not state then Exit;
if f = nil then Exit;
Lock(lHcs);
try
if lHisFile.Count >= HISTORY_FILE_LISTMAX then
begin
lHisFile.Delete(lHisFile.Count - 1);
end;
lHisFile.Insert(0, f);
finally
UnLock(lHcs);
end;
Result := TRUE;
end;
function TFileHandleList.DelHandle(h: THandle): BOOL;
var
ch: TFileHandle;
remain: TFileHandle;
i: Integer;
begin
Result := FALSE;
remain := nil;
if not state then Exit;
Lock(cs);
try
for i := lFile.Count - 1 downto 0 do
begin
ch := lFile[i];
if ch.h = h then
begin
if ch.cnt > 0 then
begin
ch.cnt := ch.cnt - 1;
end
else
begin
remain := lFile.Extract(ch);
// DVLOG('DelHandle: (%p)', [Pointer(ch.h)]);
Break;
end;
end;
end;
finally
UnLock(cs);
end;
if remain = nil then Exit;
// DVLOG('SetHistoryFile: (%p)', [Pointer(remain.h)]);
Result := SetHistoryFile(remain);
end;
function TFileHandleList.IsHandle(h: THandle; out HandleInfo: TFileHandle): BOOL;
var
fh: TFileHandle;
begin
Result := FALSE;
HandleInfo := nil;
if not state then Exit;
if lFile.Count = 0 then Exit;
Lock(cs);
try
for fh in lFile do
begin
if fh.h = h then
begin
HandleInfo:= TFileHandle.Create;
HandleInfo.Assign(fh);
Result := TRUE;
Break;
end;
end;
finally
UnLock(cs);
end;
end;
function TFileHandleList.IsHandleOutPath(h: THandle; out sPath: string): BOOL;
var
fh: TFileHandle;
begin
Result := FALSE;
if not state then Exit;
if lFile.Count = 0 then Exit;
Lock(cs);
try
for fh in lFile do
begin
if fh.h = h then
begin
sPath:= fh.path;
Result := TRUE;
Break;
end;
end;
finally
UnLock(cs);
end;
end;
function TFileHandleList.IsHistoryFileBufferCompare(const path: string; lpBuffer: PByte; size: DWORD;
out fileHandle: TFileHandle): BOOL;
var
fb: TFILE_BUFFER;
fh: TFileHandle;
i, nPos: Integer;
sBuff: string;
srcname, dstname: string;
begin
nPos := 0;
Result := FALSE;
//DVLOG('IsHistoryFileBufferCompare: lHisFile.Count(%d), %d', [lHisFile.Count, DWORD(state)]);
if not state then
Exit;
if lHisFile.Count = 0 then
Exit;
Lock(lHcs);
try
for fh in lHisFile do
begin
if (path <> '') and (fh.path <> '') then
begin
srcname := ExtractFileName(path);
dstname := ExtractFileName(fh.path);
var diff:= SameText(srcname, dstname);
DVLOG('IsHistoryFileBufferCompare: srcname(%s), dstname(%s), diff(%d)', [PChar(srcname), PChar(dstname), DWORD(diff)]);
if not diff then
Continue;
end;
for fb in fh.lbuf do
begin
// for i := 0 to fb.size - 1 do
// sBuff := sBuff + IntToHex(fb.buf[i], 2);
//DVLOG('IsHistoryFileBufferCompare: sBuff(%s)', [sBuff]);
if UtilFindCode(lpBuffer, size, @fb.buf, fb.size, nPos) = nil then
Continue;
fileHandle := TFileHandle.Create;
fileHandle.Assign(fh);
Result := TRUE;
Exit;
end;
end;
finally
UnLock(lHcs);
end;
end;
function TFileHandleList.IsBufferCompare(const path: string; buffer: PByte;
size: DWORD; out fileHandle: TFileHandle; bInterNetWriteFile: BOOL): BOOL;
var
fh: TFileHandle;
fb: TFILE_BUFFER;
i, nPos: Integer;
srcname, dstname: string;
sBuff: string;
begin
Result := FALSE;
// DVLOG('IsBufferCompare: lFile.Count(%d), %d', [lFile.Count, DWORD(state)]);
// if lFile.Count = 0 then
// Exit;
if not state then
Exit;
Lock(cs);
try
for fh in lFile do
begin
if (path <> '') and (fh.path <> '') then
begin
srcname := ExtractFileName(path);
dstname := ExtractFileName(fh.path);
var diff:= SameText(srcname, dstname);
DVLOG('IsBufferCompare: srcname(%s), dstname(%s), diff(%d)', [PChar(srcname), PChar(dstname), DWORD(diff)]);
if not diff then
begin
Continue;
// fileHandle := TFileHandle.Create;
// fileHandle.Assign(fh);
//
// ClearHistory;
// Result := TRUE;
// Exit;
end;
end;
for fb in fh.lbuf do
begin
if UtilFindCode(buffer, size, @fb.buf, fb.size, nPos) = nil then
Continue;
fileHandle := TFileHandle.Create;
fileHandle.Assign(fh);
ClearHistory;
Result := TRUE;
// DVLOG('IsBufferCompare: (%s)', [fh.path]);
Exit;
end;
end;
finally
UnLock(cs);
end;
if IsHistoryFileBufferCompare(path, buffer, size, fileHandle) then
begin
Result := TRUE;
end;
end;
end.