FTPFS.Mod 41 KB

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