Feature/sotrage system overhaul #73
No files matched your search
+325
-175
File diff suppressed because it is too large.
Load diff
+17
-8
@@ -288,7 +288,9 @@ begin
|
||||
if bootrecord <> nil then begin
|
||||
if bootrecord^.boot_sector <> $AA55 then begin
|
||||
println('No valid mbr found, initialising disk...');
|
||||
driver.storage.vol.mgr.init_disk(device);
|
||||
if driver.storage.vol.mgr.init_disk(device) <> eNone then begin
|
||||
println('Error: disk initialization failed.'); exit;
|
||||
end;
|
||||
end;
|
||||
kfree(puint32(bootrecord));
|
||||
end;
|
||||
@@ -335,7 +337,9 @@ begin
|
||||
|
||||
driver.storage.vol.mbr.setup_partition(@part, lba, sectors);
|
||||
part.system_id := 0;
|
||||
driver.storage.vol.mgr.add_partition(device, slot, part);
|
||||
if driver.storage.vol.mgr.add_partition(device, slot, part) <> eNone then begin
|
||||
println('Error: partition creation failed.'); exit;
|
||||
end;
|
||||
|
||||
print('Partition added in slot ');
|
||||
printint(slot);
|
||||
@@ -407,7 +411,9 @@ begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
driver.storage.vol.mgr.remove_partition(device, slot);
|
||||
if driver.storage.vol.mgr.remove_partition(device, slot) <> eNone then begin
|
||||
println('Error: partition removal failed.'); exit;
|
||||
end;
|
||||
|
||||
print('Partition slot ');
|
||||
printint(slot);
|
||||
@@ -523,11 +529,14 @@ begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
vol^.filesystem := fs;
|
||||
fs^.createCallback(vol, vol^.sectorCount, vol^.sectorStart, nil);
|
||||
|
||||
{ Re-probe filesystem so identify picks up the new signature }
|
||||
driver.storage.fs.mgr.probe_volume(vol);
|
||||
i := 0;
|
||||
while i < driver.storage.vol.mgr.get_volume_count() do begin
|
||||
if driver.storage.vol.mgr.get_volume(i) = vol then break;
|
||||
Inc(i);
|
||||
end;
|
||||
if not driver.storage.vol.mgr.format_volume(device, i, fsName, nil) then begin
|
||||
println('Error: format failed; the volume was not reported ready.'); exit;
|
||||
end;
|
||||
|
||||
print('Partition ');
|
||||
printint(slot);
|
||||
|
||||
@@ -271,6 +271,7 @@ procedure fpc_shortstr_assign(len: longint; sstr, dstr: Pointer); compilerproc;
|
||||
any int64/uint64 arithmetic occurs (e.g. sint32 * uint32 promotion).
|
||||
Must live in the system unit so the compiler can resolve it. }
|
||||
function fpc_mul_int64(f1, f2: int64): int64; compilerproc;
|
||||
function fpc_mul_dword_to_qword(f1, f2: uint32): qword; compilerproc;
|
||||
function fpc_div_int64(d, n: int64): int64; compilerproc;
|
||||
function fpc_mod_int64(d, n: int64): int64; compilerproc;
|
||||
function fpc_mod_qword(d, n: qword): qword; compilerproc;
|
||||
@@ -523,6 +524,18 @@ begin
|
||||
fpc_mul_int64 := res;
|
||||
end;
|
||||
|
||||
function fpc_mul_dword_to_qword(f1, f2: uint32): qword; [public, alias: 'FPC_MUL_DWORD_TO_QWORD']; compilerproc;
|
||||
var res: qword;
|
||||
begin
|
||||
asm
|
||||
MOV EAX, f1
|
||||
MUL f2
|
||||
MOV DWORD [res], EAX
|
||||
MOV DWORD [res+4], EDX
|
||||
end;
|
||||
fpc_mul_dword_to_qword := res;
|
||||
end;
|
||||
|
||||
{ ---------- 64-bit division / modulo ---------- }
|
||||
|
||||
{ Helper: unsigned 64÷64→64 using shift-subtract (binary long division).
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -154,7 +154,8 @@ type
|
||||
sleVolumeInvalidated,
|
||||
sleVolumeRemoved,
|
||||
sleDeviceAdded,
|
||||
sleDeviceRemoved
|
||||
sleDeviceRemoved,
|
||||
sleVolumeLabelChanged
|
||||
);
|
||||
|
||||
TStorageLifecycleCallback = procedure(event : TStorageLifecycleEvent;
|
||||
@@ -163,6 +164,8 @@ type
|
||||
error : TError;
|
||||
userdata : pointer);
|
||||
|
||||
TVolumeLabel = array[0..32] of char; { cached, NUL-terminated display name }
|
||||
|
||||
TFSFormatParams = record
|
||||
Version : uint16;
|
||||
Flags : uint16;
|
||||
@@ -186,13 +189,15 @@ type
|
||||
TIOCallback = procedure(error : TError; userdata : pointer);
|
||||
|
||||
{ Filesystem callback core.types }
|
||||
PPCreateHook = procedure(volume : PStorage_volume; start : uint32; size : uint32; config : PFSFormatParams);
|
||||
PPCreateHook = function(volume : PStorage_volume; sectors : uint32; start : uint32; config : PFSFormatParams) : TError;
|
||||
PPCreateAsyncHook = procedure(volume : PStorage_volume; start : uint32; size : uint32; config : PFSFormatParams; callback : TIOCallback; callbackData : pointer);
|
||||
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;
|
||||
PPDeleteFileHook = procedure(volume : PStorage_Volume; filePath : pchar; status : puint32);
|
||||
PPDeleteDirHook = procedure(volume : PStorage_Volume; path : pchar; status : puint32);
|
||||
PPValidateLabelHook = function(text : pchar; var normalized : TVolumeLabel) : TError;
|
||||
PPSetLabelHook = function(volume : PStorage_Volume; text : pchar) : TError;
|
||||
PPIdentifyHook = function(volume : PStorage_Volume) : boolean;
|
||||
PPRenameFileHook = procedure(volume : PStorage_Volume; filePath : pchar; newName : pchar; status : puint32);
|
||||
{ Offset-based read: reads byteCount bytes starting at byte offset into the file.
|
||||
@@ -271,6 +276,8 @@ type
|
||||
maxSectorCount : uint32;
|
||||
sectorSize : uint32; //in bytes
|
||||
start : uint32; //start of device in sectors
|
||||
metadataBusy : boolean; { volume/partition operation owns device }
|
||||
mbrWriteBusy : boolean; { serializes staged sector-zero writes }
|
||||
cachedMBR : pointer; { cached mbr data, nil if not yet read }
|
||||
isBootDevice : boolean; { true if this is the device GRUB booted from }
|
||||
end;
|
||||
@@ -280,6 +287,7 @@ type
|
||||
sName : pchar;
|
||||
system_id : uint8;
|
||||
createCallback : PPCreateHook;
|
||||
validateFormat : PPCreateHook; { pure preflight, before invalidation }
|
||||
detectCallback : PPDetectHook;
|
||||
createDirCallback : PPCreateDirHook;
|
||||
readDirCallback : PPReadDirHook;
|
||||
@@ -304,6 +312,8 @@ type
|
||||
openFileCallback : PPOpenFileHook;
|
||||
closeFileCallback : PPCloseFileHook;
|
||||
formatParamFlags : uint32;
|
||||
validateLabelCallback : PPValidateLabelHook;
|
||||
setLabelCallback : PPSetLabelHook;
|
||||
end;
|
||||
|
||||
{ Generic storage volume }
|
||||
@@ -317,6 +327,7 @@ type
|
||||
filesystem : PFilesystem;
|
||||
isBootDrive : boolean;
|
||||
lifecycleFlags : uint32;
|
||||
labelText : TVolumeLabel;
|
||||
fsPrivate : pointer; { FS-driver private data (e.g. PFATCache for FAT32) }
|
||||
end;
|
||||
|
||||
|
||||
@@ -134,6 +134,7 @@ procedure UnwatchDirectory(WatchID : uint32);
|
||||
{ Volume invalidation — must be called before freeing a volume.
|
||||
Closes all open FDs referencing the volume across all processes,
|
||||
evicts directory cache entries, and removes VFS mount points. }
|
||||
function VolumeHasOpenHandles(vol : PStorage_Volume) : boolean;
|
||||
function InvalidateVolume(vol : PStorage_Volume) : boolean;
|
||||
|
||||
{ VFS Functions }
|
||||
@@ -509,7 +510,7 @@ end;
|
||||
function GetObjectFromPath(path : pchar) : PVFSObject; forward;
|
||||
function GetObjectFromPathEx(path : pchar; var volRelPath : pchar) : PVFSObject; forward;
|
||||
|
||||
function volumeHasAsyncHandles(vol : PStorage_Volume) : boolean;
|
||||
function volumeHasHandles(vol : PStorage_Volume; asyncOnly : boolean) : boolean;
|
||||
var
|
||||
pCount : uint32;
|
||||
pi : uint32;
|
||||
@@ -517,7 +518,7 @@ var
|
||||
pCtx : proc.types.PProcessContext;
|
||||
tbl : PFDTable;
|
||||
begin
|
||||
volumeHasAsyncHandles := false;
|
||||
volumeHasHandles := false;
|
||||
if vol = nil then exit;
|
||||
|
||||
pCount := proc.mgr.processCount();
|
||||
@@ -530,14 +531,17 @@ begin
|
||||
if tbl = nil then continue;
|
||||
for fi := 0 to MAX_FDS - 1 do begin
|
||||
if tbl^.Entries[fi].InUse and (tbl^.Entries[fi].Volume = vol)
|
||||
and (tbl^.Entries[fi].AsyncRefs > 0) then begin
|
||||
volumeHasAsyncHandles := true;
|
||||
and ((not asyncOnly) or (tbl^.Entries[fi].AsyncRefs > 0)) then begin
|
||||
volumeHasHandles := true;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function VolumeHasOpenHandles(vol : PStorage_Volume) : boolean;
|
||||
begin VolumeHasOpenHandles := volumeHasHandles(vol,false); end;
|
||||
|
||||
function InvalidateVolume(vol : PStorage_Volume) : boolean;
|
||||
var
|
||||
pCount : uint32;
|
||||
@@ -554,7 +558,7 @@ begin
|
||||
debug.tracer.push_trace('driver.storage.vfs.InvalidateVolume.enter');
|
||||
InvalidateVolume := false;
|
||||
if vol = nil then exit;
|
||||
if volumeHasAsyncHandles(vol) then begin
|
||||
if volumeHasHandles(vol,true) then begin
|
||||
debug.tracer.push_trace('driver.storage.vfs.InvalidateVolume.busy');
|
||||
exit;
|
||||
end;
|
||||
@@ -986,6 +990,7 @@ begin
|
||||
volumeGetDirectories := nil;
|
||||
|
||||
if vol = nil then exit;
|
||||
if (vol^.device = nil) or vol^.device^.metadataBusy or driver.storage.vol.mgr.volume_is_busy(vol) then exit;
|
||||
if vol^.filesystem = nil then exit;
|
||||
if vol^.filesystem^.readDirCallback = nil then exit;
|
||||
|
||||
@@ -1153,6 +1158,15 @@ begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
mountObj := PVFSObject(core.ds.hashmap.get(ht, mountName));
|
||||
if mountObj <> nil then begin
|
||||
if (mountObj^.ObjectType = otDRIVE) and (mountObj^.Reference = void(volume)) then begin
|
||||
mountVolume := pvRegistered;
|
||||
driver.storage.vol.mgr.volume_set_mounted(volume, true);
|
||||
end;
|
||||
kfree(void(parentPath)); STRLL_Free(splitPath); exit;
|
||||
end;
|
||||
|
||||
{ Create the mount object storing the volume pointer }
|
||||
mountObj := PVFSObject(kalloc(sizeof(TVFSObject)));
|
||||
|
||||
@@ -1219,6 +1233,12 @@ begin
|
||||
end;
|
||||
|
||||
volOut^ := PStorage_Volume(Obj^.Reference);
|
||||
if (volOut^ = nil) or (volOut^^.device = nil) then begin
|
||||
if volRel <> nil then kfree(void(volRel)); exit;
|
||||
end;
|
||||
if volOut^^.device^.metadataBusy or driver.storage.vol.mgr.volume_is_busy(volOut^) then begin
|
||||
if volRel <> nil then kfree(void(volRel)); volOut^ := nil; exit;
|
||||
end;
|
||||
|
||||
{ volRel is the path within the volume, e.g. '/mydir/myfile.txt' }
|
||||
if (volRel = nil) or StringEquals(volRel, '/') then begin
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -392,6 +392,15 @@ end;
|
||||
|
||||
{ ==================== Filesystem callbacks ==================== }
|
||||
|
||||
procedure cacheVolumeLabel(volume : PStorage_Volume; pvd : PPVD);
|
||||
var n, i : uint32;
|
||||
begin
|
||||
memset(uint32(@volume^.labelText[0]),0,sizeof(volume^.labelText));
|
||||
n := 32;
|
||||
while (n > 0) and ((pvd^.volumeId[n-1] = ' ') or (pvd^.volumeId[n-1] = #0)) do Dec(n);
|
||||
i := 0; while i < n do begin volume^.labelText[i] := pvd^.volumeId[i]; Inc(i); end;
|
||||
end;
|
||||
|
||||
{ Identify: check for 'CD001' at sector 16 }
|
||||
function identify_volume(volume : PStorage_Volume) : boolean;
|
||||
var
|
||||
@@ -405,6 +414,7 @@ begin
|
||||
buf := readSectors(volume^.device, volume^.sectorStart + PVD_SECTOR, 1);
|
||||
if buf = nil then exit;
|
||||
identify_volume := isPVD(buf);
|
||||
if identify_volume then cacheVolumeLabel(volume,PPVD(buf));
|
||||
kfree(buf);
|
||||
end;
|
||||
|
||||
@@ -437,6 +447,7 @@ begin
|
||||
volume^.filesystem := @filesystem;
|
||||
volume^.isBootDrive := disk^.isBootDevice;
|
||||
|
||||
cacheVolumeLabel(volume,pvd);
|
||||
driver.storage.vol.mgr.register_volume(disk, volume);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
@@ -94,10 +94,7 @@ end;
|
||||
|
||||
function fatMaxClusterCount(bootRecord : PBootRecord) : uint32;
|
||||
begin
|
||||
if (bootRecord = nil) or (bootRecord^.sectorSize = 0) then
|
||||
fatMaxClusterCount := 0
|
||||
else
|
||||
fatMaxClusterCount := (bootRecord^.FATSize * bootRecord^.sectorSize) div 4;
|
||||
fatMaxClusterCount := FAT32ClusterLimit(bootRecord);
|
||||
end;
|
||||
|
||||
function fatClustersForBytes(byteCount : uint32; bytesPerCluster : uint32) : uint32;
|
||||
@@ -391,7 +388,9 @@ begin
|
||||
sectorBuf := puint32(kalloc(bufSize));
|
||||
if sectorBuf = nil then exit;
|
||||
memset(uint32(sectorBuf), 0, bufSize);
|
||||
driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart, 1, sectorBuf);
|
||||
if driver.storage.mgr.storage_read(volume^.device, volume^.sectorStart, 1, sectorBuf) <> eNone then begin
|
||||
kfree(sectorBuf); exit;
|
||||
end;
|
||||
bootRecord := PBootRecord(sectorBuf)^;
|
||||
kfree(sectorBuf);
|
||||
readBootRecordRaw := true;
|
||||
@@ -699,9 +698,13 @@ begin
|
||||
|
||||
{ Keep runtime addressing compatible with the legacy formatter and metadata paths. }
|
||||
ctx^.Info.DataStart := volume^.sectorStart + ctx^.Info.BootRecord.rsvSectors +
|
||||
ctx^.Info.BootRecord.FATSize;
|
||||
uint32(ctx^.Info.BootRecord.numFats) * ctx^.Info.BootRecord.FATSize;
|
||||
ctx^.Info.BytesPerCluster := uint32(ctx^.Info.BootRecord.spc) * uint32(ctx^.Info.BootRecord.sectorSize);
|
||||
ctx^.Info.MaxCluster := fatMaxClusterCount(@ctx^.Info.BootRecord);
|
||||
if (ctx^.Info.MaxCluster <= 2) or
|
||||
(ctx^.Info.BootRecord.manySectors > volume^.sectorCount) then begin
|
||||
fatCtxFree(ctx); exit;
|
||||
end;
|
||||
ctx^.InfoValid := true;
|
||||
|
||||
ctx^.Cache.Data := puint32(kalloc(FAT_CACHE_LINES * 512));
|
||||
@@ -1135,6 +1138,7 @@ begin
|
||||
end;
|
||||
if dir^.fileName[0] = char($E5) then
|
||||
continue;
|
||||
if (dir^.attributes and $08) <> 0 then continue; { volume labels and LFN entries are not files }
|
||||
if compareByteArray8(dir^.fileName, cleanName) and matchExtension(dir^.fileExtension, ext) then begin
|
||||
findEntryInSector := integer(idx);
|
||||
exit;
|
||||
@@ -2048,7 +2052,7 @@ begin
|
||||
end;
|
||||
if dir^.fileName[0] = char($E5) then
|
||||
continue;
|
||||
if dir^.attributes = $0F then
|
||||
if (dir^.attributes and $08) <> 0 then
|
||||
continue;
|
||||
if fatIsDotEntry(dir) then
|
||||
continue;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -16,6 +16,7 @@ uses
|
||||
io.syslog,
|
||||
core.util,
|
||||
driver.storage.fs.fat32.vol,
|
||||
driver.storage.fs.fat32.labels,
|
||||
driver.storage.fs.fat32.core,
|
||||
driver.storage.fs.fat32.transfer;
|
||||
|
||||
@@ -36,7 +37,8 @@ begin
|
||||
filesystem.readDirCallback := @FAT32ReadDirectory;
|
||||
filesystem.createDirCallback := @FAT32CreateDirectory;
|
||||
filesystem.createCallback := @create_volume;
|
||||
filesystem.createAsyncCallback := @create_volume_async;
|
||||
filesystem.validateFormat := @validate_format;
|
||||
filesystem.createAsyncCallback := nil; { volume manager runs checked formatter in a worker }
|
||||
filesystem.detectCallback := @detect_volumes;
|
||||
filesystem.readOffsetCallback := @FAT32ReadFileAtOffset;
|
||||
filesystem.writeOffsetCallback := @FAT32WriteFileAtOffset;
|
||||
@@ -51,7 +53,9 @@ begin
|
||||
filesystem.closeFileCallback := @FAT32CloseFile;
|
||||
filesystem.createDirAsyncCallback := nil;
|
||||
filesystem.readDirAsyncCallback := nil;
|
||||
filesystem.formatParamFlags := FS_FORMAT_PARAM_CLUSTER_SIZE;
|
||||
filesystem.formatParamFlags := FS_FORMAT_PARAM_CLUSTER_SIZE or FS_FORMAT_PARAM_LABEL;
|
||||
filesystem.validateLabelCallback := @normalize_label;
|
||||
filesystem.setLabelCallback := @write_label;
|
||||
|
||||
FAT32VolInit(@filesystem);
|
||||
driver.storage.fs.mgr.register_filesystem(@filesystem);
|
||||
|
||||
@@ -224,6 +224,28 @@ type
|
||||
WriteRefs : array[0..FAT_OPEN_HANDLE_SLOTS - 1] of TFATWriteRef;
|
||||
end;
|
||||
|
||||
{ Exclusive cluster bound, constrained by both data area and FAT capacity. }
|
||||
function FAT32ClusterLimit(br : PBootRecord) : uint32;
|
||||
|
||||
implementation
|
||||
|
||||
function FAT32ClusterLimit(br : PBootRecord) : uint32;
|
||||
var overhead, total, capacity, limit : uint64;
|
||||
begin
|
||||
FAT32ClusterLimit := 0;
|
||||
if br = nil then exit;
|
||||
if (br^.sectorSize <> 512) or (br^.spc = 0) or (br^.spc > 128) or
|
||||
((br^.spc and (br^.spc - 1)) <> 0) or (br^.rsvSectors = 0) or
|
||||
(br^.numFats = 0) or (br^.FATSize = 0) then exit;
|
||||
total := br^.manySectors;
|
||||
if total = 0 then total := br^.numSectors;
|
||||
overhead := uint64(br^.rsvSectors) + uint64(br^.numFats) * br^.FATSize;
|
||||
if overhead >= total then exit;
|
||||
limit := (total - overhead) div br^.spc + 2;
|
||||
capacity := uint64(br^.FATSize) * (br^.sectorSize div 4);
|
||||
if (limit > capacity) or (limit > $0FFFFFF0) then exit;
|
||||
FAT32ClusterLimit := uint32(limit);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
File diff suppressed because it is too large.
Load diff
@@ -86,7 +86,7 @@ procedure set_bootable(partition_table : PPartition_table);
|
||||
begin
|
||||
push_trace('driver.storage.vol.mbr.set_bootable');
|
||||
//set the bootble bit in attributes
|
||||
partition_table^.attributes := (partition_table^.attributes and $80);
|
||||
partition_table^.attributes := (partition_table^.attributes or $80);
|
||||
end;
|
||||
|
||||
{ Check a partitions bootable bit }
|
||||
@@ -105,7 +105,7 @@ begin
|
||||
partition_table^.LBA_start := address;
|
||||
partition_table^.sector_count := sectorSize;
|
||||
partition_table^.CHS_start := LBA_2_CHS(address);
|
||||
partition_table^.CHS_start := LBA_2_CHS(address + sectorSize);
|
||||
partition_table^.CHS_end := LBA_2_CHS(address + sectorSize - 1);
|
||||
push_trace('driver.storage.vol.mbr.setup_partition.end');
|
||||
end;
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -12,6 +12,7 @@ implementation
|
||||
|
||||
uses
|
||||
core.strings,
|
||||
app.diskutil,
|
||||
driver.bus.usb.types,
|
||||
driver.bus.usb.core,
|
||||
driver.bus.usb.uhci,
|
||||
@@ -32,6 +33,7 @@ uses
|
||||
core.ds.prio,
|
||||
driver.storage.vfs,
|
||||
driver.storage.test,
|
||||
driver.storage.metatest,
|
||||
core.enc.fnv1a,
|
||||
core.enc.djb2,
|
||||
core.ds.bloom,
|
||||
@@ -46,6 +48,7 @@ procedure runAllTests();
|
||||
begin
|
||||
{ Run unit tests }
|
||||
core.strings.UnitTest;
|
||||
app.diskutil.UnitTest;
|
||||
driver.bus.usb.types.UnitTest;
|
||||
driver.bus.usb.core.UnitTest;
|
||||
driver.bus.usb.uhci.UnitTest;
|
||||
@@ -66,6 +69,7 @@ begin
|
||||
core.ds.prio.UnitTest;
|
||||
driver.storage.vfs.UnitTest;
|
||||
driver.storage.test.UnitTest;
|
||||
driver.storage.metatest.UnitTest;
|
||||
core.enc.fnv1a.UnitTest;
|
||||
core.enc.djb2.UnitTest;
|
||||
core.ds.bloom.UnitTest;
|
||||
|
||||
Reference in new issue
Block a user