615 lines
13 KiB
Plaintext
615 lines
13 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
|
|
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 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;
|
|
|
|
// LOG('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;
|
|
|
|
// LOG('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);
|
|
// LOG('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;
|
|
|
|
// LOG('InsertBufferForHandle: ++',[]);
|
|
Lock(cs);
|
|
try
|
|
fh := FindHandle(h);
|
|
|
|
// LOG('InsertBufferForHandle: fh(%p) ++',[Pointer(fh)]);
|
|
if fh = nil then
|
|
begin
|
|
|
|
if path = '' then
|
|
Exit;
|
|
|
|
fh := TFileHandle.Create;
|
|
fh.h := h;
|
|
fh.path := path;
|
|
|
|
// LOG('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;
|
|
|
|
// LOG('InsertBufferForHandle: max(%d)', [max]);
|
|
Move(buf^, fbuf.buf, max);
|
|
fbuf.size := max;
|
|
fh.lbuf.Add(fbuf);
|
|
end;
|
|
// LOG('InsertBufferForHandle: Insert++', []);
|
|
lFile.Insert(0, fh);
|
|
end
|
|
else
|
|
begin
|
|
|
|
// LOG('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;
|
|
|
|
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);
|
|
// LOG('DelHandle: (%p)', [Pointer(ch.h)]);
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
UnLock(cs);
|
|
end;
|
|
if remain = nil then Exit;
|
|
|
|
// LOG('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.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;
|
|
|
|
//LOG('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);
|
|
LOG('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);
|
|
|
|
//LOG('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;
|
|
|
|
// LOG('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);
|
|
LOG('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;
|
|
// LOG('IsBufferCompare: (%s)', [fh.path]);
|
|
Exit;
|
|
end;
|
|
end;
|
|
finally
|
|
UnLock(cs);
|
|
end;
|
|
|
|
if IsHistoryFileBufferCompare(path, buffer, size, fileHandle) then
|
|
begin
|
|
Result := TRUE;
|
|
end;
|
|
end;
|
|
|
|
end.
|