fpc/rtl/nativent/sysutils.pp
sergei 4ebc34c5e7 * Promoted result type of FPC_PCHAR_LENGTH and FPC_PWIDECHAR_LENGTH to SizeInt.
+ Check for nil pointer in FPC_PWIDECHAR_LENGTH

git-svn-id: trunk@17733 -
2011-06-13 04:59:17 +00:00

786 lines
20 KiB
ObjectPascal

{
This file is part of the Free Pascal run time library.
Copyright (c) 2010 by Sven Barth
member of the Free Pascal development team
Sysutils unit for NativeNT
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
unit sysutils;
interface
{$MODE objfpc}
{$MODESWITCH OUT}
{ force ansistrings }
{$H+}
uses
ndk;
{$DEFINE HAS_SLEEP}
{$DEFINE HAS_CREATEGUID}
{ Include platform independent interface part }
{$i sysutilh.inc}
implementation
uses
sysconst, ndkutils;
{$DEFINE FPC_NOGENERICANSIROUTINES}
{ Include platform independent implementation part }
{$i sysutils.inc}
{****************************************************************************
File Functions
****************************************************************************}
function FileOpen(const FileName : string; Mode : Integer) : THandle;
const
AccessMode: array[0..2] of ACCESS_MASK = (
GENERIC_READ,
GENERIC_WRITE,
GENERIC_READ or GENERIC_WRITE);
ShareMode: array[0..4] of ULONG = (
0,
0,
FILE_SHARE_READ,
FILE_SHARE_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE);
var
ntstr: UNICODE_STRING;
objattr: OBJECT_ATTRIBUTES;
iostatus: IO_STATUS_BLOCK;
begin
AnsiStrToNtStr(FileName, ntstr);
InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
NtCreateFile(@Result, AccessMode[Mode and 3] or NT_SYNCHRONIZE, @objattr,
@iostatus, Nil, FILE_ATTRIBUTE_NORMAL, ShareMode[(Mode and $F0) shr 4],
FILE_OPEN, FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil, 0);
FreeNtStr(ntstr);
end;
function FileCreate(const FileName : String) : THandle;
var
ntstr: UNICODE_STRING;
objattr: OBJECT_ATTRIBUTES;
iostatus: IO_STATUS_BLOCK;
res: NTSTATUS;
begin
AnsiStrToNTStr(FileName, ntstr);
InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
NtCreateFile(@Result, GENERIC_READ or GENERIC_WRITE or NT_SYNCHRONIZE,
@objattr, @iostatus, Nil, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil, 0);
FreeNtStr(ntstr);
end;
function FileCreate(const FileName : String; Rights: longint) : THandle;
begin
FileCreate := FileCreate(FileName);
end;
function FileCreate(const FileName : String; ShareMode : longint; Rights: longint) : THandle;
begin
FileCreate := FileCreate(FileName);
end;
function FileRead(Handle : THandle; out Buffer; Count : longint) : Longint;
var
iostatus: IO_STATUS_BLOCK;
res: NTSTATUS;
begin
res := NtReadFile(Handle, 0, Nil, Nil, @iostatus, @Buffer, Count, Nil, Nil);
if res = STATUS_PENDING then begin
res := NtWaitForSingleObject(Handle, False, Nil);
if NT_SUCCESS(res) then
res := iostatus.union1.Status;
end;
if NT_SUCCESS(res) then
Result := LongInt(iostatus.Information)
else
Result := -1;
end;
function FileWrite(Handle : THandle; const Buffer; Count : Longint) : Longint;
var
iostatus: IO_STATUS_BLOCK;
res: NTSTATUS;
begin
res := NtWriteFile(Handle, 0, Nil, Nil, @iostatus, @Buffer, Count, Nil,
Nil);
if res = STATUS_PENDING then begin
res := NtWaitForSingleObject(Handle, False, Nil);
if NT_SUCCESS(res) then
res := iostatus.union1.Status;
end;
if NT_SUCCESS(res) then
Result := LongInt(iostatus.Information)
else
Result := -1;
end;
function FileSeek(Handle : THandle;FOffset,Origin : Longint) : Longint;
begin
Result := longint(FileSeek(Handle, Int64(FOffset), Origin));
end;
function FileSeek(Handle : THandle; FOffset: Int64; Origin: Longint) : Int64;
const
ErrorCode = $FFFFFFFFFFFFFFFF;
var
position: FILE_POSITION_INFORMATION;
standard: FILE_STANDARD_INFORMATION;
iostatus: IO_STATUS_BLOCK;
res: NTSTATUS;
begin
{ determine the new position }
case Origin of
fsFromBeginning:
position.CurrentByteOffset.QuadPart := FOffset;
fsFromCurrent: begin
res := NtQueryInformationFile(Handle, @iostatus, @position,
SizeOf(FILE_POSITION_INFORMATION), FilePositionInformation);
if res < 0 then begin
Result := ErrorCode;
Exit;
end;
position.CurrentByteOffset.QuadPart :=
position.CurrentByteOffset.QuadPart + FOffset;
end;
fsFromEnd: begin
res := NtQueryInformationFile(Handle, @iostatus, @standard,
SizeOf(FILE_STANDARD_INFORMATION), FileStandardInformation);
if res < 0 then begin
Result := ErrorCode;
Exit;
end;
position.CurrentByteOffset.QuadPart := standard.EndOfFile.QuadPart +
FOffset;
end;
else begin
Result := ErrorCode;
Exit;
end;
end;
{ set the new position }
res := NtSetInformationFile(Handle, @iostatus, @position,
SizeOf(FILE_POSITION_INFORMATION), FilePositionInformation);
if res < 0 then
Result := ErrorCode
else
Result := position.CurrentByteOffset.QuadPart;
end;
procedure FileClose(Handle : THandle);
begin
NtClose(Handle);
end;
function FileTruncate(Handle : THandle;Size: Int64) : boolean;
var
endoffileinfo: FILE_END_OF_FILE_INFORMATION;
allocinfo: FILE_ALLOCATION_INFORMATION;
iostatus: IO_STATUS_BLOCK;
res: NTSTATUS;
begin
// based on ReactOS' SetEndOfFile
endoffileinfo.EndOfFile.QuadPart := Size;
res := NtSetInformationFile(Handle, @iostatus, @endoffileinfo,
SizeOf(FILE_END_OF_FILE_INFORMATION), FileEndOfFileInformation);
if NT_SUCCESS(res) then begin
allocinfo.AllocationSize.QuadPart := Size;
res := NtSetInformationFile(handle, @iostatus, @allocinfo,
SizeOf(FILE_ALLOCATION_INFORMATION), FileAllocationInformation);
Result := NT_SUCCESS(res);
end else
Result := False;
end;
function NTToDosTime(const NtTime: LARGE_INTEGER): LongInt;
var
userdata: PKUSER_SHARED_DATA;
local, bias: LARGE_INTEGER;
fields: TIME_FIELDS;
zs: LongInt;
begin
userdata := SharedUserData;
repeat
bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
local.QuadPart := NtTime.QuadPart - bias.QuadPart;
RtlTimeToTimeFields(@local, @fields);
{ from objpas\datutil.inc\DateTimeToDosDateTime }
Result := - 1980;
Result := Result + fields.Year and 127;
Result := Result shl 4;
Result := Result + fields.Month;
Result := Result shl 5;
Result := Result + fields.Day;
Result := Result shl 16;
zs := fields.Hour;
zs := zs shl 6;
zs := zs + fields.Minute;
zs := zs shl 5;
zs := zs + fields.Second div 2;
Result := Result + (zs and $ffff);
end;
function DosToNtTime(aDTime: LongInt; var aNtTime: LARGE_INTEGER): Boolean;
var
fields: TIME_FIELDS;
local, bias: LARGE_INTEGER;
userdata: PKUSER_SHARED_DATA;
begin
{ from objpas\datutil.inc\DosDateTimeToDateTime }
fields.Second := (aDTime and 31) * 2;
aDTime := aDTime shr 5;
fields.Minute := aDTime and 63;
aDTime := aDTime shr 6;
fields.Hour := aDTime and 31;
aDTime := aDTime shr 5;
fields.Day := aDTime and 31;
aDTime := aDTime shr 5;
fields.Month := aDTime and 15;
aDTime := aDTime shr 4;
fields.Year := aDTime + 1980;
Result := RtlTimeFieldsToTime(@fields, @local);
if not Result then
Exit;
userdata := SharedUserData;
repeat
bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
aNtTime.QuadPart := local.QuadPart + bias.QuadPart;
end;
function FileAge(const FileName: String): Longint;
begin
Result := -1;
end;
function FileExists(const FileName: String): Boolean;
var
ntstr: UNICODE_STRING;
objattr: OBJECT_ATTRIBUTES;
res: NTSTATUS;
iostatus: IO_STATUS_BLOCK;
h: THandle;
begin
AnsiStrToNtStr(FileName, ntstr);
InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
res := NtOpenFile(@h, 0, @objattr, @iostatus,
FILE_SHARE_READ or FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
Result := NT_SUCCESS(res);
if Result then
NtClose(h);
FreeNtStr(ntstr);
end;
function DirectoryExists(const Directory : String) : Boolean;
var
ntstr: UNICODE_STRING;
objattr: OBJECT_ATTRIBUTES;
res: NTSTATUS;
iostatus: IO_STATUS_BLOCK;
h: THandle;
begin
AnsiStrToNtStr(Directory, ntstr);
InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
{ first test wether this is a object directory }
res := NtOpenDirectoryObject(@h, 0, @objattr);
if NT_SUCCESS(res) then
Result := True
else begin
if res = STATUS_OBJECT_TYPE_MISMATCH then begin
{ this is a file object! }
res := NtOpenFile(@h, 0, @objattr, @iostatus,
FILE_SHARE_READ or FILE_SHARE_WRITE,
FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
Result := NT_SUCCESS(res);
end else
Result := False;
end;
if Result then
NtClose(h);
FreeNtStr(ntstr);
end;
function FindMatch(var f: TSearchRec): Longint;
begin
Result := -1;
end;
function FindFirst(const Path: String; Attr: Longint; out Rslt: TSearchRec): Longint;
begin
Result := -1;
end;
function FindNext(var Rslt: TSearchRec): Longint;
begin
Result := -1;
end;
procedure FindClose(var F: TSearchrec);
begin
{ empty }
end;
function FileGetDate(Handle: THandle): Longint;
var
res: NTSTATUS;
basic: FILE_BASIC_INFORMATION;
iostatus: IO_STATUS_BLOCK;
begin
res := NtQueryInformationFile(Handle, @iostatus, @basic,
SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
if NT_SUCCESS(res) then
Result := NtToDosTime(basic.LastWriteTime)
else
Result := -1;
end;
function FileSetDate(Handle: THandle;Age: Longint): Longint;
var
res: NTSTATUS;
basic: FILE_BASIC_INFORMATION;
iostatus: IO_STATUS_BLOCK;
begin
res := NtQueryInformationFile(Handle, @iostatus, @basic,
SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
if NT_SUCCESS(res) then begin
if not DosToNtTime(Age, basic.LastWriteTime) then begin
Result := -1;
Exit;
end;
res := NtSetInformationFile(Handle, @iostatus, @basic,
SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
if NT_SUCCESS(res) then
Result := 0
else
Result := res;
end else
Result := res;
end;
function FileGetAttr(const FileName: String): Longint;
var
objattr: OBJECT_ATTRIBUTES;
info: FILE_NETWORK_OPEN_INFORMATION;
res: NTSTATUS;
ntstr: UNICODE_STRING;
begin
AnsiStrToNtStr(FileName, ntstr);
InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
res := NtQueryFullAttributesFile(@objattr, @info);
if NT_SUCCESS(res) then
Result := info.FileAttributes
else
Result := 0;
FreeNtStr(ntstr);
end;
function FileSetAttr(const Filename: String; Attr: LongInt): Longint;
var
h: THandle;
objattr: OBJECT_ATTRIBUTES;
ntstr: UNICODE_STRING;
basic: FILE_BASIC_INFORMATION;
res: NTSTATUS;
iostatus: IO_STATUS_BLOCK;
begin
AnsiStrToNtStr(Filename, ntstr);
InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
res := NtOpenFile(@h,
NT_SYNCHRONIZE or FILE_READ_ATTRIBUTES or FILE_WRITE_ATTRIBUTES,
@objattr, @iostatus,
FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT);
FreeNtStr(ntstr);
if NT_SUCCESS(res) then begin
res := NtQueryInformationFile(h, @iostatus, @basic,
SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
if NT_SUCCESS(res) then begin
basic.FileAttributes := Attr;
Result := NtSetInformationFile(h, @iostatus, @basic,
SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
end;
NtClose(h);
end else
Result := res;
end;
function DeleteFile(const FileName: String): Boolean;
var
h: THandle;
objattr: OBJECT_ATTRIBUTES;
ntstr: UNICODE_STRING;
dispinfo: FILE_DISPOSITION_INFORMATION;
res: NTSTATUS;
iostatus: IO_STATUS_BLOCK;
begin
AnsiStrToNtStr(Filename, ntstr);
InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
res := NtOpenFile(@h, NT_DELETE, @objattr, @iostatus,
FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
FILE_NON_DIRECTORY_FILE);
FreeNtStr(ntstr);
if NT_SUCCESS(res) then begin
dispinfo.DeleteFile := True;
res := NtSetInformationFile(h, @iostatus, @dispinfo,
SizeOf(FILE_DISPOSITION_INFORMATION), FileDispositionInformation);
Result := NT_SUCCESS(res);
NtClose(h);
end else
Result := False;
end;
function RenameFile(const OldName, NewName: String): Boolean;
var
h: THandle;
objattr: OBJECT_ATTRIBUTES;
iostatus: IO_STATUS_BLOCK;
dest, src: UNICODE_STRING;
renameinfo: PFILE_RENAME_INFORMATION;
res: LongInt;
begin
{ check whether the destination exists first }
AnsiStrToNtStr(NewName, dest);
InitializeObjectAttributes(objattr, @dest, 0, 0, Nil);
res := NtCreateFile(@h, 0, @objattr, @iostatus, Nil, 0,
FILE_SHARE_READ or FILE_SHARE_WRITE, FILE_OPEN,
FILE_NON_DIRECTORY_FILE, Nil, 0);
if NT_SUCCESS(res) then begin
{ destination already exists => error }
NtClose(h);
Result := False;
end else begin
AnsiStrToNtStr(OldName, src);
InitializeObjectAttributes(objattr, @src, 0, 0, Nil);
res := NtCreateFile(@h,
GENERIC_ALL or NT_SYNCHRONIZE or FILE_READ_ATTRIBUTES,
@objattr, @iostatus, Nil, 0, FILE_SHARE_READ or FILE_SHARE_WRITE,
FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT or FILE_OPEN_REMOTE_INSTANCE
or FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil,
0);
if NT_SUCCESS(res) then begin
renameinfo := GetMem(SizeOf(FILE_RENAME_INFORMATION) + dest.Length);
with renameinfo^ do begin
ReplaceIfExists := False;
RootDirectory := 0;
FileNameLength := dest.Length;
Move(dest.Buffer^, renameinfo^.FileName, dest.Length);
end;
res := NtSetInformationFile(h, @iostatus, renameinfo,
SizeOf(FILE_RENAME_INFORMATION) + dest.Length,
FileRenameInformation);
if not NT_SUCCESS(res) then begin
{ this could happen if src and destination reside on different drives,
so we need to copy the file manually }
{$message warning 'RenameFile: Implement file copy!'}
Result := False;
end else
Result := True;
NtClose(h);
end else
Result := False;
FreeNtStr(src);
end;
FreeNtStr(dest);
end;
{****************************************************************************
Disk Functions
****************************************************************************}
function diskfree(drive: byte): int64;
begin
{ here the mount manager needs to be queried }
Result := -1;
end;
function disksize(drive: byte): int64;
begin
{ here the mount manager needs to be queried }
Result := -1;
end;
function GetCurrentDir: String;
begin
GetDir(0, result);
end;
function SetCurrentDir(const NewDir: String): Boolean;
begin
{$I-}
ChDir(NewDir);
{$I+}
Result := IOResult = 0;
end;
function CreateDir(const NewDir: String): Boolean;
begin
{$I-}
MkDir(NewDir);
{$I+}
Result := IOResult = 0;
end;
function RemoveDir(const Dir: String): Boolean;
begin
{$I-}
RmDir(Dir);
{$I+}
Result := IOResult = 0;
end;
{****************************************************************************
Time Functions
****************************************************************************}
procedure GetLocalTime(var SystemTime: TSystemTime);
var
bias, syst: LARGE_INTEGER;
fields: TIME_FIELDS;
userdata: PKUSER_SHARED_DATA;
begin
// get UTC time
userdata := SharedUserData;
repeat
syst.u.HighPart := userdata^.SystemTime.High1Time;
syst.u.LowPart := userdata^.SystemTime.LowPart;
until syst.u.HighPart = userdata^.SystemTime.High2Time;
// adjust to local time
repeat
bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
syst.QuadPart := syst.QuadPart - bias.QuadPart;
RtlTimeToTimeFields(@syst, @fields);
SystemTime.Year := fields.Year;
SystemTime.Month := fields.Month;
SystemTime.Day := fields.Day;
SystemTime.Hour := fields.Hour;
SystemTime.Minute := fields.Minute;
SystemTime.Second := fields.Second;
SystemTime.Millisecond := fields.MilliSeconds;
end;
{****************************************************************************
Misc Functions
****************************************************************************}
procedure sysbeep;
begin
{ empty }
end;
procedure InitInternational;
begin
InitInternationalGeneric;
end;
{****************************************************************************
Target Dependent
****************************************************************************}
function SysErrorMessage(ErrorCode: Integer): String;
begin
Result := 'NT error code: 0x' + IntToHex(ErrorCode, 8);
end;
{****************************************************************************
Initialization code
****************************************************************************}
function wstrlen(p: PWideChar): SizeInt; external name 'FPC_PWIDECHAR_LENGTH';
function GetEnvironmentVariable(const EnvVar: String): String;
var
s : string;
i : longint;
hp: pwidechar;
len: sizeint;
begin
{ TODO : test once I know how to execute processes }
Result:='';
hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
while hp^<>#0 do
begin
len:=UnicodeToUTF8(Nil, hp, 0);
SetLength(s,len);
UnicodeToUTF8(PChar(s), hp, len);
//s:=strpas(hp);
i:=pos('=',s);
if uppercase(copy(s,1,i-1))=upcase(envvar) then
begin
Result:=copy(s,i+1,length(s)-i);
break;
end;
{ next string entry}
hp:=hp+wstrlen(hp)+1;
end;
end;
function GetEnvironmentVariableCount: Integer;
var
hp : pwidechar;
begin
Result:=0;
hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
If (Hp<>Nil) then
while hp^<>#0 do
begin
Inc(Result);
hp:=hp+wstrlen(hp)+1;
end;
end;
function GetEnvironmentString(Index: Integer): String;
var
hp : pwidechar;
len: sizeint;
begin
Result:='';
hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
If (Hp<>Nil) then
begin
while (hp^<>#0) and (Index>1) do
begin
Dec(Index);
hp:=hp+wstrlen(hp)+1;
end;
If (hp^<>#0) then
begin
len:=UnicodeToUTF8(Nil, hp, 0);
SetLength(Result, len);
UnicodeToUTF8(PChar(Result), hp, len);
end;
end;
end;
function ExecuteProcess(const Path: AnsiString; const ComLine: AnsiString;
Flags: TExecuteFlags = []): Integer;
begin
{ TODO : implement }
Result := 0;
end;
function ExecuteProcess(const Path: AnsiString;
const ComLine: Array of AnsiString; Flags:TExecuteFlags = []): Integer;
var
CommandLine: AnsiString;
I: integer;
begin
Commandline := '';
for I := 0 to High (ComLine) do
if Pos (' ', ComLine [I]) <> 0 then
CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
else
CommandLine := CommandLine + ' ' + Comline [I];
ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
end;
procedure Sleep(Milliseconds: Cardinal);
const
DelayFactor = 10000;
var
interval: LARGE_INTEGER;
begin
interval.QuadPart := - Milliseconds * DelayFactor;
NtDelayExecution(False, @interval);
end;
{****************************************************************************
Initialization code
****************************************************************************}
initialization
InitExceptions; { Initialize exceptions. OS independent }
InitInternational; { Initialize internationalization settings }
OnBeep := @SysBeep;
finalization
DoneExceptions;
end.