371 lines
12 KiB
ObjectPascal
371 lines
12 KiB
ObjectPascal
// 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(volume : PStorage_volume; start : uint32; size : 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; //create volume
|
|
detectCallback : PPDetectHook; //detect volume
|
|
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);
|
|
procedure create_volume(disk : PStorage_device; filesystem : PChar; sectorStart : uint32; sectorCount : uint32);
|
|
|
|
//IO functions
|
|
|
|
implementation
|
|
|
|
procedure format_volume_command(params : PParamList);
|
|
var
|
|
volume : PStorage_Volume;
|
|
filesystem : PFilesystem;
|
|
config : puint32;
|
|
begin
|
|
push_trace('VolumeManager.format_volume_command');
|
|
console.writestringlnWND('Not implimented, use disk format', getTerminalHWND());
|
|
exit;
|
|
|
|
if paramCount(params) < 3 then begin
|
|
console.writestringlnWND('Invalid arguments', getTerminalHWND());
|
|
end;
|
|
push_trace('VolumeManager.format_volume_command.1');
|
|
|
|
volume := PStorage_volume(LL_get(storageVolumes, stringToInt(getParam(1, params))));
|
|
filesystem := PFilesystem(LL_get(filesystems, stringToInt(getParam(2, params))));
|
|
push_trace('VolumeManager.format_volume_command.2');
|
|
|
|
config := PuInt32(kalloc(sizeof(uInt32)));
|
|
config^ := 4;
|
|
push_trace('VolumeManager.format_volume_command.3');
|
|
|
|
//TODO check things exsist
|
|
|
|
console.writestringlnWND('Staring volume formatting...', getTerminalHWND());
|
|
// filesystem^.formatVolumeCallback(volume^.device, volume^.sectorSize, volume^.sectorStart, config);
|
|
console.writestringlnWND('Volume format finished.', getTerminalHWND());
|
|
end;
|
|
|
|
procedure list_filesystems_command();
|
|
var
|
|
i : uint32;
|
|
filesystem : PFilesystem;
|
|
begin
|
|
push_trace('VolumeManager.list_filesystems_command');
|
|
|
|
if LL_Size(filesystems) < 1 then begin
|
|
console.writestringlnWnd('ERROR: no filesystems found!', getTerminalHWND());
|
|
exit;
|
|
end;
|
|
|
|
console.writestringlnWnd('Filesystems: ', getTerminalHWND());
|
|
|
|
for i:=0 to LL_Size(filesystems) - 1 do begin
|
|
filesystem := PFilesystem(LL_Get(filesystems, i));
|
|
|
|
console.writestringWnd(' ', getTerminalHWND());
|
|
console.writestringWnd(filesystem^.sName, getTerminalHWND());
|
|
console.writestringWnd(' - ', getTerminalHWND());
|
|
console.writehexlnWND(filesystem^.system_id, getTerminalHWND());
|
|
end;
|
|
end;
|
|
|
|
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, Filesystem: ', getTerminalHWND());
|
|
|
|
if volume^.filesystem <> nil then begin
|
|
console.writestringlnWnd(volume^.filesystem^.sName, getTerminalHWND());
|
|
end else begin
|
|
console.writestringlnWnd('None', getTerminalHWND());
|
|
end;
|
|
|
|
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;
|
|
|
|
if( stringEquals(subcmd, 'lsfs') ) then begin
|
|
list_filesystems_command();
|
|
exit;
|
|
end;
|
|
|
|
if( stringEquals(subcmd, 'format') ) then begin
|
|
format_volume_command(params);
|
|
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 multiple drives
|
|
|
|
//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.sectorSize := drive^.sectorSize;
|
|
storageVolume.freeSectors := 0; //TODO impliment
|
|
storageVolume.filesystem := nil;
|
|
|
|
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;
|
|
|
|
procedure remove_volume(list : PLinkedListBase; volume : PStorage_Volume);
|
|
var
|
|
i : uint32;
|
|
elm : void;
|
|
begin
|
|
|
|
for i:=0 to LL_Size(list) - 1 do begin
|
|
elm := LL_Get(list, i);
|
|
if (PStorage_Volume(elm)^.device = volume^.device)
|
|
and (PStorage_Volume(elm)^.sectorStart = volume^.sectorStart) then begin
|
|
LL_Delete(list, i);
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure create_volume(disk : PStorage_device; filesystem : PChar; sectorStart : uint32; sectorCount : uint32);
|
|
var
|
|
volume : PStorage_Volume;
|
|
elm : void;
|
|
i : uint16;
|
|
config : PuInt32;
|
|
begin
|
|
|
|
push_trace('VolumeManager.create_volume');
|
|
|
|
volume := PStorage_Volume(kalloc(SizeOf(TStorage_Volume)));
|
|
volume^.device := disk;
|
|
volume^.sectorStart := sectorStart;
|
|
volume^.sectorCount := sectorCount - 10;
|
|
volume^.sectorSize := disk^.sectorSize;
|
|
volume^.freeSectors := 0; //setup by filesystem
|
|
|
|
//find filesystem
|
|
for i:=0 to LL_Size(filesystems) - 1 do begin
|
|
if stringEquals(filesystem, PFilesystem(LL_Get(filesystems, i))^.sName) then begin
|
|
volume^.filesystem := PFilesystem(LL_Get(filesystems, i));
|
|
end;
|
|
end;
|
|
|
|
//TODO CHECK FILESYSTEM EXSISTS
|
|
|
|
//format volume
|
|
volume^.filesystem^.createCallback(volume, sectorCount, sectorStart, config);
|
|
|
|
push_trace('VolumeManager.create_volume.2');
|
|
|
|
//remove volume from list of volumes
|
|
remove_volume(storageVolumes, volume);
|
|
|
|
//add volume to list
|
|
elm := LL_Add(storageVolumes);
|
|
memcpy(uint32(volume), uint32(elm), SizeOf(TStorage_Volume));
|
|
|
|
push_trace('VolumeManager.create_volume.3');
|
|
|
|
//remove volume from list of volumes on device
|
|
remove_volume(disk^.volumes, volume);
|
|
|
|
//add volume to device
|
|
elm := LL_Add(disk^.volumes);
|
|
memcpy(uint32(volume), uint32(elm), SizeOf(TStorage_Volume));
|
|
|
|
//free memory
|
|
kfree(puint32(volume));
|
|
end;
|
|
|
|
procedure register_volume(device : PStorage_Device; volume : PStorage_Volume);
|
|
var
|
|
elm : void;
|
|
begin
|
|
push_trace('storagemanagement.register_volume');
|
|
elm := LL_Add(device^.volumes);
|
|
PStorage_volume(elm)^:= volume^;
|
|
|
|
// if rootVolume = PStorage_Volume(0) then rootVolume:= volume;
|
|
end;
|
|
|
|
end. |