mirror of
https://github.com/CloudDelphi/Virtual-File-System
synced 2025-12-19 09:53:54 +01:00
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:
parent
c4698834c2
commit
ff8192c149
@ -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.
|
||||
@ -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
|
||||
|
||||
@ -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 *)
|
||||
|
||||
31
VfsHooks.pas
31
VfsHooks.pas
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1 +1,10 @@
|
||||
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
|
||||
Loading…
Reference in New Issue
Block a user