// Copyright 2021 Aaron Hance // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. { Driver->Storage->VolumeManager Drive volume manager @author(Aaron Hance ah@aaronhance.me) } unit volumemanager; interface uses util, console, terminal, strings, lists, tracer, lmemorymanager, vfs, MBR, storagetypes; type TDirectory_Entry_Type = (directoryEntry, fileEntry, mountEntry); PDirectory_Entry = ^TDirectory_Entry; PFilesystem = ^TFilesystem; PStorage_Volume = ^TStorage_Volume; PPWriteHook = procedure(volume : PStorage_volume; directory : pchar; entry : PDirectory_Entry; byteCount : uint32; buffer : puint32; statusOut : puint32); PPReadHook = function(volume : PStorage_Volume; directory : pchar; fileName : pchar; fileExtension : pchar; buffer : puint32; bytecount : puint32) : uint32; PPHIOHook = procedure(volume : PStorage_device; addr : uint32; sectors : uint32; buffer : puint32); PPCreateHook = procedure(disk : PStorage_Device; sectors : uint32; start : uint32; config : puint32); PPDetectHook = procedure(disk : PStorage_Device); PPCreateDirHook = procedure(volume : PStorage_volume; directory : pchar; dirname : pchar; attributes : uint32; status : puint32); PPReadDirHook = function(volume : PStorage_volume; directory : pchar; status : puint32) : PLinkedListBase; //returns: 0 = success, 1 = dir not exsist, 2 = not directory, 3 = error //returns: 0 = success, 1 = dir not exsist, 2 = not directory, 3 = error PPHIOHook_ = procedure; TFilesystem = record sName : pchar; system_id : uint8; writeCallback : PPWriteHook; readCallback : PPReadHook; createCallback : PPCreateHook; detectCallback : PPDetectHook; createDirCallback : PPCreateDirHook; readDirCallback : PPReadDirHook; end; TStorage_Volume = record device : PStorage_device; sectorStart : uint32; sectorSize : uint32; sectorCount : uint32; freeSectors : uint32; filesystem : PFilesystem; { True if this drive contains the loaded OS } isBootDrive : boolean; end; { Generic directory entry } TDirectory_Entry = record { Contains filename and optionally file extension, seperated by the last period.} fileName : pchar; entryType : TDirectory_Entry_Type; // creationT : TDateTime; // modifiedT : TDateTime; end; var storageVolumes : PLinkedListBase; filesystems : PlinkedListBase; procedure init(); procedure register_filesystem(filesystem : PFilesystem); procedure check_for_volumes(drive : PStorage_device); //IO functions implementation procedure list_volume_command(); var i : uint32; volume : PStorage_Volume; begin push_trace('VolumeManager.list_volume_command'); if LL_Size(storageVolumes) < 1 then begin console.writestringlnWnd('No volumes found.', getTerminalHWND()); exit; end; console.writestringlnWnd('Volumes: ', getTerminalHWND()); for i:=0 to LL_Size(storageVolumes) - 1 do begin volume := PStorage_Volume(LL_Get(storageVolumes, i)); console.writestringWnd(' ', getTerminalHWND()); console.writeintWnd(i, getTerminalHWND()); console.writestringWnd(' - Capacity: ', getTerminalHWND()); console.writeintWnd(uint32(volume^.sectorSize * volume^.sectorCount DIV 1024 DIV 1024), getTerminalHWND()); console.writestringWnd('MB System: ', getTerminalHWND()); console.writestringlnWnd(volume^.filesystem^.sName, getTerminalHWND()); end; end; procedure volume_command(params : PParamList); var i : uint16; subcmd : pchar; begin push_trace('VolumeManager.volume_command'); subcmd:= getParam(0, params); if ((paramCount(params) = 0)) then begin console.writestringlnWnd('Please provide valid arguments.', getTerminalHWND()); console.writestringlnWnd(' ls - for listing all volumes', getTerminalHWND()); console.writestringlnWnd(' lsfs - for listing all filesystems', getTerminalHWND()); console.writestringlnWnd(' info [volume] - display formation for specified volume', getTerminalHWND()); console.writestringlnWnd(' format [volume] [filesystem] - destructive, formats a volume with a specified filesystem', getTerminalHWND()); exit; end; if( stringEquals(subcmd, 'ls') ) then begin list_volume_command(); exit; end; end; { Initialise volume manager } procedure init(); begin push_trace('VolumeManager.init'); { setup lists } storageVolumes:= ll_New(sizeof(TFilesystem)); filesystems:= ll_New(sizeof(TFilesystem)); terminal.registerCommand('volume', @volume_command, 'Volume utility'); end; { register a new type of filesystem } procedure register_filesystem(filesystem : PFilesystem); //TODO on init create null filesystem for empty partition var elm : void; begin //add filesystem elm := LL_add(filesystems); memcpy(uint32(filesystem), uInt32(elm), SizeOf(TFilesystem)); //check drives for volumes of new type end; { Check for volumes on a physical device } procedure check_for_volumes(drive : PStorage_device); var bootrecord : PMaster_Boot_Record; storageVolume : TStorage_Volume; i : uint32 = 0; elm : void; begin push_trace('VolumeManager.check_for_volumes'); bootrecord := PMaster_Boot_Record(kalloc(SizeOf(TMaster_Boot_Record))); drive^.readCallback(drive, 0, 1, puint32(bootrecord)); //TODO multipe partition entries if bootrecord^.partition_0.LBA_start <> 0 then begin //set volume information storageVolume.device := drive; storageVolume.sectorStart := bootrecord^.partition_0.LBA_start; storageVolume.sectorCount := bootrecord^.partition_0.sector_count; storageVolume.freeSectors := 0; //TODO impliment push_trace('VolumeManager.init2'); if LL_Size(filesystems) < 1 then begin console.writestringln('Failed to initalise storage system, no filesystems found, stopping!'); exit; end; //check for filesystem type for i:=0 to LL_Size(filesystems) - 1 do begin if bootrecord^.partition_0.system_id = PFilesystem(LL_Get(filesystems, i))^.system_id then begin storageVolume.filesystem := PFilesystem(LL_Get(filesystems, i)); end; end; push_trace('VolumeManager.init3'); //add volume to list elm := LL_Add(storageVolumes); memcpy(uint32(@storageVolume), uint32(elm), SizeOf(TStorage_Volume)); push_trace('VolumeManager.init4'); elm := LL_Add(drive^.volumes); memcpy(uint32(@storageVolume), uint32(elm), SizeOf(TStorage_Volume)); end; end; end.