sysutils.pp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2010 by Sven Barth
  4. member of the Free Pascal development team
  5. Sysutils unit for NativeNT
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit sysutils;
  13. interface
  14. {$MODE objfpc}
  15. {$MODESWITCH OUT}
  16. { force ansistrings }
  17. {$H+}
  18. uses
  19. ndk;
  20. {$DEFINE HAS_SLEEP}
  21. {$DEFINE HAS_CREATEGUID}
  22. type
  23. TNativeNTFindData = record
  24. SearchSpec: String;
  25. NamePos: LongInt;
  26. Handle: THandle;
  27. IsDirObj: Boolean;
  28. SearchAttr: LongInt;
  29. Context: ULONG;
  30. LastRes: NTSTATUS;
  31. end;
  32. { Include platform independent interface part }
  33. {$i sysutilh.inc}
  34. implementation
  35. uses
  36. sysconst, ndkutils;
  37. {$DEFINE FPC_NOGENERICANSIROUTINES}
  38. { Include platform independent implementation part }
  39. {$i sysutils.inc}
  40. {****************************************************************************
  41. File Functions
  42. ****************************************************************************}
  43. function FileOpen(const FileName : string; Mode : Integer) : THandle;
  44. const
  45. AccessMode: array[0..2] of ACCESS_MASK = (
  46. GENERIC_READ,
  47. GENERIC_WRITE,
  48. GENERIC_READ or GENERIC_WRITE);
  49. ShareMode: array[0..4] of ULONG = (
  50. 0,
  51. 0,
  52. FILE_SHARE_READ,
  53. FILE_SHARE_WRITE,
  54. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE);
  55. var
  56. ntstr: UNICODE_STRING;
  57. objattr: OBJECT_ATTRIBUTES;
  58. iostatus: IO_STATUS_BLOCK;
  59. begin
  60. AnsiStrToNtStr(FileName, ntstr);
  61. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  62. NtCreateFile(@Result, AccessMode[Mode and 3] or NT_SYNCHRONIZE, @objattr,
  63. @iostatus, Nil, FILE_ATTRIBUTE_NORMAL, ShareMode[(Mode and $F0) shr 4],
  64. FILE_OPEN, FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil, 0);
  65. FreeNtStr(ntstr);
  66. end;
  67. function FileCreate(const FileName : String) : THandle;
  68. begin
  69. FileCreate := FileCreate(FileName, fmShareDenyNone, 0);
  70. end;
  71. function FileCreate(const FileName : String; Rights: longint) : THandle;
  72. begin
  73. FileCreate := FileCreate(FileName, fmShareDenyNone, Rights);
  74. end;
  75. function FileCreate(const FileName : String; ShareMode : longint; Rights: longint) : THandle;
  76. const
  77. ShareModeFlags: array[0..4] of ULONG = (
  78. 0,
  79. 0,
  80. FILE_SHARE_READ,
  81. FILE_SHARE_WRITE,
  82. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE);
  83. var
  84. ntstr: UNICODE_STRING;
  85. objattr: OBJECT_ATTRIBUTES;
  86. iostatus: IO_STATUS_BLOCK;
  87. res: NTSTATUS;
  88. begin
  89. AnsiStrToNTStr(FileName, ntstr);
  90. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  91. NtCreateFile(@Result, GENERIC_READ or GENERIC_WRITE or NT_SYNCHRONIZE,
  92. @objattr, @iostatus, Nil, FILE_ATTRIBUTE_NORMAL,
  93. ShareModeFlags[(ShareMode and $F0) shr 4], FILE_OVERWRITE_IF,
  94. FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil, 0);
  95. FreeNtStr(ntstr);
  96. end;
  97. function FileRead(Handle : THandle; out Buffer; Count : longint) : Longint;
  98. var
  99. iostatus: IO_STATUS_BLOCK;
  100. res: NTSTATUS;
  101. begin
  102. res := NtReadFile(Handle, 0, Nil, Nil, @iostatus, @Buffer, Count, Nil, Nil);
  103. if res = STATUS_PENDING then begin
  104. res := NtWaitForSingleObject(Handle, False, Nil);
  105. if NT_SUCCESS(res) then
  106. res := iostatus.union1.Status;
  107. end;
  108. if NT_SUCCESS(res) then
  109. Result := LongInt(iostatus.Information)
  110. else
  111. Result := -1;
  112. end;
  113. function FileWrite(Handle : THandle; const Buffer; Count : Longint) : Longint;
  114. var
  115. iostatus: IO_STATUS_BLOCK;
  116. res: NTSTATUS;
  117. begin
  118. res := NtWriteFile(Handle, 0, Nil, Nil, @iostatus, @Buffer, Count, Nil,
  119. Nil);
  120. if res = STATUS_PENDING then begin
  121. res := NtWaitForSingleObject(Handle, False, Nil);
  122. if NT_SUCCESS(res) then
  123. res := iostatus.union1.Status;
  124. end;
  125. if NT_SUCCESS(res) then
  126. Result := LongInt(iostatus.Information)
  127. else
  128. Result := -1;
  129. end;
  130. function FileSeek(Handle : THandle;FOffset,Origin : Longint) : Longint;
  131. begin
  132. Result := longint(FileSeek(Handle, Int64(FOffset), Origin));
  133. end;
  134. function FileSeek(Handle : THandle; FOffset: Int64; Origin: Longint) : Int64;
  135. const
  136. ErrorCode = $FFFFFFFFFFFFFFFF;
  137. var
  138. position: FILE_POSITION_INFORMATION;
  139. standard: FILE_STANDARD_INFORMATION;
  140. iostatus: IO_STATUS_BLOCK;
  141. res: NTSTATUS;
  142. begin
  143. { determine the new position }
  144. case Origin of
  145. fsFromBeginning:
  146. position.CurrentByteOffset.QuadPart := FOffset;
  147. fsFromCurrent: begin
  148. res := NtQueryInformationFile(Handle, @iostatus, @position,
  149. SizeOf(FILE_POSITION_INFORMATION), FilePositionInformation);
  150. if res < 0 then begin
  151. Result := ErrorCode;
  152. Exit;
  153. end;
  154. position.CurrentByteOffset.QuadPart :=
  155. position.CurrentByteOffset.QuadPart + FOffset;
  156. end;
  157. fsFromEnd: begin
  158. res := NtQueryInformationFile(Handle, @iostatus, @standard,
  159. SizeOf(FILE_STANDARD_INFORMATION), FileStandardInformation);
  160. if res < 0 then begin
  161. Result := ErrorCode;
  162. Exit;
  163. end;
  164. position.CurrentByteOffset.QuadPart := standard.EndOfFile.QuadPart +
  165. FOffset;
  166. end;
  167. else begin
  168. Result := ErrorCode;
  169. Exit;
  170. end;
  171. end;
  172. { set the new position }
  173. res := NtSetInformationFile(Handle, @iostatus, @position,
  174. SizeOf(FILE_POSITION_INFORMATION), FilePositionInformation);
  175. if res < 0 then
  176. Result := ErrorCode
  177. else
  178. Result := position.CurrentByteOffset.QuadPart;
  179. end;
  180. procedure FileClose(Handle : THandle);
  181. begin
  182. NtClose(Handle);
  183. end;
  184. function FileTruncate(Handle : THandle;Size: Int64) : boolean;
  185. var
  186. endoffileinfo: FILE_END_OF_FILE_INFORMATION;
  187. allocinfo: FILE_ALLOCATION_INFORMATION;
  188. iostatus: IO_STATUS_BLOCK;
  189. res: NTSTATUS;
  190. begin
  191. // based on ReactOS' SetEndOfFile
  192. endoffileinfo.EndOfFile.QuadPart := Size;
  193. res := NtSetInformationFile(Handle, @iostatus, @endoffileinfo,
  194. SizeOf(FILE_END_OF_FILE_INFORMATION), FileEndOfFileInformation);
  195. if NT_SUCCESS(res) then begin
  196. allocinfo.AllocationSize.QuadPart := Size;
  197. res := NtSetInformationFile(handle, @iostatus, @allocinfo,
  198. SizeOf(FILE_ALLOCATION_INFORMATION), FileAllocationInformation);
  199. Result := NT_SUCCESS(res);
  200. end else
  201. Result := False;
  202. end;
  203. function NTToDosTime(const NtTime: LARGE_INTEGER): LongInt;
  204. var
  205. userdata: PKUSER_SHARED_DATA;
  206. local, bias: LARGE_INTEGER;
  207. fields: TIME_FIELDS;
  208. zs: LongInt;
  209. begin
  210. userdata := SharedUserData;
  211. repeat
  212. bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
  213. bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
  214. until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
  215. local.QuadPart := NtTime.QuadPart - bias.QuadPart;
  216. RtlTimeToTimeFields(@local, @fields);
  217. { from objpas\datutil.inc\DateTimeToDosDateTime }
  218. Result := - 1980;
  219. Result := Result + fields.Year and 127;
  220. Result := Result shl 4;
  221. Result := Result + fields.Month;
  222. Result := Result shl 5;
  223. Result := Result + fields.Day;
  224. Result := Result shl 16;
  225. zs := fields.Hour;
  226. zs := zs shl 6;
  227. zs := zs + fields.Minute;
  228. zs := zs shl 5;
  229. zs := zs + fields.Second div 2;
  230. Result := Result + (zs and $ffff);
  231. end;
  232. function DosToNtTime(aDTime: LongInt; var aNtTime: LARGE_INTEGER): Boolean;
  233. var
  234. fields: TIME_FIELDS;
  235. local, bias: LARGE_INTEGER;
  236. userdata: PKUSER_SHARED_DATA;
  237. begin
  238. { from objpas\datutil.inc\DosDateTimeToDateTime }
  239. fields.Second := (aDTime and 31) * 2;
  240. aDTime := aDTime shr 5;
  241. fields.Minute := aDTime and 63;
  242. aDTime := aDTime shr 6;
  243. fields.Hour := aDTime and 31;
  244. aDTime := aDTime shr 5;
  245. fields.Day := aDTime and 31;
  246. aDTime := aDTime shr 5;
  247. fields.Month := aDTime and 15;
  248. aDTime := aDTime shr 4;
  249. fields.Year := aDTime + 1980;
  250. Result := RtlTimeFieldsToTime(@fields, @local);
  251. if not Result then
  252. Exit;
  253. userdata := SharedUserData;
  254. repeat
  255. bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
  256. bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
  257. until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
  258. aNtTime.QuadPart := local.QuadPart + bias.QuadPart;
  259. end;
  260. function FileAge(const FileName: String): Longint;
  261. begin
  262. { TODO }
  263. Result := -1;
  264. end;
  265. function FileExists(const FileName: String): Boolean;
  266. var
  267. ntstr: UNICODE_STRING;
  268. objattr: OBJECT_ATTRIBUTES;
  269. res: NTSTATUS;
  270. iostatus: IO_STATUS_BLOCK;
  271. h: THandle;
  272. begin
  273. AnsiStrToNtStr(FileName, ntstr);
  274. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  275. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  276. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  277. FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  278. Result := NT_SUCCESS(res);
  279. if Result then
  280. NtClose(h);
  281. FreeNtStr(ntstr);
  282. end;
  283. function DirectoryExists(const Directory : String) : Boolean;
  284. var
  285. ntstr: UNICODE_STRING;
  286. objattr: OBJECT_ATTRIBUTES;
  287. res: NTSTATUS;
  288. iostatus: IO_STATUS_BLOCK;
  289. h: THandle;
  290. begin
  291. AnsiStrToNtStr(Directory, ntstr);
  292. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  293. { first test wether this is a object directory }
  294. res := NtOpenDirectoryObject(@h, DIRECTORY_QUERY, @objattr);
  295. if NT_SUCCESS(res) then
  296. Result := True
  297. else begin
  298. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  299. { this is a file object! }
  300. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  301. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  302. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  303. Result := NT_SUCCESS(res);
  304. end else
  305. Result := False;
  306. end;
  307. if Result then
  308. NtClose(h);
  309. FreeNtStr(ntstr);
  310. end;
  311. { copied from rtl/unix/sysutils.pp }
  312. Function FNMatch(const Pattern,Name:string):Boolean;
  313. Var
  314. LenPat,LenName : longint;
  315. Function DoFNMatch(i,j:longint):Boolean;
  316. Var
  317. Found : boolean;
  318. Begin
  319. Found:=true;
  320. While Found and (i<=LenPat) Do
  321. Begin
  322. Case Pattern[i] of
  323. '?' : Found:=(j<=LenName);
  324. '*' : Begin
  325. {find the next character in pattern, different of ? and *}
  326. while Found do
  327. begin
  328. inc(i);
  329. if i>LenPat then Break;
  330. case Pattern[i] of
  331. '*' : ;
  332. '?' : begin
  333. if j>LenName then begin DoFNMatch:=false; Exit; end;
  334. inc(j);
  335. end;
  336. else
  337. Found:=false;
  338. end;
  339. end;
  340. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  341. {Now, find in name the character which i points to, if the * or ?
  342. wasn't the last character in the pattern, else, use up all the
  343. chars in name}
  344. Found:=false;
  345. if (i<=LenPat) then
  346. begin
  347. repeat
  348. {find a letter (not only first !) which maches pattern[i]}
  349. while (j<=LenName) and (name[j]<>pattern[i]) do
  350. inc (j);
  351. if (j<LenName) then
  352. begin
  353. if DoFnMatch(i+1,j+1) then
  354. begin
  355. i:=LenPat;
  356. j:=LenName;{we can stop}
  357. Found:=true;
  358. Break;
  359. end else
  360. inc(j);{We didn't find one, need to look further}
  361. end else
  362. if j=LenName then
  363. begin
  364. Found:=true;
  365. Break;
  366. end;
  367. { This 'until' condition must be j>LenName, not j>=LenName.
  368. That's because when we 'need to look further' and
  369. j = LenName then loop must not terminate. }
  370. until (j>LenName);
  371. end else
  372. begin
  373. j:=LenName;{we can stop}
  374. Found:=true;
  375. end;
  376. end;
  377. else {not a wildcard character in pattern}
  378. Found:=(j<=LenName) and (pattern[i]=name[j]);
  379. end;
  380. inc(i);
  381. inc(j);
  382. end;
  383. DoFnMatch:=Found and (j>LenName);
  384. end;
  385. Begin {start FNMatch}
  386. LenPat:=Length(Pattern);
  387. LenName:=Length(Name);
  388. FNMatch:=DoFNMatch(1,1);
  389. End;
  390. function FindGetFileInfo(const s: String; var f: TSearchRec): Boolean;
  391. var
  392. ntstr: UNICODE_STRING;
  393. objattr: OBJECT_ATTRIBUTES;
  394. res: NTSTATUS;
  395. h: THandle;
  396. iostatus: IO_STATUS_BLOCK;
  397. attr: LongInt;
  398. filename: String;
  399. isfileobj: Boolean;
  400. buf: array of Byte;
  401. objinfo: OBJECT_BASIC_INFORMATION;
  402. fileinfo: FILE_BASIC_INFORMATION;
  403. time: LongInt;
  404. begin
  405. AnsiStrToNtStr(s, ntstr);
  406. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  407. filename := ExtractFileName(s);
  408. { TODO : handle symlinks }
  409. { If Assigned(F.FindHandle) and ((((PUnixFindData(f.FindHandle)^.searchattr)) and faSymlink) > 0) then
  410. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  411. else
  412. FindGetFileInfo:=(fpstat(pointer(s),st)=0);}
  413. attr := 0;
  414. Result := False;
  415. if (faDirectory and f.FindData.SearchAttr <> 0) and
  416. ((filename = '.') or (filename = '..')) then begin
  417. attr := faDirectory;
  418. res := STATUS_SUCCESS;
  419. end else
  420. res := STATUS_INVALID_PARAMETER;
  421. isfileobj := False;
  422. if not NT_SUCCESS(res) then begin
  423. { first check whether it's a directory }
  424. res := NtOpenDirectoryObject(@h, DIRECTORY_QUERY, @objattr);
  425. if not NT_SUCCESS(res) then
  426. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  427. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  428. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  429. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  430. isfileobj := NT_SUCCESS(res);
  431. end;
  432. if NT_SUCCESS(res) then
  433. attr := faDirectory;
  434. end;
  435. if not NT_SUCCESS(res) then begin
  436. { first try whether we have a file object }
  437. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  438. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  439. FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  440. isfileobj := NT_SUCCESS(res);
  441. if res = STATUS_OBJECT_TYPE_MISMATCH then begin
  442. { is this an object? }
  443. res := NtOpenFile(@h, FILE_READ_ATTRIBUTES or NT_SYNCHRONIZE, @objattr,
  444. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  445. FILE_SYNCHRONOUS_IO_NONALERT);
  446. if (res = STATUS_OBJECT_TYPE_MISMATCH)
  447. and (f.FindData.SearchAttr and faSysFile <> 0) then begin
  448. { this is some other system file like an event or port, so we can only
  449. provide it's name }
  450. res := STATUS_SUCCESS;
  451. attr := faSysFile;
  452. end;
  453. end;
  454. end;
  455. FreeNtStr(ntstr);
  456. if not NT_SUCCESS(res) then
  457. Exit;
  458. time := 0;
  459. if isfileobj then begin
  460. res := NtQueryInformationFile(h, @iostatus, @fileinfo, SizeOf(fileinfo),
  461. FileBasicInformation);
  462. if NT_SUCCESS(res) then begin
  463. time := NtToDosTime(fileinfo.LastWriteTime);
  464. { copy file attributes? }
  465. end;
  466. end else begin
  467. res := NtQueryObject(h, ObjectBasicInformation, @objinfo, SizeOf(objinfo),
  468. Nil);
  469. if NT_SUCCESS(res) then begin
  470. time := NtToDosTime(objinfo.CreateTime);
  471. { what about attributes? }
  472. end;
  473. end;
  474. if (attr and not f.FindData.SearchAttr) = 0 then begin
  475. f.Name := filename;
  476. f.Attr := attr;
  477. f.Size := 0;
  478. {$ifndef FPUNONE}
  479. if time = 0 then
  480. { for now we use "Now" as a fall back; ideally this should be the system
  481. start time }
  482. f.Time := DateTimeToFileDate(Now)
  483. else
  484. f.Time := time;
  485. {$endif}
  486. Result := True;
  487. end else
  488. Result := False;
  489. NtClose(h);
  490. end;
  491. procedure FindClose(var F: TSearchrec);
  492. begin
  493. if f.FindData.Handle <> 0 then
  494. NtClose(f.FindData.Handle);
  495. end;
  496. function FindNext(var Rslt: TSearchRec): LongInt;
  497. {
  498. re-opens dir if not already in array and calls FindGetFileInfo
  499. }
  500. Var
  501. DirName : String;
  502. FName,
  503. SName : string;
  504. Found,
  505. Finished : boolean;
  506. ntstr: UNICODE_STRING;
  507. objattr: OBJECT_ATTRIBUTES;
  508. buf: array of WideChar;
  509. len: LongWord;
  510. res: NTSTATUS;
  511. i: LongInt;
  512. dirinfo: POBJECT_DIRECTORY_INFORMATION;
  513. filedirinfo: PFILE_DIRECTORY_INFORMATION;
  514. pc: PChar;
  515. name: AnsiString;
  516. iostatus: IO_STATUS_BLOCK;
  517. begin
  518. { TODO : relative directories }
  519. Result := -1;
  520. { SearchSpec='' means that there were no wild cards, so only one file to
  521. find.
  522. }
  523. if Rslt.FindData.SearchSpec = '' then
  524. Exit;
  525. { relative directories not supported for now }
  526. if Rslt.FindData.NamePos = 0 then
  527. Exit;
  528. if Rslt.FindData.Handle = 0 then begin
  529. if Rslt.FindData.NamePos > 1 then
  530. name := Copy(Rslt.FindData.SearchSpec, 1, Rslt.FindData.NamePos - 1)
  531. else
  532. if Rslt.FindData.NamePos = 1 then
  533. name := Copy(Rslt.FindData.SearchSpec, 1, 1)
  534. else
  535. name := Rslt.FindData.SearchSpec;
  536. AnsiStrToNtStr(name, ntstr);
  537. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  538. res := NtOpenDirectoryObject(@Rslt.FindData.Handle,
  539. DIRECTORY_QUERY or DIRECTORY_TRAVERSE, @objattr);
  540. if not NT_SUCCESS(res) then begin
  541. if res = STATUS_OBJECT_TYPE_MISMATCH then
  542. res := NtOpenFile(@Rslt.FindData.Handle,
  543. FILE_LIST_DIRECTORY or NT_SYNCHRONIZE, @objattr,
  544. @iostatus, FILE_SHARE_READ or FILE_SHARE_WRITE,
  545. FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT);
  546. end else
  547. Rslt.FindData.IsDirObj := True;
  548. FreeNTStr(ntstr);
  549. if not NT_SUCCESS(res) then
  550. Exit;
  551. end;
  552. { if (NTFindData^.SearchType = 0) and
  553. (NTFindData^.Dirptr = Nil) then
  554. begin
  555. If NTFindData^.NamePos = 0 Then
  556. DirName:='./'
  557. Else
  558. DirName:=Copy(NTFindData^.SearchSpec,1,NTFindData^.NamePos);
  559. NTFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  560. end;}
  561. SName := Copy(Rslt.FindData.SearchSpec, Rslt.FindData.NamePos + 1,
  562. Length(Rslt.FindData.SearchSpec));
  563. Found := False;
  564. Finished := not NT_SUCCESS(Rslt.FindData.LastRes)
  565. or (Rslt.FindData.LastRes = STATUS_NO_MORE_ENTRIES);
  566. SetLength(buf, 200);
  567. dirinfo := @buf[0];
  568. filedirinfo := @buf[0];
  569. while not Finished do begin
  570. if Rslt.FindData.IsDirObj then
  571. res := NtQueryDirectoryObject(Rslt.FindData.Handle, @buf[0],
  572. Length(buf) * SizeOf(buf[0]), True, False,
  573. @Rslt.FindData.Context, @len)
  574. else
  575. res := NtQueryDirectoryFile(Rslt.FindData.Handle, 0, Nil, Nil, @iostatus,
  576. @buf[0], Length(buf) * SizeOf(buf[0]), FileDirectoryInformation,
  577. True, Nil, False);
  578. if Rslt.FindData.IsDirObj then begin
  579. Finished := (res = STATUS_NO_MORE_ENTRIES)
  580. or (res = STATUS_NO_MORE_FILES)
  581. or not NT_SUCCESS(res);
  582. Rslt.FindData.LastRes := res;
  583. if dirinfo^.Name.Length > 0 then begin
  584. SetLength(FName, dirinfo^.Name.Length div 2);
  585. pc := PChar(FName);
  586. for i := 0 to dirinfo^.Name.Length div 2 - 1 do begin
  587. if dirinfo^.Name.Buffer[i] < #256 then
  588. pc^ := AnsiChar(Byte(dirinfo^.Name.Buffer[i]))
  589. else
  590. pc^ := '?';
  591. pc := pc + 1;
  592. end;
  593. {$ifdef debug_findnext}
  594. Write(FName, ' (');
  595. for i := 0 to dirinfo^.TypeName.Length div 2 - 1 do
  596. if dirinfo^.TypeName.Buffer[i] < #256 then
  597. Write(AnsiChar(Byte(dirinfo^.TypeName.Buffer[i])))
  598. else
  599. Write('?');
  600. Writeln(')');
  601. {$endif debug_findnext}
  602. end else
  603. FName := '';
  604. end else begin
  605. SetLength(FName, filedirinfo^.FileNameLength div 2);
  606. pc := PChar(FName);
  607. for i := 0 to filedirinfo^.FileNameLength div 2 - 1 do begin
  608. if filedirinfo^.FileName[i] < #256 then
  609. pc^ := AnsiChar(Byte(filedirinfo^.FileName[i]))
  610. else
  611. pc^ := '?';
  612. pc := pc + 1;
  613. end;
  614. end;
  615. if FName = '' then
  616. Finished := True
  617. else begin
  618. if FNMatch(SName, FName) then begin
  619. Found := FindGetFileInfo(Copy(Rslt.FindData.SearchSpec, 1,
  620. Rslt.FindData.NamePos) + FName, Rslt);
  621. if Found then begin
  622. Result := 0;
  623. Exit;
  624. end;
  625. end;
  626. end;
  627. end;
  628. end;
  629. function FindFirst(const Path: String; Attr: Longint; out Rslt: TSearchRec): Longint;
  630. {
  631. opens dir and calls FindNext if needed.
  632. }
  633. Begin
  634. Result := -1;
  635. FillChar(Rslt, SizeOf(Rslt), 0);
  636. if Path = '' then
  637. Exit;
  638. Rslt.FindData.SearchAttr := Attr;
  639. {Wildcards?}
  640. if (Pos('?', Path) = 0) and (Pos('*', Path) = 0) then begin
  641. if FindGetFileInfo(Path, Rslt) then
  642. Result := 0;
  643. end else begin
  644. {Create Info}
  645. Rslt.FindData.SearchSpec := Path;
  646. Rslt.FindData.NamePos := Length(Rslt.FindData.SearchSpec);
  647. while (Rslt.FindData.NamePos > 0)
  648. and (Rslt.FindData.SearchSpec[Rslt.FindData.NamePos] <> DirectorySeparator)
  649. do
  650. Dec(Rslt.FindData.NamePos);
  651. Result := FindNext(Rslt);
  652. end;
  653. if Result <> 0 then
  654. FindClose(Rslt);
  655. end;
  656. function FileGetDate(Handle: THandle): Longint;
  657. var
  658. res: NTSTATUS;
  659. basic: FILE_BASIC_INFORMATION;
  660. iostatus: IO_STATUS_BLOCK;
  661. begin
  662. res := NtQueryInformationFile(Handle, @iostatus, @basic,
  663. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  664. if NT_SUCCESS(res) then
  665. Result := NtToDosTime(basic.LastWriteTime)
  666. else
  667. Result := -1;
  668. end;
  669. function FileSetDate(Handle: THandle;Age: Longint): Longint;
  670. var
  671. res: NTSTATUS;
  672. basic: FILE_BASIC_INFORMATION;
  673. iostatus: IO_STATUS_BLOCK;
  674. begin
  675. res := NtQueryInformationFile(Handle, @iostatus, @basic,
  676. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  677. if NT_SUCCESS(res) then begin
  678. if not DosToNtTime(Age, basic.LastWriteTime) then begin
  679. Result := -1;
  680. Exit;
  681. end;
  682. res := NtSetInformationFile(Handle, @iostatus, @basic,
  683. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  684. if NT_SUCCESS(res) then
  685. Result := 0
  686. else
  687. Result := res;
  688. end else
  689. Result := res;
  690. end;
  691. function FileGetAttr(const FileName: String): Longint;
  692. var
  693. objattr: OBJECT_ATTRIBUTES;
  694. info: FILE_NETWORK_OPEN_INFORMATION;
  695. res: NTSTATUS;
  696. ntstr: UNICODE_STRING;
  697. begin
  698. AnsiStrToNtStr(FileName, ntstr);
  699. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  700. res := NtQueryFullAttributesFile(@objattr, @info);
  701. if NT_SUCCESS(res) then
  702. Result := info.FileAttributes
  703. else
  704. Result := 0;
  705. FreeNtStr(ntstr);
  706. end;
  707. function FileSetAttr(const Filename: String; Attr: LongInt): Longint;
  708. var
  709. h: THandle;
  710. objattr: OBJECT_ATTRIBUTES;
  711. ntstr: UNICODE_STRING;
  712. basic: FILE_BASIC_INFORMATION;
  713. res: NTSTATUS;
  714. iostatus: IO_STATUS_BLOCK;
  715. begin
  716. AnsiStrToNtStr(Filename, ntstr);
  717. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  718. res := NtOpenFile(@h,
  719. NT_SYNCHRONIZE or FILE_READ_ATTRIBUTES or FILE_WRITE_ATTRIBUTES,
  720. @objattr, @iostatus,
  721. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
  722. FILE_SYNCHRONOUS_IO_NONALERT);
  723. FreeNtStr(ntstr);
  724. if NT_SUCCESS(res) then begin
  725. res := NtQueryInformationFile(h, @iostatus, @basic,
  726. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  727. if NT_SUCCESS(res) then begin
  728. basic.FileAttributes := Attr;
  729. Result := NtSetInformationFile(h, @iostatus, @basic,
  730. SizeOf(FILE_BASIC_INFORMATION), FileBasicInformation);
  731. end;
  732. NtClose(h);
  733. end else
  734. Result := res;
  735. end;
  736. function DeleteFile(const FileName: String): Boolean;
  737. var
  738. h: THandle;
  739. objattr: OBJECT_ATTRIBUTES;
  740. ntstr: UNICODE_STRING;
  741. dispinfo: FILE_DISPOSITION_INFORMATION;
  742. res: NTSTATUS;
  743. iostatus: IO_STATUS_BLOCK;
  744. begin
  745. AnsiStrToNtStr(Filename, ntstr);
  746. InitializeObjectAttributes(objattr, @ntstr, 0, 0, Nil);
  747. res := NtOpenFile(@h, NT_DELETE, @objattr, @iostatus,
  748. FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
  749. FILE_NON_DIRECTORY_FILE);
  750. FreeNtStr(ntstr);
  751. if NT_SUCCESS(res) then begin
  752. dispinfo.DeleteFile := True;
  753. res := NtSetInformationFile(h, @iostatus, @dispinfo,
  754. SizeOf(FILE_DISPOSITION_INFORMATION), FileDispositionInformation);
  755. Result := NT_SUCCESS(res);
  756. NtClose(h);
  757. end else
  758. Result := False;
  759. end;
  760. function RenameFile(const OldName, NewName: String): Boolean;
  761. var
  762. h: THandle;
  763. objattr: OBJECT_ATTRIBUTES;
  764. iostatus: IO_STATUS_BLOCK;
  765. dest, src: UNICODE_STRING;
  766. renameinfo: PFILE_RENAME_INFORMATION;
  767. res: LongInt;
  768. begin
  769. { check whether the destination exists first }
  770. AnsiStrToNtStr(NewName, dest);
  771. InitializeObjectAttributes(objattr, @dest, 0, 0, Nil);
  772. res := NtCreateFile(@h, 0, @objattr, @iostatus, Nil, 0,
  773. FILE_SHARE_READ or FILE_SHARE_WRITE, FILE_OPEN,
  774. FILE_NON_DIRECTORY_FILE, Nil, 0);
  775. if NT_SUCCESS(res) then begin
  776. { destination already exists => error }
  777. NtClose(h);
  778. Result := False;
  779. end else begin
  780. AnsiStrToNtStr(OldName, src);
  781. InitializeObjectAttributes(objattr, @src, 0, 0, Nil);
  782. res := NtCreateFile(@h,
  783. GENERIC_ALL or NT_SYNCHRONIZE or FILE_READ_ATTRIBUTES,
  784. @objattr, @iostatus, Nil, 0, FILE_SHARE_READ or FILE_SHARE_WRITE,
  785. FILE_OPEN, FILE_OPEN_FOR_BACKUP_INTENT or FILE_OPEN_REMOTE_INSTANCE
  786. or FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, Nil,
  787. 0);
  788. if NT_SUCCESS(res) then begin
  789. renameinfo := GetMem(SizeOf(FILE_RENAME_INFORMATION) + dest.Length);
  790. with renameinfo^ do begin
  791. ReplaceIfExists := False;
  792. RootDirectory := 0;
  793. FileNameLength := dest.Length;
  794. Move(dest.Buffer^, renameinfo^.FileName, dest.Length);
  795. end;
  796. res := NtSetInformationFile(h, @iostatus, renameinfo,
  797. SizeOf(FILE_RENAME_INFORMATION) + dest.Length,
  798. FileRenameInformation);
  799. if not NT_SUCCESS(res) then begin
  800. { this could happen if src and destination reside on different drives,
  801. so we need to copy the file manually }
  802. {$message warning 'RenameFile: Implement file copy!'}
  803. Result := False;
  804. end else
  805. Result := True;
  806. NtClose(h);
  807. end else
  808. Result := False;
  809. FreeNtStr(src);
  810. end;
  811. FreeNtStr(dest);
  812. end;
  813. {****************************************************************************
  814. Disk Functions
  815. ****************************************************************************}
  816. function diskfree(drive: byte): int64;
  817. begin
  818. { here the mount manager needs to be queried }
  819. Result := -1;
  820. end;
  821. function disksize(drive: byte): int64;
  822. begin
  823. { here the mount manager needs to be queried }
  824. Result := -1;
  825. end;
  826. function GetCurrentDir: String;
  827. begin
  828. GetDir(0, result);
  829. end;
  830. function SetCurrentDir(const NewDir: String): Boolean;
  831. begin
  832. {$I-}
  833. ChDir(NewDir);
  834. {$I+}
  835. Result := IOResult = 0;
  836. end;
  837. function CreateDir(const NewDir: String): Boolean;
  838. begin
  839. {$I-}
  840. MkDir(NewDir);
  841. {$I+}
  842. Result := IOResult = 0;
  843. end;
  844. function RemoveDir(const Dir: String): Boolean;
  845. begin
  846. {$I-}
  847. RmDir(Dir);
  848. {$I+}
  849. Result := IOResult = 0;
  850. end;
  851. {****************************************************************************
  852. Time Functions
  853. ****************************************************************************}
  854. procedure GetLocalTime(var SystemTime: TSystemTime);
  855. var
  856. bias, syst: LARGE_INTEGER;
  857. fields: TIME_FIELDS;
  858. userdata: PKUSER_SHARED_DATA;
  859. begin
  860. // get UTC time
  861. userdata := SharedUserData;
  862. repeat
  863. syst.u.HighPart := userdata^.SystemTime.High1Time;
  864. syst.u.LowPart := userdata^.SystemTime.LowPart;
  865. until syst.u.HighPart = userdata^.SystemTime.High2Time;
  866. // adjust to local time
  867. repeat
  868. bias.u.HighPart := userdata^.TimeZoneBias.High1Time;
  869. bias.u.LowPart := userdata^.TimeZoneBias.LowPart;
  870. until bias.u.HighPart = userdata^.TimeZoneBias.High2Time;
  871. syst.QuadPart := syst.QuadPart - bias.QuadPart;
  872. RtlTimeToTimeFields(@syst, @fields);
  873. SystemTime.Year := fields.Year;
  874. SystemTime.Month := fields.Month;
  875. SystemTime.Day := fields.Day;
  876. SystemTime.Hour := fields.Hour;
  877. SystemTime.Minute := fields.Minute;
  878. SystemTime.Second := fields.Second;
  879. SystemTime.Millisecond := fields.MilliSeconds;
  880. end;
  881. {****************************************************************************
  882. Misc Functions
  883. ****************************************************************************}
  884. procedure sysbeep;
  885. begin
  886. { empty }
  887. end;
  888. procedure InitInternational;
  889. begin
  890. InitInternationalGeneric;
  891. end;
  892. {****************************************************************************
  893. Target Dependent
  894. ****************************************************************************}
  895. function SysErrorMessage(ErrorCode: Integer): String;
  896. begin
  897. Result := 'NT error code: 0x' + IntToHex(ErrorCode, 8);
  898. end;
  899. {****************************************************************************
  900. Initialization code
  901. ****************************************************************************}
  902. function wstrlen(p: PWideChar): SizeInt; external name 'FPC_PWIDECHAR_LENGTH';
  903. function GetEnvironmentVariable(const EnvVar: String): String;
  904. var
  905. s : string;
  906. i : longint;
  907. hp: pwidechar;
  908. len: sizeint;
  909. begin
  910. { TODO : test once I know how to execute processes }
  911. Result:='';
  912. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  913. while hp^<>#0 do
  914. begin
  915. len:=UnicodeToUTF8(Nil, hp, 0);
  916. SetLength(s,len);
  917. UnicodeToUTF8(PChar(s), hp, len);
  918. //s:=strpas(hp);
  919. i:=pos('=',s);
  920. if uppercase(copy(s,1,i-1))=upcase(envvar) then
  921. begin
  922. Result:=copy(s,i+1,length(s)-i);
  923. break;
  924. end;
  925. { next string entry}
  926. hp:=hp+wstrlen(hp)+1;
  927. end;
  928. end;
  929. function GetEnvironmentVariableCount: Integer;
  930. var
  931. hp : pwidechar;
  932. begin
  933. Result:=0;
  934. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  935. If (Hp<>Nil) then
  936. while hp^<>#0 do
  937. begin
  938. Inc(Result);
  939. hp:=hp+wstrlen(hp)+1;
  940. end;
  941. end;
  942. function GetEnvironmentString(Index: Integer): String;
  943. var
  944. hp : pwidechar;
  945. len: sizeint;
  946. begin
  947. Result:='';
  948. hp:=PPEB(CurrentPEB)^.ProcessParameters^.Environment;
  949. If (Hp<>Nil) then
  950. begin
  951. while (hp^<>#0) and (Index>1) do
  952. begin
  953. Dec(Index);
  954. hp:=hp+wstrlen(hp)+1;
  955. end;
  956. If (hp^<>#0) then
  957. begin
  958. len:=UnicodeToUTF8(Nil, hp, 0);
  959. SetLength(Result, len);
  960. UnicodeToUTF8(PChar(Result), hp, len);
  961. end;
  962. end;
  963. end;
  964. function ExecuteProcess(const Path: AnsiString; const ComLine: AnsiString;
  965. Flags: TExecuteFlags = []): Integer;
  966. begin
  967. { TODO : implement }
  968. Result := 0;
  969. end;
  970. function ExecuteProcess(const Path: AnsiString;
  971. const ComLine: Array of AnsiString; Flags:TExecuteFlags = []): Integer;
  972. var
  973. CommandLine: AnsiString;
  974. I: integer;
  975. begin
  976. Commandline := '';
  977. for I := 0 to High (ComLine) do
  978. if Pos (' ', ComLine [I]) <> 0 then
  979. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  980. else
  981. CommandLine := CommandLine + ' ' + Comline [I];
  982. ExecuteProcess := ExecuteProcess (Path, CommandLine,Flags);
  983. end;
  984. procedure Sleep(Milliseconds: Cardinal);
  985. const
  986. DelayFactor = 10000;
  987. var
  988. interval: LARGE_INTEGER;
  989. begin
  990. interval.QuadPart := - Milliseconds * DelayFactor;
  991. NtDelayExecution(False, @interval);
  992. end;
  993. {****************************************************************************
  994. Initialization code
  995. ****************************************************************************}
  996. initialization
  997. InitExceptions; { Initialize exceptions. OS independent }
  998. InitInternational; { Initialize internationalization settings }
  999. OnBeep := @SysBeep;
  1000. finalization
  1001. DoneExceptions;
  1002. end.