ISO9660Files.Mod 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE ISO9660Files; (** AUTHOR "?/be"; PURPOSE "ISO 9660 File System (ported from Native Oberon)"; *)
  3. IMPORT SYSTEM, Modules, Files, KernelLog, Strings;
  4. CONST
  5. debug = FALSE; nameDebug = FALSE;
  6. SS = 2048;
  7. MaxBufs = 4;
  8. Directory = 1;
  9. eFileDoesNotExist = 8903;
  10. eCannotOpenSubDir = 8916;
  11. eInvalidFirstCluster = 8917;
  12. eNameIsWild = 8927;
  13. eInvalidFileName = 8941;
  14. eInvalidVolume = 9000;
  15. TYPE
  16. Filename = ARRAY 256 OF CHAR;
  17. VolDesc = POINTER TO RECORD
  18. root, rootDirSize: LONGINT (* sector number of root directory and root directory size *)
  19. END;
  20. Buffer = POINTER TO RECORD (Files.Hint)
  21. pos, lim: LONGINT;
  22. next: Buffer;
  23. data: POINTER TO ARRAY OF CHAR
  24. END;
  25. FileSystem = OBJECT(Files.FileSystem)
  26. VAR
  27. pri, sup, cur: VolDesc;
  28. jolietLevel: LONGINT;
  29. (** Open an existing file. The same file descriptor is returned if a file is opened multiple times. End users use Files.Old instead. *)
  30. PROCEDURE Old0*(name: ARRAY OF CHAR): Files.File;
  31. VAR f: File; namebuf: Filename; dircl, dirpos, time, date, filecl, len: LONGINT; attr: SET; res: INTEGER;
  32. BEGIN {EXCLUSIVE}
  33. res := 0; f := NIL;
  34. Check(name, namebuf, res);
  35. IF res = 0 THEN
  36. LocateFile(namebuf, SELF, dircl, dirpos, time, date, filecl, len, attr, res);
  37. IF debug THEN LogString("Old0; filecl: "); LogInt(filecl); LogLn END;
  38. IF res = 0 THEN
  39. IF Directory IN attr THEN res := eCannotOpenSubDir
  40. ELSIF filecl < 16 THEN res := eInvalidFirstCluster
  41. ELSE f := OpenFile(namebuf, SELF, dircl, dirpos, time, date, filecl, len, attr)
  42. END
  43. END
  44. END;
  45. RETURN f
  46. END Old0;
  47. (** Enumerate canonical file names. mask may contain * wildcards. For internal use only. End users use Enumerator instead. *)
  48. PROCEDURE Enumerate0*(mask: ARRAY OF CHAR; flags: SET; enum: Files.Enumerator);
  49. VAR
  50. fname, name, mmask, pname, fullname: Filename;
  51. f: Files.File; R: Files.Rider;
  52. attr: SET; bAddToEnum: BOOLEAN;
  53. pos, time, date, len, cl: LONGINT; res: INTEGER;
  54. BEGIN {EXCLUSIVE}
  55. Check(mask, name, res);
  56. IF (res = 0) OR (res = eNameIsWild) THEN
  57. SeparateName(name, name, mmask); IF (mmask = "") THEN COPY("*", mmask) END;
  58. Files.JoinName(prefix, name, pname);
  59. IF nameDebug THEN LogString("Enumerate; dir name: "); LogString(pname); LogLn END;
  60. f := OldDir(SELF, name);
  61. IF f # NIL THEN
  62. f.Set(R, 0); pos := 0;
  63. LOOP
  64. MatchFile(R, mmask, fname, pos, cl, time, date, len, attr, res);
  65. IF res # 0 THEN EXIT END;
  66. COPY(pname, fullname);
  67. IF name[0] # 0X THEN Files.AppendStr("/", fullname) END;
  68. Files.AppendStr(fname, fullname);
  69. bAddToEnum := TRUE;
  70. IF Directory IN attr THEN
  71. IF (fname = ".") OR (fname = "..") THEN
  72. bAddToEnum := FALSE;
  73. END;
  74. flags := { Files.Directory };
  75. len := 0;
  76. ELSE
  77. flags := {};
  78. END;
  79. IF bAddToEnum THEN
  80. enum.PutEntry(fullname, flags, time, date, len)
  81. END;
  82. END;
  83. ELSE res := eFileDoesNotExist
  84. END
  85. END
  86. END Enumerate0;
  87. (** Return the unique non-zero key of the named file, if it exists. *)
  88. PROCEDURE FileKey*(name: ARRAY OF CHAR): LONGINT;
  89. VAR res: INTEGER; namebuf: Filename; t, key, filecl: LONGINT; attr: SET;
  90. BEGIN {EXCLUSIVE}
  91. IF nameDebug THEN LogString("OFSFATFiles.FileKey: "); LogString(name); LogLn END;
  92. key := 0;
  93. Check(name, namebuf, res);
  94. IF res = 0 THEN
  95. LocateFile(namebuf, SELF, t, t, t, t, filecl, t, attr, res);
  96. IF res = 0 THEN key := filecl END
  97. END;
  98. RETURN key
  99. END FileKey;
  100. (** Finalize the file system. *)
  101. PROCEDURE Finalize*;
  102. BEGIN {EXCLUSIVE}
  103. vol.Finalize;
  104. Finalize^
  105. END Finalize;
  106. END FileSystem;
  107. File = OBJECT (Files.File)
  108. VAR
  109. len,
  110. time, date,
  111. filecl: LONGINT; (* first cluster *)
  112. attr: SET ; (* ISO file attributes *)
  113. (* directory info *)
  114. name: Filename;
  115. dircl, (* start cluster of dir. that contains entry for file *)
  116. dirpos: LONGINT; (* position in cluster of dir. in which entry lies *)
  117. nofbufs: INTEGER;
  118. firstbuf: Buffer;
  119. PROCEDURE Set*(VAR r: Files.Rider; pos: LONGINT);
  120. BEGIN {EXCLUSIVE}
  121. r.eof := FALSE; r.res := 0; r.file := SELF; r.fs := fs;
  122. IF (pos < 0) THEN r.apos := 0
  123. ELSIF (pos < len) THEN r.apos := pos
  124. ELSE r.apos := len
  125. END;
  126. r.hint := firstbuf
  127. END Set;
  128. PROCEDURE Pos*(VAR r: Files.Rider): LONGINT;
  129. BEGIN {EXCLUSIVE}
  130. RETURN r.apos
  131. END Pos;
  132. PROCEDURE FindBuf(pos: LONGINT; hint: Buffer): Buffer;
  133. VAR buf: Buffer;
  134. BEGIN
  135. buf := hint;
  136. LOOP
  137. IF (pos >= buf.pos) & (pos < buf.pos+buf.lim) THEN EXIT END;
  138. buf := buf.next;
  139. IF buf = hint THEN buf := NIL; EXIT END
  140. END;
  141. RETURN buf
  142. END FindBuf;
  143. PROCEDURE ReadBuf(buf: Buffer; pos: LONGINT);
  144. BEGIN
  145. ASSERT(pos <= len, 100);
  146. buf.pos := pos - pos MOD fs.vol.blockSize;
  147. pos := pos DIV fs.vol.blockSize;
  148. IF pos = len DIV fs.vol.blockSize THEN buf.lim := len MOD fs.vol.blockSize
  149. ELSE buf.lim := fs.vol.blockSize
  150. END;
  151. IF debug THEN LogString("ReadBuf; block: "); LogInt(filecl+pos); LogLn END;
  152. fs.vol.GetBlock(filecl+pos, buf.data^)
  153. END ReadBuf;
  154. PROCEDURE GetBuf(pos: LONGINT; hint: Buffer): Buffer;
  155. VAR buf: Buffer;
  156. BEGIN
  157. buf := FindBuf(pos, hint);
  158. IF buf = NIL THEN
  159. IF nofbufs < MaxBufs THEN (*allocate new buffer*)
  160. NEW(buf); NEW(buf.data, fs.vol.blockSize);
  161. buf.next := firstbuf.next; firstbuf.next := buf;
  162. INC(nofbufs)
  163. ELSE (*reuse one of the buffers; round robin *)
  164. buf := firstbuf; firstbuf := buf.next;
  165. END;
  166. ReadBuf(buf, pos);
  167. END;
  168. RETURN buf
  169. END GetBuf;
  170. PROCEDURE Read*(VAR r: Files.Rider; VAR x: CHAR);
  171. VAR buf: Buffer;
  172. BEGIN {EXCLUSIVE}
  173. r.res := 0;
  174. IF (r.apos < len) THEN
  175. buf := GetBuf(r.apos, r.hint(Buffer));
  176. x := buf.data[r.apos-buf.pos];
  177. INC(r.apos)
  178. ELSE
  179. x := 0X; r.eof := TRUE
  180. END
  181. END Read;
  182. PROCEDURE ReadBytes*(VAR r: Files.Rider; VAR x: ARRAY OF CHAR; ofs, len: LONGINT);
  183. VAR m, pos: LONGINT; src: ADDRESS; buf: Buffer;
  184. BEGIN {EXCLUSIVE}
  185. IF LEN(x) < len THEN SYSTEM.HALT(19) END;
  186. IF len <= 0 THEN RETURN END;
  187. buf := r.hint(Buffer);
  188. m := SELF.len - r.apos;
  189. IF len <= m THEN r.res := 0 ELSE r.eof := TRUE; r.res := len-m; len := m END;
  190. WHILE len > 0 DO
  191. buf := GetBuf(r.apos, buf);
  192. pos := r.apos - buf.pos;
  193. src := ADDRESSOF(buf.data[pos]); m := buf.lim-pos;
  194. IF m > len THEN m := len END;
  195. SYSTEM.MOVE(src, ADDRESSOF(x[ofs]), m);
  196. DEC(len, m); INC(ofs, m); INC(r.apos, m);
  197. END;
  198. r.hint := buf
  199. END ReadBytes;
  200. PROCEDURE Length*(): LONGINT;
  201. BEGIN RETURN len
  202. END Length;
  203. PROCEDURE GetDate*(VAR t, d: LONGINT);
  204. BEGIN t := time; d := date
  205. END GetDate;
  206. PROCEDURE GetName*(VAR name: ARRAY OF CHAR);
  207. BEGIN COPY(SELF.name, name)
  208. END GetName;
  209. PROCEDURE Update*;
  210. END Update; (* nothing *)
  211. END File;
  212. VAR (* svr *)
  213. ExtractNameProc: PROCEDURE(VAR dir, name: ARRAY OF CHAR);
  214. (* debug procedures *)
  215. PROCEDURE LogString(s: ARRAY OF CHAR);
  216. BEGIN
  217. KernelLog.String(s)
  218. END LogString;
  219. PROCEDURE LogInt(i: LONGINT);
  220. BEGIN
  221. KernelLog.Int(i, 0)
  222. END LogInt;
  223. PROCEDURE LogLn;
  224. BEGIN
  225. KernelLog.Ln
  226. END LogLn;
  227. (* help procedures *)
  228. (* Get733 - 32 bit, both byte orders *)
  229. PROCEDURE Get733(VAR s: ARRAY OF CHAR; first: LONGINT; VAR d: LONGINT);
  230. BEGIN
  231. d := LONG(ORD(s[first]));
  232. d := d + LONG(ORD(s[first+1]))*100H;
  233. d := d + LONG(ORD(s[first+2]))*10000H;
  234. d := d + LONG(ORD(s[first+3]))*1000000H
  235. END Get733;
  236. (* Check - check filename. Return correct name, or empty name if incorrect. *)
  237. PROCEDURE Check(s: ARRAY OF CHAR; VAR name: Filename; VAR res: INTEGER);
  238. VAR i, j: LONGINT; ch: CHAR;
  239. BEGIN
  240. IF nameDebug THEN LogString("Check: "); LogString(s) END;
  241. res := 0; i := 0;
  242. IF (s[0] = "/") OR (s[0] = "\") THEN j := 1 ELSE j := 0 END; (* remove leading / or \ *)
  243. LOOP
  244. ch := s[j];
  245. IF ch = 0X THEN EXIT END;
  246. IF ch = "\" THEN ch := "/" END;
  247. IF (ch < " ") OR (ch >= 07FX) THEN res := eInvalidFileName; i := 0; EXIT END;
  248. IF (ch = "?") OR (ch = "*") THEN res := eNameIsWild END;
  249. name[i] := ch;
  250. INC(i); INC(j)
  251. END;
  252. name[i] := 0X;
  253. IF nameDebug THEN LogString(" => "); LogString(name); LogLn END;
  254. END Check;
  255. PROCEDURE GetVolumeDescriptors(fs: FileSystem; res: INTEGER);
  256. VAR b: ARRAY SS OF CHAR; i: LONGINT; vol: Files.Volume;
  257. BEGIN
  258. vol := fs.vol;
  259. i := 16; fs.pri := NIL; fs.sup := NIL; fs.cur := NIL; fs.jolietLevel := 0;
  260. REPEAT
  261. vol.GetBlock(i, b); (* read boot sector *)
  262. CASE b[0] OF
  263. 1X: (* Primary volume descriptor *)
  264. ASSERT(fs.pri = NIL, 102); (* exactly one primary volume desc *)
  265. NEW(fs.pri);
  266. Get733(b, 158, fs.pri.root); (* location of root directory *)
  267. Get733(b, 166, fs.pri.rootDirSize) (* size of root directory in bytes *)
  268. | 2X: (* Supplementary volume descriptor *)
  269. ASSERT(fs.sup = NIL, 103); (* 0 or 1 supplementary volume descriptor *)
  270. ASSERT((b[88] = 25X) & (b[89] = 2FX) & ((b[90] = 40X) OR (b[90] = 43X) OR (b[90] = 45X)), 104);
  271. IF b[90] = 40X THEN fs.jolietLevel := 1
  272. ELSIF b[90] = 43X THEN fs.jolietLevel := 2
  273. ELSIF b[90] = 45X THEN fs.jolietLevel := 3
  274. END;
  275. NEW(fs.sup);
  276. Get733(b, 158, fs.sup.root); (* location of root directory *)
  277. Get733(b, 166, fs.sup.rootDirSize) (* size of root directory in bytes *)
  278. ELSE ASSERT((b[0] = 0X) OR (b[0] = 2X) OR (b[0] = 0FFX), 100) (* boot or end *)
  279. END;
  280. INC(i)
  281. UNTIL (res # 0) OR (b[0] = 0FFX);
  282. IF res = 0 THEN
  283. IF fs.pri = NIL THEN res := eInvalidVolume
  284. ELSIF fs.sup # NIL THEN fs.cur := fs.sup; ExtractNameProc := ExtractLongName
  285. ELSE fs.cur := fs.pri; ExtractNameProc := ExtractShortName
  286. END
  287. END;
  288. END GetVolumeDescriptors;
  289. (* GetDir - Get information from a directory entry *)
  290. PROCEDURE GetDir(VAR dir, fname: ARRAY OF CHAR; VAR time, date, cl, len: LONGINT; VAR attr: SET);
  291. VAR t: LONGINT;
  292. BEGIN
  293. ExtractName(dir, fname);
  294. t (*attr*) := ORD(dir[24]); attr := SYSTEM.VAL(SET, t);
  295. time := LONG(ORD(dir[20]))*64*64 + LONG(ORD(dir[21]))*64 + LONG(ORD(dir[22]));
  296. date := LONG(ORD(dir[17]))*32*16 + LONG(ORD(dir[18]))*16 + LONG(ORD(dir[19]));
  297. Get733(dir, 1, cl);
  298. Get733(dir, 9, len)
  299. END GetDir;
  300. PROCEDURE SplitName(str: ARRAY OF CHAR; VAR prefix, name: ARRAY OF CHAR);
  301. VAR i, j: LONGINT;
  302. BEGIN
  303. IF nameDebug THEN LogString("SplitName: "); LogString(str) END;
  304. i := -1; j := -1;
  305. REPEAT INC(i); INC(j); prefix[j] := str[i] UNTIL (str[i] = 0X) OR (str[i] = "/");
  306. IF str[i] = "/" THEN
  307. prefix[j] := 0X; j := -1;
  308. REPEAT INC(i); INC(j); name[j] := str[i] UNTIL name[j] = 0X
  309. ELSE name[0] := 0X
  310. END;
  311. IF nameDebug THEN LogString(" => "); LogString(prefix); LogString(", "); LogString(name); LogLn END
  312. END SplitName;
  313. (* SeparateName - separate str into a prefix and a name. *)
  314. PROCEDURE SeparateName(str: ARRAY OF CHAR; VAR prefix: ARRAY OF CHAR; VAR name: Filename);
  315. VAR i, j : LONGINT;
  316. BEGIN
  317. (* Pre: str is result of a Check operation; all "\"s have been changed to "/" *)
  318. i := 0; j := -1;
  319. WHILE str[i] # 0X DO
  320. IF str[i] = "/" THEN j := i END;
  321. INC(i)
  322. END;
  323. IF j >= 0 THEN
  324. COPY(str, prefix); prefix[j] := 0X;
  325. i := -1;
  326. REPEAT INC(i); INC(j); name[i] := str[j] UNTIL name[i] = 0X
  327. ELSE COPY(str, name); prefix[0] := 0X
  328. END
  329. END SeparateName;
  330. PROCEDURE ExtractShortName(VAR dir, name: ARRAY OF CHAR);
  331. VAR i, j, len: LONGINT;
  332. BEGIN
  333. len := ORD(dir[31]);
  334. i := 0; j := 32;
  335. WHILE (i < len) & (dir[j] # ";") DO name[i] := dir[j]; INC(i); INC(j) END;
  336. name[i] := 0X;
  337. END ExtractShortName;
  338. PROCEDURE ExtractLongName(VAR dir, name: ARRAY OF CHAR);
  339. VAR i, j, end: LONGINT;
  340. BEGIN
  341. end := 33+ORD(dir[31]);
  342. i := 0; j := 33;
  343. WHILE (j < end) & (dir[j] # ";") DO name[i] := dir[j]; INC(i); INC(j, 2) END;
  344. name[i] := 0X;
  345. END ExtractLongName;
  346. PROCEDURE ExtractName(VAR dir, name: ARRAY OF CHAR);
  347. VAR len: LONGINT;
  348. BEGIN
  349. len := ORD(dir[31]);
  350. IF len = 1 THEN
  351. IF dir[33] = 0X THEN COPY(".", name)
  352. ELSIF dir[33] = 1X THEN COPY("..", name)
  353. END
  354. ELSE ExtractNameProc(dir, name)
  355. END
  356. END ExtractName;
  357. PROCEDURE MatchFile(VAR R: Files.Rider; name: ARRAY OF CHAR; VAR fname: ARRAY OF CHAR;
  358. VAR pos, cl, time, date, len: LONGINT; VAR attr: SET; VAR res: INTEGER);
  359. VAR
  360. found: BOOLEAN; f: File; fs: FileSystem; buf: ARRAY 256 OF CHAR; entryLen, padding: LONGINT;
  361. BEGIN
  362. f := R.file(File); fs := R.fs(FileSystem);
  363. found := FALSE;
  364. LOOP
  365. pos := R.file.Pos(R);
  366. IF debug THEN LogString("MatchFile; pos: "); LogInt(pos); LogLn END;
  367. R.file.Read(R, buf[0]); entryLen := ORD(buf[0]);
  368. IF debug THEN LogString("MatchFile; entryLen: "); LogInt(entryLen); LogLn END;
  369. IF R.eof THEN
  370. IF debug THEN LogString("MatchFile; eof"); LogLn END;
  371. EXIT
  372. END;
  373. IF entryLen > 0 THEN
  374. R.file.ReadBytes(R, buf, 0, entryLen-1);
  375. GetDir(buf, fname, time, date, cl, len, attr);
  376. found := Strings.Match(name, fname);
  377. ELSE (* Directory entries may not cross sectors. Skip padding bytes *)
  378. padding := SS - (R.file.Pos(R) MOD SS);
  379. IF (padding > 0) & (padding <= 256) THEN
  380. IF debug THEN LogString("MatchFile; skip padding: "); LogInt(padding); LogLn; END;
  381. R.file.ReadBytes(R, buf, 0, padding); (* Skip padding *)
  382. ELSE
  383. IF debug THEN LogString("MatchFile; Confusing directory structure... givin' up"); END;
  384. EXIT;
  385. END;
  386. END;
  387. IF found THEN EXIT END;
  388. END;
  389. IF found THEN res := 0 ELSE res := eInvalidFileName END;
  390. END MatchFile;
  391. PROCEDURE FindFile(fs: FileSystem; name: ARRAY OF CHAR; dircl, dirlen: LONGINT;
  392. VAR dirpos, time, date, filecl, len: LONGINT; VAR attr: SET; VAR res: INTEGER);
  393. VAR f: File; R: Files.Rider; fname: Filename;
  394. BEGIN
  395. ASSERT(name # "", 100);
  396. f := OpenFile("", fs, -1, -1, -1, -1, dircl, dirlen, {});
  397. f.Set(R, 0);
  398. MatchFile(R, name, fname, dirpos, filecl, time, date, len, attr, res);
  399. END FindFile;
  400. PROCEDURE LocateFile(name: ARRAY OF CHAR; fs: FileSystem;
  401. VAR dircl, dirpos, time, date, filecl, len: LONGINT; VAR attr: SET; VAR res: INTEGER);
  402. VAR cur: Filename; dirlen: LONGINT;
  403. BEGIN
  404. res := 0;
  405. dircl := fs.cur.root; dirlen := fs.cur.rootDirSize; (* start in root directory *)
  406. IF name[0] = 0X THEN (* root dir *)
  407. filecl := dircl; attr := {Directory};
  408. len := dirlen; dirpos := -1;
  409. ELSE
  410. LOOP
  411. SplitName(name, cur, name);
  412. FindFile(fs, cur, dircl, dirlen, dirpos, time, date, filecl, len, attr, res);
  413. IF (res = 0) & (name # "") & ~(Directory IN attr) THEN res := eInvalidFileName END;
  414. IF (res # 0) OR (name = "") THEN EXIT END;
  415. dircl := filecl; dirlen := len
  416. END
  417. END
  418. END LocateFile;
  419. PROCEDURE OpenFile(name: ARRAY OF CHAR; fs: FileSystem; dircl, dirpos, time, date, filecl, len: LONGINT; attr: SET): File;
  420. VAR f: File; buf: Buffer;
  421. BEGIN
  422. NEW(f); COPY(name, f.name); f.fs := fs; f.key := filecl;
  423. f.dircl := dircl; f.dirpos := dirpos; f.time := time; f.date := date;
  424. f.filecl := filecl; f.len := len; f.attr := attr;
  425. NEW(buf); buf.next := buf;
  426. NEW(buf.data, fs.vol.blockSize);
  427. IF f.len = 0 THEN buf.pos := 0; buf.lim := 0
  428. ELSE f.ReadBuf(buf, 0) (* file is not empty *)
  429. END;
  430. f.firstbuf := buf; f.nofbufs := 1;
  431. RETURN f
  432. END OpenFile;
  433. PROCEDURE OldDir(fs: Files.FileSystem; name: ARRAY OF CHAR): Files.File;
  434. VAR f: File; dircl, dirpos, time, date, filecl, len: LONGINT; attr: SET; res: INTEGER;
  435. BEGIN
  436. res := 0; f := NIL;
  437. LocateFile(name, fs(FileSystem), dircl, dirpos, time, date, filecl, len, attr, res);
  438. IF res = 0 THEN
  439. IF ~(Directory IN attr) THEN res := eCannotOpenSubDir
  440. ELSIF filecl < 16 THEN res := eInvalidFirstCluster
  441. ELSE f := OpenFile(name, fs(FileSystem), dircl, dirpos, time, date, filecl, len, attr)
  442. END
  443. END;
  444. RETURN f
  445. END OldDir;
  446. (** Generate a new file system object. OFS.NewVol has volume parameter, OFS.Par has mount prefix. *)
  447. PROCEDURE NewFS*(context : Files.Parameters);
  448. VAR fs: FileSystem; res: INTEGER;
  449. BEGIN
  450. IF Files.This(context.prefix) = NIL THEN
  451. NEW(fs); fs.vol := context.vol;
  452. GetVolumeDescriptors(fs, res);
  453. IF res = 0 THEN
  454. IF debug THEN
  455. LogString(" primary root: "); LogInt(fs.pri.root); LogLn;
  456. LogString(" primary root dir size: "); LogInt(fs.pri.rootDirSize); LogLn
  457. END;
  458. fs.desc[0] := 0X; Files.AppendStr(context.vol.name, fs.desc); Files.AppendStr(" / ISO9660FS", fs.desc);
  459. Files.Add(fs, context.prefix)
  460. ELSE context.error.String("No ISO9660 file system found on "); context.error.String(context.vol.name); context.error.Ln;
  461. END
  462. ELSE context.error.String(context.prefix); context.error.String(" already in use"); context.error.Ln;
  463. END;
  464. END NewFS;
  465. (* Clean up when module freed. *)
  466. PROCEDURE Cleanup;
  467. VAR ft: Files.FileSystemTable; i: LONGINT;
  468. BEGIN
  469. IF Modules.shutdown = Modules.None THEN
  470. Files.GetList(ft);
  471. IF ft # NIL THEN
  472. FOR i := 0 TO LEN(ft^)-1 DO
  473. IF ft[i] IS FileSystem THEN Files.Remove(ft[i]) END
  474. END
  475. END
  476. END
  477. END Cleanup;
  478. BEGIN
  479. Modules.InstallTermHandler(Cleanup)
  480. END ISO9660Files.
  481. ISO9660Volumes.Mod
  482. Partitions.Show
  483. OFSTools.Mount CD IsoFS IDE2 ~
  484. OFSTools.Unmount CD0 ~
  485. SystemTools.Free ISO9660Files ISO9660Volumes ~
  486. System.Directory CD:*.* ~
  487. History:
  488. 30.05.2006 Fixed MatchFile: Directory entries may not cross sector boundaries. Skip padding bytes if necessary. (staubesv)