MODULE OldDiskVolumes;
IMPORT SYSTEM, Machine, Plugins, Disks, Caches, Files;
CONST
BS = 512;
CDBS = 2048;
SystemReserved = 32;
CacheSS = 4096;
CacheHash1 = 97;
CacheHash2 = 997;
CacheHash3 = 3331;
CacheHash4 = 9973;
CacheMin = CacheHash1;
Header = "AosDiskVolumes: ";
VAR
cache: Caches.Cache;
cacheSize, cacheHash: LONGINT;
writeback: BOOLEAN;
cdid: ARRAY 32 OF CHAR;
TYPE
Volume* = OBJECT (Files.Volume)
VAR
dev-: Disks.Device;
cache: Caches.Cache;
blocks: LONGINT;
startfs-: LONGINT;
PROCEDURE GetBlock*(adr: LONGINT; VAR blk: ARRAY OF CHAR);
VAR res, block: LONGINT; buf: Caches.Buffer; valid: BOOLEAN;
BEGIN {EXCLUSIVE}
IF (adr < 1) OR (adr > size) THEN SYSTEM.HALT(15) END;
ASSERT(startfs > 0);
ASSERT(LEN(blk) >= blockSize);
block := startfs + (adr-1) * blocks;
IF cache # NIL THEN
ASSERT(cache.blockSize >= blockSize);
cache.Acquire(dev, block, buf, valid);
IF ~valid THEN dev.Transfer(Disks.Read, block, blocks, buf.data^, 0, res)
ELSE res := Disks.Ok
END;
SYSTEM.MOVE(SYSTEM.ADR(buf.data[0]), SYSTEM.ADR(blk[0]), blockSize);
cache.Release(buf, FALSE, FALSE)
ELSE
dev.Transfer(Disks.Read, block, blocks, blk, 0, res)
END;
IF res # Disks.Ok THEN SYSTEM.HALT(17) END
END GetBlock;
PROCEDURE PutBlock*(adr: LONGINT; VAR blk: ARRAY OF CHAR);
VAR res, block: LONGINT; buf: Caches.Buffer; valid: BOOLEAN;
BEGIN {EXCLUSIVE}
IF (adr < 1) OR (adr > size) THEN SYSTEM.HALT(15) END;
ASSERT(startfs > 0);
ASSERT(LEN(blk) >= blockSize);
block := startfs + (adr-1) * blocks;
IF cache # NIL THEN
ASSERT(cache.blockSize >= blockSize);
cache.Acquire(dev, block, buf, valid);
ASSERT(LEN(buf.data) >= blockSize);
SYSTEM.MOVE(SYSTEM.ADR(blk[0]), SYSTEM.ADR(buf.data[0]), blockSize);
IF writeback THEN
cache.Release(buf, TRUE, FALSE)
ELSE
dev.Transfer(Disks.Write, block, blocks, buf.data^, 0, res);
cache.Release(buf, TRUE, TRUE)
END
ELSE
dev.Transfer(Disks.Write, block, blocks, blk, 0, res)
END;
IF res # Disks.Ok THEN SYSTEM.HALT(17) END
END PutBlock;
PROCEDURE Finalize*;
VAR res, i, j: LONGINT; ptable: Disks.PartitionTable;
BEGIN {EXCLUSIVE}
IF cache # NIL THEN cache.Synchronize; cache := NIL END;
i := 0; j := -1; ptable := dev.table;
WHILE i # LEN(ptable) DO
IF (startfs > ptable[i].start) & (startfs < ptable[i].start + ptable[i].size) THEN
j := i
END;
INC(i)
END;
IF j # -1 THEN
ASSERT(Disks.Mounted IN ptable[j].flags);
EXCL(ptable[j].flags, Disks.Mounted)
END;
dev.Close(res);
dev := NIL;
Finalize^
END Finalize;
END Volume;
PROCEDURE Get4(VAR b: ARRAY OF CHAR; i: LONGINT): LONGINT;
BEGIN
RETURN ORD(b[i]) + ASH(ORD(b[i+1]), 8) + ASH(ORD(b[i+2]), 16) + ASH(ORD(b[i+3]), 24)
END Get4;
PROCEDURE GetOberonFS(dev: Disks.Device; pstart, psize: LONGINT; VAR startfs, size, vbs, res: LONGINT);
CONST FSID = 21534F41H; FSVer = 1; AosSS = 4096; NSS = 2048;
VAR i, x, bc, fsofs: LONGINT; b: ARRAY CDBS OF CHAR;
BEGIN
startfs := 0; size := 0; vbs := 0; fsofs := 0;
IF (dev.blockSize = BS) & (psize > 0) THEN
dev.Transfer(Disks.Read, pstart, 1, b, 0, res)
ELSIF (dev.blockSize = CDBS) & (psize > 17) THEN
dev.Transfer(Disks.Read, pstart + 17, 1, b, 0, res);
IF res = Disks.Ok THEN
bc := Get4(b, 47H);
i := 0; WHILE (i < 20H) & (b[i] = cdid[i]) DO INC(i) END;
IF (i = 20H) & (bc > 0) & (bc < psize) THEN
dev.Transfer(Disks.Read, pstart + bc, 1, b, 0, res);
IF (b[0] = 1X) & (b[1EH] = 55X) & (b[1FH] = 0AAX) THEN
x := Get4(b, 20H+8);
IF (x > 0) & (x < psize) THEN
dev.Transfer(Disks.Read, pstart + x, 1, b, 0, res);
fsofs := x * (CDBS DIV BS)
ELSE
res := 3
END
ELSE
res := 3
END
ELSE
res := 3
END
END
ELSE
res := 2
END;
IF res = Disks.Ok THEN
b[0] := "x"; b[1] := "x"; b[2] := "x"; b[9] := 0X;
IF (b[510] = 55X) & (b[511] = 0AAX) THEN
ASSERT(fsofs >= 0);
IF (Get4(b, 1F8H) = FSID) & (b[1FCH] = CHR(FSVer)) & (ASH(1, ORD(b[1FDH])) = AosSS) THEN
vbs := AosSS;
x := fsofs + Get4(b, 1F0H);
ASSERT(x >= 0);
size := Get4(b, 1F4H);
ASSERT(size >= 0);
ASSERT(AosSS MOD dev.blockSize = 0);
ASSERT(x + size * (AosSS DIV BS) <= psize * (dev.blockSize DIV BS));
ASSERT(x MOD (dev.blockSize DIV BS) = 0);
startfs := pstart + x DIV (dev.blockSize DIV BS)
ELSIF b = "xxxOBERON" THEN
vbs := NSS;
x := ORD(b[0EH]) + 256*LONG(ORD(b[0FH]));
size := ORD(b[13H]) + 256*LONG(ORD(b[14H]));
IF size = 0 THEN size := Get4(b, 20H) END;
IF size > psize * (dev.blockSize DIV BS) THEN
size := psize * (dev.blockSize DIV BS)
END;
DEC(size, x);
INC(x, fsofs);
ASSERT(x MOD (dev.blockSize DIV BS) = 0);
startfs := pstart + x DIV (dev.blockSize DIV BS);
size := size DIV (NSS DIV BS)
ELSE
res := 1
END
ELSE
res := 1
END
END;
ASSERT((startfs >= 0) & (size >= 0))
END GetOberonFS;
PROCEDURE InitCache;
VAR i: LONGINT; str: ARRAY 16 OF CHAR;
BEGIN
IF cache = NIL THEN
Machine.GetConfig("CacheSize", str);
i := 0; cacheSize := Machine.StrToInt(i, str);
IF cacheSize # 0 THEN
writeback := cacheSize < 0;
cacheSize := ABS(cacheSize);
IF cacheSize < CacheMin THEN cacheSize := CacheMin END;
IF cacheSize >= CacheHash4 THEN cacheHash := CacheHash4
ELSIF cacheSize >= CacheHash3 THEN cacheHash := CacheHash3
ELSIF cacheSize >= CacheHash2 THEN cacheHash := CacheHash2
ELSE cacheHash := CacheHash1
END;
NEW(cache, CacheSS, cacheHash, cacheSize)
END
END
END InitCache;
PROCEDURE InitVol(vol: Volume; startfs, size, vbs, part: LONGINT; ptable: Disks.PartitionTable; readonly: BOOLEAN);
VAR vflags: SET;
BEGIN
vflags := {};
IF readonly OR (Disks.ReadOnly IN vol.dev.flags) THEN INCL(vflags, Files.ReadOnly) END;
IF Disks.Removable IN vol.dev.flags THEN INCL(vflags, Files.Removable) END;
ASSERT(vbs MOD BS = 0);
vol.blockSize := vbs;
ASSERT(vbs MOD vol.dev.blockSize = 0);
vol.blocks := vbs DIV vol.dev.blockSize;
vol.Init(vflags, size, SystemReserved);
COPY(vol.dev.name, vol.name); Files.AppendStr("#", vol.name); Files.AppendInt(part, vol.name);
vol.startfs := startfs;
INCL(ptable[part].flags, Disks.Mounted);
IF (cache = NIL) & (CacheSS >= vbs) THEN InitCache END;
IF (cache # NIL) & (cache.blockSize >= vbs) THEN vol.cache := cache ELSE vol.cache := NIL END
END InitVol;
PROCEDURE TryOpen(context: Files.Parameters; dev: Disks.Device; part, dbs: LONGINT; readonly: BOOLEAN);
VAR vol: Volume; startfs, size, vbs, res: LONGINT; ptable: Disks.PartitionTable;
BEGIN
context.out.String(Header); context.out.String(dev.name);
context.out.Char("#"); context.out.Int(part, 1); context.out.Char(" ");
dev.Open(res);
IF res = Disks.Ok THEN
ptable := dev.table;
IF ((LEN(ptable) = 1) & (part = 0)) OR ((part > 0) & (part < LEN(ptable))) THEN
IF (dbs = -1) OR (dev.blockSize = dbs) THEN
IF ~(Disks.Mounted IN ptable[part].flags) THEN
GetOberonFS(dev, ptable[part].start, ptable[part].size, startfs, size, vbs, res);
IF (res = Disks.Ok) & (size > 0) & (vbs MOD dev.blockSize = 0) THEN
NEW(vol); vol.dev := dev;
InitVol(vol, startfs, size, vbs, part, ptable, readonly);
context.vol := vol
ELSE
CASE res OF
|1: context.error.String(" partition not formatted")
|2: context.error.String(" bad block size")
|3: context.error.String(" not bootable CD")
ELSE
context.error.String(" boot block error "); context.error.Int(res, 1);
context.error.String(" startfs="); context.error.Int(startfs, 1);
context.error.String(" size="); context.error.Int(size, 1);
context.error.String(" vbs="); context.error.Int(vbs, 1);
context.error.String(" start="); context.error.Int(ptable[part].start, 1);
END;
context.error.Ln;
END
ELSE context.error.String(" already mounted"); context.error.Ln;
END
ELSE context.error.String(" wrong block size"); context.error.Ln;
END
ELSE context.error.String(" invalid partition"); context.error.Ln;
END;
IF context.vol = NIL THEN
dev.Close(res)
END
ELSE
context.error.String(" error "); context.error.Int(res, 1); context.error.Ln;
END
END TryOpen;
PROCEDURE New*(context : Files.Parameters);
VAR
name: Plugins.Name; part, i: LONGINT;
options : ARRAY 8 OF CHAR; ch : CHAR;
table: Plugins.Table; readonly, retry: BOOLEAN;
BEGIN
context.vol := NIL; retry := FALSE;
Files.GetDevPart(context.arg, name, part);
context.arg.SkipWhitespace; ch := context.arg.Peek();
IF (ch = ",") THEN context.arg.String(options); END;
readonly := options = ",R";
Disks.registry.GetAll(table);
IF table # NIL THEN
IF name # "" THEN
i := 0; WHILE (i # LEN(table)) & (table[i].name # name) DO INC(i) END;
IF i # LEN(table) THEN
TryOpen(context, table[i](Disks.Device), part, -1, readonly)
ELSE
context.error.String(Header); context.error.String(name); context.error.String(" not found"); context.error.Ln;
END
ELSE
i := 0;
LOOP
TryOpen(context, table[i](Disks.Device), part, CDBS, readonly);
INC(i);
IF (context.vol # NIL) OR (i >= LEN(table)) THEN EXIT END;
END
END
ELSE
context.error.String(Header); context.error.String("no devices"); context.error.Ln;
END;
END New;
BEGIN
cdid := "?CD001?EL TORITO SPECIFICATION?";
cdid[0] := 0X; cdid[6] := 1X; cdid[30] := 0X; cdid[31] := 0X;
cache := NIL; writeback := FALSE
END OldDiskVolumes.
(*
to do:
o fix races here, so that concurrent tools other than OFSTools and AosConsole can be used for mounting
o do not HALT blindly when drivers returns a bad res
*)