mirror of https://github.com/red-prig/fpPS4.git
695 lines
15 KiB
Plaintext
695 lines
15 KiB
Plaintext
unit md_map;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
ntapi,
|
|
vm,
|
|
vmparam,
|
|
windows;
|
|
|
|
const
|
|
MD_PAGE_SHIFT = 12;
|
|
MD_PAGE_SIZE = 4*1024;
|
|
MD_PAGE_MASK = MD_PAGE_SIZE-1;
|
|
MD_ALLOC_GRANULARITY= 64*1024;
|
|
|
|
MD_MAP_FIXED =$100;
|
|
MD_MAP_RESERVED =$200;
|
|
|
|
MD_MAP_ALIGN_SHIFT=24;
|
|
|
|
function MD_MAP_ALIGN(align:QWORD):DWORD; inline;
|
|
|
|
const
|
|
VM_RW =VM_PROT_READ or VM_PROT_WRITE;
|
|
VM_RX =VM_PROT_READ or VM_PROT_EXECUTE;
|
|
VM_RWX=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
|
|
|
|
function md_placeholder_mmap (var base:Pointer;size:QWORD;flags:DWORD=0;hProcess:THandle=NtCurrentProcess):Integer;
|
|
function md_placeholder_unmap (base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
function md_placeholder_split (base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer; inline;
|
|
function md_placeholder_union (base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer; inline;
|
|
function md_placeholder_commit (base:Pointer;size:QWORD;prot:DWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
function md_placeholder_commit (base:Pointer;size:QWORD;prot:DWORD;fd:THandle;offset:QWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
function md_placeholder_decommit(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
|
|
function md_memfd_create(var hMem:THandle;size:QWORD;maxprot:Byte):Integer;
|
|
function md_memfd_open (var hMem:THandle;hFile:THandle;maxprot:Byte):Integer;
|
|
function md_memfd_close (hMem:THandle):Integer; inline;
|
|
|
|
function md_protect (base:Pointer;size:QWORD;prot:Integer;hProcess:THandle=NtCurrentProcess):Integer;
|
|
function md_dontneed(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer; inline;
|
|
function md_activate(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer; inline;
|
|
|
|
function md_mmap (var base:Pointer;size:QWORD;prot:DWORD;fd:THandle=0;offset:QWORD=0;hProcess:THandle=NtCurrentProcess):Integer;
|
|
function md_unmap(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
|
|
function kmem_alloc(size:QWORD;prot:DWORD):Pointer;
|
|
procedure kmem_free (base:Pointer;size:QWORD); inline;
|
|
|
|
const
|
|
ICACHE=1; //Flush the instruction cache.
|
|
DCACHE=2; //Write back to memory and invalidate the affected valid cache lines.
|
|
BCACHE=ICACHE or DCACHE;
|
|
|
|
procedure md_cacheflush(addr:Pointer;nbytes,cache:Integer);
|
|
|
|
Function md_create_swap_file(const FNAME:RawByteString;SIZE:QWORD;Var FD:THandle):DWORD;
|
|
|
|
implementation
|
|
|
|
function MD_MAP_ALIGN(align:QWORD):DWORD; inline;
|
|
begin
|
|
Result:=BsfQWORD(align) shl MD_MAP_ALIGN_SHIFT;
|
|
end;
|
|
|
|
const
|
|
MD_PROT_NONE=PAGE_NOACCESS;
|
|
MD_PROT_R =PAGE_READONLY;
|
|
MD_PROT_W =PAGE_READWRITE;
|
|
MD_PROT_RW =PAGE_READWRITE;
|
|
MD_PROT_X =PAGE_EXECUTE;
|
|
MD_PROT_RX =PAGE_EXECUTE_READ;
|
|
MD_PROT_WX =PAGE_EXECUTE_READWRITE;
|
|
MD_PROT_RWX =PAGE_EXECUTE_READWRITE;
|
|
|
|
wprots:array[0..7] of Byte=(
|
|
MD_PROT_NONE,//___
|
|
MD_PROT_R ,//__R
|
|
MD_PROT_W ,//_W_
|
|
MD_PROT_RW ,//_WR
|
|
MD_PROT_X ,//X__
|
|
MD_PROT_RX ,//X_R
|
|
MD_PROT_WX ,//XW_
|
|
MD_PROT_RWX //XWR
|
|
);
|
|
|
|
waccess:array[0..7] of Byte=(
|
|
SECTION_QUERY, //___
|
|
SECTION_QUERY or SECTION_MAP_READ, //__R
|
|
SECTION_QUERY or SECTION_MAP_WRITE, //_W_
|
|
SECTION_QUERY or SECTION_MAP_WRITE or SECTION_MAP_READ, //_WR
|
|
SECTION_QUERY or SECTION_MAP_EXECUTE, //X__
|
|
SECTION_QUERY or SECTION_MAP_EXECUTE or SECTION_MAP_READ, //X_R
|
|
SECTION_QUERY or SECTION_MAP_EXECUTE or SECTION_MAP_WRITE, //XW_
|
|
SECTION_QUERY or SECTION_MAP_EXECUTE or SECTION_MAP_WRITE or SECTION_MAP_READ //XWR
|
|
);
|
|
|
|
function md_dw_gran(x:Pointer):Pointer; inline;
|
|
begin
|
|
Result:=Pointer(QWORD(x) and (not (MD_ALLOC_GRANULARITY-1)));
|
|
end;
|
|
|
|
function md_dw_page(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=x and (not (MD_PAGE_SIZE-1));
|
|
end;
|
|
|
|
function md_up_page(x:QWORD):QWORD; inline;
|
|
begin
|
|
Result:=(x+(MD_PAGE_SIZE-1)) and (not (MD_PAGE_SIZE-1));
|
|
end;
|
|
|
|
function md_placeholder_mmap(var base:Pointer;size:QWORD;flags:DWORD=0;hProcess:THandle=NtCurrentProcess):Integer;
|
|
var
|
|
ADDR:Pointer;
|
|
len :ULONG_PTR;
|
|
info:TMemoryBasicInformation;
|
|
EXT :TMEM_EXTENDED_PARAMETER;
|
|
REQ :TMEM_ADDRESS_REQUIREMENTS;
|
|
begin
|
|
size:=md_up_page(size);
|
|
|
|
if ((flags and MD_MAP_FIXED)<>0) then
|
|
begin
|
|
ADDR:=md_dw_gran(base);
|
|
|
|
len:=0;
|
|
Result:=NtQueryVirtualMemory(
|
|
hProcess,
|
|
ADDR,
|
|
MemoryBasicInformation,
|
|
@info,
|
|
sizeof(TMemoryBasicInformation),
|
|
@len);
|
|
|
|
if (Result=0) and (info.State=MEM_RESERVE) then
|
|
begin
|
|
if (ADDR>=info.BaseAddress) and
|
|
((ADDR+size)<=(info.BaseAddress+info.RegionSize)) then
|
|
begin
|
|
base:=info.AllocationBase;
|
|
Exit(0);
|
|
end;
|
|
end;
|
|
|
|
REQ.LowestStartingAddress:=nil;
|
|
REQ.Alignment :=0;
|
|
end else
|
|
begin
|
|
ADDR:=nil;
|
|
REQ.LowestStartingAddress:=base;
|
|
|
|
REQ.Alignment:=(flags shr MD_MAP_ALIGN_SHIFT) and $1F;
|
|
|
|
if (REQ.Alignment<=16) then
|
|
begin
|
|
REQ.Alignment:=0;
|
|
end else
|
|
begin
|
|
REQ.Alignment:=QWORD(1) shl REQ.Alignment;
|
|
end;
|
|
end;
|
|
|
|
EXT.pType :=MemExtendedParameterAddressRequirements;
|
|
EXT.Pointer:=@REQ;
|
|
|
|
REQ.HighestEndingAddress:=nil;
|
|
|
|
Result:=NtAllocateVirtualMemoryEx(
|
|
hProcess,
|
|
@ADDR,
|
|
@size,
|
|
MEM_RESERVE or MEM_RESERVE_PLACEHOLDER,
|
|
PAGE_NOACCESS,
|
|
@EXT,
|
|
1
|
|
);
|
|
|
|
if (Result=0) then
|
|
begin
|
|
base:=ADDR;
|
|
end else
|
|
begin
|
|
base:=nil;
|
|
end;
|
|
|
|
end;
|
|
|
|
function md_placeholder_unmap(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
var
|
|
pend:Pointer;
|
|
|
|
addr,prev:Pointer;
|
|
info:TMemoryBasicInformation;
|
|
len:ULONG_PTR;
|
|
begin
|
|
if (base=nil) or (size=0) then Exit(0);
|
|
|
|
pend:=base+size;
|
|
addr:=base;
|
|
|
|
repeat
|
|
|
|
len:=0;
|
|
NtQueryVirtualMemory(
|
|
hProcess,
|
|
addr,
|
|
0,
|
|
@info,
|
|
sizeof(TMemoryBasicInformation),
|
|
@len);
|
|
if (len=0) then Break;
|
|
|
|
if (info.State<>MEM_FREE) then
|
|
begin
|
|
addr:=info.BaseAddress;
|
|
|
|
case info._Type of
|
|
MEM_MAPPED:
|
|
begin
|
|
//unmap
|
|
Result:=NtUnmapViewOfSectionEx(hProcess,addr,MEM_PRESERVE_PLACEHOLDER);
|
|
end;
|
|
MEM_PRIVATE:
|
|
begin
|
|
//unmap
|
|
len:=Info.RegionSize;
|
|
Result:=NtFreeVirtualMemory(
|
|
hProcess,
|
|
@addr,
|
|
@len,
|
|
MEM_RELEASE or MEM_PRESERVE_PLACEHOLDER
|
|
);
|
|
end;
|
|
else
|
|
Result:=-1;
|
|
end;
|
|
|
|
if (Result<>0) then Exit;
|
|
end;
|
|
|
|
prev:=addr;
|
|
addr:=addr+Info.RegionSize;
|
|
|
|
if (addr>=pend) then Break;
|
|
|
|
until (prev>=addr);
|
|
|
|
//union all
|
|
Result:=NtFreeVirtualMemory(
|
|
NtCurrentProcess,
|
|
@base,
|
|
@size,
|
|
MEM_RELEASE or MEM_COALESCE_PLACEHOLDERS
|
|
);
|
|
//ignore errors
|
|
|
|
//free
|
|
size:=0;
|
|
Result:=NtFreeVirtualMemory(
|
|
NtCurrentProcess,
|
|
@base,
|
|
@size,
|
|
MEM_RELEASE
|
|
);
|
|
end;
|
|
|
|
function md_placeholder_split(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer; inline;
|
|
begin
|
|
Result:=NtFreeVirtualMemory(
|
|
hProcess,
|
|
@base,
|
|
@size,
|
|
MEM_RELEASE or MEM_PRESERVE_PLACEHOLDER
|
|
);
|
|
end;
|
|
|
|
function md_placeholder_union(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer; inline;
|
|
begin
|
|
Result:=NtFreeVirtualMemory(
|
|
hProcess,
|
|
@base,
|
|
@size,
|
|
MEM_RELEASE or MEM_COALESCE_PLACEHOLDERS
|
|
);
|
|
end;
|
|
|
|
function md_placeholder_commit(base:Pointer;size:QWORD;prot:DWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
begin
|
|
prot:=wprots[prot and VM_RWX];
|
|
|
|
Result:=NtAllocateVirtualMemoryEx(
|
|
hProcess,
|
|
@base,
|
|
@size,
|
|
MEM_COMMIT or MEM_RESERVE or MEM_REPLACE_PLACEHOLDER,
|
|
prot,
|
|
nil,
|
|
0
|
|
);
|
|
end;
|
|
|
|
function md_placeholder_commit(base:Pointer;size:QWORD;prot:DWORD;fd:THandle;offset:QWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
begin
|
|
prot:=wprots[prot and VM_RWX];
|
|
|
|
Result:=NtMapViewOfSectionEx(
|
|
fd,
|
|
hProcess,
|
|
@base,
|
|
@offset,
|
|
@size,
|
|
MEM_REPLACE_PLACEHOLDER,
|
|
prot,
|
|
nil,
|
|
0
|
|
);
|
|
end;
|
|
|
|
function md_placeholder_decommit(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
begin
|
|
Result:=NtUnmapViewOfSectionEx(hProcess,base,MEM_PRESERVE_PLACEHOLDER);
|
|
|
|
if (DWORD(Result)=$C0000019) then //STATUS_NOT_MAPPED_VIEW
|
|
begin
|
|
Result:=NtFreeVirtualMemory(
|
|
hProcess,
|
|
@base,
|
|
@size,
|
|
MEM_RELEASE or MEM_PRESERVE_PLACEHOLDER
|
|
);
|
|
end;
|
|
end;
|
|
|
|
function md_memfd_create(var hMem:THandle;size:QWORD;maxprot:Byte):Integer;
|
|
var
|
|
Access:DWORD;
|
|
prot:DWORD;
|
|
begin
|
|
Access:=waccess[maxprot and VM_RWX];
|
|
prot :=wprots [maxprot and VM_RWX];
|
|
|
|
hMem:=0;
|
|
Result:=NtCreateSectionEx(
|
|
@hMem,
|
|
Access,
|
|
nil,
|
|
@size,
|
|
prot,
|
|
SEC_COMMIT,
|
|
THandle(0),
|
|
nil,
|
|
0
|
|
);
|
|
end;
|
|
|
|
function md_memfd_open(var hMem:THandle;hFile:THandle;maxprot:Byte):Integer;
|
|
var
|
|
Access:DWORD;
|
|
prot:DWORD;
|
|
size:QWORD;
|
|
begin
|
|
Access:=waccess[maxprot and VM_RWX];
|
|
prot :=wprots [maxprot and VM_RWX];
|
|
|
|
size:=0;
|
|
hMem:=0;
|
|
Result:=NtCreateSectionEx(
|
|
@hMem,
|
|
Access,
|
|
nil,
|
|
@size,
|
|
prot,
|
|
SEC_COMMIT,
|
|
hFile,
|
|
nil,
|
|
0
|
|
);
|
|
end;
|
|
|
|
function md_memfd_close(hMem:THandle):Integer; inline;
|
|
begin
|
|
Result:=NtClose(hMem);
|
|
end;
|
|
|
|
function md_protect(base:Pointer;size:QWORD;prot:Integer;hProcess:THandle=NtCurrentProcess):Integer;
|
|
var
|
|
old:Integer;
|
|
begin
|
|
prot:=wprots[prot and VM_RWX];
|
|
|
|
old:=0;
|
|
Result:=NtProtectVirtualMemory(
|
|
hProcess,
|
|
@base,
|
|
@size,
|
|
prot,
|
|
@old
|
|
);
|
|
end;
|
|
|
|
function md_dontneed(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer; inline;
|
|
begin
|
|
Result:=NtAllocateVirtualMemory(
|
|
hProcess,
|
|
@base,
|
|
0,
|
|
@size,
|
|
MEM_RESET,
|
|
PAGE_NOACCESS
|
|
);
|
|
end;
|
|
|
|
function md_activate(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer; inline;
|
|
begin
|
|
Result:=NtAllocateVirtualMemory(
|
|
hProcess,
|
|
@base,
|
|
0,
|
|
@size,
|
|
MEM_RESET_UNDO,
|
|
PAGE_NOACCESS
|
|
);
|
|
end;
|
|
|
|
const
|
|
atypes:array[0..3] of DWORD=(
|
|
MEM_COMMIT , //___
|
|
MEM_COMMIT or MEM_RESERVE, //__F
|
|
MEM_RESERVE , //_R_
|
|
MEM_RESERVE //_RF
|
|
);
|
|
|
|
function md_mmap(var base:Pointer;size:QWORD;prot:DWORD;fd:THandle=0;offset:QWORD=0;hProcess:THandle=NtCurrentProcess):Integer;
|
|
var
|
|
atype:DWORD;
|
|
ADDR :Pointer;
|
|
EXT :TMEM_EXTENDED_PARAMETER;
|
|
REQ :TMEM_ADDRESS_REQUIREMENTS;
|
|
begin
|
|
EXT.pType :=MemExtendedParameterAddressRequirements;
|
|
EXT.Pointer:=@REQ;
|
|
|
|
if ((prot and MD_MAP_FIXED)<>0) then
|
|
begin
|
|
ADDR:=md_dw_gran(base);
|
|
REQ.LowestStartingAddress:=nil;
|
|
REQ.Alignment :=0;
|
|
end else
|
|
begin
|
|
ADDR:=nil;
|
|
REQ.LowestStartingAddress:=base;
|
|
|
|
REQ.Alignment:=(prot shr MD_MAP_ALIGN_SHIFT) and $1F;
|
|
|
|
if (REQ.Alignment<=16) then
|
|
begin
|
|
REQ.Alignment:=0;
|
|
end else
|
|
begin
|
|
REQ.Alignment:=QWORD(1) shl REQ.Alignment;
|
|
end;
|
|
end;
|
|
|
|
REQ.HighestEndingAddress:=nil;
|
|
|
|
atype:=atypes[(prot shr 8) and 3];
|
|
|
|
if (prot and MD_MAP_RESERVED)<>0 then
|
|
begin
|
|
prot:=PAGE_NOACCESS;
|
|
fd :=0;
|
|
end else
|
|
begin
|
|
prot:=wprots[prot and VM_RWX];
|
|
end;
|
|
|
|
if (fd=THandle(0)) or (fd=THandle(-1)) then
|
|
begin
|
|
Result:=NtAllocateVirtualMemoryEx(
|
|
hProcess,
|
|
@ADDR,
|
|
@size,
|
|
atype,
|
|
prot,
|
|
@EXT,
|
|
1
|
|
);
|
|
end else
|
|
begin
|
|
Result:=NtMapViewOfSectionEx(
|
|
fd,
|
|
hProcess,
|
|
@ADDR,
|
|
@offset,
|
|
@size,
|
|
0,
|
|
prot,
|
|
@EXT,
|
|
1
|
|
);
|
|
end;
|
|
|
|
if (Result=0) then
|
|
begin
|
|
base:=ADDR;
|
|
end else
|
|
begin
|
|
base:=nil;
|
|
end;
|
|
|
|
end;
|
|
|
|
function md_unmap(base:Pointer;size:QWORD;hProcess:THandle=NtCurrentProcess):Integer;
|
|
var
|
|
pend:Pointer;
|
|
|
|
addr,prev:Pointer;
|
|
info:TMemoryBasicInformation;
|
|
len:ULONG_PTR;
|
|
begin
|
|
if (base=nil) or (size=0) then Exit(0);
|
|
|
|
pend:=base+size;
|
|
addr:=base;
|
|
|
|
repeat
|
|
|
|
len:=0;
|
|
NtQueryVirtualMemory(
|
|
hProcess,
|
|
addr,
|
|
0,
|
|
@info,
|
|
sizeof(TMemoryBasicInformation),
|
|
@len);
|
|
if (len=0) then Break;
|
|
|
|
if (info.State<>MEM_FREE) then
|
|
begin
|
|
addr:=info.AllocationBase;
|
|
|
|
case info._Type of
|
|
MEM_MAPPED:
|
|
begin
|
|
//unmap
|
|
Result:=NtUnmapViewOfSectionEx(hProcess,addr,0);
|
|
end;
|
|
MEM_PRIVATE:
|
|
begin
|
|
//unmap
|
|
len:=0;
|
|
Result:=NtFreeVirtualMemory(
|
|
hProcess,
|
|
@addr,
|
|
@len,
|
|
MEM_RELEASE
|
|
);
|
|
end;
|
|
else
|
|
Result:=-1;
|
|
end;
|
|
|
|
if (Result<>0) then Exit;
|
|
end else
|
|
begin
|
|
addr:=info.BaseAddress;
|
|
end;
|
|
|
|
prev:=addr;
|
|
addr:=info.BaseAddress+Info.RegionSize;
|
|
|
|
if (addr>=pend) then Break;
|
|
|
|
until (prev>=addr);
|
|
end;
|
|
|
|
function kmem_alloc(size:QWORD;prot:DWORD):Pointer;
|
|
var
|
|
r:Integer;
|
|
begin
|
|
Result:=Pointer(KERNEL_LOWER); //lower
|
|
r:=md_mmap(Result,size,prot);
|
|
if (r<>0) then
|
|
begin
|
|
Writeln(stderr,'kmem_alloc(0x',HexStr(size,11),',0x',HexStr(prot,3),'):0x',HexStr(r,8));
|
|
end;
|
|
end;
|
|
|
|
procedure kmem_free(base:Pointer;size:QWORD); inline;
|
|
begin
|
|
md_unmap(base,size);
|
|
end;
|
|
|
|
//
|
|
|
|
procedure md_cacheflush(addr:Pointer;nbytes,cache:Integer);
|
|
begin
|
|
if ((cache and ICACHE)<>0) then
|
|
begin
|
|
FlushInstructionCache(NtCurrentProcess,addr,nbytes);
|
|
end;
|
|
if ((cache and DCACHE)<>0) then
|
|
begin
|
|
FlushViewOfFile(addr,nbytes);
|
|
end;
|
|
end;
|
|
|
|
Function NtTruncate(FD:THandle;SIZE:QWORD):DWORD; inline;
|
|
var
|
|
BLK:IO_STATUS_BLOCK;
|
|
begin
|
|
Result:=NtSetInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@SIZE,
|
|
SizeOf(Int64),
|
|
FileEndOfFileInformation);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
Result:=NtSetInformationFile(
|
|
FD,
|
|
@BLK,
|
|
@SIZE,
|
|
SizeOf(Int64),
|
|
FileAllocationInformation);
|
|
end;
|
|
end;
|
|
|
|
function StrLen(p: pwidechar): sizeint; external name 'FPC_PWIDECHAR_LENGTH'; overload;
|
|
|
|
Function md_create_swap_file(const FNAME:RawByteString;SIZE:QWORD;Var FD:THandle):DWORD;
|
|
var
|
|
W:WideString;
|
|
|
|
OBJ :OBJECT_ATTRIBUTES;
|
|
UPATH:UNICODE_STRING;
|
|
BLK :IO_STATUS_BLOCK;
|
|
|
|
begin
|
|
W:=UTF8Decode(FNAME);
|
|
W:='\??\'+W;
|
|
|
|
OBJ:=Default(OBJECT_ATTRIBUTES);
|
|
OBJ.Length :=SizeOf(OBJECT_ATTRIBUTES);
|
|
OBJ.ObjectName:=@UPATH;
|
|
|
|
UPATH:=Default(UNICODE_STRING);
|
|
UPATH.Length :=strlen(PWideChar(w))*SizeOf(WideChar);
|
|
UPATH.MaximumLength:=UPATH.Length+SizeOf(WideChar);
|
|
UPATH.Buffer :=PWideChar(w);
|
|
|
|
BLK:=Default(IO_STATUS_BLOCK);
|
|
FD:=0;
|
|
|
|
Result:=NtCreateFile(@FD,
|
|
FILE_READ_DATA or
|
|
FILE_WRITE_DATA or
|
|
FILE_APPEND_DATA or
|
|
FILE_READ_ATTRIBUTES or
|
|
FILE_WRITE_ATTRIBUTES or
|
|
FILE_CAN_DELETE or
|
|
SYNCHRONIZE,
|
|
@OBJ,
|
|
@BLK,
|
|
nil,
|
|
FILE_ATTRIBUTE_TEMPORARY,
|
|
0,
|
|
FILE_OVERWRITE_IF,
|
|
FILE_SYNCHRONOUS_IO_NONALERT or
|
|
FILE_OPEN_REPARSE_POINT or
|
|
FILE_NON_DIRECTORY_FILE or
|
|
FILE_DELETE_ON_CLOSE,
|
|
nil,
|
|
0);
|
|
|
|
if (Result<>0) then Exit;
|
|
|
|
Result:=NtTruncate(FD,SIZE);
|
|
|
|
if (Result<>0) then
|
|
begin
|
|
NtClose(FD);
|
|
FD:=0;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|