(* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)

MODULE ISO9660Volumes;	(* AUTHOR "?/be"; PURPOSE "ISO 9660 volume (ported from Native Oberon)" *)

(** non-portable *)

	IMPORT
		KernelLog, Plugins, Disks, Files;

	CONST
		debug = FALSE; getBlockDebug = FALSE;

	CONST	(* svr *)
		SS = 2048;	(* sector size *)
		MaxRetries = 10;

	TYPE
		Volume* = OBJECT (Files.Volume)
		VAR
			dev-: Disks.Device;
			bpc: LONGINT;	(* bytes per sector *)
			spc: LONGINT;	(* sectors per cluster *)

			PROCEDURE Finalize*;
			VAR res: LONGINT;
			BEGIN {EXCLUSIVE}
				IF debug THEN KernelLog.String("Entering OFSISO9660Volumes.Finalize"); KernelLog.Ln END;
				EXCL(dev.flags, Disks.Mounted);
				dev.Close(res)
			END Finalize;

			PROCEDURE Available*(): LONGINT;
			BEGIN
				RETURN 0
			END Available;

			PROCEDURE GetBlock(adr: LONGINT; VAR blk: ARRAY OF CHAR);
			VAR res, i: LONGINT;
			BEGIN {EXCLUSIVE}
				ASSERT(dev # NIL, 101);
				i := 0;
				REPEAT
					dev.Transfer(Disks.Read, adr, 1, blk, 0, res);
					INC(i)
				UNTIL (res = 0) OR (i >= MaxRetries);
				IF getBlockDebug & (i > 1) THEN KernelLog.String("GetBlock; "); KernelLog.Int(i, 0); KernelLog.String(" retries"); KernelLog.Ln END;
				ASSERT(res = 0, 102)
			END GetBlock;

			PROCEDURE AllocBlock(hint: Files.Address; VAR adr: Files.Address);
			BEGIN HALT(301)
			END AllocBlock;

			PROCEDURE FreeBlock(adr: Files.Address);
			BEGIN HALT(301)
			END FreeBlock;

			PROCEDURE MarkBlock(adr: Files.Address);
			BEGIN HALT(301)
			END MarkBlock;

			PROCEDURE Marked(adr: Files.Address): BOOLEAN;
			BEGIN HALT(301)
			END Marked;
		END Volume;

PROCEDURE GetISO9660Volume(p: Files.Parameters; dev: Disks.Device);
VAR vol: Volume; b: ARRAY SS OF CHAR;
BEGIN
	NEW(vol); vol.flags := {}; vol.dev := dev;
	INCL(vol.flags, Files.ReadOnly); INCL(vol.flags, Files.Removable);
	vol.bpc := SS; vol.spc := 1;
	vol.GetBlock(16, b); (* dummy; necessary after disc change *)
	COPY(vol.dev.name, vol.name);
	vol.blockSize := vol.bpc;
	IF debug THEN
		KernelLog.String("GetISO9660Volume"); KernelLog.Ln;
		KernelLog.String("  spc="); KernelLog.Int(vol.spc, 0); KernelLog.String("  bpc="); KernelLog.Int(vol.bpc, 0); KernelLog.Ln
	END;
	p.vol := vol
END GetISO9660Volume;

(** Generate a new ISO9660 volume object. Files.Par: device [# part (ignored)] *)
PROCEDURE New*(context : Files.Parameters);
VAR
	name: Plugins.Name;  i, ignore, res: LONGINT;
	table: Plugins.Table; dev: Disks.Device;
BEGIN
	context.vol := NIL;
	Files.GetDevPart(context.arg, name, ignore);
	IF (name # "") THEN
		Disks.registry.GetAll(table);
		IF (table # NIL) THEN
			context.out.String("ISO9660Volumes: Device ");  context.out.String(name);

			i := 0; WHILE (i # LEN(table)) & (table[i].name # name) DO INC(i) END;
			IF (i < LEN(table)) THEN
				dev := table[i](Disks.Device);
				dev.Open(res);
				IF (res = Disks.Ok) THEN
					IF ~(Disks.Mounted IN dev.table[0].flags) THEN
						GetISO9660Volume(context, dev);
					ELSE context.error.String(" already mounted")
					END;

					IF (context.vol = NIL) THEN
						dev.Close(res) (* close again - ignore res *)
					END
				ELSE context.error.String(" cannot open device"); context.error.Ln;
				END
			ELSE context.error.String(" not found"); context.error.Ln;
			END;
		END
	END;
END New;

END ISO9660Volumes.

OFSTools.Mount TEST "IDE1.0" OFSISO9660Volumes.New OFSN2KFiles.NewFS
OFSTools.Mount A "Diskette0" OFSISO9660Volumes.New OFSN2KFiles.NewFS
OFSTools.Unmount ^ TEST A


System.Free OFSISO9660Volumes ~