TFTPFS.Mod 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE TFTPFS; (** AUTHOR "be/pjm"; PURPOSE "Simple TFTP-based file system"; *)
  3. (* Aos file system intended for RAM-disk based storage with automatic file fetching via TFTP. *)
  4. IMPORT SYSTEM, Machine, KernelLog, Modules, Clock, Files, Objects, IP, TFTP;
  5. CONST
  6. MinVolSize = 4;
  7. SF = 29; (* SectorFactor *)
  8. FnLength = 32; (* includes 0X *)
  9. STS = 128; (* SecTabSize *)
  10. SS = 4096; (* SectorSize *)
  11. XS = SS DIV 4; (* IndexSize *)
  12. HS = 568; (* HeaderSize *)
  13. DirRootAdr = 1*SF;
  14. DirPgSize = 102;
  15. N = DirPgSize DIV 2;
  16. DirMark = LONGINT(9B1EA38DH);
  17. HeaderMark = LONGINT(9BA71D86H);
  18. FillerSize = 4;
  19. MapIndexSize = (SS-4) DIV 4;
  20. MapSize = SS DIV SIZEOF (SET); (* {MapSize MOD SIZE (SET) = 0} *)
  21. MapMark = LONGINT(9C2F977FH);
  22. MaxBufs = 4;
  23. InitHint = 200*SF;
  24. Closed = 0X; Opening = 1X; Opened = 2X; Closing = 3X;
  25. MaxRetries = 3;
  26. SetSize = MAX (SET) + 1;
  27. TYPE
  28. DiskSector = RECORD END; (* Oberon Sector, size SS *)
  29. DiskSectorArr = ARRAY SS OF CHAR;
  30. DiskAdr = LONGINT;
  31. FileName = ARRAY FnLength OF CHAR;
  32. SectorTable = ARRAY STS OF DiskAdr;
  33. FileHeader = RECORD (DiskSector) (* allocated in the first page of each file on disk *)
  34. mark: LONGINT;
  35. name: FileName;
  36. aleng, bleng: LONGINT;
  37. date, time: LONGINT;
  38. sec: SectorTable;
  39. ext: DiskAdr;
  40. data: ARRAY SS-HS OF CHAR
  41. END;
  42. IndexSector = RECORD (DiskSector)
  43. x: ARRAY XS OF DiskAdr
  44. END;
  45. DataSector = RECORD (DiskSector)
  46. B: ARRAY SS OF CHAR
  47. END;
  48. DirEntry = RECORD (*B-tree node*)
  49. name: FileName;
  50. adr: DiskAdr; (*sec no of file header*)
  51. p: DiskAdr (*sec no of descendant in directory*)
  52. END;
  53. DirPage = RECORD (DiskSector)
  54. mark: LONGINT;
  55. m: LONGINT;
  56. p0: DiskAdr; (*sec no of left descendant in directory*)
  57. fill: ARRAY FillerSize OF CHAR;
  58. e: ARRAY DirPgSize OF DirEntry
  59. END;
  60. MapIndex = RECORD (DiskSector)
  61. mark: LONGINT;
  62. index: ARRAY MapIndexSize OF DiskAdr
  63. END;
  64. MapSector = RECORD (DiskSector)
  65. map: ARRAY MapSize OF SET
  66. END;
  67. FileHd = POINTER TO FileHeader;
  68. Buffer = POINTER TO RECORD (Files.Hint)
  69. apos, lim: LONGINT;
  70. mod: BOOLEAN;
  71. next: Buffer;
  72. data: DataSector
  73. END;
  74. SuperIndex = POINTER TO RECORD
  75. adr: DiskAdr;
  76. mod: BOOLEAN;
  77. sub: ARRAY XS OF SubIndex
  78. END;
  79. SubIndex = POINTER TO RECORD
  80. adr: DiskAdr;
  81. mod: BOOLEAN;
  82. sec: IndexSector
  83. END;
  84. TYPE
  85. Directory = OBJECT
  86. VAR
  87. vol: Files.Volume;
  88. state: CHAR;
  89. lastSectorReserved: BOOLEAN;
  90. (* "exported" methods: Search, Insert, Delete *)
  91. PROCEDURE Search(VAR name: FileName; VAR A: DiskAdr);
  92. VAR i, L, R: LONGINT; dadr: DiskAdr; a: DirPage;
  93. BEGIN {EXCLUSIVE}
  94. ASSERT(state = Opened);
  95. dadr := DirRootAdr;
  96. LOOP
  97. GetSector(vol, dadr, a);
  98. ASSERT(a.mark = DirMark);
  99. L := 0; R := a.m; (*binary search*)
  100. WHILE L < R DO
  101. i := (L+R) DIV 2;
  102. IF name <= a.e[i].name THEN R := i ELSE L := i+1 END
  103. END ;
  104. IF (R < a.m) & (name = a.e[R].name) THEN
  105. A := a.e[R].adr; EXIT (*found*)
  106. END ;
  107. IF R = 0 THEN dadr := a.p0 ELSE dadr := a.e[R-1].p END ;
  108. IF dadr = 0 THEN A := 0; EXIT (*not found*) END
  109. END
  110. END Search;
  111. PROCEDURE insert(VAR name: FileName; dpg0: DiskAdr; VAR h: BOOLEAN; VAR v: DirEntry; fad: DiskAdr);
  112. (*h = "tree has become higher and v is ascending element"*)
  113. VAR ch: CHAR; i, j, L, R: LONGINT; dpg1: DiskAdr; u: DirEntry; a: DirPage;
  114. BEGIN (*~h*)
  115. ASSERT(state = Opened);
  116. GetSector(vol, dpg0, a);
  117. L := 0; R := a.m; (*binary search*)
  118. WHILE L < R DO
  119. i := (L+R) DIV 2;
  120. IF name <= a.e[i].name THEN R := i ELSE L := i+1 END
  121. END ;
  122. IF (R < a.m) & (name = a.e[R].name) THEN
  123. a.e[R].adr := fad; PutSector(vol, dpg0, a) (*replace*)
  124. ELSE (*not on this page*)
  125. IF R = 0 THEN dpg1 := a.p0 ELSE dpg1 := a.e[R-1].p END ;
  126. IF dpg1 = 0 THEN (*not in tree, insert*)
  127. u.adr := fad; u.p := 0; h := TRUE; j := 0;
  128. REPEAT ch := name[j]; u.name[j] := ch; INC(j)
  129. UNTIL ch = 0X;
  130. WHILE j < FnLength DO u.name[j] := 0X; INC(j) END
  131. ELSE
  132. insert(name, dpg1, h, u, fad)
  133. END ;
  134. IF h THEN (*insert u to the left of e[R]*)
  135. IF a.m < DirPgSize THEN
  136. h := FALSE; i := a.m;
  137. WHILE i > R DO DEC(i); a.e[i+1] := a.e[i] END ;
  138. a.e[R] := u; INC(a.m)
  139. ELSE (*split page and assign the middle element to v*)
  140. a.m := N; a.mark := DirMark;
  141. IF R < N THEN (*insert in left half*)
  142. v := a.e[N-1]; i := N-1;
  143. WHILE i > R DO DEC(i); a.e[i+1] := a.e[i] END ;
  144. a.e[R] := u; PutSector(vol, dpg0, a);
  145. AllocSector(vol, dpg0, dpg0); i := 0;
  146. WHILE i < N DO a.e[i] := a.e[i+N]; INC(i) END
  147. ELSE (*insert in right half*)
  148. PutSector(vol, dpg0, a);
  149. AllocSector(vol, dpg0, dpg0); DEC(R, N); i := 0;
  150. IF R = 0 THEN v := u
  151. ELSE v := a.e[N];
  152. WHILE i < R-1 DO a.e[i] := a.e[N+1+i]; INC(i) END ;
  153. a.e[i] := u; INC(i)
  154. END ;
  155. WHILE i < N DO a.e[i] := a.e[N+i]; INC(i) END
  156. END ;
  157. a.p0 := v.p; v.p := dpg0
  158. END ;
  159. PutSector(vol, dpg0, a)
  160. END
  161. END
  162. END insert;
  163. PROCEDURE Insert(VAR name: FileName; fad: DiskAdr);
  164. VAR oldroot: DiskAdr; h: BOOLEAN; U: DirEntry; a: DirPage;
  165. BEGIN {EXCLUSIVE}
  166. h := FALSE;
  167. insert(name, DirRootAdr, h, U, fad);
  168. IF h THEN (*root overflow*)
  169. GetSector(vol, DirRootAdr, a);
  170. AllocSector(vol, DirRootAdr, oldroot); PutSector(vol, oldroot, a);
  171. a.mark := DirMark; a.m := 1; a.p0 := oldroot; a.e[0] := U;
  172. PutSector(vol, DirRootAdr, a)
  173. END
  174. END Insert;
  175. PROCEDURE underflow(VAR c: DirPage; (*ancestor page*) dpg0: DiskAdr; s: LONGINT; (*insertion point in c*)
  176. VAR h: BOOLEAN); (*c undersize*)
  177. VAR i, k: LONGINT; dpg1: DiskAdr; a, b: DirPage; (*a := underflowing page, b := neighbouring page*)
  178. BEGIN
  179. GetSector(vol, dpg0, a);
  180. (*h & a.m = N-1 & dpg0 = c.e[s-1].p*)
  181. IF s < c.m THEN (*b := page to the right of a*)
  182. dpg1 := c.e[s].p; GetSector(vol, dpg1, b);
  183. k := (b.m-N+1) DIV 2; (*k = no. of items available on page b*)
  184. a.e[N-1] := c.e[s]; a.e[N-1].p := b.p0;
  185. IF k > 0 THEN
  186. (*move k-1 items from b to a, one to c*) i := 0;
  187. WHILE i < k-1 DO a.e[i+N] := b.e[i]; INC(i) END ;
  188. c.e[s] := b.e[i]; b.p0 := c.e[s].p;
  189. c.e[s].p := dpg1; DEC(b.m, k); i := 0;
  190. WHILE i < b.m DO b.e[i] := b.e[i+k]; INC(i) END ;
  191. PutSector(vol, dpg1, b); a.m := N-1+k; h := FALSE
  192. ELSE (*merge pages a and b, discard b*) i := 0;
  193. WHILE i < N DO a.e[i+N] := b.e[i]; INC(i) END ;
  194. i := s; DEC(c.m);
  195. WHILE i < c.m DO c.e[i] := c.e[i+1]; INC(i) END ;
  196. a.m := 2*N; h := c.m < N
  197. END ;
  198. PutSector(vol, dpg0, a)
  199. ELSE (*b := page to the left of a*) DEC(s);
  200. IF s = 0 THEN dpg1 := c.p0 ELSE dpg1 := c.e[s-1].p END ;
  201. GetSector(vol, dpg1, b);
  202. k := (b.m-N+1) DIV 2; (*k = no. of items available on page b*)
  203. IF k > 0 THEN
  204. i := N-1;
  205. WHILE i > 0 DO DEC(i); a.e[i+k] := a.e[i] END ;
  206. i := k-1; a.e[i] := c.e[s]; a.e[i].p := a.p0;
  207. (*move k-1 items from b to a, one to c*) DEC(b.m, k);
  208. WHILE i > 0 DO DEC(i); a.e[i] := b.e[i+b.m+1] END ;
  209. c.e[s] := b.e[b.m]; a.p0 := c.e[s].p;
  210. c.e[s].p := dpg0; a.m := N-1+k; h := FALSE;
  211. PutSector(vol, dpg0, a)
  212. ELSE (*merge pages a and b, discard a*)
  213. c.e[s].p := a.p0; b.e[N] := c.e[s]; i := 0;
  214. WHILE i < N-1 DO b.e[i+N+1] := a.e[i]; INC(i) END ;
  215. b.m := 2*N; DEC(c.m); h := c.m < N
  216. END ;
  217. PutSector(vol, dpg1, b)
  218. END
  219. END underflow;
  220. PROCEDURE delete(VAR name: FileName; dpg0: DiskAdr; VAR h: BOOLEAN; VAR fad: DiskAdr);
  221. (*search and delete entry with key name; if a page underflow arises,
  222. balance with adjacent page or merge; h := "page dpg0 is undersize"*)
  223. VAR i, L, R: LONGINT; dpg1: DiskAdr; a: DirPage;
  224. PROCEDURE del(dpg1: DiskAdr; VAR h: BOOLEAN);
  225. VAR dpg2: DiskAdr; (*global: a, R*) b: DirPage;
  226. BEGIN
  227. GetSector(vol, dpg1, b); dpg2 := b.e[b.m-1].p;
  228. IF dpg2 # 0 THEN del(dpg2, h);
  229. IF h THEN underflow(b, dpg2, b.m, h); PutSector(vol, dpg1, b) END
  230. ELSE
  231. b.e[b.m-1].p := a.e[R].p; a.e[R] := b.e[b.m-1];
  232. DEC(b.m); h := b.m < N; PutSector(vol, dpg1, b)
  233. END
  234. END del;
  235. BEGIN (*~h*)
  236. ASSERT(state = Opened);
  237. GetSector(vol, dpg0, a);
  238. L := 0; R := a.m; (*binary search*)
  239. WHILE L < R DO
  240. i := (L+R) DIV 2;
  241. IF name <= a.e[i].name THEN R := i ELSE L := i+1 END
  242. END ;
  243. IF R = 0 THEN dpg1 := a.p0 ELSE dpg1 := a.e[R-1].p END ;
  244. IF (R < a.m) & (name = a.e[R].name) THEN
  245. (*found, now delete*) fad := a.e[R].adr;
  246. IF dpg1 = 0 THEN (*a is a leaf page*)
  247. DEC(a.m); h := a.m < N; i := R;
  248. WHILE i < a.m DO a.e[i] := a.e[i+1]; INC(i) END
  249. ELSE del(dpg1, h);
  250. IF h THEN underflow(a, dpg1, R, h) END
  251. END ;
  252. PutSector(vol, dpg0, a)
  253. ELSIF dpg1 # 0 THEN
  254. delete(name, dpg1, h, fad);
  255. IF h THEN underflow(a, dpg1, R, h); PutSector(vol, dpg0, a) END
  256. ELSE (*not in tree*) fad := 0
  257. END
  258. END delete;
  259. PROCEDURE Delete(VAR name: FileName; VAR fad: DiskAdr);
  260. VAR h: BOOLEAN; newroot: DiskAdr; a: DirPage;
  261. BEGIN {EXCLUSIVE}
  262. h := FALSE;
  263. delete(name, DirRootAdr, h, fad);
  264. IF h THEN (*root underflow*)
  265. GetSector(vol, DirRootAdr, a);
  266. IF (a.m = 0) & (a.p0 # 0) THEN
  267. newroot := a.p0; GetSector(vol, newroot, a);
  268. PutSector(vol, DirRootAdr, a) (*discard newroot*)
  269. END
  270. END
  271. END Delete;
  272. PROCEDURE Startup;
  273. VAR
  274. j, sec, size, q, free, thres: LONGINT; mi: MapIndex; ms: MapSector;
  275. s: ARRAY 10 OF CHAR; found: BOOLEAN;
  276. BEGIN (* only called from Init *)
  277. size := vol.size; found := FALSE;
  278. IF (vol.Available() = size) & (size # 0) THEN (* all sectors available *)
  279. GetSector(vol, size*SF, mi);
  280. IF mi.mark = MapMark THEN
  281. j := 0; (* check consistency of index *)
  282. WHILE (j # MapIndexSize) & (mi.index[j] >= 0) & (mi.index[j] MOD SF = 0) DO
  283. INC(j)
  284. END;
  285. IF j = MapIndexSize THEN
  286. found := TRUE;
  287. mi.mark := 0; PutSector(vol, size*SF, mi); (* invalidate index *)
  288. j := 0; sec := 1; q := 0;
  289. LOOP
  290. IF (j = MapIndexSize) OR (mi.index[j] = 0) THEN EXIT END;
  291. GetSector(vol, mi.index[j], ms);
  292. REPEAT
  293. IF (sec MOD SetSize) IN ms.map[sec DIV SetSize MOD MapSize] THEN
  294. MarkSector(vol, sec*SF);
  295. INC(q)
  296. END;
  297. IF sec = size THEN EXIT END;
  298. INC(sec)
  299. UNTIL sec MOD (MapSize*SetSize) = 0;
  300. INC(j)
  301. END;
  302. Machine.GetConfig("DiskGC", s);
  303. thres := 0; j := 0;
  304. WHILE s[j] # 0X DO thres := thres*10+(ORD(s[j])-48); INC(j) END;
  305. IF thres < 10 THEN thres := 10
  306. ELSIF thres > 100 THEN thres := 100
  307. END;
  308. ASSERT(q = size-vol.Available());
  309. free := vol.Available()*100 DIV size;
  310. IF (free > thres) & (vol.Available()*SS > 100000H) THEN
  311. state := Opened
  312. ELSE (* undo *)
  313. FOR j := SF TO size*SF BY SF DO
  314. IF Marked(vol, j) THEN FreeSector(vol, j) END
  315. END;
  316. ASSERT(vol.Available() = size);
  317. KernelLog.String("DiskFS: "); KernelLog.Int(free, 1);
  318. KernelLog.String("% free, forcing disk GC on ");
  319. KernelLog.String(vol.name); KernelLog.Ln
  320. END
  321. END
  322. END;
  323. IF ~found THEN
  324. KernelLog.String("DiskFS: Index not found on ");
  325. KernelLog.String(vol.name); KernelLog.Ln
  326. END
  327. END
  328. END Startup;
  329. PROCEDURE &Init*(vol: Files.Volume);
  330. VAR k: LONGINT; A: ARRAY 2000 OF DiskAdr; files: LONGINT; bad: BOOLEAN;
  331. PROCEDURE MarkSectors;
  332. VAR L, R, i, j, n: LONGINT; x: DiskAdr; hd: FileHeader; sup, sub: IndexSector;
  333. PROCEDURE sift(L, R: LONGINT);
  334. VAR i, j: LONGINT; x: DiskAdr;
  335. BEGIN j := L; x := A[j];
  336. LOOP i := j; j := 2*j + 1;
  337. IF (j+1 < R) & (A[j] < A[j+1]) THEN INC(j) END ;
  338. IF (j >= R) OR (x > A[j]) THEN EXIT END ;
  339. A[i] := A[j]
  340. END ;
  341. A[i] := x
  342. END sift;
  343. BEGIN
  344. KernelLog.String(" marking");
  345. L := k DIV 2; R := k; (*heapsort*)
  346. WHILE L > 0 DO DEC(L); sift(L, R) END ;
  347. WHILE R > 0 DO
  348. DEC(R); x := A[0]; A[0] := A[R]; A[R] := x; sift(L, R)
  349. END;
  350. WHILE L < k DO
  351. bad := FALSE; INC(files);
  352. IF files MOD 128 = 0 THEN KernelLog.Char(".") END;
  353. GetSector(vol, A[L], hd);
  354. IF hd.aleng < STS THEN
  355. j := hd.aleng + 1;
  356. REPEAT
  357. DEC(j);
  358. IF hd.sec[j] # 0 THEN MarkSector(vol, hd.sec[j]) ELSE hd.aleng := j-1; bad := TRUE END
  359. UNTIL j = 0
  360. ELSE
  361. j := STS;
  362. REPEAT
  363. DEC(j);
  364. IF hd.sec[j] # 0 THEN MarkSector(vol, hd.sec[j]) ELSE hd.aleng := j-1; bad := TRUE END
  365. UNTIL j = 0;
  366. IF hd.ext = 0 THEN hd.aleng := STS-1; bad := TRUE END;
  367. IF ~bad THEN
  368. MarkSector(vol, hd.ext); GetSector(vol, hd.ext, sup);
  369. n := (hd.aleng - STS) DIV XS; i := 0;
  370. WHILE (i <= n) & ~bad DO
  371. IF sup.x[i] # 0 THEN
  372. MarkSector(vol, sup.x[i]); GetSector(vol, sup.x[i], sub);
  373. IF i < n THEN j := XS
  374. ELSE j := (hd.aleng - STS) MOD XS + 1
  375. END;
  376. REPEAT
  377. DEC(j);
  378. IF (sub.x[j] MOD SF = 0) & (sub.x[j] > 0) THEN
  379. MarkSector(vol, sub.x[j])
  380. ELSE
  381. bad := TRUE
  382. END
  383. UNTIL j = 0;
  384. INC(i)
  385. ELSE bad := TRUE
  386. END;
  387. IF bad THEN
  388. IF i = 0 THEN hd.aleng := STS-1
  389. ELSE hd.aleng := STS + (i-1) * XS
  390. END
  391. END
  392. END
  393. END
  394. END;
  395. IF bad THEN
  396. KernelLog.Ln; KernelLog.String(hd.name); KernelLog.String(" truncated");
  397. hd.bleng := SS; IF hd.aleng < 0 THEN hd.aleng := 0 (* really bad *) END;
  398. PutSector(vol, A[L], hd)
  399. END;
  400. INC(L)
  401. END
  402. END MarkSectors;
  403. PROCEDURE TraverseDir(dpg: DiskAdr);
  404. VAR i: LONGINT; a: DirPage;
  405. BEGIN
  406. GetSector(vol, dpg, a); MarkSector(vol, dpg); i := 0;
  407. WHILE i < a.m DO
  408. A[k] := a.e[i].adr;
  409. (*
  410. IF A[k] = 0DEADDEADH THEN
  411. KernelLog.Enter; KernelLog.Int(dpg DIV SF, 1); KernelLog.Char(" "); KernelLog.Int(k, 1); KernelLog.Exit
  412. END;
  413. *)
  414. INC(k); INC(i);
  415. IF k = 2000 THEN MarkSectors; k := 0 END
  416. END ;
  417. IF a.p0 # 0 THEN
  418. TraverseDir(a.p0); i := 0;
  419. WHILE i < a.m DO
  420. TraverseDir(a.e[i].p); INC(i)
  421. END
  422. END
  423. END TraverseDir;
  424. BEGIN
  425. SELF.vol := vol; lastSectorReserved := FALSE;
  426. IF ~(Files.ReadOnly IN vol.flags) THEN
  427. state := Opening; k := 0;
  428. Startup;
  429. IF state # Opened THEN
  430. files := 0; KernelLog.String("DiskFS: Scanning ");
  431. KernelLog.String(vol.name); KernelLog.String("...");
  432. TraverseDir(DirRootAdr);
  433. MarkSectors;
  434. KernelLog.Int(files, 6); KernelLog.String(" files"); KernelLog.Ln;
  435. state := Opened
  436. END;
  437. IF ~Marked(vol, vol.size*SF) THEN (* last sector still free *)
  438. MarkSector(vol, vol.size*SF); lastSectorReserved := TRUE (* allocate it *)
  439. END;
  440. KernelLog.String("DiskFS: "); KernelLog.Int(vol.Available() * (SS DIV 1024), 1);
  441. KernelLog.String("K of "); KernelLog.Int(vol.size * (SS DIV 1024), 1);
  442. KernelLog.String("K available on "); KernelLog.String(vol.name);
  443. KernelLog.Ln
  444. ELSE
  445. state := Opened
  446. END
  447. END Init;
  448. PROCEDURE Cleanup;
  449. VAR i, j, p, q, sec, size: LONGINT; mi: MapIndex; ms: MapSector;
  450. BEGIN {EXCLUSIVE}
  451. (*KernelLog.String("DiskFS: Cleanup "); KernelLog.String(vol.name); KernelLog.Ln;*)
  452. state := Closing;
  453. size := vol.size; i := size*SF;
  454. IF ~(Files.ReadOnly IN vol.flags) THEN
  455. IF lastSectorReserved THEN FreeSector(vol, i); lastSectorReserved := FALSE END;
  456. IF ~Marked(vol, i) THEN (* last sector is available for us *)
  457. j := 0; sec := 1; q := 0;
  458. LOOP
  459. REPEAT DEC(i, SF) UNTIL (i = 0) OR ~Marked(vol, i); (* find a free sector *)
  460. IF i = 0 THEN RETURN END; (* no more space, don't commit *)
  461. mi.index[j] := i; INC(j);
  462. FOR p := 0 TO MapSize-1 DO ms.map[p] := {} END;
  463. REPEAT
  464. IF Marked(vol, sec*SF) THEN
  465. INCL(ms.map[sec DIV SetSize MOD MapSize], sec MOD SetSize);
  466. INC(q)
  467. END;
  468. IF sec = size THEN
  469. PutSector(vol, i, ms);
  470. EXIT
  471. END;
  472. INC(sec)
  473. UNTIL sec MOD (MapSize*SetSize) = 0;
  474. PutSector(vol, i, ms)
  475. END;
  476. WHILE j # MapIndexSize DO mi.index[j] := 0; INC(j) END;
  477. mi.mark := MapMark;
  478. PutSector(vol, size*SF, mi); (* commit *)
  479. KernelLog.String("DiskFS: Map saved on ");
  480. KernelLog.String(vol.name); KernelLog.Ln
  481. (*ELSE
  482. KernelLog.String("DiskFS: sector in use "); KernelLog.Int(size, 1); KernelLog.Ln*)
  483. END
  484. (*ELSE
  485. KernelLog.String("DiskFS: Read-only"); KernelLog.Ln*)
  486. END;
  487. state := Closed; vol := NIL
  488. END Cleanup;
  489. END Directory;
  490. TYPE
  491. RecursiveLock* = OBJECT
  492. VAR lockedBy: ANY; level: LONGINT;
  493. PROCEDURE Acquire*;
  494. VAR me: ANY;
  495. BEGIN {EXCLUSIVE}
  496. me := Objects.ActiveObject();
  497. IF lockedBy = me THEN
  498. ASSERT(level # -1); (* overflow *)
  499. INC(level)
  500. ELSE
  501. AWAIT(lockedBy = NIL);
  502. lockedBy := me; level := 1
  503. END
  504. END Acquire;
  505. PROCEDURE Release*;
  506. BEGIN {EXCLUSIVE}
  507. ASSERT(lockedBy = Objects.ActiveObject()); (* must hold lock *)
  508. DEC(level);
  509. IF level = 0 THEN lockedBy := NIL END
  510. END Release;
  511. PROCEDURE &Init*;
  512. BEGIN
  513. lockedBy := NIL; level := 0
  514. END Init;
  515. END RecursiveLock;
  516. FileSystem = OBJECT (Files.FileSystem) (* our file system type *)
  517. VAR dir: Directory;
  518. server: IP.Adr;
  519. lock: RecursiveLock;
  520. PROCEDURE &Init*(server: IP.Adr);
  521. BEGIN SELF.server := server; NEW(lock)
  522. END Init;
  523. PROCEDURE New0(name: ARRAY OF CHAR): Files.File;
  524. VAR i: LONGINT; res: WORD; f: File; buf: Buffer; head: FileHd; namebuf: FileName;
  525. BEGIN (*{EXCLUSIVE}*)
  526. lock.Acquire;
  527. f := NIL; Check(name, namebuf, res);
  528. IF res <= 0 THEN
  529. NEW(buf); buf.apos := 0; buf.mod := TRUE; buf.lim := HS; buf.next := buf;
  530. head := SYSTEM.VAL(FileHd, ADDRESSOF(buf.data));
  531. head.mark := HeaderMark;
  532. head.aleng := 0; head.bleng := HS; head.name := namebuf;
  533. Clock.Get(head.time, head.date);
  534. NEW(f); f.fs := SELF; f.key := 0; f.aleng := 0; f.bleng := HS; f.modH := TRUE;
  535. f.time := head.time; f.date := head.date;
  536. f.firstbuf := buf; f.nofbufs := 1; f.name := namebuf; f.sechint := InitHint;
  537. f.registered := (f.name[0] = 0X);
  538. f.ext := NIL; i := 0;
  539. REPEAT f.sec[i] := 0; head.sec[i] := 0; INC(i) UNTIL i = STS
  540. END;
  541. lock.Release;
  542. RETURN f
  543. END New0;
  544. PROCEDURE Old0(name: ARRAY OF CHAR): Files.File;
  545. VAR
  546. i, k: LONGINT; res: WORD; f: File; header: DiskAdr; buf: Buffer; head: FileHd;
  547. namebuf, local: FileName; super: SuperIndex; sub: SubIndex; sec: IndexSector;
  548. BEGIN (*{EXCLUSIVE}*)
  549. lock.Acquire;
  550. f := NIL; Check(name, namebuf, res);
  551. IF res = 0 THEN
  552. dir.Search(namebuf, header); (* search locally *)
  553. (*
  554. IF (header = 0) & BimboTFTP.Receive(SELF, namebuf, namebuf, server) THEN (* search remote *)
  555. dir.Search(namebuf, header)
  556. END;
  557. *)
  558. IF (header = 0) THEN
  559. Files.JoinName(prefix, namebuf, local);
  560. i := 0;
  561. WHILE (i < MaxRetries) & ~TFTP.Receive(local, namebuf, server) DO INC(i) END;
  562. IF (i < MaxRetries) THEN
  563. dir.Search(namebuf, header)
  564. END
  565. END;
  566. IF header # 0 THEN
  567. NEW(buf); buf.apos := 0; buf.next := buf; buf.mod := FALSE;
  568. GetSector(vol, header, buf.data);
  569. head := SYSTEM.VAL(FileHd, ADDRESSOF(buf.data));
  570. NEW(f); f.fs := SELF; f.key := header;
  571. f.aleng := head.aleng; f.bleng := head.bleng;
  572. f.time := head.time; f.date := head.date;
  573. IF f.aleng = 0 THEN buf.lim := f.bleng ELSE buf.lim := SS END;
  574. f.firstbuf := buf; f.nofbufs := 1;
  575. f.name := namebuf; f.registered := TRUE;
  576. f.sec := head.sec;
  577. k := (f.aleng + (XS-STS)) DIV XS;
  578. IF k # 0 THEN
  579. NEW(super); super.adr := head.ext; super.mod := FALSE; f.ext := super;
  580. GetSector(vol, super.adr, sec); i := 0;
  581. WHILE i # k DO
  582. NEW(sub); sub.adr := sec.x[i]; sub.mod := FALSE; super.sub[i] := sub;
  583. GetSector(vol, sub.adr, sub.sec); INC(i)
  584. END;
  585. WHILE i # XS DO super.sub[i] := NIL; INC(i) END
  586. ELSE
  587. f.ext := NIL
  588. END;
  589. f.sechint := header; f.modH := FALSE
  590. END
  591. END;
  592. lock.Release;
  593. RETURN f
  594. END Old0;
  595. PROCEDURE Delete0(name: ARRAY OF CHAR; VAR key: LONGINT; VAR res: WORD);
  596. VAR adr: DiskAdr; namebuf: FileName; head: FileHeader;
  597. BEGIN (*{EXCLUSIVE}*)
  598. lock.Acquire;
  599. Check(name, namebuf, res);
  600. IF res = 0 THEN
  601. dir.Delete(namebuf, adr);
  602. key := adr;
  603. IF adr # 0 THEN
  604. GetSector(vol, adr, head);
  605. head.mark := HeaderMark+1; (* invalidate mark *)
  606. PutSector(vol, adr, head)
  607. ELSE
  608. res := 2
  609. END
  610. ELSE
  611. key := 0
  612. END;
  613. lock.Release
  614. END Delete0;
  615. PROCEDURE Rename0(old, new: ARRAY OF CHAR; f: Files.File; VAR res: WORD);
  616. VAR adr: DiskAdr; oldbuf, newbuf: FileName; head: FileHeader;
  617. BEGIN (*{EXCLUSIVE}*)
  618. lock.Acquire;
  619. Check(old, oldbuf, res);
  620. IF res = 0 THEN
  621. Check(new, newbuf, res);
  622. IF res = 0 THEN
  623. dir.Delete(oldbuf, adr);
  624. IF adr # 0 THEN
  625. IF f # NIL THEN (* file is open *)
  626. ASSERT(f.key = adr); (* it's key must match *)
  627. f(File).name := newbuf
  628. END;
  629. dir.Insert(newbuf, adr);
  630. GetSector(vol, adr, head);
  631. head.name := newbuf;
  632. PutSector(vol, adr, head)
  633. ELSE res := 2
  634. END
  635. END
  636. END;
  637. lock.Release
  638. END Rename0;
  639. PROCEDURE Enumerate0(mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator);
  640. VAR b: BOOLEAN; fh: FileHeader; fn: ARRAY Files.PrefixLength+FnLength OF CHAR;
  641. BEGIN (*{EXCLUSIVE}*)
  642. lock.Acquire;
  643. b := TRUE; enumerate(SELF, mask, DirRootAdr, flags, enum, b, fh, fn);
  644. lock.Release
  645. END Enumerate0;
  646. PROCEDURE FileKey(name: ARRAY OF CHAR): LONGINT;
  647. VAR res: WORD; namebuf: FileName; header: DiskAdr;
  648. BEGIN (*{EXCLUSIVE}*)
  649. lock.Acquire;
  650. header := 0;
  651. Check(name, namebuf, res);
  652. IF res = 0 THEN
  653. dir.Search(namebuf, header)
  654. END;
  655. lock.Release;
  656. RETURN header
  657. END FileKey;
  658. PROCEDURE Finalize;
  659. BEGIN (*{EXCLUSIVE}*)
  660. lock.Acquire;
  661. dir.Cleanup();
  662. vol.Finalize;
  663. Finalize^; (* see note in Files *)
  664. lock.Release
  665. END Finalize;
  666. END FileSystem;
  667. TYPE
  668. File = OBJECT (Files.File)
  669. VAR
  670. aleng, bleng: LONGINT;
  671. nofbufs: LONGINT;
  672. modH, registered: BOOLEAN;
  673. firstbuf: Buffer;
  674. sechint: DiskAdr;
  675. name: FileName;
  676. time, date: LONGINT;
  677. ext: SuperIndex;
  678. sec: SectorTable;
  679. PROCEDURE Set(VAR r: Files.Rider; pos: LONGINT);
  680. VAR a, b: LONGINT;
  681. BEGIN {EXCLUSIVE}
  682. r.eof := FALSE; r.res := 0; r.file := SELF; r.fs := fs;
  683. IF pos < 0 THEN
  684. a := 0; b := HS
  685. ELSIF pos < aleng*SS + bleng - HS THEN
  686. a := (pos + HS) DIV SS; b := (pos + HS) MOD SS
  687. ELSE
  688. a := aleng; b := bleng
  689. END;
  690. r.apos := a; r.bpos := b; r.hint := firstbuf
  691. END Set;
  692. PROCEDURE Pos(VAR r: Files.Rider): LONGINT;
  693. BEGIN
  694. RETURN r.apos*SS + r.bpos - HS
  695. END Pos;
  696. PROCEDURE Read(VAR r: Files.Rider; VAR x: CHAR);
  697. VAR buf: Buffer;
  698. BEGIN {EXCLUSIVE}
  699. buf := r.hint(Buffer);
  700. IF r.apos # buf.apos THEN buf := GetBuf(SELF, r.apos); r.hint := buf END;
  701. IF r.bpos < buf.lim THEN
  702. x := buf.data.B[r.bpos]; INC(r.bpos)
  703. ELSIF r.apos < aleng THEN
  704. INC(r.apos);
  705. buf := SearchBuf(SELF, r.apos);
  706. IF buf = NIL THEN
  707. buf := r.hint(Buffer);
  708. IF buf.mod THEN WriteBuf(SELF, buf) END ;
  709. ReadBuf(SELF, buf, r.apos)
  710. ELSE
  711. r.hint := buf
  712. END ;
  713. x := buf.data.B[0]; r.bpos := 1
  714. ELSE
  715. x := 0X; r.eof := TRUE
  716. END
  717. END Read;
  718. PROCEDURE ReadBytes(VAR r: Files.Rider; VAR x: ARRAY OF CHAR; ofs, len: LONGINT);
  719. VAR src, dst: ADDRESS; m: LONGINT; buf: Buffer;
  720. BEGIN {EXCLUSIVE}
  721. IF LEN(x)-ofs < len THEN SYSTEM.HALT(19) END;
  722. IF len > 0 THEN
  723. dst := ADDRESSOF(x[ofs]);
  724. buf := r.hint(Buffer);
  725. IF r.apos # buf.apos THEN buf := GetBuf(SELF, r.apos); r.hint := buf END;
  726. LOOP
  727. IF len <= 0 THEN EXIT END ;
  728. src := ADDRESSOF(buf.data.B[0]) + r.bpos; m := r.bpos + len;
  729. IF m <= buf.lim THEN
  730. SYSTEM.MOVE(src, dst, len); r.bpos := m; r.res := 0; EXIT
  731. ELSIF buf.lim = SS THEN
  732. m := buf.lim - r.bpos;
  733. IF m > 0 THEN SYSTEM.MOVE(src, dst, m); INC(dst, m); DEC(len, m) END ;
  734. IF r.apos < aleng THEN
  735. INC(r.apos); r.bpos := 0; buf := SearchBuf(SELF, r.apos);
  736. IF buf = NIL THEN
  737. buf := r.hint(Buffer);
  738. IF buf.mod THEN WriteBuf(SELF, buf) END ;
  739. ReadBuf(SELF, buf, r.apos)
  740. ELSE
  741. r.hint := buf
  742. END
  743. ELSE
  744. r.bpos := buf.lim; r.res := len; r.eof := TRUE; EXIT
  745. END
  746. ELSE
  747. m := buf.lim - r.bpos;
  748. IF m > 0 THEN SYSTEM.MOVE(src, dst, m); r.bpos := buf.lim END ;
  749. r.res := len - m; r.eof := TRUE; EXIT
  750. END
  751. END
  752. ELSE
  753. r.res := 0
  754. END
  755. END ReadBytes;
  756. PROCEDURE Write(VAR r: Files.Rider; x: CHAR);
  757. VAR buf: Buffer;
  758. BEGIN {EXCLUSIVE}
  759. buf := r.hint(Buffer);
  760. IF r.apos # buf.apos THEN buf := GetBuf(SELF, r.apos); r.hint := buf END;
  761. IF r.bpos >= buf.lim THEN
  762. IF r.bpos < SS THEN
  763. INC(buf.lim); INC(bleng); modH := TRUE
  764. ELSE
  765. WriteBuf(SELF, buf); INC(r.apos); buf := SearchBuf(SELF, r.apos);
  766. IF buf = NIL THEN
  767. buf := r.hint(Buffer);
  768. IF r.apos <= aleng THEN
  769. ReadBuf(SELF, buf, r.apos)
  770. ELSE
  771. buf.apos := r.apos; buf.lim := 1; INC(aleng); bleng := 1; modH := TRUE;
  772. IF (aleng - STS) MOD XS = 0 THEN NewSub(SELF) END
  773. END
  774. ELSE
  775. r.hint := buf
  776. END;
  777. r.bpos := 0
  778. END
  779. END;
  780. buf.data.B[r.bpos] := x; INC(r.bpos); buf.mod := TRUE
  781. END Write;
  782. PROCEDURE WriteBytes(VAR r: Files.Rider; CONST x: ARRAY OF CHAR; ofs, len: LONGINT);
  783. VAR src, dst: ADDRESS; m: LONGINT; buf: Buffer;
  784. BEGIN {EXCLUSIVE}
  785. IF LEN(x)-ofs < len THEN SYSTEM.HALT(19) END;
  786. IF len > 0 THEN
  787. src := ADDRESSOF(x[ofs]);
  788. buf := r.hint(Buffer);
  789. IF r.apos # buf.apos THEN buf := GetBuf(SELF, r.apos); r.hint := buf END;
  790. LOOP
  791. IF len <= 0 THEN EXIT END;
  792. buf.mod := TRUE; dst := ADDRESSOF(buf.data.B[0]) + r.bpos; m := r.bpos + len;
  793. IF m <= buf.lim THEN
  794. SYSTEM.MOVE(src, dst, len); r.bpos := m; EXIT
  795. ELSIF m <= SS THEN
  796. SYSTEM.MOVE(src, dst, len); r.bpos := m;
  797. bleng := m; buf.lim := m; modH := TRUE; EXIT
  798. ELSE
  799. m := SS - r.bpos;
  800. IF m > 0 THEN SYSTEM.MOVE(src, dst, m); INC(src, m); DEC(len, m) END;
  801. WriteBuf(SELF, buf); INC(r.apos); r.bpos := 0; buf := SearchBuf(SELF, r.apos);
  802. IF buf = NIL THEN
  803. buf := r.hint(Buffer);
  804. IF r.apos <= aleng THEN ReadBuf(SELF, buf, r.apos)
  805. ELSE
  806. buf.apos := r.apos; buf.lim := 0; INC(aleng); bleng := 0; modH := TRUE;
  807. IF (aleng - STS) MOD XS = 0 THEN NewSub(SELF) END
  808. END
  809. ELSE
  810. r.hint := buf
  811. END
  812. END
  813. END
  814. END
  815. END WriteBytes;
  816. PROCEDURE Length(): LONGINT;
  817. BEGIN {EXCLUSIVE}
  818. RETURN aleng*SS + bleng - HS
  819. END Length;
  820. PROCEDURE GetDate(VAR t, d: LONGINT);
  821. BEGIN {EXCLUSIVE}
  822. t := time; d := date
  823. END GetDate;
  824. PROCEDURE SetDate(t, d: LONGINT);
  825. BEGIN {EXCLUSIVE}
  826. modH := TRUE; time := t; date := d
  827. END SetDate;
  828. PROCEDURE GetName(VAR name: ARRAY OF CHAR);
  829. BEGIN {EXCLUSIVE}
  830. Files.JoinName(fs.prefix, SELF.name, name)
  831. END GetName;
  832. PROCEDURE Register0(VAR res: WORD);
  833. BEGIN {EXCLUSIVE}
  834. Unbuffer(SELF);
  835. IF ~registered & (name # "") THEN
  836. fs(FileSystem).dir.Insert(name, sec[0]);
  837. registered := TRUE; key := sec[0];
  838. res := 0
  839. ELSE
  840. res := 1
  841. END
  842. END Register0;
  843. PROCEDURE Update;
  844. BEGIN {EXCLUSIVE}
  845. Unbuffer(SELF)
  846. END Update;
  847. END File;
  848. PROCEDURE GetSector(vol: Files.Volume; src: DiskAdr; VAR dest: DiskSector);
  849. BEGIN
  850. IF src MOD SF # 0 THEN SYSTEM.HALT(15) END;
  851. vol.GetBlock(src DIV SF, SYSTEM.VAL(DiskSectorArr, dest))
  852. END GetSector;
  853. PROCEDURE PutSector(vol: Files.Volume; dest: DiskAdr; VAR src: DiskSector);
  854. BEGIN
  855. ASSERT(~(Files.ReadOnly IN vol.flags));
  856. IF dest MOD SF # 0 THEN SYSTEM.HALT(15) END;
  857. vol.PutBlock(dest DIV SF, SYSTEM.VAL(DiskSectorArr, src))
  858. END PutSector;
  859. PROCEDURE AllocSector(vol: Files.Volume; hint: DiskAdr; VAR sec: DiskAdr);
  860. BEGIN
  861. ASSERT(~(Files.ReadOnly IN vol.flags));
  862. vol.AllocBlock(hint DIV SF, sec);
  863. sec := sec * SF
  864. END AllocSector;
  865. PROCEDURE MarkSector(vol: Files.Volume; sec: LONGINT);
  866. BEGIN
  867. ASSERT(~(Files.ReadOnly IN vol.flags));
  868. vol.MarkBlock(sec DIV SF)
  869. END MarkSector;
  870. PROCEDURE FreeSector(vol: Files.Volume; sec: LONGINT);
  871. BEGIN
  872. ASSERT(~(Files.ReadOnly IN vol.flags));
  873. vol.FreeBlock(sec DIV SF)
  874. END FreeSector;
  875. PROCEDURE Marked(vol: Files.Volume; sec: LONGINT): BOOLEAN;
  876. BEGIN
  877. ASSERT(~(Files.ReadOnly IN vol.flags));
  878. RETURN vol.Marked(sec DIV SF)
  879. END Marked;
  880. PROCEDURE MatchPrefix(VAR mask, name: ARRAY OF CHAR; VAR pos, diff: LONGINT);
  881. BEGIN
  882. pos := 0;
  883. LOOP
  884. IF mask[pos] = 0X THEN
  885. pos := -1; diff := 0; EXIT (* no "*" found, match all files with this prefix *)
  886. ELSIF mask[pos] = "*" THEN
  887. IF mask[pos+1] = 0X THEN pos := -1 END; (* "*" found at end, match all files with this prefix *)
  888. diff := 0; EXIT (* "*" found, do Match *)
  889. END;
  890. diff := ORD(name[pos]) - ORD(mask[pos]);
  891. IF diff # 0 THEN EXIT END;
  892. INC(pos)
  893. END
  894. END MatchPrefix;
  895. PROCEDURE Match(pos: LONGINT; VAR pat, name: ARRAY OF CHAR): BOOLEAN;
  896. VAR i0, i1, j0, j1: LONGINT; f: BOOLEAN;
  897. BEGIN
  898. f := TRUE;
  899. IF pos # -1 THEN
  900. i0 := pos; j0 := pos;
  901. LOOP
  902. IF pat[i0] = "*" THEN
  903. INC(i0);
  904. IF pat[i0] = 0X THEN EXIT END
  905. ELSE
  906. IF name[j0] # 0X THEN f := FALSE END;
  907. EXIT
  908. END;
  909. f := FALSE;
  910. LOOP
  911. IF name[j0] = 0X THEN EXIT END;
  912. i1 := i0; j1 := j0;
  913. LOOP
  914. IF (pat[i1] = 0X) OR (pat[i1] = "*") THEN f := TRUE; EXIT END;
  915. IF pat[i1] # name[j1] THEN EXIT END;
  916. INC(i1); INC(j1)
  917. END;
  918. IF f THEN j0 := j1; i0 := i1; EXIT END;
  919. INC(j0)
  920. END;
  921. IF ~f THEN EXIT END
  922. END
  923. END;
  924. RETURN f & (name[0] # 0X)
  925. END Match;
  926. PROCEDURE enumerate(fs: Files.FileSystem; VAR mask: ARRAY OF CHAR; dpg: DiskAdr; flags: SET; enum: Files.Enumerator; VAR continue: BOOLEAN; VAR fh: FileHeader; VAR fn: ARRAY OF CHAR);
  927. VAR i, pos, diff: LONGINT; dpg1: DiskAdr; a: DirPage; time, date, size: LONGINT;
  928. BEGIN
  929. GetSector(fs.vol, dpg, a); i := 0;
  930. WHILE (i < a.m) & continue DO
  931. MatchPrefix(mask, a.e[i].name, pos, diff);
  932. IF i = 0 THEN dpg1 := a.p0 ELSE dpg1 := a.e[i-1].p END;
  933. IF diff >= 0 THEN (* matching prefix *)
  934. IF dpg1 # 0 THEN enumerate(fs, mask, dpg1, flags, enum, continue, fh, fn) END;
  935. IF diff = 0 THEN
  936. IF continue & Match(pos, mask, a.e[i].name) THEN
  937. time := 0; date := 0; size := 0;
  938. IF flags * {Files.EnumTime, Files.EnumSize} # {} THEN
  939. GetSector(fs.vol, a.e[i].adr, fh);
  940. IF Files.EnumTime IN flags THEN
  941. time := fh.time; date := fh.date
  942. END;
  943. IF Files.EnumSize IN flags THEN
  944. size := fh.aleng*SS + fh.bleng - HS
  945. END
  946. END;
  947. Files.JoinName(fs.prefix, a.e[i].name, fn);
  948. enum.PutEntry(fn, {}, time, date, size)
  949. END
  950. ELSE continue := FALSE
  951. END
  952. END;
  953. INC(i)
  954. END;
  955. IF continue & (i > 0) & (a.e[i-1].p # 0) THEN
  956. enumerate(fs, mask, a.e[i-1].p, flags, enum, continue, fh, fn)
  957. END
  958. END enumerate;
  959. (* Check a file name. *)
  960. PROCEDURE Check(VAR s: ARRAY OF CHAR; VAR name: FileName; VAR res: WORD);
  961. VAR i: LONGINT; ch: CHAR;
  962. BEGIN
  963. ch := s[0]; i := 0;
  964. IF ("A" <= CAP(ch)) & (CAP(ch) <= "Z") THEN
  965. LOOP name[i] := ch; INC(i); ch := s[i];
  966. IF ch = 0X THEN
  967. WHILE i < FnLength DO name[i] := 0X; INC(i) END ;
  968. res := 0; EXIT
  969. END ;
  970. IF ~(("A" <= CAP(ch)) & (CAP(ch) <= "Z")
  971. OR ("0" <= ch) & (ch <= "9") OR (ch = ".") OR (ch = "_")) THEN res := 3; EXIT
  972. END ;
  973. IF i = FnLength-1 THEN res := 4; EXIT END
  974. END
  975. ELSIF ch = 0X THEN name[0] := 0X; res := -1
  976. ELSE res := 3
  977. END
  978. END Check;
  979. PROCEDURE UpdateHeader(f: File; VAR h: FileHeader);
  980. BEGIN
  981. h.aleng := f.aleng; h.bleng := f.bleng;
  982. h.sec := f.sec;
  983. IF f.ext # NIL THEN h.ext := f.ext.adr ELSE h.ext := 0 END;
  984. h.date := f.date; h.time := f.time
  985. END UpdateHeader;
  986. PROCEDURE ReadBuf(f: File; buf: Buffer; pos: LONGINT);
  987. VAR sec: DiskAdr; xpos: LONGINT;
  988. BEGIN
  989. IF pos < STS THEN
  990. sec := f.sec[pos]
  991. ELSE
  992. xpos := pos-STS;
  993. sec := f.ext.sub[xpos DIV XS].sec.x[xpos MOD XS]
  994. END;
  995. GetSector(f.fs.vol, sec, buf.data);
  996. IF pos < f.aleng THEN buf.lim := SS ELSE buf.lim := f.bleng END;
  997. buf.apos := pos; buf.mod := FALSE
  998. END ReadBuf;
  999. PROCEDURE NewSuper(f: File);
  1000. VAR i: LONGINT; super: SuperIndex;
  1001. BEGIN
  1002. NEW(super); super.adr := 0; super.mod := TRUE; f.modH := TRUE; f.ext := super;
  1003. FOR i := 0 TO XS-1 DO super.sub[i] := NIL END
  1004. END NewSuper;
  1005. PROCEDURE WriteBuf(f: File; buf: Buffer);
  1006. VAR i, k, xpos: LONGINT; secadr: DiskAdr; super: SuperIndex; sub: SubIndex; vol: Files.Volume;
  1007. BEGIN
  1008. vol := f.fs.vol;
  1009. Clock.Get(f.time, f.date); f.modH := TRUE;
  1010. IF buf.apos < STS THEN
  1011. secadr := f.sec[buf.apos];
  1012. IF secadr = 0 THEN
  1013. AllocSector(vol, f.sechint, secadr);
  1014. f.modH := TRUE; f.sec[buf.apos] := secadr; f.sechint := secadr
  1015. END;
  1016. IF buf.apos = 0 THEN
  1017. UpdateHeader(f, SYSTEM.VAL(FileHeader, buf.data)); f.modH := FALSE
  1018. END
  1019. ELSE
  1020. super := f.ext;
  1021. IF super = NIL THEN NewSuper(f); super := f.ext END;
  1022. xpos := buf.apos-STS;
  1023. i := xpos DIV XS; sub := super.sub[i];
  1024. IF sub = NIL THEN
  1025. NEW(sub); sub.adr := 0; sub.sec.x[0] := 0; super.sub[i] := sub; super.mod := TRUE
  1026. END;
  1027. k := xpos MOD XS; secadr := sub.sec.x[k];
  1028. IF secadr = 0 THEN
  1029. AllocSector(vol, f.sechint, secadr); f.sechint := secadr;
  1030. sub.mod := TRUE; sub.sec.x[k] := secadr
  1031. END
  1032. END;
  1033. PutSector(vol, secadr, buf.data); buf.mod := FALSE
  1034. END WriteBuf;
  1035. PROCEDURE SearchBuf(f: File; pos: LONGINT): Buffer;
  1036. VAR buf: Buffer;
  1037. BEGIN
  1038. buf := f.firstbuf;
  1039. LOOP
  1040. IF buf.apos = pos THEN EXIT END;
  1041. buf := buf.next;
  1042. IF buf = f.firstbuf THEN buf := NIL; EXIT END
  1043. END;
  1044. RETURN buf
  1045. END SearchBuf;
  1046. PROCEDURE GetBuf(f: File; pos: LONGINT): Buffer;
  1047. VAR buf: Buffer;
  1048. BEGIN
  1049. buf := f.firstbuf;
  1050. LOOP
  1051. IF buf.apos = pos THEN EXIT END;
  1052. IF buf.next = f.firstbuf THEN
  1053. IF f.nofbufs < MaxBufs THEN (* allocate new buffer *)
  1054. NEW(buf); buf.next := f.firstbuf.next; f.firstbuf.next := buf;
  1055. INC(f.nofbufs)
  1056. ELSE (* take one of the buffers *)
  1057. f.firstbuf := buf;
  1058. IF buf.mod THEN WriteBuf(f, buf) END
  1059. END;
  1060. buf.apos := pos;
  1061. IF pos <= f.aleng THEN ReadBuf(f, buf, pos) END;
  1062. EXIT
  1063. END;
  1064. buf := buf.next
  1065. END;
  1066. RETURN buf
  1067. END GetBuf;
  1068. PROCEDURE Unbuffer(f: File);
  1069. VAR
  1070. i, k: LONGINT; buf: Buffer; super: SuperIndex; sub: SubIndex; head: FileHeader;
  1071. sec: IndexSector; vol: Files.Volume;
  1072. BEGIN
  1073. vol := f.fs.vol;
  1074. buf := f.firstbuf;
  1075. REPEAT
  1076. IF buf.mod THEN WriteBuf(f, buf) END;
  1077. buf := buf.next
  1078. UNTIL buf = f.firstbuf;
  1079. super := f.ext;
  1080. IF super # NIL THEN
  1081. k := (f.aleng + (XS-STS)) DIV XS; i := 0;
  1082. WHILE i # k DO
  1083. sub := super.sub[i]; INC(i);
  1084. IF sub.mod THEN
  1085. IF sub.adr = 0 THEN
  1086. AllocSector(vol, f.sechint, sub.adr); f.sechint := sub.adr;
  1087. super.mod := TRUE
  1088. END;
  1089. PutSector(vol, sub.adr, sub.sec); sub.mod := FALSE
  1090. END
  1091. END;
  1092. IF super.mod THEN
  1093. IF super.adr = 0 THEN
  1094. AllocSector(vol, f.sechint, super.adr); f.sechint := super.adr;
  1095. f.modH := TRUE
  1096. END;
  1097. i := 0;
  1098. WHILE i # k DO sec.x[i] := super.sub[i].adr; INC(i) END;
  1099. WHILE i # XS DO sec.x[i] := 0; INC(i) END;
  1100. PutSector(vol, super.adr, sec); super.mod := FALSE
  1101. END
  1102. END;
  1103. IF f.modH THEN
  1104. GetSector(vol, f.sec[0], head); UpdateHeader(f, head);
  1105. PutSector(vol, f.sec[0], head); f.modH := FALSE
  1106. END
  1107. END Unbuffer;
  1108. PROCEDURE NewSub(f: File);
  1109. VAR i, k: LONGINT; sub: SubIndex;
  1110. BEGIN
  1111. k := (f.aleng - STS) DIV XS;
  1112. IF k = XS THEN SYSTEM.HALT(18) END;
  1113. NEW(sub); sub.adr := 0; sub.mod := TRUE;
  1114. FOR i := 0 TO XS-1 DO sub.sec.x[i] := 0 END;
  1115. IF f.ext = NIL THEN NewSuper(f) END;
  1116. f.ext.sub[k] := sub
  1117. END NewSub;
  1118. (** Generate a new file system object. Files.NewVol has volume parameter, Files.Par has mount prefix. *)
  1119. PROCEDURE NewFS*(context : Files.Parameters);
  1120. VAR
  1121. vol: Files.Volume; fs: FileSystem; j: LONGINT; fh: FileHeader;
  1122. adr: IP.Adr;
  1123. TFTPServer: ARRAY 16 OF CHAR;
  1124. BEGIN
  1125. vol := context.vol; j := 0;
  1126. IF Files.This(context.prefix) = NIL THEN
  1127. IF (vol.blockSize = SS) & (vol.size >= MinVolSize) THEN
  1128. GetSector(vol, DirRootAdr, fh);
  1129. IF fh.mark = DirMark THEN (* assume it is an Aos filesystem *)
  1130. context.arg.SkipWhitespace; context.arg.String(TFTPServer);
  1131. adr := IP.StrToAdr(TFTPServer);
  1132. NEW(fs, adr); fs.vol := vol;
  1133. ASSERT(vol.size < MAX(LONGINT) DIV SF);
  1134. fs.desc := "AosFS";
  1135. NEW(fs.dir, vol); (* initialize directory and volume *)
  1136. ASSERT(fs.dir.state = Opened); (* will have to undo changes to vol before continuing *)
  1137. Files.Add(fs, context.prefix)
  1138. END
  1139. END
  1140. END;
  1141. END NewFS;
  1142. (* Clean up when module unloaded. *)
  1143. PROCEDURE Cleanup;
  1144. VAR ft: Files.FileSystemTable; i: LONGINT;
  1145. BEGIN
  1146. IF Modules.shutdown = Modules.None THEN
  1147. Files.GetList(ft);
  1148. IF ft # NIL THEN
  1149. FOR i := 0 TO LEN(ft^)-1 DO
  1150. IF ft[i] IS FileSystem THEN Files.Remove(ft[i]) END
  1151. END
  1152. END
  1153. END
  1154. END Cleanup;
  1155. BEGIN
  1156. ASSERT((SIZEOF(FileHeader) = SS) & (SIZEOF(IndexSector) = SS) & (SIZEOF(DataSector) = SS) &
  1157. (SIZEOF(DirPage) = SS) & (SIZEOF(MapIndex) = SS) & (SIZEOF(MapSector) = SS));
  1158. Modules.InstallTermHandler(Cleanup)
  1159. END TFTPFS.
  1160. (*
  1161. aleng * SS + bleng = length (including header)
  1162. apos * SS + bpos = current position
  1163. 0 <= bpos <= lim <= SS
  1164. 0 <= apos <= aleng < STS + XS*XS
  1165. (apos < aleng) & (lim = SS) OR (apos = aleng)
  1166. Methods with {} notation are explicitly unprotected. They must be called only from a protected context.
  1167. *)
  1168. http://www.cs.inf.ethz.ch/gutknecht/stud_work/2001SS_begger/
  1169. 'vol' parameter: vol = <# blocks> "4096"
  1170. 'fs' parameter: fs = <prefix> <TFTP server ip>
  1171. BimboFS="RAMVolumes.New TFTPFS.NewFS"