sysutils.pp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Sysutils unit for linux
  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. { force ansistrings }
  16. {$H+}
  17. {$if (defined(BSD) or defined(SUNOS)) and defined(FPC_USE_LIBC)}
  18. {$define USE_VFORK}
  19. {$endif}
  20. {$DEFINE OS_FILESETDATEBYNAME}
  21. {$DEFINE HAS_SLEEP}
  22. {$DEFINE HAS_OSERROR}
  23. {$DEFINE HAS_OSCONFIG}
  24. {$DEFINE HAS_TEMPDIR}
  25. {$DEFINE HASUNIX}
  26. {$DEFINE HASCREATEGUID}
  27. {$DEFINE HAS_OSUSERDIR}
  28. uses
  29. Unix,errors,sysconst,Unixtype;
  30. { Include platform independent interface part }
  31. {$i sysutilh.inc}
  32. Function AddDisk(const path:string) : Byte;
  33. { the following is Kylix compatibility stuff, it should be moved to a
  34. special compatibilty unit (FK) }
  35. const
  36. RTL_SIGINT = 0;
  37. RTL_SIGFPE = 1;
  38. RTL_SIGSEGV = 2;
  39. RTL_SIGILL = 3;
  40. RTL_SIGBUS = 4;
  41. RTL_SIGQUIT = 5;
  42. RTL_SIGLAST = RTL_SIGQUIT;
  43. RTL_SIGDEFAULT = -1;
  44. type
  45. TSignalState = (ssNotHooked, ssHooked, ssOverridden);
  46. function InquireSignal(RtlSigNum: Integer): TSignalState;
  47. procedure AbandonSignalHandler(RtlSigNum: Integer);
  48. procedure HookSignal(RtlSigNum: Integer);
  49. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  50. implementation
  51. Uses
  52. {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix, unixutil;
  53. function InquireSignal(RtlSigNum: Integer): TSignalState;
  54. begin
  55. end;
  56. procedure AbandonSignalHandler(RtlSigNum: Integer);
  57. begin
  58. end;
  59. procedure HookSignal(RtlSigNum: Integer);
  60. begin
  61. end;
  62. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  63. begin
  64. end;
  65. {$Define OS_FILEISREADONLY} // Specific implementation for Unix.
  66. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  67. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  68. { Include platform independent implementation part }
  69. {$i sysutils.inc}
  70. { Include SysCreateGUID function }
  71. {$i suuid.inc}
  72. Const
  73. {Date Translation}
  74. C1970=2440588;
  75. D0 = 1461;
  76. D1 = 146097;
  77. D2 =1721119;
  78. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  79. Var
  80. YYear,XYear,Temp,TempMonth : LongInt;
  81. Begin
  82. Temp:=((JulianDN-D2) shl 2)-1;
  83. JulianDN:=Temp Div D1;
  84. XYear:=(Temp Mod D1) or 3;
  85. YYear:=(XYear Div D0);
  86. Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
  87. Day:=((Temp Mod 153)+5) Div 5;
  88. TempMonth:=Temp Div 153;
  89. If TempMonth>=10 Then
  90. Begin
  91. inc(YYear);
  92. dec(TempMonth,12);
  93. End;
  94. inc(TempMonth,3);
  95. Month := TempMonth;
  96. Year:=YYear+(JulianDN*100);
  97. end;
  98. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  99. {
  100. Transforms Epoch time into local time (hour, minute,seconds)
  101. }
  102. Var
  103. DateNum: LongInt;
  104. Begin
  105. inc(Epoch,TZSeconds);
  106. Datenum:=(Epoch Div 86400) + c1970;
  107. JulianToGregorian(DateNum,Year,Month,day);
  108. Epoch:=Abs(Epoch Mod 86400);
  109. Hour:=Epoch Div 3600;
  110. Epoch:=Epoch Mod 3600;
  111. Minute:=Epoch Div 60;
  112. Second:=Epoch Mod 60;
  113. End;
  114. {****************************************************************************
  115. File Functions
  116. ****************************************************************************}
  117. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  118. Var
  119. DotPos,SlashPos,i : longint;
  120. Begin
  121. SlashPos:=0;
  122. DotPos:=256;
  123. i:=Length(Path);
  124. While (i>0) and (SlashPos=0) Do
  125. Begin
  126. If (DotPos=256) and (Path[i]='.') Then
  127. begin
  128. DotPos:=i;
  129. end;
  130. If (Path[i]='/') Then
  131. SlashPos:=i;
  132. Dec(i);
  133. End;
  134. Ext:=Copy(Path,DotPos,255);
  135. Dir:=Copy(Path,1,SlashPos);
  136. Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
  137. End;
  138. Function DoFileLocking(Handle: Longint; Mode: Integer) : Longint;
  139. var
  140. lockop: cint;
  141. lockres: cint;
  142. closeres: cint;
  143. begin
  144. DoFileLocking:=Handle;
  145. {$ifdef beos}
  146. {$else}
  147. if (Handle>=0) then
  148. begin
  149. {$ifdef solaris}
  150. { Solaris' flock is based on top of fcntl, which does not allow
  151. exclusive locks for files only opened for reading nor shared
  152. locks for files opened only for writing.
  153. If no locking is specified, we normally need an exclusive lock.
  154. So create an exclusive lock for fmOpenWrite and fmOpenReadWrite,
  155. but only a shared lock for fmOpenRead (since an exclusive lock
  156. is not possible in that case)
  157. }
  158. if ((mode and (fmShareCompat or fmShareExclusive or fmShareDenyWrite or fmShareDenyRead or fmShareDenyNone)) = 0) then
  159. begin
  160. if ((mode and (fmOpenRead or fmOpenWrite or fmOpenReadWrite)) = fmOpenRead) then
  161. mode := mode or fmShareDenyWrite
  162. else
  163. mode := mode or fmShareExclusive;
  164. end;
  165. {$endif solaris}
  166. case (mode and (fmShareCompat or fmShareExclusive or fmShareDenyWrite or fmShareDenyRead or fmShareDenyNone)) of
  167. fmShareCompat,
  168. fmShareExclusive:
  169. lockop:=LOCK_EX or LOCK_NB;
  170. fmShareDenyWrite:
  171. lockop:=LOCK_SH or LOCK_NB;
  172. fmShareDenyNone:
  173. exit;
  174. else
  175. begin
  176. { fmShareDenyRead does not exit under *nix, only shared access
  177. (similar to fmShareDenyWrite) and exclusive access (same as
  178. fmShareExclusive)
  179. }
  180. repeat
  181. closeres:=FpClose(Handle);
  182. until (closeres<>-1) or (fpgeterrno<>ESysEINTR);
  183. DoFileLocking:=-1;
  184. exit;
  185. end;
  186. end;
  187. repeat
  188. lockres:=fpflock(Handle,lockop);
  189. until (lockres=0) or
  190. (fpgeterrno<>ESysEIntr);
  191. if (lockres<>0) then
  192. begin
  193. repeat
  194. closeres:=FpClose(Handle);
  195. until (closeres<>-1) or (fpgeterrno<>ESysEINTR);
  196. DoFileLocking:=-1;
  197. exit;
  198. end;
  199. end;
  200. {$endif not beos}
  201. end;
  202. Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
  203. Var
  204. LinuxFlags : longint;
  205. begin
  206. LinuxFlags:=0;
  207. case (Mode and (fmOpenRead or fmOpenWrite or fmOpenReadWrite)) of
  208. fmOpenRead : LinuxFlags:=LinuxFlags or O_RdOnly;
  209. fmOpenWrite : LinuxFlags:=LinuxFlags or O_WrOnly;
  210. fmOpenReadWrite : LinuxFlags:=LinuxFlags or O_RdWr;
  211. end;
  212. repeat
  213. FileOpen:=fpOpen (pointer(FileName),LinuxFlags);
  214. until (FileOpen<>-1) or (fpgeterrno<>ESysEINTR);
  215. FileOpen:=DoFileLocking(FileOpen, Mode);
  216. end;
  217. Function FileCreate (Const FileName : String) : Longint;
  218. begin
  219. repeat
  220. FileCreate:=fpOpen(pointer(FileName),O_RdWr or O_Creat or O_Trunc);
  221. until (FileCreate<>-1) or (fpgeterrno<>ESysEINTR);
  222. end;
  223. Function FileCreate (Const FileName : String;Mode : Longint) : Longint;
  224. begin
  225. repeat
  226. FileCreate:=fpOpen(pointer(FileName),O_RdWr or O_Creat or O_Trunc,Mode);
  227. until (FileCreate<>-1) or (fpgeterrno<>ESysEINTR);
  228. end;
  229. Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
  230. begin
  231. repeat
  232. FileRead:=fpRead (Handle,Buffer,Count);
  233. until (FileRead<>-1) or (fpgeterrno<>ESysEINTR);
  234. end;
  235. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  236. begin
  237. repeat
  238. FileWrite:=fpWrite (Handle,Buffer,Count);
  239. until (FileWrite<>-1) or (fpgeterrno<>ESysEINTR);
  240. end;
  241. Function FileSeek (Handle,FOffset,Origin : Longint) : Longint;
  242. begin
  243. result:=longint(FileSeek(Handle,int64(FOffset),Origin));
  244. end;
  245. Function FileSeek (Handle : Longint; FOffset : Int64; Origin : Longint) : Int64;
  246. begin
  247. FileSeek:=fplSeek (Handle,FOffset,Origin);
  248. end;
  249. Procedure FileClose (Handle : Longint);
  250. var
  251. res: cint;
  252. begin
  253. repeat
  254. res:=fpclose(Handle);
  255. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  256. end;
  257. Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
  258. var
  259. res: cint;
  260. begin
  261. if (SizeOf (TOff) < 8) (* fpFTruncate only supporting signed 32-bit size *)
  262. and (Size > high (longint)) then
  263. FileTruncate := false
  264. else
  265. begin
  266. repeat
  267. res:=fpftruncate(Handle,Size);
  268. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  269. FileTruncate:=res>=0;
  270. end;
  271. end;
  272. {$ifndef FPUNONE}
  273. Function UnixToWinAge(UnixAge : time_t): Longint;
  274. Var
  275. Y,M,D,hh,mm,ss : word;
  276. begin
  277. EpochToLocal(UnixAge,y,m,d,hh,mm,ss);
  278. Result:=DateTimeToFileDate(EncodeDate(y,m,d)+EncodeTime(hh,mm,ss,0));
  279. end;
  280. Function FileAge (Const FileName : String): Longint;
  281. Var Info : Stat;
  282. begin
  283. If fpstat (pointer(FileName),Info)<0 then
  284. exit(-1)
  285. else
  286. Result:=UnixToWinAge(info.st_mtime);
  287. end;
  288. {$endif}
  289. Function FileExists (Const FileName : String) : Boolean;
  290. begin
  291. // Don't use stat. It fails on files >2 GB.
  292. // Access obeys the same access rules, so the result should be the same.
  293. FileExists:=fpAccess(pointer(filename),F_OK)=0;
  294. end;
  295. Function DirectoryExists (Const Directory : String) : Boolean;
  296. Var Info : Stat;
  297. begin
  298. DirectoryExists:=(fpstat(pointer(Directory),Info)>=0) and fpS_ISDIR(Info.st_mode);
  299. end;
  300. Function LinuxToWinAttr (FN : Pchar; Const Info : Stat) : Longint;
  301. Var
  302. FNL : String;
  303. LinkInfo : Stat;
  304. begin
  305. Result:=faArchive;
  306. If fpS_ISDIR(Info.st_mode) then
  307. Result:=Result or faDirectory;
  308. If (FN[0]='.') and (not (FN[1] in [#0,'.'])) then
  309. Result:=Result or faHidden;
  310. If (Info.st_Mode and S_IWUSR)=0 Then
  311. Result:=Result or faReadOnly;
  312. If fpS_ISSOCK(Info.st_mode) or fpS_ISBLK(Info.st_mode) or fpS_ISCHR(Info.st_mode) or fpS_ISFIFO(Info.st_mode) Then
  313. Result:=Result or faSysFile;
  314. If fpS_ISLNK(Info.st_mode) Then
  315. begin
  316. Result:=Result or faSymLink;
  317. // Windows reports if the link points to a directory.
  318. FNL:=StrPas(FN);
  319. if (fpstat(FNL,LinkInfo)>=0) and fpS_ISDIR(LinkInfo.st_mode) then
  320. Result := Result or faDirectory;
  321. end;
  322. end;
  323. Function FNMatch(const Pattern,Name:string):Boolean;
  324. Var
  325. LenPat,LenName : longint;
  326. Function DoFNMatch(i,j:longint):Boolean;
  327. Var
  328. Found : boolean;
  329. Begin
  330. Found:=true;
  331. While Found and (i<=LenPat) Do
  332. Begin
  333. Case Pattern[i] of
  334. '?' : Found:=(j<=LenName);
  335. '*' : Begin
  336. {find the next character in pattern, different of ? and *}
  337. while Found do
  338. begin
  339. inc(i);
  340. if i>LenPat then Break;
  341. case Pattern[i] of
  342. '*' : ;
  343. '?' : begin
  344. if j>LenName then begin DoFNMatch:=false; Exit; end;
  345. inc(j);
  346. end;
  347. else
  348. Found:=false;
  349. end;
  350. end;
  351. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  352. {Now, find in name the character which i points to, if the * or ?
  353. wasn't the last character in the pattern, else, use up all the
  354. chars in name}
  355. Found:=false;
  356. if (i<=LenPat) then
  357. begin
  358. repeat
  359. {find a letter (not only first !) which maches pattern[i]}
  360. while (j<=LenName) and (name[j]<>pattern[i]) do
  361. inc (j);
  362. if (j<LenName) then
  363. begin
  364. if DoFnMatch(i+1,j+1) then
  365. begin
  366. i:=LenPat;
  367. j:=LenName;{we can stop}
  368. Found:=true;
  369. Break;
  370. end else
  371. inc(j);{We didn't find one, need to look further}
  372. end else
  373. if j=LenName then
  374. begin
  375. Found:=true;
  376. Break;
  377. end;
  378. { This 'until' condition must be j>LenName, not j>=LenName.
  379. That's because when we 'need to look further' and
  380. j = LenName then loop must not terminate. }
  381. until (j>LenName);
  382. end else
  383. begin
  384. j:=LenName;{we can stop}
  385. Found:=true;
  386. end;
  387. end;
  388. else {not a wildcard character in pattern}
  389. Found:=(j<=LenName) and (pattern[i]=name[j]);
  390. end;
  391. inc(i);
  392. inc(j);
  393. end;
  394. DoFnMatch:=Found and (j>LenName);
  395. end;
  396. Begin {start FNMatch}
  397. LenPat:=Length(Pattern);
  398. LenName:=Length(Name);
  399. FNMatch:=DoFNMatch(1,1);
  400. End;
  401. Type
  402. TUnixFindData = Record
  403. NamePos : LongInt; {to track which search this is}
  404. DirPtr : Pointer; {directory pointer for reading directory}
  405. SearchSpec : String;
  406. SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file}
  407. SearchAttr : Byte; {attribute we are searching for}
  408. End;
  409. PUnixFindData = ^TUnixFindData;
  410. Var
  411. CurrSearchNum : LongInt;
  412. Procedure FindClose(Var f: TSearchRec);
  413. var
  414. UnixFindData : PUnixFindData;
  415. Begin
  416. UnixFindData:=PUnixFindData(f.FindHandle);
  417. if UnixFindData^.SearchType=0 then
  418. begin
  419. if UnixFindData^.dirptr<>nil then
  420. fpclosedir(pdir(UnixFindData^.dirptr)^);
  421. end;
  422. Dispose(UnixFindData);
  423. f.FindHandle:=nil;
  424. End;
  425. Function FindGetFileInfo(const s:string;var f:TSearchRec):boolean;
  426. var
  427. st : baseunix.stat;
  428. WinAttr : longint;
  429. ResolvedPath : string;
  430. LinkLen : ssize_t;
  431. begin
  432. FindGetFileInfo:=false;
  433. If Assigned(F.FindHandle) and ((((PUnixFindData(f.FindHandle)^.searchattr)) and faSymlink) > 0) then
  434. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  435. else
  436. FindGetFileInfo:=(fpstat(pointer(s),st)=0);
  437. If not FindGetFileInfo then
  438. exit;
  439. WinAttr:=LinuxToWinAttr(PChar(pointer(s)),st);
  440. If ((WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0) Then
  441. Begin
  442. f.Name:=ExtractFileName(s);
  443. f.Attr:=WinAttr;
  444. f.Size:=st.st_Size;
  445. f.Mode:=st.st_mode;
  446. {$ifndef FPUNONE}
  447. f.Time:=UnixToWinAge(st.st_mtime);
  448. {$endif}
  449. FindGetFileInfo:=true;
  450. End
  451. else
  452. FindGetFileInfo:=false;
  453. end;
  454. Function FindNext (Var Rslt : TSearchRec) : Longint;
  455. {
  456. re-opens dir if not already in array and calls FindGetFileInfo
  457. }
  458. Var
  459. DirName : String;
  460. FName,
  461. SName : string;
  462. Found,
  463. Finished : boolean;
  464. p : pdirent;
  465. UnixFindData : PUnixFindData;
  466. Begin
  467. Result:=-1;
  468. UnixFindData:=PUnixFindData(Rslt.FindHandle);
  469. { SearchSpec='' means that there were no wild cards, so only one file to
  470. find.
  471. }
  472. if UnixFindData^.SearchSpec='' then
  473. exit;
  474. if (UnixFindData^.SearchType=0) and
  475. (UnixFindData^.Dirptr=nil) then
  476. begin
  477. If UnixFindData^.NamePos = 0 Then
  478. DirName:='./'
  479. Else
  480. DirName:=Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos);
  481. UnixFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  482. end;
  483. SName:=Copy(UnixFindData^.SearchSpec,UnixFindData^.NamePos+1,Length(UnixFindData^.SearchSpec));
  484. Found:=False;
  485. Finished:=(UnixFindData^.dirptr=nil);
  486. While Not Finished Do
  487. Begin
  488. p:=fpreaddir(pdir(UnixFindData^.dirptr)^);
  489. if p=nil then
  490. FName:=''
  491. else
  492. FName:=p^.d_name;
  493. If FName='' Then
  494. Finished:=True
  495. Else
  496. Begin
  497. If FNMatch(SName,FName) Then
  498. Begin
  499. Found:=FindGetFileInfo(Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos)+FName,Rslt);
  500. if Found then
  501. begin
  502. Result:=0;
  503. exit;
  504. end;
  505. End;
  506. End;
  507. End;
  508. End;
  509. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  510. {
  511. opens dir and calls FindNext if needed.
  512. }
  513. var
  514. UnixFindData : PUnixFindData;
  515. Begin
  516. Result:=-1;
  517. fillchar(Rslt,sizeof(Rslt),0);
  518. if Path='' then
  519. exit;
  520. { Allocate UnixFindData (we always need it, for the search attributes) }
  521. New(UnixFindData);
  522. FillChar(UnixFindData^,sizeof(UnixFindData^),0);
  523. Rslt.FindHandle:=UnixFindData;
  524. {We always also search for readonly and archive, regardless of Attr:}
  525. UnixFindData^.SearchAttr := Attr or faarchive or fareadonly;
  526. {Wildcards?}
  527. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  528. begin
  529. if FindGetFileInfo(Path,Rslt) then
  530. Result:=0;
  531. end
  532. else
  533. begin
  534. {Create Info}
  535. UnixFindData^.SearchSpec := Path;
  536. UnixFindData^.NamePos := Length(UnixFindData^.SearchSpec);
  537. while (UnixFindData^.NamePos>0) and (UnixFindData^.SearchSpec[UnixFindData^.NamePos]<>'/') do
  538. dec(UnixFindData^.NamePos);
  539. Result:=FindNext(Rslt);
  540. end;
  541. End;
  542. Function FileGetDate (Handle : Longint) : Longint;
  543. Var Info : Stat;
  544. begin
  545. If (fpFStat(Handle,Info))<0 then
  546. Result:=-1
  547. else
  548. Result:=Info.st_Mtime;
  549. end;
  550. Function FileSetDate (Handle,Age : Longint) : Longint;
  551. begin
  552. // Impossible under Linux from FileHandle !!
  553. FileSetDate:=-1;
  554. end;
  555. Function FileGetAttr (Const FileName : String) : Longint;
  556. Var Info : Stat;
  557. begin
  558. If FpStat (pointer(FileName),Info)<0 then
  559. Result:=-1
  560. Else
  561. Result:=LinuxToWinAttr(Pchar(ExtractFileName(FileName)),Info);
  562. end;
  563. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  564. begin
  565. Result:=-1;
  566. end;
  567. Function DeleteFile (Const FileName : String) : Boolean;
  568. begin
  569. Result:=fpUnLink (pointer(FileName))>=0;
  570. end;
  571. Function RenameFile (Const OldName, NewName : String) : Boolean;
  572. begin
  573. RenameFile:=BaseUnix.FpRename(pointer(OldNAme),pointer(NewName))>=0;
  574. end;
  575. Function FileIsReadOnly(const FileName: String): Boolean;
  576. begin
  577. Result := fpAccess(PChar(pointer(FileName)),W_OK)<>0;
  578. end;
  579. Function FileSetDate (Const FileName : String;Age : Longint) : Longint;
  580. var
  581. t: TUTimBuf;
  582. begin
  583. Result := 0;
  584. t.actime := Age;
  585. t.modtime := Age;
  586. if fputime(PChar(pointer(FileName)), @t) = -1 then
  587. Result := fpgeterrno;
  588. end;
  589. {****************************************************************************
  590. Disk Functions
  591. ****************************************************************************}
  592. {
  593. The Diskfree and Disksize functions need a file on the specified drive, since this
  594. is required for the statfs system call.
  595. These filenames are set in drivestr[0..26], and have been preset to :
  596. 0 - '.' (default drive - hence current dir is ok.)
  597. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  598. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  599. 3 - '/' (C: equivalent of dos is the root partition)
  600. 4..26 (can be set by you're own applications)
  601. ! Use AddDisk() to Add new drives !
  602. They both return -1 when a failure occurs.
  603. }
  604. Const
  605. FixDriveStr : array[0..3] of pchar=(
  606. '.',
  607. '/fd0/.',
  608. '/fd1/.',
  609. '/.'
  610. );
  611. var
  612. Drives : byte = 4;
  613. DriveStr : array[4..26] of pchar;
  614. Function AddDisk(const path:string) : Byte;
  615. begin
  616. if not (DriveStr[Drives]=nil) then
  617. FreeMem(DriveStr[Drives]);
  618. GetMem(DriveStr[Drives],length(Path)+1);
  619. StrPCopy(DriveStr[Drives],path);
  620. Result:=Drives;
  621. inc(Drives);
  622. if Drives>26 then
  623. Drives:=4;
  624. end;
  625. Function DiskFree(Drive: Byte): int64;
  626. var
  627. fs : tstatfs;
  628. Begin
  629. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
  630. ((Drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
  631. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  632. else
  633. Diskfree:=-1;
  634. End;
  635. Function DiskSize(Drive: Byte): int64;
  636. var
  637. fs : tstatfs;
  638. Begin
  639. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
  640. ((drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
  641. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  642. else
  643. DiskSize:=-1;
  644. End;
  645. Procedure FreeDriveStr;
  646. var
  647. i: longint;
  648. begin
  649. for i:=low(drivestr) to high(drivestr) do
  650. if assigned(drivestr[i]) then
  651. begin
  652. freemem(drivestr[i]);
  653. drivestr[i]:=nil;
  654. end;
  655. end;
  656. Function GetCurrentDir : String;
  657. begin
  658. GetDir (0,Result);
  659. end;
  660. Function SetCurrentDir (Const NewDir : String) : Boolean;
  661. begin
  662. {$I-}
  663. ChDir(NewDir);
  664. {$I+}
  665. result := (IOResult = 0);
  666. end;
  667. Function CreateDir (Const NewDir : String) : Boolean;
  668. begin
  669. {$I-}
  670. MkDir(NewDir);
  671. {$I+}
  672. result := (IOResult = 0);
  673. end;
  674. Function RemoveDir (Const Dir : String) : Boolean;
  675. begin
  676. {$I-}
  677. RmDir(Dir);
  678. {$I+}
  679. result := (IOResult = 0);
  680. end;
  681. {****************************************************************************
  682. Misc Functions
  683. ****************************************************************************}
  684. procedure Beep;
  685. begin
  686. end;
  687. {****************************************************************************
  688. Locale Functions
  689. ****************************************************************************}
  690. Function GetEpochTime: cint;
  691. {
  692. Get the number of seconds since 00:00, January 1 1970, GMT
  693. the time NOT corrected any way
  694. }
  695. begin
  696. GetEpochTime:=fptime;
  697. end;
  698. procedure GetTime(var hour,min,sec,msec,usec:word);
  699. {
  700. Gets the current time, adjusted to local time
  701. }
  702. var
  703. year,day,month:Word;
  704. tz:timeval;
  705. begin
  706. fpgettimeofday(@tz,nil);
  707. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  708. msec:=tz.tv_usec div 1000;
  709. usec:=tz.tv_usec mod 1000;
  710. end;
  711. procedure GetTime(var hour,min,sec,sec100:word);
  712. {
  713. Gets the current time, adjusted to local time
  714. }
  715. var
  716. usec : word;
  717. begin
  718. gettime(hour,min,sec,sec100,usec);
  719. sec100:=sec100 div 10;
  720. end;
  721. Procedure GetTime(Var Hour,Min,Sec:Word);
  722. {
  723. Gets the current time, adjusted to local time
  724. }
  725. var
  726. msec,usec : Word;
  727. Begin
  728. gettime(hour,min,sec,msec,usec);
  729. End;
  730. Procedure GetDate(Var Year,Month,Day:Word);
  731. {
  732. Gets the current date, adjusted to local time
  733. }
  734. var
  735. hour,minute,second : word;
  736. Begin
  737. EpochToLocal(fptime,year,month,day,hour,minute,second);
  738. End;
  739. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  740. {
  741. Gets the current date, adjusted to local time
  742. }
  743. Begin
  744. EpochToLocal(fptime,year,month,day,hour,minute,second);
  745. End;
  746. {$ifndef FPUNONE}
  747. Procedure GetLocalTime(var SystemTime: TSystemTime);
  748. var
  749. usecs : Word;
  750. begin
  751. GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond, usecs);
  752. GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day);
  753. // SystemTime.MilliSecond := 0;
  754. end ;
  755. {$endif}
  756. Procedure InitAnsi;
  757. Var
  758. i : longint;
  759. begin
  760. { Fill table entries 0 to 127 }
  761. for i := 0 to 96 do
  762. UpperCaseTable[i] := chr(i);
  763. for i := 97 to 122 do
  764. UpperCaseTable[i] := chr(i - 32);
  765. for i := 123 to 191 do
  766. UpperCaseTable[i] := chr(i);
  767. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  768. for i := 0 to 64 do
  769. LowerCaseTable[i] := chr(i);
  770. for i := 65 to 90 do
  771. LowerCaseTable[i] := chr(i + 32);
  772. for i := 91 to 191 do
  773. LowerCaseTable[i] := chr(i);
  774. Move (CPISO88591LCT,LowerCaseTable[192],SizeOf(CPISO88591UCT));
  775. end;
  776. Procedure InitInternational;
  777. begin
  778. InitInternationalGeneric;
  779. InitAnsi;
  780. end;
  781. function SysErrorMessage(ErrorCode: Integer): String;
  782. begin
  783. Result:=StrError(ErrorCode);
  784. end;
  785. {****************************************************************************
  786. OS utility functions
  787. ****************************************************************************}
  788. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  789. begin
  790. Result:=StrPas(BaseUnix.FPGetenv(PChar(pointer(EnvVar))));
  791. end;
  792. Function GetEnvironmentVariableCount : Integer;
  793. begin
  794. Result:=FPCCountEnvVar(EnvP);
  795. end;
  796. Function GetEnvironmentString(Index : Integer) : String;
  797. begin
  798. Result:=FPCGetEnvStrFromP(Envp,Index);
  799. end;
  800. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString):integer;
  801. var
  802. pid : longint;
  803. e : EOSError;
  804. CommandLine: AnsiString;
  805. cmdline2 : ppchar;
  806. Begin
  807. { always surround the name of the application by quotes
  808. so that long filenames will always be accepted. But don't
  809. do it if there are already double quotes!
  810. }
  811. // Only place we still parse
  812. cmdline2:=nil;
  813. if Comline<>'' Then
  814. begin
  815. CommandLine:=ComLine;
  816. { Make an unique copy because stringtoppchar modifies the
  817. string }
  818. UniqueString(CommandLine);
  819. cmdline2:=StringtoPPChar(CommandLine,1);
  820. cmdline2^:=pchar(pointer(Path));
  821. end
  822. else
  823. begin
  824. getmem(cmdline2,2*sizeof(pchar));
  825. cmdline2^:=pchar(Path);
  826. cmdline2[1]:=nil;
  827. end;
  828. {$ifdef USE_VFORK}
  829. pid:=fpvFork;
  830. {$else USE_VFORK}
  831. pid:=fpFork;
  832. {$endif USE_VFORK}
  833. if pid=0 then
  834. begin
  835. {The child does the actual exec, and then exits}
  836. fpexecv(pchar(pointer(Path)),Cmdline2);
  837. { If the execve fails, we return an exitvalue of 127, to let it be known}
  838. fpExit(127);
  839. end
  840. else
  841. if pid=-1 then {Fork failed}
  842. begin
  843. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  844. e.ErrorCode:=-1;
  845. raise e;
  846. end;
  847. { We're in the parent, let's wait. }
  848. result:=WaitProcess(pid); // WaitPid and result-convert
  849. if Comline<>'' Then
  850. freemem(cmdline2);
  851. if (result<0) or (result=127) then
  852. begin
  853. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  854. E.ErrorCode:=result;
  855. Raise E;
  856. end;
  857. End;
  858. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array Of AnsiString):integer;
  859. var
  860. pid : longint;
  861. e : EOSError;
  862. Begin
  863. pid:=fpFork;
  864. if pid=0 then
  865. begin
  866. {The child does the actual exec, and then exits}
  867. fpexecl(Path,Comline);
  868. { If the execve fails, we return an exitvalue of 127, to let it be known}
  869. fpExit(127);
  870. end
  871. else
  872. if pid=-1 then {Fork failed}
  873. begin
  874. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  875. e.ErrorCode:=-1;
  876. raise e;
  877. end;
  878. { We're in the parent, let's wait. }
  879. result:=WaitProcess(pid); // WaitPid and result-convert
  880. if (result<0) or (result=127) then
  881. begin
  882. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  883. E.ErrorCode:=result;
  884. raise E;
  885. end;
  886. End;
  887. procedure Sleep(milliseconds: Cardinal);
  888. Var
  889. timeout,timeoutresult : TTimespec;
  890. res: cint;
  891. begin
  892. timeout.tv_sec:=milliseconds div 1000;
  893. timeout.tv_nsec:=1000*1000*(milliseconds mod 1000);
  894. repeat
  895. res:=fpnanosleep(@timeout,@timeoutresult);
  896. timeout:=timeoutresult;
  897. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  898. end;
  899. Function GetLastOSError : Integer;
  900. begin
  901. Result:=fpgetErrNo;
  902. end;
  903. { ---------------------------------------------------------------------
  904. Application config files
  905. ---------------------------------------------------------------------}
  906. Function GetHomeDir : String;
  907. begin
  908. Result:=GetEnvironmentVariable('HOME');
  909. If (Result<>'') then
  910. Result:=IncludeTrailingPathDelimiter(Result);
  911. end;
  912. { Follows base-dir spec,
  913. see [http://freedesktop.org/Standards/basedir-spec].
  914. Always ends with PathDelim. }
  915. Function XdgConfigHome : String;
  916. begin
  917. Result:=GetEnvironmentVariable('XDG_CONFIG_HOME');
  918. if (Result='') then
  919. Result:=GetHomeDir + '.config/'
  920. else
  921. Result:=IncludeTrailingPathDelimiter(Result);
  922. end;
  923. Function GetAppConfigDir(Global : Boolean) : String;
  924. begin
  925. If Global then
  926. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  927. else
  928. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  929. if VendorName<>'' then
  930. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  931. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  932. end;
  933. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  934. begin
  935. If Global then
  936. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  937. else
  938. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  939. if SubDir then
  940. begin
  941. if VendorName<>'' then
  942. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  943. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  944. end;
  945. Result:=Result+ApplicationName+ConfigExtension;
  946. end;
  947. {****************************************************************************
  948. GetTempDir
  949. ****************************************************************************}
  950. Function GetTempDir(Global : Boolean) : String;
  951. begin
  952. If Assigned(OnGetTempDir) then
  953. Result:=OnGetTempDir(Global)
  954. else
  955. begin
  956. Result:=GetEnvironmentVariable('TEMP');
  957. If (Result='') Then
  958. Result:=GetEnvironmentVariable('TMP');
  959. if (Result='') then
  960. Result:='/tmp/' // fallback.
  961. end;
  962. if (Result<>'') then
  963. Result:=IncludeTrailingPathDelimiter(Result);
  964. end;
  965. {****************************************************************************
  966. GetUserDir
  967. ****************************************************************************}
  968. Var
  969. TheUserDir : String;
  970. Function GetUserDir : String;
  971. begin
  972. If (TheUserDir='') then
  973. begin
  974. TheUserDir:=GetEnvironmentVariable('HOME');
  975. if (TheUserDir<>'') then
  976. TheUserDir:=IncludeTrailingPathDelimiter(TheUserDir)
  977. else
  978. TheUserDir:=GetTempDir(False);
  979. end;
  980. Result:=TheUserDir;
  981. end;
  982. {****************************************************************************
  983. Initialization code
  984. ****************************************************************************}
  985. Initialization
  986. InitExceptions; { Initialize exceptions. OS independent }
  987. InitInternational; { Initialize internationalization settings }
  988. SysConfigDir:='/etc'; { Initialize system config dir }
  989. Finalization
  990. FreeDriveStr;
  991. DoneExceptions;
  992. end.