Generic.Unix.UnixFiles.Mod 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE UnixFiles; (** AUTHOR "gf"; PURPOSE "Unix file systems" *)
  3. (* derived fron (SPARCOberon) Files.Mod by J. Templ 1.12. 89/14.05.93 *)
  4. IMPORT S := SYSTEM, Unix, Kernel, Modules, Log := KernelLog, Files;
  5. CONST
  6. NBufs = 4; Bufsize = 4096; (*FileTabSize = 1024; ResFiles = 128; *) NoDesc = -1;
  7. Open = 0; Create = 1; Closed = 2; (* file states *)
  8. NoKey = -1;
  9. CreateFlags = Unix.rdwr + Unix.creat + Unix.trunc;
  10. TraceCollection = 0;
  11. (* TraceSearch=1;*)
  12. Trace = {};
  13. VAR
  14. tempno: INTEGER;
  15. openfiles: LONGINT;
  16. searchPath: ARRAY 1024 OF CHAR;
  17. cwd: ARRAY 256 OF CHAR;
  18. unixFS: UnixFileSystem; (* must be unique *)
  19. collection: Collection; (* must be unique *)
  20. TYPE
  21. Filename = ARRAY 256 OF CHAR;
  22. NameSet = OBJECT
  23. VAR
  24. name: ARRAY 64 OF CHAR;
  25. left, right: NameSet;
  26. PROCEDURE Add( CONST filename: ARRAY OF CHAR ): BOOLEAN;
  27. (* add filename if it not already exists. else return false *)
  28. BEGIN
  29. IF filename = name THEN RETURN FALSE END;
  30. IF filename < name THEN
  31. IF left = NIL THEN NEW( left, filename ); RETURN TRUE
  32. ELSE RETURN left.Add( filename )
  33. END
  34. ELSE
  35. IF right = NIL THEN NEW( right, filename ); RETURN TRUE
  36. ELSE RETURN right.Add( filename )
  37. END
  38. END
  39. END Add;
  40. PROCEDURE & Init( CONST filename: ARRAY OF CHAR );
  41. BEGIN
  42. COPY( filename, name );
  43. left := NIL; right := NIL
  44. END Init;
  45. END NameSet;
  46. AliasFileSystem = OBJECT (Files.FileSystem)
  47. VAR
  48. fs: UnixFileSystem;
  49. PROCEDURE & Init*( realFS: UnixFileSystem);
  50. BEGIN
  51. SELF.fs := realFS;
  52. END Init;
  53. PROCEDURE New0( name: ARRAY OF CHAR ): Files.File;
  54. VAR f: Files.File;
  55. BEGIN
  56. f := fs.New0( name );
  57. IF f # NIL THEN f.fs := SELF END;
  58. RETURN f;
  59. END New0;
  60. PROCEDURE Old0( name: ARRAY OF CHAR ): Files.File;
  61. VAR f: Files.File;
  62. BEGIN
  63. f := fs.Old0( name );
  64. IF f # NIL THEN f.fs := SELF END;
  65. RETURN f;
  66. END Old0;
  67. PROCEDURE Delete0( name: ARRAY OF CHAR; VAR key, res: LONGINT );
  68. BEGIN
  69. fs.Delete0( name, key, res );
  70. END Delete0;
  71. PROCEDURE Rename0( old, new: ARRAY OF CHAR; fold: Files.File; VAR res: LONGINT );
  72. BEGIN
  73. fs.Rename0( old, new, fold, res );
  74. END Rename0;
  75. PROCEDURE Enumerate0( mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator );
  76. BEGIN
  77. fs.Enumerate0( mask, flags, enum );
  78. END Enumerate0;
  79. PROCEDURE FileKey( name: ARRAY OF CHAR ): LONGINT;
  80. VAR
  81. BEGIN
  82. RETURN fs.FileKey( name );
  83. END FileKey;
  84. PROCEDURE CreateDirectory0( name: ARRAY OF CHAR; VAR res: LONGINT );
  85. BEGIN
  86. fs.CreateDirectory0( name, res );
  87. END CreateDirectory0;
  88. PROCEDURE RemoveDirectory0( name: ARRAY OF CHAR; force: BOOLEAN; VAR key, res: LONGINT );
  89. BEGIN
  90. fs.RemoveDirectory0( name, force, key, res );
  91. END RemoveDirectory0;
  92. END AliasFileSystem;
  93. FinalizeFiles = OBJECT
  94. PROCEDURE EnumFile( f: ANY; VAR cont: BOOLEAN );
  95. VAR F: File;
  96. BEGIN
  97. F := f( File ); F.Finalize(); cont := TRUE
  98. END EnumFile;
  99. END FinalizeFiles;
  100. SearchByFstat = OBJECT
  101. VAR
  102. found: File;
  103. stat: Unix.Status;
  104. PROCEDURE Init( s: Unix.Status );
  105. BEGIN
  106. found := NIL;
  107. stat := s;
  108. END Init;
  109. PROCEDURE EnumFile( f: ANY; VAR cont: BOOLEAN );
  110. BEGIN
  111. WITH f: File DO
  112. IF (stat.ino = f.ino) & (stat.dev = f.dev) THEN
  113. (* possible different name but same file! *)
  114. ResetBuffers( f, stat );
  115. found := f; cont := FALSE;
  116. END;
  117. END;
  118. END EnumFile;
  119. END SearchByFstat;
  120. Collection = OBJECT (* methods in Collection shared by objects Filesystem and File *)
  121. VAR oldFiles, newFiles: Kernel.FinalizedCollection;
  122. ssearch: SearchByFstat;
  123. fileKey: LONGINT;
  124. PROCEDURE & Init*;
  125. BEGIN
  126. NEW( oldFiles ); NEW( newFiles ); NEW(ssearch); fileKey := -1;
  127. END Init;
  128. PROCEDURE AddNew( F: File );
  129. BEGIN {EXCLUSIVE}
  130. IF TraceCollection IN Trace THEN Log.String( "Collections.AddNew: " ); Log.String( F.workName ); Log.Ln; END;
  131. newFiles.Add( F, FinalizeFile );
  132. END AddNew;
  133. PROCEDURE AddOld( F: File );
  134. BEGIN {EXCLUSIVE}
  135. IF TraceCollection IN Trace THEN Log.String( "Collections.AddOld: " ); Log.String( F.workName ); Log.Ln; END;
  136. oldFiles.Add( F, FinalizeFile );
  137. END AddOld;
  138. PROCEDURE ByStat(CONST stat: Unix.Status): File;
  139. BEGIN{EXCLUSIVE}
  140. ssearch.Init(stat);
  141. oldFiles.Enumerate(ssearch.EnumFile);
  142. IF ssearch.found = NIL THEN
  143. newFiles.Enumerate(ssearch.EnumFile)
  144. END;
  145. IF TraceCollection IN Trace THEN
  146. Log.String( "Collections.ByStatus: " ); Log.Ln;
  147. IF ssearch.found = NIL THEN Log.String("not found") ELSE Log.String("found") END;
  148. END;
  149. RETURN ssearch.found;
  150. END ByStat;
  151. PROCEDURE Finalize;
  152. VAR fin: FinalizeFiles;
  153. BEGIN {EXCLUSIVE}
  154. IF TraceCollection IN Trace THEN Log.String( "Collections.Finalize " ); Log.Ln; END;
  155. NEW( fin ); newFiles.Enumerate( fin.EnumFile ); newFiles.Clear(); oldFiles.Enumerate( fin.EnumFile ); oldFiles.Clear();
  156. END Finalize;
  157. PROCEDURE FinalizeFile( obj: ANY );
  158. VAR F: File;
  159. BEGIN
  160. F := obj( File );
  161. IF TraceCollection IN Trace THEN Log.String( "Collections.FinalizeFile " ); Log.String( F.workName ); Log.Ln; END;
  162. F.Finalize()
  163. END FinalizeFile;
  164. END Collection;
  165. UnixFileSystem* = OBJECT (Files.FileSystem)
  166. PROCEDURE & Init;
  167. BEGIN
  168. prefix := ""; vol := NIL; desc := "UnixFS"
  169. END Init;
  170. PROCEDURE New0*( name: ARRAY OF CHAR ): Files.File;
  171. VAR f: File;
  172. BEGIN {EXCLUSIVE}
  173. (*AwaitFinalizingDone;*)
  174. NEW( f, SELF );
  175. f.workName := ""; COPY( name, f.registerName );
  176. f.fd := NoDesc; f.state := Create; f.fsize := 0; f.fpos := 0;
  177. f.swapper := -1; (*all f.buf[i] = NIL*)
  178. f.key := NoKey; f.fs := SELF;
  179. RETURN f
  180. END New0;
  181. PROCEDURE IsDirectory( VAR stat: Unix.Status ): BOOLEAN;
  182. VAR mode: LONGINT;
  183. BEGIN
  184. mode := stat.mode;
  185. RETURN ODD( mode DIV 4000H )
  186. END IsDirectory;
  187. PROCEDURE Old0*( name: ARRAY OF CHAR ): Files.File;
  188. VAR f: File; stat: Unix.Status; fd, r, errno, pos: LONGINT;
  189. oflags: SET; nextdir, path: Filename; fo: LONGINT;
  190. BEGIN {EXCLUSIVE}
  191. IF name = "" THEN RETURN NIL END;
  192. IF IsFullName( name ) THEN
  193. COPY( name, path ); nextdir := "";
  194. ELSE
  195. pos := 0; ScanPath( pos, nextdir ); MakePath( nextdir, name, path );
  196. ScanPath( pos, nextdir )
  197. END;
  198. (*IF (FileTabSize - openfiles) < ResFiles THEN (*! GC *) END;*)
  199. LOOP
  200. r := Unix.access( ADDRESSOF( path ), Unix.R_OK );
  201. IF r >= 0 THEN
  202. r := Unix.access( ADDRESSOF( path ), Unix.W_OK );
  203. IF r < 0 THEN oflags := Unix.rdonly ELSE oflags := Unix.rdwr END;
  204. fd := Unix.open( ADDRESSOF( path ), oflags, {} ); errno := Unix.errno();
  205. IF ((fd < 0) & (errno IN {Unix.ENFILE, Unix.EMFILE})) (* OR (fd >= FileTabSize)*) THEN
  206. (*IF fd > 0 THEN r := Unix.p( fd ) END;*)
  207. REPEAT
  208. TRACE(errno, openfiles);
  209. fo := openfiles;
  210. Kernel.GC;
  211. WaitClose(fo);
  212. fd := Unix.open( ADDRESSOF( path ), oflags, {} ); errno := Unix.errno();
  213. UNTIL (fd >= 0) OR ~ (errno IN {Unix.ENFILE, Unix.EMFILE})
  214. END;
  215. IF fd >= 0 THEN
  216. r := Unix.fstat( fd, stat );
  217. f := collection.ByStat(stat);
  218. (*f := FindCachedEntry( stat );*)
  219. IF f # NIL THEN
  220. (* use the file already cached *) r := Unix.close( fd );
  221. EXIT
  222. ELSE
  223. (*ELSIF fd < FileTabSize THEN*)
  224. (*AwaitFinalizingDone;*)
  225. NEW( f, SELF );
  226. f.fd := fd; f.dev := stat.dev; f.ino := stat.ino;
  227. f.mtime := stat.mtime.sec; f.fsize := stat.size; f.fpos := 0;
  228. f.state := Open; f.swapper := -1; (*all f.buf[i] = NIL*)
  229. COPY( path, f.workName ); f.registerName := "";
  230. f.tempFile := FALSE;
  231. IF IsDirectory( stat ) THEN
  232. f.flags := {Files.Directory, Files.ReadOnly}
  233. ELSIF oflags = Unix.rdonly THEN
  234. f.flags := {Files.ReadOnly}
  235. END;
  236. f.key := NoKey; f.fs := SELF;
  237. (*fileTab[fd].f := f; (* cache file *)*)
  238. IncOpenFiles();
  239. collection.AddOld(f);
  240. (*RegisterFinalizer( f, Cleanup );*)
  241. EXIT
  242. (*ELSE
  243. r := Unix.close( fd );
  244. Halt( f, FALSE, "UnixFiles.File.Old0: too many files open" );
  245. *)
  246. END
  247. END
  248. ELSIF nextdir # "" THEN
  249. MakePath( nextdir, name, path ); ScanPath( pos, nextdir );
  250. ELSE
  251. f := NIL; EXIT
  252. END;
  253. END; (* loop *)
  254. RETURN f
  255. END Old0;
  256. (** Return the unique non-zero key of the named file, if it exists. *)
  257. PROCEDURE FileKey*( name: ARRAY OF CHAR ): LONGINT;
  258. (* Can not be used for Unix files as LONGINT is too small.
  259. In the Unix filesystem a file is identified by
  260. - dev (64 bit (Linux), 32 bit (Solaris, Darwin)) +
  261. - ino (32 bit)
  262. *)
  263. BEGIN
  264. RETURN 0
  265. END FileKey;
  266. PROCEDURE Delete0*( name: ARRAY OF CHAR; VAR key, res: LONGINT );
  267. VAR r: LONGINT;
  268. BEGIN {EXCLUSIVE}
  269. r := Unix.unlink( ADDRESSOF( name ) );
  270. IF r = 0 THEN res := Files.Ok
  271. ELSE res := Unix.errno( )
  272. END;
  273. key := 0;
  274. END Delete0;
  275. (* return remaining old file, if any *)
  276. PROCEDURE TryRename*( old, new: ARRAY OF CHAR; f: Files.File; VAR res: LONGINT ): LONGINT;
  277. CONST Bufsize = 4096;
  278. VAR fdold, fdnew, fo, n, r: LONGINT; ostat, nstat: Unix.Status;
  279. buf: ARRAY Bufsize OF CHAR;
  280. BEGIN {EXCLUSIVE}
  281. fo := NoDesc;
  282. r:= Unix.stat( ADDRESSOF( old ), ostat );
  283. IF r >= 0 THEN
  284. r := Unix.stat( ADDRESSOF( new ), nstat );
  285. IF (r >= 0) & ((ostat.dev # nstat.dev) OR (ostat.ino # nstat.ino)) THEN
  286. r := Unix.unlink( ADDRESSOF( new ) ) (* work around stale nfs handles *);
  287. END;
  288. r := Unix.rename( ADDRESSOF( old ), ADDRESSOF( new ) );
  289. IF r < 0 THEN (* could not rename, try copy *)
  290. res := Unix.errno( );
  291. IF (res = Unix.EXDEV) OR (res = Unix.ETXTBSY) THEN (* cross device link, move the file / file busy frequently happens in VirtualBox *)
  292. fdold := Unix.open( ADDRESSOF( old ), Unix.rdonly, {} );
  293. fo := fdold;
  294. IF fdold < 0 THEN
  295. res := Unix.errno( );
  296. RETURN NoDesc;
  297. END;
  298. fdnew := Unix.open( ADDRESSOF( new ), Unix.rdwr + Unix.creat + Unix.trunc, Unix.rwrwr );
  299. IF fdnew < 0 THEN
  300. res := Unix.errno( );
  301. RETURN NoDesc;
  302. END;
  303. n := Unix.read( fdold, ADDRESSOF( buf ), Bufsize );
  304. WHILE n > 0 DO
  305. r := Unix.write( fdnew, ADDRESSOF( buf ), n );
  306. IF r < 0 THEN
  307. res := Unix.errno();
  308. r := Unix.close( fdold );
  309. r := Unix.close( fdnew );
  310. RETURN NoDesc;
  311. END;
  312. n := Unix.read( fdold, ADDRESSOF( buf ), Bufsize )
  313. END;
  314. r := Unix.unlink( ADDRESSOF( old ) );
  315. r := Unix.close( fdold );
  316. r := Unix.close( fdnew );
  317. res := Files.Ok
  318. ELSE
  319. RETURN NoDesc (* res is Unix.rename return code *)
  320. END
  321. END;
  322. res := Files.Ok
  323. ELSE
  324. res := Unix.errno();
  325. END;
  326. RETURN fo;
  327. END TryRename;
  328. PROCEDURE Rename0*( old, new: ARRAY OF CHAR; f: Files.File; VAR res: LONGINT );
  329. VAR of: LONGINT;
  330. BEGIN
  331. of := TryRename(old, new, f, res);
  332. END Rename0;
  333. PROCEDURE CreateDirectory0*( path: ARRAY OF CHAR; VAR res: LONGINT );
  334. VAR r: LONGINT;
  335. BEGIN {EXCLUSIVE}
  336. r := Unix.mkdir( ADDRESSOF( path ), Unix.rwxrwxrwx );
  337. IF r = 0 THEN res := Files.Ok
  338. ELSE res := Unix.errno( )
  339. END
  340. END CreateDirectory0;
  341. PROCEDURE RemoveDirectory0*( path: ARRAY OF CHAR; force: BOOLEAN; VAR key, res: LONGINT );
  342. VAR r: LONGINT;
  343. BEGIN {EXCLUSIVE}
  344. r := Unix.rmdir( ADDRESSOF( path ) );
  345. IF r = 0 THEN res := Files.Ok
  346. ELSE res := Unix.errno( )
  347. END
  348. END RemoveDirectory0;
  349. PROCEDURE Enumerate0*( mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator );
  350. VAR
  351. path, filemask: Filename;
  352. i, j: INTEGER; dirName, fileName, fullName: Filename;
  353. checkSet: NameSet; ent: Unix.Dirent;
  354. PROCEDURE GetEntryName;
  355. VAR i: INTEGER; adr: ADDRESS;
  356. BEGIN
  357. i := -1; adr := ADDRESSOF( ent.name );
  358. REPEAT INC( i ); S.GET( adr, fileName[i] ); INC( adr ) UNTIL fileName[i] = 0X
  359. END GetEntryName;
  360. PROCEDURE EnumDir( CONST dirName: ARRAY OF CHAR );
  361. VAR
  362. dir: ADDRESS;
  363. tm: Unix.TmPtr; date, time: LONGINT;
  364. stat: Unix.Status; r: LONGINT;
  365. BEGIN
  366. dir := Unix.opendir( ADDRESSOF( dirName ) );
  367. IF dir # 0 THEN
  368. ent := Unix.readdir( dir );
  369. WHILE ent # NIL DO
  370. COPY( dirName, fullName );
  371. GetEntryName; AppendName( fullName, fileName );
  372. IF (fileName[0] # '.') & Match( fileName, filemask, 0, 0 ) THEN
  373. IF checkSet.Add( fileName ) THEN (* not a covered name *)
  374. r := Unix.stat( ADDRESSOF( fullName ), stat );
  375. tm := Unix.localtime( stat.mtime );
  376. date := tm.year*200H + (tm.mon + 1)*20H + tm.mday;
  377. time := tm.hour*1000H + tm.min*40H + tm.sec;
  378. flags := {};
  379. IF IsDirectory( stat ) THEN
  380. flags := {Files.ReadOnly, Files.Directory}
  381. ELSE
  382. r := Unix.access( ADDRESSOF( fullName ), Unix.W_OK );
  383. IF r < 0 THEN flags := {Files.ReadOnly} END
  384. END;
  385. enum.PutEntry( fullName, flags, time, date, stat.size );
  386. END
  387. END;
  388. ent := Unix.readdir( dir );
  389. END;
  390. Unix.closedir( dir )
  391. END;
  392. END EnumDir;
  393. BEGIN {EXCLUSIVE}
  394. Files.SplitName( mask, prefix, fullName );
  395. Files.SplitPath( fullName, path, filemask );
  396. NEW( checkSet, "M###N" );
  397. IF path # "" THEN
  398. CleanPath( path );
  399. EnumDir( path )
  400. ELSE
  401. i := 0; j := 0;
  402. LOOP
  403. IF (searchPath[i] = " ") OR (searchPath[i] = 0X) THEN
  404. dirName[j] := 0X;
  405. EnumDir( dirName );
  406. IF searchPath[i] = 0X THEN EXIT
  407. ELSE INC( i ); j := 0
  408. END
  409. ELSE
  410. dirName[j] := searchPath[i]; INC( j ); INC( i )
  411. END
  412. END
  413. END;
  414. checkSet := NIL;
  415. END Enumerate0;
  416. END UnixFileSystem;
  417. Buffer = POINTER TO RECORD (Files.Hint)
  418. chg: BOOLEAN;
  419. org, size: LONGINT;
  420. data: ARRAY Bufsize OF CHAR;
  421. END;
  422. File* = OBJECT (Files.File)
  423. VAR
  424. fd: LONGINT;
  425. workName, registerName: Filename;
  426. tempFile: BOOLEAN;
  427. dev: Unix.DevT;
  428. ino: LONGINT;
  429. mtime: HUGEINT;
  430. fsize, fpos: SIZE;
  431. bufs: ARRAY NBufs OF Buffer;
  432. swapper, state: LONGINT;
  433. PROCEDURE & Init( fs: Files.FileSystem );
  434. BEGIN
  435. SELF.fs := fs; flags := {};
  436. END Init;
  437. PROCEDURE CreateUnixFile;
  438. VAR
  439. stat: Unix.Status; done: BOOLEAN; errno,fo: LONGINT;
  440. BEGIN
  441. IF state = Create THEN
  442. GetTempName( registerName, workName ); tempFile := TRUE
  443. ELSIF state = Closed THEN
  444. IF registerName # "" THEN
  445. workName := registerName; registerName := ""; tempFile := FALSE;
  446. ELSE
  447. RETURN;
  448. END;
  449. END;
  450. errno := Unix.unlink( ADDRESSOF( workName ) );
  451. (*unlink first to avoid stale NFS handles and to avoid reuse of inodes*)
  452. (*IF (FileTabSize - openfiles) < ResFiles THEN Kernel.GC END;*)
  453. fd := Unix.open( ADDRESSOF( workName ), CreateFlags, Unix.rwrwr );
  454. done := fd >= 0; errno := Unix.errno();
  455. IF (~done & (errno IN {Unix.ENFILE, Unix.EMFILE})) THEN
  456. REPEAT
  457. TRACE(errno, openfiles);
  458. fo := openfiles;
  459. Kernel.GC;
  460. WaitClose(fo);
  461. fd := Unix.open( ADDRESSOF( workName ), CreateFlags, Unix.rwrwr); errno := Unix.errno();
  462. UNTIL (fd >= 0) OR ~ (errno IN {Unix.ENFILE, Unix.EMFILE});
  463. (*
  464. TRACE(r, openfiles);
  465. Kernel.GC; (*! + wait ? *)
  466. fd := Unix.open( ADDRESSOF( workName ), CreateFlags, Unix.rwrwr );
  467. *)
  468. done := fd >= 0
  469. END;
  470. IF done THEN
  471. (*IF fd >= FileTabSize THEN
  472. r := Unix.close( fd );
  473. Halt( SELF, FALSE, "UnixFiles.File.Create: too many files open" )
  474. ELSE*)
  475. errno := Unix.fstat( fd, stat );
  476. dev := stat.dev; ino := stat.ino; mtime := stat.mtime.sec;
  477. state := Open; fpos := 0;
  478. (*fileTab[fd].f := SELF;*)
  479. IncOpenFiles();
  480. collection.AddNew(SELF);
  481. (*RegisterFinalizer( SELF, Cleanup );*)
  482. (*END*)
  483. ELSE
  484. Halt( SELF, TRUE, "UnixFiles.File.Create: open failed" );
  485. END
  486. END CreateUnixFile;
  487. PROCEDURE Flush( buf: Buffer );
  488. VAR res: LONGINT; stat: Unix.Status;
  489. BEGIN
  490. IF buf.chg THEN
  491. IF fd = NoDesc THEN CreateUnixFile END;
  492. IF buf.org # fpos THEN res := Unix.lseek( fd, buf.org, 0 ) END;
  493. res := Unix.write( fd, ADDRESSOF( buf.data ), buf.size );
  494. IF res < 0 THEN Halt( SELF, TRUE, "UnixFiles.File.Flush: write failed" ) END;
  495. fpos := buf.org + buf.size; buf.chg := FALSE;
  496. res := Unix.fstat( fd, stat ); mtime := stat.mtime.sec
  497. END
  498. END Flush;
  499. PROCEDURE Set*( VAR r: Files.Rider; pos: LONGINT );
  500. BEGIN {EXCLUSIVE}
  501. SetX( r, pos )
  502. END Set;
  503. PROCEDURE SetX( VAR r: Files.Rider; p: LONGINT );
  504. VAR org, offset, i, n, res: LONGINT; buf: Buffer;
  505. BEGIN
  506. IF p > fsize THEN p := LONGINT(fsize)
  507. ELSIF p < 0 THEN p := 0
  508. END;
  509. offset := p MOD Bufsize; org := p - offset;
  510. i := 0;
  511. WHILE (i < NBufs) & (bufs[i] # NIL) & (org # bufs[i].org) DO INC( i ) END;
  512. IF i < NBufs THEN
  513. IF bufs[i] = NIL THEN
  514. NEW( buf ); buf.chg := FALSE; buf.org := -1;
  515. bufs[i] := buf
  516. ELSE
  517. swapper := i;
  518. buf := bufs[swapper]; Flush( buf )
  519. END
  520. ELSE
  521. swapper := (swapper + 1) MOD NBufs;
  522. buf := bufs[swapper]; Flush( buf )
  523. END;
  524. IF buf.org # org THEN
  525. IF org = fsize THEN
  526. buf.size := 0
  527. ELSE
  528. IF fd = NoDesc THEN CreateUnixFile END;
  529. IF fpos # org THEN res := Unix.lseek( fd, org, 0 ) END;
  530. IF res < 0 THEN Halt( SELF, TRUE, "UnixFiles.File.Set: lseek failed" ) END;
  531. n := Unix.read( fd, ADDRESSOF( buf.data ), Bufsize );
  532. IF n < 0 THEN
  533. IF p < fsize THEN Halt( SELF, TRUE, "UnixFiles.File.Set: read failed" )
  534. ELSE n := 0
  535. END
  536. END;
  537. fpos := org + n; buf.size := n
  538. END;
  539. buf.org := org; buf.chg := FALSE
  540. ELSE
  541. org := buf.org
  542. END;
  543. r.hint := buf; r.apos := org; r.bpos := offset;
  544. r.res := 0; r.eof := FALSE;
  545. r.file := SELF; r.fs := fs
  546. END SetX;
  547. PROCEDURE Pos*( VAR r: Files.Rider ): LONGINT;
  548. BEGIN
  549. RETURN r.apos + r.bpos
  550. END Pos;
  551. PROCEDURE Read*( VAR r: Files.Rider; VAR x: CHAR );
  552. VAR offset: LONGINT; buf: Buffer;
  553. BEGIN {EXCLUSIVE}
  554. buf := r.hint(Buffer); offset := r.bpos;
  555. IF r.apos # buf.org THEN
  556. SetX( r, r.apos + offset );
  557. buf := r.hint(Buffer); offset := r.bpos
  558. END;
  559. IF (offset < buf.size) THEN
  560. x := buf.data[offset]; r.bpos := offset + 1
  561. ELSIF r.apos + offset < fsize THEN
  562. SetX( r, r.apos + offset );
  563. x := r.hint(Buffer).data[0]; r.bpos := 1
  564. ELSE
  565. x := 0X; r.eof := TRUE
  566. END
  567. END Read;
  568. PROCEDURE ReadBytes*( VAR r: Files.Rider; VAR x: ARRAY OF CHAR; ofs, len: LONGINT );
  569. VAR xpos, min, restInBuf, offset: LONGINT; buf: Buffer;
  570. BEGIN {EXCLUSIVE}
  571. x[ofs] := 0X; xpos := ofs;
  572. buf := r.hint(Buffer); offset := r.bpos;
  573. WHILE len > 0 DO
  574. IF (r.apos # buf.org) OR (offset >= Bufsize) THEN
  575. SetX( r, r.apos + offset );
  576. buf := r.hint(Buffer); offset := r.bpos
  577. END;
  578. restInBuf := buf.size - offset;
  579. IF restInBuf = 0 THEN r.res := len; r.eof := TRUE; RETURN
  580. ELSIF len > restInBuf THEN min := restInBuf
  581. ELSE min := len
  582. END;
  583. S.MOVE( ADDRESSOF( buf.data ) + offset, ADDRESSOF( x ) + xpos, min );
  584. INC( offset, min ); r.bpos := offset;
  585. INC( xpos, min ); DEC( len, min )
  586. END;
  587. r.res := 0; r.eof := FALSE;
  588. END ReadBytes;
  589. PROCEDURE Write*( VAR r: Files.Rider; x: CHAR );
  590. VAR buf: Buffer; offset: LONGINT;
  591. BEGIN {EXCLUSIVE}
  592. buf := r.hint(Buffer); offset := r.bpos;
  593. IF (r.apos # buf.org) OR (offset >= Bufsize) THEN
  594. SetX( r, r.apos + offset );
  595. buf := r.hint(Buffer); offset := r.bpos
  596. END;
  597. buf.data[offset] := x; buf.chg := TRUE;
  598. IF offset = buf.size THEN INC( buf.size ); INC( fsize ) END;
  599. r.bpos := offset + 1; r.res := Files.Ok
  600. END Write;
  601. PROCEDURE WriteBytes*( VAR r: Files.Rider; CONST x: ARRAY OF CHAR; ofs, len: LONGINT );
  602. VAR xpos, min, restInBuf, offset: LONGINT; buf: Buffer;
  603. BEGIN {EXCLUSIVE}
  604. xpos := ofs; buf := r.hint(Buffer); offset := r.bpos;
  605. WHILE len > 0 DO
  606. IF (r.apos # buf.org) OR (offset >= Bufsize) THEN
  607. SetX( r, r.apos + offset );
  608. buf := r.hint(Buffer); offset := r.bpos
  609. END;
  610. restInBuf := Bufsize - offset;
  611. IF len > restInBuf THEN min := restInBuf ELSE min := len END;
  612. S.MOVE( ADDRESSOF( x ) + xpos, ADDRESSOF( buf.data ) + offset, min );
  613. INC( offset, min ); r.bpos := offset;
  614. IF offset > buf.size THEN
  615. INC( fsize, offset - buf.size ); buf.size := offset
  616. END;
  617. INC( xpos, min ); DEC( len, min ); buf.chg := TRUE
  618. END;
  619. r.res := Files.Ok
  620. END WriteBytes;
  621. PROCEDURE Length*( ): LONGINT;
  622. BEGIN
  623. RETURN LONGINT(fsize)
  624. END Length;
  625. PROCEDURE GetDate*( VAR t, d: LONGINT );
  626. VAR stat: Unix.Status; r: LONGINT; time: Unix.TmPtr;
  627. BEGIN {EXCLUSIVE}
  628. IF fd = NoDesc THEN CreateUnixFile END;
  629. r := Unix.fstat( fd, stat );
  630. time := Unix.localtime( stat.mtime );
  631. t := time.sec + ASH( time.min, 6 ) + ASH( time.hour, 12 );
  632. d := time.mday + ASH( time.mon + 1, 5 ) + ASH( time.year, 9 );
  633. END GetDate;
  634. PROCEDURE SetDate*( t, d: LONGINT );
  635. TYPE
  636. Time = RECORD actime, modtime: LONGINT END;
  637. VAR
  638. tm: Unix.Tm; buf: Time; r: LONGINT; path: Filename;
  639. BEGIN {EXCLUSIVE}
  640. IF registerName # "" THEN COPY( registerName, path )
  641. ELSE COPY( workName, path )
  642. END;
  643. (* get year and timezone *)
  644. (* fill in new date *)
  645. tm.isdst := -1; tm.sec := t MOD 64; tm.min := t DIV 64 MOD 64;
  646. tm.hour := t DIV 4096 MOD 32;
  647. tm.mday := d MOD 32; tm.mon := d DIV 32 MOD 16 - 1; tm.year := d DIV 512;
  648. tm.wday := 0; tm.yday := 0;
  649. buf.actime := Unix.mktime( tm ); buf.modtime := buf.actime;
  650. r := Unix.utime( ADDRESSOF( path ), ADDRESSOF( buf ) );
  651. END SetDate;
  652. PROCEDURE GetAttributes*( ): SET;
  653. BEGIN {EXCLUSIVE}
  654. RETURN flags
  655. END GetAttributes;
  656. PROCEDURE SetAttributes*( attr: SET );
  657. BEGIN {EXCLUSIVE}
  658. (* flags := attr *)
  659. END SetAttributes;
  660. PROCEDURE Register0*( VAR res: LONGINT );
  661. VAR fo: LONGINT;
  662. BEGIN {EXCLUSIVE}
  663. IF (state = Create) & (registerName # "") THEN
  664. state := Closed (* shortcut renaming *) ;
  665. END;
  666. FlushBuffers;
  667. IF registerName # "" THEN
  668. fo := unixFS.TryRename( workName, registerName, SELF, res );
  669. IF res # Files.Ok THEN
  670. Halt( SELF, FALSE, "UnixFiles.File.Register: rename failed" )
  671. END;
  672. IF fo # NoDesc THEN (* SELF still refers to old file *)
  673. res := Unix.close(fd);
  674. res := Unix.unlink(ADDRESSOF(workName)); (* VirtualBox ! Can only delete file when closed. *)
  675. fd := Unix.open( ADDRESSOF( registerName ), Unix.rdwr, Unix.rwrwr );
  676. END;
  677. workName := registerName; registerName := ""; tempFile := FALSE;
  678. END;
  679. (*collection.Register(SELF);*)
  680. END Register0;
  681. PROCEDURE Update*;
  682. BEGIN {EXCLUSIVE}
  683. FlushBuffers
  684. END Update;
  685. PROCEDURE FlushBuffers;
  686. VAR i: LONGINT;
  687. BEGIN
  688. IF fd = NoDesc THEN CreateUnixFile END;
  689. FOR i := 0 TO NBufs - 1 DO
  690. IF bufs[i] # NIL THEN Flush( bufs[i] ) END
  691. END;
  692. END FlushBuffers;
  693. PROCEDURE Finalize*;
  694. VAR r: LONGINT;
  695. BEGIN {EXCLUSIVE}
  696. IF tempFile THEN
  697. IF fd # NoDesc THEN r := Unix.close(fd) END;
  698. r := Unix.unlink( ADDRESSOF( registerName ) );
  699. fd := NoDesc;
  700. ELSE
  701. FlushBuffers;
  702. IF fd # NoDesc THEN
  703. r := Unix.close( fd );
  704. fd := NoDesc;
  705. END;
  706. END;
  707. DecOpenFiles();
  708. state := Closed;
  709. END Finalize;
  710. PROCEDURE Close;
  711. BEGIN
  712. Finalize;
  713. collection.oldFiles.Remove(SELF);
  714. END Close;
  715. PROCEDURE GetName*( VAR name: ARRAY OF CHAR );
  716. BEGIN {EXCLUSIVE}
  717. IF registerName = "" THEN COPY( workName, name ) ;
  718. ELSE COPY( registerName, name )
  719. END;
  720. CleanPath( name )
  721. END GetName;
  722. END File;
  723. (*===================================================================*)
  724. (** Get the current directory. *)
  725. PROCEDURE GetWorkingDirectory*( VAR path: ARRAY OF CHAR );
  726. BEGIN
  727. COPY( cwd, path )
  728. END GetWorkingDirectory;
  729. (** Change to directory path. *)
  730. PROCEDURE ChangeDirectory*( CONST path: ARRAY OF CHAR; VAR done: BOOLEAN );
  731. VAR r: LONGINT; newdir: Filename;
  732. BEGIN
  733. IF path[0] # '/' THEN
  734. COPY( cwd, newdir ); AppendName( newdir, path );
  735. CleanPath( newdir )
  736. ELSE
  737. COPY( path, newdir );
  738. END;
  739. r := Unix.chdir( ADDRESSOF( newdir ) );
  740. IF r = 0 THEN COPY( newdir, cwd ); done := TRUE ELSE done := FALSE END
  741. END ChangeDirectory;
  742. (*===================================================================*)
  743. PROCEDURE StripPath*( CONST path: ARRAY OF CHAR; VAR name: ARRAY OF CHAR );
  744. VAR i, p: INTEGER; c: CHAR;
  745. BEGIN
  746. i := 0; p := 0;
  747. REPEAT
  748. IF path[i] = '/' THEN p := i + 1 END;
  749. INC( i )
  750. UNTIL path[i] = 0X;
  751. i := 0;
  752. REPEAT c := path[p]; name[i] := c; INC( i ); INC( p ) UNTIL c = 0X
  753. END StripPath;
  754. PROCEDURE CleanPath*( VAR path: ARRAY OF CHAR );
  755. (*
  756. /aaa/../bbb/./ccc/../ddd/. ==> /bbb/ddd
  757. ../aaa ==> CWD/../aaa ==> . . .
  758. *)
  759. VAR
  760. i, prevNameStart, nameStart: INTEGER;
  761. c1, c2, c3: CHAR;
  762. PROCEDURE prependCWD;
  763. VAR tmp: ARRAY 256 OF CHAR;
  764. BEGIN
  765. COPY( cwd, tmp ); AppendName( tmp, path ); COPY( tmp, path )
  766. END prependCWD;
  767. PROCEDURE restart;
  768. BEGIN
  769. IF path[0] = '/' THEN nameStart := 1 ELSE nameStart := 0 END;
  770. i := -1; prevNameStart := -1;
  771. END restart;
  772. PROCEDURE shift( p0, p1: INTEGER );
  773. VAR c: CHAR;
  774. BEGIN
  775. REPEAT c := path[p1]; path[p0] := c; INC( p0 ); INC( p1 ) UNTIL c = 0X;
  776. IF p0 > 1 THEN restart ELSE i := 0 END
  777. END shift;
  778. BEGIN
  779. restart;
  780. REPEAT
  781. INC( i );
  782. IF i = nameStart THEN
  783. c1 := path[i]; c2 := path[i + 1]; c3 := path[i + 2];
  784. IF c1 = '/' THEN shift( i, i + 1 ) (* // *)
  785. ELSIF c1 = '.' THEN
  786. IF c2 = 0X THEN
  787. IF i > 1 THEN DEC( i ) END;
  788. path[i] := 0X
  789. ELSIF c2 = '/' THEN shift( i, i + 2 ); (* ./ *)
  790. ELSIF (c2 = '.') & ((c3 = 0X) OR (c3 = '/')) THEN (* .. *)
  791. IF i = 0 THEN prependCWD; restart
  792. ELSIF c3 = 0X THEN DEC( i ); path[i] := 0X
  793. ELSIF c3 = '/' THEN (* ../ *)
  794. IF prevNameStart >= 0 THEN shift( prevNameStart, i + 3 ) END
  795. END
  796. END
  797. END
  798. ELSIF path[i] = '/' THEN
  799. IF i > 0 THEN prevNameStart := nameStart END;
  800. nameStart := i + 1
  801. END;
  802. UNTIL (i >= 0) & (path[i] = 0X);
  803. IF (i > 1) & (path[i - 1] = '/') THEN path[i - 1] := 0X END;
  804. IF path = "" THEN path := "." END;
  805. END CleanPath;
  806. PROCEDURE Match( CONST name, pat: ARRAY OF CHAR; i, j: INTEGER ): BOOLEAN;
  807. BEGIN
  808. IF (name[i] = 0X) & (pat[j] = 0X) THEN RETURN TRUE
  809. ELSIF pat[j] # "*" THEN RETURN (name[i] = pat[j]) & Match( name, pat, i + 1, j + 1 )
  810. ELSE (* pat[j] = "*", name[i] may be 0X *)
  811. RETURN Match( name, pat, i, j + 1 ) OR ((name[i] # 0X) & Match( name, pat, i + 1, j ))
  812. END
  813. END Match;
  814. PROCEDURE Append( VAR a: Filename; CONST this: ARRAY OF CHAR );
  815. VAR i, j: LONGINT;
  816. BEGIN
  817. i := 0; j := 0;
  818. WHILE a[i] # 0X DO INC( i ) END;
  819. WHILE (i < LEN( a ) - 1) & (this[j] # 0X) DO a[i] := this[j]; INC( i ); INC( j ) END;
  820. a[i] := 0X
  821. END Append;
  822. PROCEDURE AppendName( VAR path: Filename; CONST filename: ARRAY OF CHAR );
  823. VAR i, j, max: LONGINT;
  824. BEGIN
  825. i := 0; j := 0; max := LEN( path ) - 1;
  826. WHILE path[i] # 0X DO INC( i ) END;
  827. IF (i > 0) & (path[i - 1] # "/") THEN path[i] := "/"; INC( i ); path[i] := 0X END;
  828. Append( path, filename );
  829. END AppendName;
  830. PROCEDURE AppendInt( VAR str: Filename; n: LONGINT );
  831. VAR i: LONGINT;
  832. BEGIN
  833. i := 0;
  834. WHILE str[i] # 0X DO INC(i) END;
  835. WHILE n > 0 DO str[i] := CHR( n MOD 10 + ORD('0') ); n := n DIV 10; INC(i) END;
  836. str[i] := 0X
  837. END AppendInt;
  838. PROCEDURE IsFullName( CONST name: ARRAY OF CHAR ): BOOLEAN;
  839. VAR i: INTEGER; ch: CHAR;
  840. BEGIN
  841. i := 0; ch := name[0];
  842. WHILE (ch # 0X) & (ch # "/") DO INC( i ); ch := name[i] END;
  843. RETURN ch = "/"
  844. END IsFullName;
  845. PROCEDURE Halt( f: File; unixError: BOOLEAN; CONST msg: ARRAY OF CHAR );
  846. VAR fd, errno: LONGINT;
  847. workName, registerName: Filename;
  848. BEGIN
  849. IF f = NIL THEN
  850. workName := "???"; registerName := "???"
  851. ELSE
  852. workName := f.workName; registerName := f.registerName; fd := f.fd
  853. END;
  854. IF unixError THEN errno := Unix.errno( ); Unix.Perror( msg ) END;
  855. HALT( 99 )
  856. END Halt;
  857. (*
  858. PROCEDURE RegisterFinalizer( obj: ANY; fin: Heaps.Finalizer );
  859. VAR n: Heaps.FinalizerNode;
  860. BEGIN
  861. NEW( n ); n.finalizer := fin; Heaps.AddFinalizer( obj, n );
  862. END RegisterFinalizer;
  863. *)
  864. (*
  865. PROCEDURE GC;
  866. BEGIN
  867. Kernel.GC;
  868. AwaitFinalizingDone
  869. END GC;
  870. PROCEDURE AwaitFinalizingDone;
  871. BEGIN
  872. (* wait until finalizers have finished! (Cleanup)*)
  873. WHILE Machine.GCacquired DO Objects.Sleep( 10 ) END
  874. END AwaitFinalizingDone;
  875. *)
  876. PROCEDURE ResetBuffers( f: File; VAR stat: Unix.Status );
  877. VAR i: INTEGER;
  878. BEGIN
  879. f.fsize := stat.size;
  880. IF (f.mtime # stat.mtime.sec) THEN
  881. FOR i := 0 TO NBufs - 1 DO
  882. IF f.bufs[i] # NIL THEN f.bufs[i].org := -1; f.bufs[i] := NIL END;
  883. END;
  884. f.swapper := -1; f.mtime := stat.mtime.sec
  885. END
  886. END ResetBuffers;
  887. (*
  888. PROCEDURE FindCachedEntry( VAR stat: Unix.Status ): File;
  889. VAR f: File; i: INTEGER;
  890. BEGIN
  891. FOR i := 0 TO FileTabSize - 1 DO
  892. f := fileTab[i].f;
  893. IF (f # NIL ) & (stat.ino = f.ino) & (stat.dev = f.dev) THEN
  894. (* possible different name but same file! *)
  895. ResetBuffers( f, stat );
  896. RETURN f
  897. END;
  898. END;
  899. RETURN NIL
  900. END FindCachedEntry;
  901. *)
  902. PROCEDURE MakePath( CONST dir, name: ARRAY OF CHAR; VAR dest: ARRAY OF CHAR );
  903. VAR i, j: INTEGER;
  904. BEGIN
  905. i := 0; j := 0;
  906. WHILE dir[i] # 0X DO dest[i] := dir[i]; INC( i ) END;
  907. IF (i>0) & (dest[i - 1] # "/") THEN dest[i] := "/"; INC( i ) END;
  908. WHILE name[j] # 0X DO dest[i] := name[j]; INC( i ); INC( j ) END;
  909. dest[i] := 0X
  910. END MakePath;
  911. PROCEDURE ScanPath( VAR pos: LONGINT; VAR dir: ARRAY OF CHAR );
  912. VAR i: LONGINT; ch: CHAR;
  913. BEGIN
  914. i := 0; ch := searchPath[pos];
  915. WHILE ch = " " DO INC( pos ); ch := searchPath[pos] END;
  916. WHILE ch > " " DO dir[i] := ch; INC( i ); INC( pos ); ch := searchPath[pos] END;
  917. dir[i] := 0X
  918. END ScanPath;
  919. PROCEDURE GetTempName( CONST finalName: ARRAY OF CHAR; VAR tempName: Filename );
  920. VAR n, i, j, pe, pid: LONGINT;
  921. BEGIN
  922. INC(tempno); n := tempno; i := 0; j := 0; pe := 1;
  923. WHILE finalName[j] = ' ' DO INC(j) END; (* skip leading spaces *)
  924. IF finalName[j] # "/" THEN (* relative pathname *)
  925. WHILE cwd[i] # 0X DO tempName[i] := cwd[i]; INC(i) END;
  926. IF tempName[i - 1] # '/' THEN tempName[i] := '/'; INC(i) END;
  927. pe := i - 1
  928. END;
  929. WHILE finalName[j] # 0X DO tempName[i] := finalName[j]; INC(i); INC(j) END;
  930. WHILE (i > pe) & (tempName[i-1] # '/') DO DEC(i) END; (* remove filename *)
  931. tempName[i] := 0X;
  932. Append( tempName, ".tmp." );
  933. AppendInt( tempName, n ); Append( tempName, "." );
  934. pid := Unix.getpid();
  935. AppendInt( tempName, pid )
  936. END GetTempName;
  937. (*
  938. PROCEDURE CloseFiles;
  939. VAR i: LONGINT; f: File;
  940. BEGIN
  941. i := 0;
  942. WHILE i < FileTabSize DO
  943. f := fileTab[i].f;
  944. IF f # NIL THEN f.Close END;
  945. INC( i )
  946. END;
  947. END CloseFiles;
  948. *)
  949. PROCEDURE Install;
  950. VAR aliasFS: AliasFileSystem;
  951. BEGIN
  952. NEW(collection);
  953. NEW( unixFS ); (* Files.Add( unixFS, "" ); *)
  954. NEW( aliasFS, unixFS ); Files.Add( aliasFS, "searcher" )
  955. END Install;
  956. PROCEDURE Initialize;
  957. VAR a: ADDRESS; i: INTEGER; ch: CHAR;
  958. BEGIN
  959. (* get current working directory *)
  960. a := Unix.getenv( ADDRESSOF( "PWD" ) );
  961. IF a > 0 THEN
  962. i := 0;
  963. REPEAT S.GET( a, ch ); INC( a ); cwd[i] := ch; INC( i ) UNTIL ch = 0X;
  964. ELSE
  965. (* $PWD not set *)
  966. a := Unix.getcwd( ADDRESSOF( cwd ), LEN( cwd ) )
  967. END;
  968. i := 0;
  969. WHILE cwd[i] # 0X DO INC( i ) END;
  970. DEC( i );
  971. IF (i > 0) & (cwd[i] = '/') THEN cwd[i] := 0X END;
  972. (* get search pathes *)
  973. a := Unix.getenv( ADDRESSOF( "AOSPATH" ) ); i := 0;
  974. IF a = 0 THEN
  975. Log.String( "UnixFiles.Initialize: environment variable AOSPATH not defined" ); Log.Ln;
  976. (* Unix.exit( 1 ) *)
  977. ELSE
  978. REPEAT
  979. S.GET( a, ch ); INC( a );
  980. IF ch = ":" THEN ch := " " END;
  981. searchPath[i] := ch; INC( i )
  982. UNTIL ch = 0X;
  983. END;
  984. i := 0;
  985. (*
  986. WHILE i < DO fileTab[i].f := NIL; INC( i ) END;
  987. *)
  988. tempno := 1; openfiles := 0;
  989. Modules.InstallTermHandler( Finalization )
  990. END Initialize;
  991. PROCEDURE Finalization;
  992. VAR ft: Files.FileSystemTable; i: LONGINT;
  993. BEGIN
  994. Files.GetList( ft );
  995. IF ft # NIL THEN
  996. FOR i := 0 TO LEN( ft^ ) - 1 DO
  997. IF ft[i] IS AliasFileSystem THEN Files.Remove( ft[i] ) END
  998. END
  999. END;
  1000. collection.Finalize;
  1001. unixFS.Finalize;
  1002. END Finalization;
  1003. PROCEDURE DecOpenFiles;
  1004. BEGIN{EXCLUSIVE}
  1005. DEC(openfiles);
  1006. END DecOpenFiles;
  1007. PROCEDURE IncOpenFiles;
  1008. BEGIN{EXCLUSIVE}
  1009. INC(openfiles);
  1010. END IncOpenFiles;
  1011. PROCEDURE WaitClose(no: LONGINT);
  1012. BEGIN{EXCLUSIVE}
  1013. AWAIT(openfiles < no);
  1014. END WaitClose;
  1015. BEGIN
  1016. Initialize;
  1017. Install
  1018. END UnixFiles.