sysutils.pp 32 KB

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