dos.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt and Peter Vreman,
  4. members of the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. Unit Dos;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. Interface
  15. {$IFDEF FPC_DOTTEDUNITS}
  16. uses UnixApi.Base;
  17. {$ELSE FPC_DOTTEDUNITS}
  18. uses baseunix;
  19. {$ENDIF FPC_DOTTEDUNITS}
  20. {$MACRO ON}
  21. {$IFNDEF FPC_DOTTEDUNITS}
  22. {$DEFINE SUT:=sysutils}
  23. {$DEFINE BU:=baseunix}
  24. {$DEFINE UA:=unix}
  25. {$ELSE}
  26. {$DEFINE SUT:=System.SysUtils}
  27. {$DEFINE BU:=UnixApi.Base}
  28. {$DEFINE UA:=UnixApi.Unix}
  29. {$ENDIF}
  30. Const
  31. FileNameLen = 255;
  32. Type
  33. SearchRec =
  34. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  35. packed
  36. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  37. Record
  38. {Fill : array[1..21] of byte; Fill replaced with below}
  39. SearchPos : TOff; {directory position}
  40. SearchNum : LongInt; {to track which search this is}
  41. DirPtr : Pointer; {directory pointer for reading directory}
  42. SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file}
  43. SearchAttr : Byte; {attribute we are searching for}
  44. Mode : Word;
  45. Fill : Array[1..1] of Byte; {future use}
  46. {End of fill}
  47. Attr : Byte; {attribute of found file}
  48. Time : LongInt; {last modify date of found file}
  49. Size : LongInt; {file size of found file}
  50. Reserved : Word; {future use}
  51. Name : String[FileNameLen]; {name of found file}
  52. SearchSpec : String[FileNameLen]; {search pattern}
  53. NamePos : Word; {end of path, start of name position}
  54. End;
  55. {$DEFINE HAS_FILENAMELEN}
  56. {$i dosh.inc}
  57. {Extra Utils}
  58. function weekday(y,m,d : longint) : longint; platform;
  59. Procedure UnixDateToDt(SecsPast: LongInt; Var Dt: DateTime); platform;
  60. Function DTToUnixDate(DT: DateTime): LongInt; platform;
  61. {Disk}
  62. Function AddDisk(const path:string) : byte; platform;
  63. Implementation
  64. {$IFDEF FPC_DOTTEDUNITS}
  65. Uses
  66. UnixApi.Utils,
  67. System.Strings,
  68. UnixApi.Unix,
  69. {$ifdef FPC_USE_LIBC}System.InitC{$ELSE}UnixApi.SysCall{$ENDIF};
  70. {$ELSE FPC_DOTTEDUNITS}
  71. Uses
  72. UnixUtil,
  73. Strings,
  74. Unix,
  75. {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF};
  76. {$ENDIF FPC_DOTTEDUNITS}
  77. {$DEFINE HAS_GETMSCOUNT}
  78. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  79. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PAnsiChar }
  80. {$I dos.inc}
  81. {******************************************************************************
  82. --- Link C Lib if set ---
  83. ******************************************************************************}
  84. type
  85. RtlInfoType = Record
  86. FMode,
  87. FInode,
  88. FUid,
  89. FGid,
  90. FSize,
  91. FMTime : LongInt;
  92. End;
  93. {******************************************************************************
  94. --- Info / Date / Time ---
  95. ******************************************************************************}
  96. Function DosVersion:Word;
  97. Var
  98. Buffer : Array[0..255] of AnsiChar;
  99. Tmp2,
  100. TmpStr : String[40];
  101. TmpPos,
  102. SubRel,
  103. Rel : LongInt;
  104. info : utsname;
  105. Begin
  106. FPUName(info);
  107. Move(info.release,buffer[0],40);
  108. TmpStr:=StrPas(Buffer);
  109. SubRel:=0;
  110. TmpPos:=Pos('.',TmpStr);
  111. if TmpPos>0 then
  112. begin
  113. Tmp2:=Copy(TmpStr,TmpPos+1,40);
  114. Delete(TmpStr,TmpPos,40);
  115. end;
  116. TmpPos:=Pos('.',Tmp2);
  117. if TmpPos>0 then
  118. Delete(Tmp2,TmpPos,40);
  119. Val(TmpStr,Rel);
  120. Val(Tmp2,SubRel);
  121. DosVersion:=Rel+(SubRel shl 8);
  122. End;
  123. function WeekDay (y,m,d:longint):longint;
  124. {
  125. Calculates th day of the week. returns -1 on error
  126. }
  127. var
  128. u,v : longint;
  129. begin
  130. if (m<1) or (m>12) or (y<1600) or (y>4000) or
  131. (d<1) or (d>30+((m+ord(m>7)) and 1)-ord(m=2)) or
  132. ((m*d=58) and (((y mod 4>0) or (y mod 100=0)) and (y mod 400>0))) then
  133. WeekDay:=-1
  134. else
  135. begin
  136. u:=m;
  137. v:=y;
  138. if m<3 then
  139. begin
  140. inc(u,12);
  141. dec(v);
  142. end;
  143. WeekDay:=(d+2*u+((3*(u+1)) div 5)+v+(v div 4)-(v div 100)+(v div 400)+1) mod 7;
  144. end;
  145. end;
  146. Procedure GetDate(Var Year, Month, MDay, WDay: Word);
  147. var
  148. tz:timeval;
  149. hour,min,sec : word;
  150. begin
  151. fpgettimeofday(@tz,nil);
  152. EpochToLocal(tz.tv_sec,year,month,mday,hour,min,sec);
  153. Wday:=weekday(Year,Month,MDay);
  154. end;
  155. procedure SetTime(Hour,Minute,Second,sec100:word);
  156. var
  157. dow,Year, Month, Day : Word;
  158. tv : timeval;
  159. begin
  160. GetDate (Year, Month, Day,dow);
  161. tv.tv_sec:= LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) ;
  162. tv.tv_usec:= Sec100 * 10000;
  163. fpSettimeofday(@tv,nil);
  164. end;
  165. procedure SetDate(Year,Month,Day:Word);
  166. var
  167. Hour, Min, Sec, Sec100 : Word;
  168. tv : timeval;
  169. begin
  170. GetTime ( Hour, Min, Sec, Sec100 );
  171. tv.tv_sec:= LocalToEpoch ( Year, Month, Day, Hour, Min, Sec ) ;
  172. tv.tv_usec:= Sec100 * 10000;
  173. fpSettimeofday(@tv,nil);
  174. end;
  175. Function SetDateTime(Year,Month,Day,hour,minute,second:Word) : Boolean;
  176. var
  177. tv : timeval;
  178. begin
  179. tv.tv_sec:= LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) ;
  180. tv.tv_usec:= 0;
  181. SetDatetime:=fpSettimeofday(@tv,nil)=0;
  182. end;
  183. Procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
  184. var
  185. tz:timeval;
  186. year,month,day : word;
  187. begin
  188. fpgettimeofday(@tz,nil);
  189. EpochToLocal(tz.tv_sec,year,month,day,hour,minute,second);
  190. sec100:=tz.tv_usec div 10000;
  191. end;
  192. Procedure UnixDateToDt(SecsPast: LongInt; Var Dt: DateTime);
  193. Begin
  194. EpochToLocal(SecsPast,dt.Year,dt.Month,dt.Day,dt.Hour,dt.Min,dt.Sec);
  195. End;
  196. Function DTToUnixDate(DT: DateTime): LongInt;
  197. Begin
  198. DTToUnixDate:=LocalToEpoch(dt.Year,dt.Month,dt.Day,dt.Hour,dt.Min,dt.Sec);
  199. End;
  200. function GetMsCount: int64;
  201. var
  202. tv : TimeVal;
  203. { tz : TimeZone;}
  204. begin
  205. FPGetTimeOfDay (@tv, nil {,tz});
  206. GetMsCount := int64(tv.tv_Sec) * 1000 + tv.tv_uSec div 1000;
  207. end;
  208. {******************************************************************************
  209. --- Exec ---
  210. ******************************************************************************}
  211. Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
  212. var
  213. pid : longint; // pid_t?
  214. cmdline2 : PPAnsiChar;
  215. commandline : RawByteString;
  216. realpath : ansistring;
  217. // The Error-Checking in the previous Version failed, since halt($7F) gives an WaitPid-status of $7F00
  218. Begin
  219. LastDosExitCode:=0;
  220. if Path='' then
  221. begin
  222. doserror:=2;
  223. exit;
  224. end;
  225. pid:=fpFork;
  226. if pid=0 then
  227. begin
  228. cmdline2:=nil;
  229. realpath:=path;
  230. if Comline<>'' Then
  231. begin
  232. CommandLine:=ToSingleByteFileSystemEncodedFileName(ComLine); // conversion must live till after fpexec!
  233. cmdline2:=StringtoPPChar(CommandLine,1);
  234. cmdline2^:=PAnsiChar(realPath);
  235. end
  236. else
  237. begin
  238. getmem(cmdline2,2*sizeof(PAnsiChar));
  239. cmdline2^:=PAnsiChar(realPath);
  240. cmdline2[1]:=nil;
  241. end;
  242. {The child does the actual exec, and then exits}
  243. fpExecv(PAnsiChar(realPath),cmdline2);
  244. {If the execve fails, we return an exitvalue of 127, to let it be known}
  245. fpExit(127);
  246. end
  247. else
  248. if pid=-1 then {Fork failed}
  249. begin
  250. DosError:=8;
  251. exit
  252. end;
  253. {We're in the parent, let's wait.}
  254. LastDosExitCode:=WaitProcess(pid); // WaitPid and result-convert
  255. if (LastDosExitCode>=0) and (LastDosExitCode<>127) then
  256. DosError:=0
  257. else
  258. DosError:=8; // perhaps one time give an better error
  259. End;
  260. {******************************************************************************
  261. --- Disk ---
  262. ******************************************************************************}
  263. {
  264. The Diskfree and Disksize functions need a file on the specified drive, since this
  265. is required for the fpstatfs system call.
  266. These filenames are set in drivestr[0..26], and have been preset to :
  267. 0 - '.' (default drive - hence current dir is ok.)
  268. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  269. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  270. 3 - '/' (C: equivalent of dos is the root partition)
  271. 4..26 (can be set by you're own applications)
  272. ! Use AddDisk() to Add new drives !
  273. They both return -1 when a failure occurs.
  274. }
  275. Const
  276. FixDriveStr : array[0..3] of PAnsiChar=(
  277. '.',
  278. '/fd0/.',
  279. '/fd1/.',
  280. '/.'
  281. );
  282. const
  283. Drives : byte = 4;
  284. var
  285. DriveStr : array[4..26] of PAnsiChar;
  286. Function AddDisk(const path:string) : byte;
  287. begin
  288. if not (DriveStr[Drives]=nil) then
  289. FreeMem(DriveStr[Drives]);
  290. GetMem(DriveStr[Drives],length(Path)+1);
  291. StrPCopy(DriveStr[Drives],path);
  292. AddDisk:=Drives;
  293. inc(Drives);
  294. if Drives>26 then
  295. Drives:=4;
  296. end;
  297. Function DiskFree(Drive: Byte): int64;
  298. var
  299. fs : tstatfs;
  300. Begin
  301. if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or
  302. ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then
  303. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  304. else
  305. Diskfree:=-1;
  306. End;
  307. Function DiskSize(Drive: Byte): int64;
  308. var
  309. fs : tstatfs;
  310. Begin
  311. if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (fpStatFS(fixdrivestr[drive],@fs)<>-1)) or
  312. ((not (drivestr[Drive]=nil)) and (fpStatFS(drivestr[drive],@fs)<>-1)) then
  313. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  314. else
  315. DiskSize:=-1;
  316. End;
  317. Procedure FreeDriveStr;
  318. var
  319. i: longint;
  320. begin
  321. for i:=low(drivestr) to high(drivestr) do
  322. if assigned(drivestr[i]) then
  323. begin
  324. freemem(drivestr[i]);
  325. drivestr[i]:=nil;
  326. end;
  327. end;
  328. {******************************************************************************
  329. --- Findfirst FindNext ---
  330. ******************************************************************************}
  331. Function FNMatch(const Pattern,Name:string):Boolean;
  332. Var
  333. LenPat,LenName : longint;
  334. Function DoFNMatch(i,j:longint):Boolean;
  335. Var
  336. Found : boolean;
  337. Begin
  338. Found:=true;
  339. While Found and (i<=LenPat) Do
  340. Begin
  341. Case Pattern[i] of
  342. '?' : Found:=(j<=LenName);
  343. '*' : Begin
  344. {find the next character in pattern, different of ? and *}
  345. while Found do
  346. begin
  347. inc(i);
  348. if i>LenPat then Break;
  349. case Pattern[i] of
  350. '*' : ;
  351. '?' : begin
  352. if j>LenName then begin DoFNMatch:=false; Exit; end;
  353. inc(j);
  354. end;
  355. else
  356. Found:=false;
  357. end;
  358. end;
  359. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  360. {Now, find in name the character which i points to, if the * or ?
  361. wasn't the last character in the pattern, else, use up all the
  362. chars in name}
  363. Found:=false;
  364. if (i<=LenPat) then
  365. begin
  366. repeat
  367. {find a letter (not only first !) which maches pattern[i]}
  368. while (j<=LenName) and (name[j]<>pattern[i]) do
  369. inc (j);
  370. if (j<LenName) then
  371. begin
  372. if DoFnMatch(i+1,j+1) then
  373. begin
  374. i:=LenPat;
  375. j:=LenName;{we can stop}
  376. Found:=true;
  377. Break;
  378. end else
  379. inc(j);{We didn't find one, need to look further}
  380. end else
  381. if j=LenName then
  382. begin
  383. Found:=true;
  384. Break;
  385. end;
  386. { This 'until' condition must be j>LenName, not j>=LenName.
  387. That's because when we 'need to look further' and
  388. j = LenName then loop must not terminate. }
  389. until (j>LenName);
  390. end else
  391. begin
  392. j:=LenName;{we can stop}
  393. Found:=true;
  394. end;
  395. end;
  396. else {not a wildcard character in pattern}
  397. Found:=(j<=LenName) and (pattern[i]=name[j]);
  398. end;
  399. inc(i);
  400. inc(j);
  401. end;
  402. DoFnMatch:=Found and (j>LenName);
  403. end;
  404. Begin {start FNMatch}
  405. LenPat:=Length(Pattern);
  406. LenName:=Length(Name);
  407. FNMatch:=DoFNMatch(1,1);
  408. End;
  409. Const
  410. RtlFindSize = 15;
  411. Type
  412. RtlFindRecType = Record
  413. DirPtr : Pointer;
  414. SearchNum,
  415. LastUsed : LongInt;
  416. End;
  417. Var
  418. RtlFindRecs : Array[1..RtlFindSize] of RtlFindRecType;
  419. CurrSearchNum : LongInt;
  420. Procedure FindClose(Var f: SearchRec);
  421. {
  422. Closes dirptr if it is open
  423. }
  424. Var
  425. i : longint;
  426. Begin
  427. if f.SearchType=0 then
  428. begin
  429. i:=1;
  430. repeat
  431. if (RtlFindRecs[i].SearchNum=f.SearchNum) then
  432. break;
  433. inc(i);
  434. until (i>RtlFindSize);
  435. If i<=RtlFindSize Then
  436. Begin
  437. RtlFindRecs[i].SearchNum:=0;
  438. if f.dirptr<>nil then
  439. fpclosedir(pdir(f.dirptr)^);
  440. End;
  441. end;
  442. f.dirptr:=nil;
  443. End;
  444. Function FindGetFileInfo(const s:string;var f:SearchRec):boolean;
  445. var
  446. DT : DateTime;
  447. Info : RtlInfoType;
  448. st : BU.stat;
  449. begin
  450. FindGetFileInfo:=false;
  451. if not fpstat(s,st)>=0 then
  452. exit;
  453. info.FSize:=st.st_Size;
  454. info.FMTime:=st.st_mtime;
  455. if (st.st_mode and STAT_IFMT)=STAT_IFDIR then
  456. info.fmode:=$10
  457. else
  458. info.fmode:=$0;
  459. if (st.st_mode and STAT_IWUSR)=0 then
  460. info.fmode:=info.fmode or 1;
  461. if s[f.NamePos+1]='.' then
  462. info.fmode:=info.fmode or $2;
  463. If ((Info.FMode and Not(f.searchattr))=0) Then
  464. Begin
  465. f.Name:=Copy(s,f.NamePos+1,255);
  466. f.Attr:=Info.FMode;
  467. f.Size:=Info.FSize;
  468. f.mode:=st.st_mode;
  469. UnixDateToDT(Info.FMTime, DT);
  470. PackTime(DT,f.Time);
  471. FindGetFileInfo:=true;
  472. End;
  473. end;
  474. Function FindLastUsed: Longint;
  475. {
  476. Find unused or least recently used dirpointer slot in findrecs array
  477. }
  478. Var
  479. BestMatch,i : Longint;
  480. Found : Boolean;
  481. Begin
  482. BestMatch:=1;
  483. i:=1;
  484. Found:=False;
  485. While (i <= RtlFindSize) And (Not Found) Do
  486. Begin
  487. If (RtlFindRecs[i].SearchNum = 0) Then
  488. Begin
  489. BestMatch := i;
  490. Found := True;
  491. End
  492. Else
  493. Begin
  494. If RtlFindRecs[i].LastUsed > RtlFindRecs[BestMatch].LastUsed Then
  495. BestMatch := i;
  496. End;
  497. Inc(i);
  498. End;
  499. FindLastUsed := BestMatch;
  500. End;
  501. Procedure FindNext(Var f: SearchRec);
  502. {
  503. re-opens dir if not already in array and calls FindWorkProc
  504. }
  505. Var
  506. DirName : Array[0..256] of AnsiChar;
  507. i,
  508. ArrayPos : Longint;
  509. FName,
  510. SName : string;
  511. Found,
  512. Finished : boolean;
  513. p : pdirent;
  514. Begin
  515. If f.SearchType=0 Then
  516. Begin
  517. ArrayPos:=0;
  518. For i:=1 to RtlFindSize Do
  519. Begin
  520. If RtlFindRecs[i].SearchNum = f.SearchNum Then
  521. ArrayPos:=i;
  522. Inc(RtlFindRecs[i].LastUsed);
  523. End;
  524. If ArrayPos=0 Then
  525. Begin
  526. If f.NamePos = 0 Then
  527. Begin
  528. DirName[0] := '.';
  529. DirName[1] := '/';
  530. DirName[2] := #0;
  531. End
  532. Else
  533. Begin
  534. Move(f.SearchSpec[1], DirName[0], f.NamePos);
  535. DirName[f.NamePos] := #0;
  536. End;
  537. f.DirPtr := fpopendir(@DirName[0]);
  538. If f.DirPtr <> nil Then
  539. begin
  540. ArrayPos:=FindLastUsed;
  541. If RtlFindRecs[ArrayPos].SearchNum > 0 Then
  542. FpCloseDir((pdir(rtlfindrecs[arraypos].dirptr)^));
  543. RtlFindRecs[ArrayPos].SearchNum := f.SearchNum;
  544. RtlFindRecs[ArrayPos].DirPtr := f.DirPtr;
  545. if f.searchpos>0 then
  546. seekdir(pdir(f.dirptr), f.searchpos);
  547. end;
  548. End;
  549. if ArrayPos>0 then
  550. RtlFindRecs[ArrayPos].LastUsed:=0;
  551. end;
  552. {Main loop}
  553. SName:=Copy(f.SearchSpec,f.NamePos+1,255);
  554. Found:=False;
  555. Finished:=(f.dirptr=nil);
  556. While Not Finished Do
  557. Begin
  558. p:=fpreaddir(pdir(f.dirptr)^);
  559. if p=nil then
  560. FName:=''
  561. else
  562. FName:=Strpas(@p^.d_name[0]);
  563. If FName='' Then
  564. Finished:=True
  565. Else
  566. Begin
  567. If FNMatch(SName,FName) Then
  568. Begin
  569. Found:=FindGetFileInfo(Copy(f.SearchSpec,1,f.NamePos)+FName,f);
  570. if Found then
  571. Finished:=true;
  572. End;
  573. End;
  574. End;
  575. {Shutdown}
  576. If Found Then
  577. Begin
  578. f.searchpos:=telldir(pdir(f.dirptr));
  579. DosError:=0;
  580. End
  581. Else
  582. Begin
  583. FindClose(f);
  584. DosError:=18;
  585. End;
  586. End;
  587. Procedure FindFirst(Const Path: PathStr; Attr: Word; Var f: SearchRec);
  588. {
  589. opens dir and calls FindWorkProc
  590. }
  591. Begin
  592. fillchar(f,sizeof(f),0);
  593. if Path='' then
  594. begin
  595. DosError:=3;
  596. exit;
  597. end;
  598. {Create Info}
  599. f.SearchSpec := Path;
  600. {We always also search for readonly and archive, regardless of Attr:}
  601. f.SearchAttr := Attr or archive or readonly;
  602. f.SearchPos := 0;
  603. f.NamePos := Length(f.SearchSpec);
  604. while (f.NamePos>0) and (f.SearchSpec[f.NamePos]<>'/') do
  605. dec(f.NamePos);
  606. {Wildcards?}
  607. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  608. begin
  609. if FindGetFileInfo(Path,f) then
  610. DosError:=0
  611. else
  612. begin
  613. { According to tdos2 test it should return 18
  614. if ErrNo=Sys_ENOENT then
  615. DosError:=3
  616. else }
  617. DosError:=18;
  618. end;
  619. f.DirPtr:=nil;
  620. f.SearchType:=1;
  621. f.searchnum:=-1;
  622. end
  623. else
  624. {Find Entry}
  625. begin
  626. Inc(CurrSearchNum);
  627. f.SearchNum:=CurrSearchNum;
  628. f.SearchType:=0;
  629. FindNext(f);
  630. end;
  631. End;
  632. {******************************************************************************
  633. --- File ---
  634. ******************************************************************************}
  635. Function FSearch(path : pathstr;dirlist : shortstring) : pathstr;
  636. Var
  637. info : BU.stat;
  638. Begin
  639. if (length(Path)>0) and (path[1]='/') and (fpStat(path,info)>=0) and (not fpS_ISDIR(Info.st_Mode)) then
  640. FSearch:=path
  641. else
  642. FSearch:=UA.FSearch(path,dirlist);
  643. End;
  644. Procedure GetFAttr(var f; var attr : word);
  645. Var
  646. info : BU.stat;
  647. LinAttr : longint;
  648. p : PAnsiChar;
  649. {$ifndef FPC_ANSI_TEXTFILEREC}
  650. r : RawByteString;
  651. {$endif not FPC_ANSI_TEXTFILEREC}
  652. Begin
  653. DosError:=0;
  654. {$ifdef FPC_ANSI_TEXTFILEREC}
  655. { encoding is already correct }
  656. p:=@textrec(f).name;
  657. {$else}
  658. r:=ToSingleByteFileSystemEncodedFileName(textrec(f).name);
  659. p:=PAnsiChar(r);
  660. {$endif}
  661. { use the PAnsiChar rather than the rawbytestring version so that we don't check
  662. a second time whether the string needs to be converted to the right code
  663. page
  664. }
  665. if FPStat(p,info)<0 then
  666. begin
  667. Attr:=0;
  668. DosError:=3;
  669. exit;
  670. end
  671. else
  672. LinAttr:=Info.st_Mode;
  673. if fpS_ISDIR(LinAttr) then
  674. Attr:=$10
  675. else
  676. Attr:=$0;
  677. if fpAccess(p,W_OK)<0 then
  678. Attr:=Attr or $1;
  679. if filerec(f).name[0]='.' then
  680. Attr:=Attr or $2;
  681. end;
  682. Procedure getftime (var f; var time : longint);
  683. Var
  684. Info: BU.stat;
  685. DT: DateTime;
  686. Begin
  687. doserror:=0;
  688. if fpfstat(filerec(f).handle,info)<0 then
  689. begin
  690. Time:=0;
  691. doserror:=6;
  692. exit
  693. end
  694. else
  695. UnixDateToDT(Info.st_mTime,DT);
  696. PackTime(DT,Time);
  697. End;
  698. Procedure setftime(var f; time : longint);
  699. Var
  700. utim: utimbuf;
  701. DT: DateTime;
  702. p : PAnsiChar;
  703. {$ifndef FPC_ANSI_TEXTFILEREC}
  704. r : Rawbytestring;
  705. {$endif not FPC_ANSI_TEXTFILEREC}
  706. Begin
  707. doserror:=0;
  708. with utim do
  709. begin
  710. actime:=fptime;
  711. UnPackTime(Time,DT);
  712. modtime:=DTToUnixDate(DT);
  713. end;
  714. {$ifdef FPC_ANSI_TEXTFILEREC}
  715. { encoding is already correct }
  716. p:=@textrec(f).name;
  717. {$else}
  718. r:=ToSingleByteFileSystemEncodedFileName(textrec(f).name);
  719. p:=PAnsiChar(r);
  720. {$endif}
  721. { use the PAnsiChar rather than the rawbytestring version so that we don't check
  722. a second time whether the string needs to be converted to the right code
  723. page
  724. }
  725. if fputime(p,@utim)<0 then
  726. begin
  727. Time:=0;
  728. doserror:=3;
  729. end;
  730. End;
  731. {******************************************************************************
  732. --- Environment ---
  733. ******************************************************************************}
  734. Function EnvCount: Longint;
  735. var
  736. envcnt : longint;
  737. p : PPAnsiChar;
  738. Begin
  739. envcnt:=0;
  740. p:=envp; {defined in system unit}
  741. while (p^<>nil) do
  742. begin
  743. inc(envcnt);
  744. inc(p);
  745. end;
  746. EnvCount := envcnt
  747. End;
  748. Function EnvStr (Index: longint): ShortString;
  749. Var
  750. i : longint;
  751. p : PPAnsiChar;
  752. Begin
  753. if Index <= 0 then
  754. envstr:=''
  755. else
  756. begin
  757. p:=envp; {defined in system unit}
  758. i:=1;
  759. while (i<Index) and (p^<>nil) do
  760. begin
  761. inc(i);
  762. inc(p);
  763. end;
  764. if p=nil then
  765. envstr:=''
  766. else
  767. envstr:=strpas(p^)
  768. end;
  769. end;
  770. Function GetEnv(EnvVar: ShortString): ShortString;
  771. var
  772. p : PAnsiChar;
  773. Begin
  774. p:=BU.fpGetEnv(EnvVar);
  775. if p=nil then
  776. GetEnv:=''
  777. else
  778. GetEnv:=StrPas(p);
  779. End;
  780. Procedure setfattr (var f;attr : word);
  781. Begin
  782. {! No Unix equivalent !}
  783. { Fail for setting VolumeId }
  784. if (attr and VolumeID)<>0 then
  785. doserror:=5;
  786. End;
  787. {******************************************************************************
  788. --- Initialization ---
  789. ******************************************************************************}
  790. Finalization
  791. FreeDriveStr;
  792. End.