Started working on high-level exported mod API. Fixed Delphi bug with wrong stack variables alignment. Fixed bug in IsVfsOn (leave crit section without entering). Now XP normally passes all tests

This commit is contained in:
Berserker 2019-05-11 13:27:17 +03:00
parent c4698834c2
commit ff8192c149
7 changed files with 154 additions and 30 deletions

View File

@ -8,8 +8,17 @@ unit VfsControl;
uses
Windows, SysUtils,
Utils, WinUtils,
VfsBase, VfsUtils, VfsHooks;
Utils, WinUtils, TypeWrappers, DataLib,
Files, StrLib,
VfsBase, VfsUtils, VfsHooks, DlgMes;
type
(* Import *)
TWideString = TypeWrappers.TWideString;
const
(* Flag forces to skip directory names, starting with '#' *)
SKIP_HASHTAGGED_MODS = 1;
(* Runs all VFS subsystems, unless VFS is already running *)
@ -44,4 +53,87 @@ begin
end; // .with
end; // function RunVfs
function ValidateModName (const ModName: WideString): boolean;
const
DISALLOWED_CHARS = ['<', '>', '"', '?', '*', '\', '/', '|', ':', #0];
var
StrLen: integer;
i: integer;
begin
StrLen := Length(ModName);
i := 1;
while (i <= StrLen) and ((ord(ModName[i]) > 255) or not (AnsiChar(ModName[i]) in DISALLOWED_CHARS)) do begin
Inc(i);
end;
result := (i > StrLen) and (ModName <> '') and (ModName <> '.') and (ModName <> '..');
end;
function LoadModList (const ModListFilePath: WideString): {O} DataLib.TList {of (O) TWideString};
var
AbsFilePath: WideString;
FileContents: string;
Lines: Utils.TArrayOfStr;
ModNameUtf8: string;
ModName: WideString;
i: integer;
begin
result := DataLib.NewList(Utils.OWNS_ITEMS);
// * * * * * //
AbsFilePath := VfsUtils.NormalizePath(ModListFilePath);
if (AbsFilePath <> '') and (Files.ReadFileContents(AbsFilePath, FileContents)) then begin
Lines := StrLib.Explode(FileContents, #10);
for i := 0 to High(Lines) do begin
ModNameUtf8 := Lines[i];
ModName := StrLib.Utf8ToWide(ModNameUtf8);
if ValidateModName(ModName) then begin
result.Add(TWideString.Create(ModName));
end;
end;
end;
end; // .function LoadModList
// function MapModsDir (const RootDir, ModsDir: WideString; Flags: integer = 0);
// var
// AbsRootDir: WideString;
// AbsModsDir: WideString;
// FileInfo: VfsUtils.TNativeFileInfo;
// ModName: WideString;
// begin
// AbsRootDir := VfsUtils.NormalizePath(RootDir);
// AbsModsDir := VfsUtils.NormalizePath(ModsDir);
// result := (AbsRootDir <> '') and (AbsModsDir <> '') and VfsUtils.GetFileInfo(AbsRootDir, FileInfo);
// result := result and Utils.HasFlag(Windows.FILE_ATTRIBUTE_DIRECTORY, FileInfo.Base.FileAttributes);
// result := result and VfsUtils.GetFileInfo(AbsModsDir, FileInfo);
// result := result and Utils.HasFlag(Windows.FILE_ATTRIBUTE_DIRECTORY, FileInfo.Base.FileAttributes);
// if result then begin
// with VfsUtils.SysScanDir(AbsModsDir, '*') do begin
// while IterNext(ModName, @FileInfo.Base) do begin
// if (ModName <> '.') and (ModName <> '..') and Utils.HasFlag(Windows.FILE_ATTRIBUTE_DIRECTORY, FileInfo.Base.FileAttributes) then begin
// end;
// end;
// end;
// end;
// end;
var
L: TList;
i: integer;
begin
// L := LoadModList('D:\Heroes 3\Mods\list.txt');
// for i := 0 to L.Count- 1 do begin
// VarDump([TWideString(L[i]).Value]);
// end;
end.

View File

@ -61,7 +61,7 @@ end;
procedure TestIntegrated.TearDown;
begin
VfsBase.ResetVfs();
VfsDebug.SetLoggingProc(nil);
//VfsDebug.SetLoggingProc(nil);
end;
procedure TestIntegrated.TestGetFileAttributes;
@ -88,12 +88,14 @@ var
end; // .function HasValidAttrs
begin
VfsDebug.WriteLog('TestGetFileAttributes', 'Started');
RootDir := VfsTestHelper.GetTestsRootDir;
Check(not HasValidAttrs(VfsUtils.MakePath([RootDir, '\non-existing.non'])), '{1}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\Hobbots\mms.cfg']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{2}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\503.html']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{3}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\Hobbots\']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{4}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '\Mods']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{5}');
Check(not HasValidAttrs(VfsUtils.MakePath([RootDir, 'non-existing.non'])), '{1}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, 'Hobbots\mms.cfg']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{2}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, '503.html']), 0, Windows.FILE_ATTRIBUTE_DIRECTORY), '{3}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, 'Hobbots\']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{4}');
Check(HasValidAttrs(VfsUtils.MakePath([RootDir, 'Mods']), Windows.FILE_ATTRIBUTE_DIRECTORY), '{5}');
VfsDebug.WriteLog('TestGetFileAttributes', 'Ended');
end; // .procedure TestIntegrated.TestGetFileAttributes;
procedure TestIntegrated.TestGetFileAttributesEx;
@ -113,11 +115,13 @@ var
end;
begin
VfsDebug.WriteLog('TestGetFileAttributesEx', 'Started');
RootDir := VfsTestHelper.GetTestsRootDir;
CheckEquals(-1, GetFileSize(VfsUtils.MakePath([RootDir, '\non-existing.non'])), '{1}');
CheckEquals(42, GetFileSize(VfsUtils.MakePath([RootDir, '\Hobbots\mms.cfg'])), '{2}');
CheckEquals(22, GetFileSize(VfsUtils.MakePath([RootDir, '\503.html'])), '{3}');
CheckEquals(318, GetFileSize(VfsUtils.MakePath([RootDir, '\default'])), '{4}');
CheckEquals(-1, GetFileSize(VfsUtils.MakePath([RootDir, 'non-existing.non'])), '{1}');
CheckEquals(42, GetFileSize(VfsUtils.MakePath([RootDir, 'Hobbots\mms.cfg'])), '{2}');
CheckEquals(22, GetFileSize(VfsUtils.MakePath([RootDir, '503.html'])), '{3}');
CheckEquals(318, GetFileSize(VfsUtils.MakePath([RootDir, 'default'])), '{4}');
VfsDebug.WriteLog('TestGetFileAttributesEx', 'Ended');
end; // .procedure TestIntegrated.TestGetFileAttributesEx;
procedure TestIntegrated.TestFilesOpenClose;
@ -137,6 +141,7 @@ begin
RootDir := VfsTestHelper.GetTestsRootDir;
try
VfsDebug.WriteLog('TestFilesOpenClose', 'Started');
Check(WinUtils.SetCurrentDirW(RootDir), 'Setting current directory to real path must succeed. Path: ' + RootDir);
Check(OpenFile(VfsUtils.MakePath([RootDir, 'non-existing.non'])) <= 0, 'Opening non-existing file must fail');
@ -165,6 +170,8 @@ begin
finally
WinUtils.SetCurrentDirW(CurrDir);
end; // .try
VfsDebug.WriteLog('TestFilesOpenClose', 'Ended');
end; // .procedure TestIntegrated.TestFilesOpenClose;
procedure TestIntegrated.TestDirectoryListing;
@ -223,6 +230,7 @@ begin
RootDir := VfsTestHelper.GetTestsRootDir;
try
VfsDebug.WriteLog('TestDirectoryListing', 'Started');
FileList := GetDirListing(VfsUtils.MakePath([RootDir, '*']));
DirContents := FileList.ToText(#13#10);
CheckEquals(VALID_ROOT_DIR_LISTING, DirContents);
@ -242,6 +250,8 @@ begin
SysUtils.FreeAndNil(FileList);
SysUtils.FreeAndNil(DirListing);
end; // .try
VfsDebug.WriteLog('TestDirectoryListing', 'Ended');
end; // .procedure TestIntegrated.TestDirectoryListing;
begin

View File

@ -331,7 +331,10 @@ end;
function IsVfsActive: boolean;
begin
result := EnterVfs;
LeaveVfs;
if result then begin
LeaveVfs;
end;
end;
(* Returns real path for vfs item by its absolute virtual path or empty string. Optionally returns file info structure *)

View File

@ -83,11 +83,12 @@ end; // .function GetFileObjectPath
function Hook_NtQueryAttributesFile (OrigFunc: WinNative.TNtQueryAttributesFile; ObjectAttributes: POBJECT_ATTRIBUTES; FileInformation: PFILE_BASIC_INFORMATION): NTSTATUS; stdcall;
var
ExpandedPath: WideString;
RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes;
FileInfo: TNativeFileInfo;
HadTrailingDelim: boolean;
ExpandedPath: WideString;
RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes;
FileInfo: TNativeFileInfo;
HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin
if VfsDebug.LoggingEnabled then begin
@ -140,11 +141,12 @@ end; // .function Hook_NtQueryAttributesFile
function Hook_NtQueryFullAttributesFile (OrigFunc: WinNative.TNtQueryFullAttributesFile; ObjectAttributes: POBJECT_ATTRIBUTES; FileInformation: PFILE_NETWORK_OPEN_INFORMATION): NTSTATUS; stdcall;
var
ExpandedPath: WideString;
RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes;
FileInfo: TNativeFileInfo;
HadTrailingDelim: boolean;
ExpandedPath: WideString;
RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes;
FileInfo: TNativeFileInfo;
HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin
if VfsDebug.LoggingEnabled then begin
@ -211,10 +213,11 @@ end;
function Hook_NtCreateFile (OrigFunc: WinNative.TNtCreateFile; FileHandle: PHANDLE; DesiredAccess: ACCESS_MASK; ObjectAttributes: POBJECT_ATTRIBUTES; IoStatusBlock: PIO_STATUS_BLOCK;
AllocationSize: PLARGE_INTEGER; FileAttributes: ULONG; ShareAccess: ULONG; CreateDisposition: ULONG; CreateOptions: ULONG; EaBuffer: PVOID; EaLength: ULONG): NTSTATUS; stdcall;
var
ExpandedPath: WideString;
RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes;
HadTrailingDelim: boolean;
ExpandedPath: WideString;
RedirectedPath: WideString;
ReplacedObjAttrs: WinNative.TObjectAttributes;
HadTrailingDelim_: array [0..3] of byte; // Fix Delphi bug: HadTrailingDelim causes stack 4-bytes misalignment
HadTrailingDelim: boolean absolute HadTrailingDelim_;
begin
if VfsDebug.LoggingEnabled then begin

View File

@ -96,7 +96,7 @@ begin
ExcludedItems := DataLib.NewDict(not Utils.OWNS_ITEMS, DataLib.CASE_SENSITIVE);
if VfsItemFound then begin
while DirListing.GetNextItem(DirItem) do begin
while Self.DirListing.GetNextItem(DirItem) do begin
ExcludedItems[WideStrToCaselessKey(DirItem.Data.FileName)] := Ptr(1);
end;

View File

@ -24,7 +24,6 @@
<DCC_ObjPath>..\Lib\B2;.\Tests</DCC_ObjPath>
<DCC_IncludePath>..\Lib\B2;.\Tests</DCC_IncludePath>
<DCC_MapFile>3</DCC_MapFile>
<DCC_Optimize>False</DCC_Optimize>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality</Borland.Personality>
@ -58,6 +57,14 @@

View File

@ -1 +1,10 @@
UTF-8 Logging
UTF-8 Logging
Editor/Development mode:
Separate thread with FindFirstChangeNotificationA/FindNextChangeNotification on mods root dir + WaitForSingleObject
+ ResetVfs + BlockVfs + MapDir for each cached mapped directory + RunVfs.
We will need some API like RefreshVfs.
Add ANSI versions of exported API.
Write VfsImport.pas nad vfs_import.c