Compare commits

...
2 Commits
18 changed files with 1648 additions and 1546 deletions

No files matched your search

+324 -174
View File
File diff suppressed because it is too large. Load diff
+17 -8
View File
@@ -288,7 +288,9 @@ begin
if bootrecord <> nil then begin if bootrecord <> nil then begin
if bootrecord^.boot_sector <> $AA55 then begin if bootrecord^.boot_sector <> $AA55 then begin
println('No valid mbr found, initialising disk...'); 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; end;
kfree(puint32(bootrecord)); kfree(puint32(bootrecord));
end; end;
@@ -335,7 +337,9 @@ begin
driver.storage.vol.mbr.setup_partition(@part, lba, sectors); driver.storage.vol.mbr.setup_partition(@part, lba, sectors);
part.system_id := 0; 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 '); print('Partition added in slot ');
printint(slot); printint(slot);
@@ -407,7 +411,9 @@ begin
exit; exit;
end; 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 '); print('Partition slot ');
printint(slot); printint(slot);
@@ -523,11 +529,14 @@ begin
exit; exit;
end; end;
vol^.filesystem := fs; i := 0;
fs^.createCallback(vol, vol^.sectorCount, vol^.sectorStart, nil); while i < driver.storage.vol.mgr.get_volume_count() do begin
if driver.storage.vol.mgr.get_volume(i) = vol then break;
{ Re-probe filesystem so identify picks up the new signature } Inc(i);
driver.storage.fs.mgr.probe_volume(vol); 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 '); print('Partition ');
printint(slot); printint(slot);
+13
View File
@@ -271,6 +271,7 @@ procedure fpc_shortstr_assign(len: longint; sstr, dstr: Pointer); compilerproc;
any int64/uint64 arithmetic occurs (e.g. sint32 * uint32 promotion). any int64/uint64 arithmetic occurs (e.g. sint32 * uint32 promotion).
Must live in the system unit so the compiler can resolve it. } Must live in the system unit so the compiler can resolve it. }
function fpc_mul_int64(f1, f2: int64): int64; compilerproc; 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_div_int64(d, n: int64): int64; compilerproc;
function fpc_mod_int64(d, n: int64): int64; compilerproc; function fpc_mod_int64(d, n: int64): int64; compilerproc;
function fpc_mod_qword(d, n: qword): qword; compilerproc; function fpc_mod_qword(d, n: qword): qword; compilerproc;
@@ -523,6 +524,18 @@ begin
fpc_mul_int64 := res; fpc_mul_int64 := res;
end; 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 ---------- } { ---------- 64-bit division / modulo ---------- }
{ Helper: unsigned 64÷64→64 using shift-subtract (binary long division). { 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
+13 -2
View File
@@ -154,7 +154,8 @@ type
sleVolumeInvalidated, sleVolumeInvalidated,
sleVolumeRemoved, sleVolumeRemoved,
sleDeviceAdded, sleDeviceAdded,
sleDeviceRemoved sleDeviceRemoved,
sleVolumeLabelChanged
); );
TStorageLifecycleCallback = procedure(event : TStorageLifecycleEvent; TStorageLifecycleCallback = procedure(event : TStorageLifecycleEvent;
@@ -163,6 +164,8 @@ type
error : TError; error : TError;
userdata : pointer); userdata : pointer);
TVolumeLabel = array[0..32] of char; { cached, NUL-terminated display name }
TFSFormatParams = record TFSFormatParams = record
Version : uint16; Version : uint16;
Flags : uint16; Flags : uint16;
@@ -186,13 +189,15 @@ type
TIOCallback = procedure(error : TError; userdata : pointer); TIOCallback = procedure(error : TError; userdata : pointer);
{ Filesystem callback core.types } { 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); PPCreateAsyncHook = procedure(volume : PStorage_volume; start : uint32; size : uint32; config : PFSFormatParams; callback : TIOCallback; callbackData : pointer);
PPDetectHook = procedure(disk : PStorage_Device); PPDetectHook = procedure(disk : PStorage_Device);
PPCreateDirHook = procedure(volume : PStorage_volume; directory : pchar; dirname : pchar; attributes : uint32; status : puint32); PPCreateDirHook = procedure(volume : PStorage_volume; directory : pchar; dirname : pchar; attributes : uint32; status : puint32);
PPReadDirHook = function(volume : PStorage_volume; directory : pchar; status : puint32) : PLinkedListBase; PPReadDirHook = function(volume : PStorage_volume; directory : pchar; status : puint32) : PLinkedListBase;
PPDeleteFileHook = procedure(volume : PStorage_Volume; filePath : pchar; status : puint32); PPDeleteFileHook = procedure(volume : PStorage_Volume; filePath : pchar; status : puint32);
PPDeleteDirHook = procedure(volume : PStorage_Volume; path : 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; PPIdentifyHook = function(volume : PStorage_Volume) : boolean;
PPRenameFileHook = procedure(volume : PStorage_Volume; filePath : pchar; newName : pchar; status : puint32); PPRenameFileHook = procedure(volume : PStorage_Volume; filePath : pchar; newName : pchar; status : puint32);
{ Offset-based read: reads byteCount bytes starting at byte offset into the file. { Offset-based read: reads byteCount bytes starting at byte offset into the file.
@@ -271,6 +276,8 @@ type
maxSectorCount : uint32; maxSectorCount : uint32;
sectorSize : uint32; //in bytes sectorSize : uint32; //in bytes
start : uint32; //start of device in sectors 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 } cachedMBR : pointer; { cached mbr data, nil if not yet read }
isBootDevice : boolean; { true if this is the device GRUB booted from } isBootDevice : boolean; { true if this is the device GRUB booted from }
end; end;
@@ -280,6 +287,7 @@ type
sName : pchar; sName : pchar;
system_id : uint8; system_id : uint8;
createCallback : PPCreateHook; createCallback : PPCreateHook;
validateFormat : PPCreateHook; { pure preflight, before invalidation }
detectCallback : PPDetectHook; detectCallback : PPDetectHook;
createDirCallback : PPCreateDirHook; createDirCallback : PPCreateDirHook;
readDirCallback : PPReadDirHook; readDirCallback : PPReadDirHook;
@@ -304,6 +312,8 @@ type
openFileCallback : PPOpenFileHook; openFileCallback : PPOpenFileHook;
closeFileCallback : PPCloseFileHook; closeFileCallback : PPCloseFileHook;
formatParamFlags : uint32; formatParamFlags : uint32;
validateLabelCallback : PPValidateLabelHook;
setLabelCallback : PPSetLabelHook;
end; end;
{ Generic storage volume } { Generic storage volume }
@@ -317,6 +327,7 @@ type
filesystem : PFilesystem; filesystem : PFilesystem;
isBootDrive : boolean; isBootDrive : boolean;
lifecycleFlags : uint32; lifecycleFlags : uint32;
labelText : TVolumeLabel;
fsPrivate : pointer; { FS-driver private data (e.g. PFATCache for FAT32) } fsPrivate : pointer; { FS-driver private data (e.g. PFATCache for FAT32) }
end; end;
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -392,6 +392,15 @@ end;
{ ==================== Filesystem callbacks ==================== } { ==================== 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 } { Identify: check for 'CD001' at sector 16 }
function identify_volume(volume : PStorage_Volume) : boolean; function identify_volume(volume : PStorage_Volume) : boolean;
var var
@@ -405,6 +414,7 @@ begin
buf := readSectors(volume^.device, volume^.sectorStart + PVD_SECTOR, 1); buf := readSectors(volume^.device, volume^.sectorStart + PVD_SECTOR, 1);
if buf = nil then exit; if buf = nil then exit;
identify_volume := isPVD(buf); identify_volume := isPVD(buf);
if identify_volume then cacheVolumeLabel(volume,PPVD(buf));
kfree(buf); kfree(buf);
end; end;
@@ -437,6 +447,7 @@ begin
volume^.filesystem := @filesystem; volume^.filesystem := @filesystem;
volume^.isBootDrive := disk^.isBootDevice; volume^.isBootDrive := disk^.isBootDevice;
cacheVolumeLabel(volume,pvd);
driver.storage.vol.mgr.register_volume(disk, volume); driver.storage.vol.mgr.register_volume(disk, volume);
kfree(buf); kfree(buf);
@@ -94,10 +94,7 @@ end;
function fatMaxClusterCount(bootRecord : PBootRecord) : uint32; function fatMaxClusterCount(bootRecord : PBootRecord) : uint32;
begin begin
if (bootRecord = nil) or (bootRecord^.sectorSize = 0) then fatMaxClusterCount := FAT32ClusterLimit(bootRecord);
fatMaxClusterCount := 0
else
fatMaxClusterCount := (bootRecord^.FATSize * bootRecord^.sectorSize) div 4;
end; end;
function fatClustersForBytes(byteCount : uint32; bytesPerCluster : uint32) : uint32; function fatClustersForBytes(byteCount : uint32; bytesPerCluster : uint32) : uint32;
@@ -391,7 +388,9 @@ begin
sectorBuf := puint32(kalloc(bufSize)); sectorBuf := puint32(kalloc(bufSize));
if sectorBuf = nil then exit; if sectorBuf = nil then exit;
memset(uint32(sectorBuf), 0, bufSize); 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)^; bootRecord := PBootRecord(sectorBuf)^;
kfree(sectorBuf); kfree(sectorBuf);
readBootRecordRaw := true; readBootRecordRaw := true;
@@ -699,9 +698,13 @@ begin
{ Keep runtime addressing compatible with the legacy formatter and metadata paths. } { Keep runtime addressing compatible with the legacy formatter and metadata paths. }
ctx^.Info.DataStart := volume^.sectorStart + ctx^.Info.BootRecord.rsvSectors + 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.BytesPerCluster := uint32(ctx^.Info.BootRecord.spc) * uint32(ctx^.Info.BootRecord.sectorSize);
ctx^.Info.MaxCluster := fatMaxClusterCount(@ctx^.Info.BootRecord); 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^.InfoValid := true;
ctx^.Cache.Data := puint32(kalloc(FAT_CACHE_LINES * 512)); ctx^.Cache.Data := puint32(kalloc(FAT_CACHE_LINES * 512));
@@ -1135,6 +1138,7 @@ begin
end; end;
if dir^.fileName[0] = char($E5) then if dir^.fileName[0] = char($E5) then
continue; 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 if compareByteArray8(dir^.fileName, cleanName) and matchExtension(dir^.fileExtension, ext) then begin
findEntryInSector := integer(idx); findEntryInSector := integer(idx);
exit; exit;
@@ -2048,7 +2052,7 @@ begin
end; end;
if dir^.fileName[0] = char($E5) then if dir^.fileName[0] = char($E5) then
continue; continue;
if dir^.attributes = $0F then if (dir^.attributes and $08) <> 0 then
continue; continue;
if fatIsDotEntry(dir) then if fatIsDotEntry(dir) then
continue; continue;
File diff suppressed because it is too large. Load diff
@@ -16,6 +16,7 @@ uses
io.syslog, io.syslog,
core.util, core.util,
driver.storage.fs.fat32.vol, driver.storage.fs.fat32.vol,
driver.storage.fs.fat32.labels,
driver.storage.fs.fat32.core, driver.storage.fs.fat32.core,
driver.storage.fs.fat32.transfer; driver.storage.fs.fat32.transfer;
@@ -36,7 +37,8 @@ begin
filesystem.readDirCallback := @FAT32ReadDirectory; filesystem.readDirCallback := @FAT32ReadDirectory;
filesystem.createDirCallback := @FAT32CreateDirectory; filesystem.createDirCallback := @FAT32CreateDirectory;
filesystem.createCallback := @create_volume; 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.detectCallback := @detect_volumes;
filesystem.readOffsetCallback := @FAT32ReadFileAtOffset; filesystem.readOffsetCallback := @FAT32ReadFileAtOffset;
filesystem.writeOffsetCallback := @FAT32WriteFileAtOffset; filesystem.writeOffsetCallback := @FAT32WriteFileAtOffset;
@@ -51,7 +53,9 @@ begin
filesystem.closeFileCallback := @FAT32CloseFile; filesystem.closeFileCallback := @FAT32CloseFile;
filesystem.createDirAsyncCallback := nil; filesystem.createDirAsyncCallback := nil;
filesystem.readDirAsyncCallback := 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); FAT32VolInit(@filesystem);
driver.storage.fs.mgr.register_filesystem(@filesystem); driver.storage.fs.mgr.register_filesystem(@filesystem);
@@ -224,6 +224,28 @@ type
WriteRefs : array[0..FAT_OPEN_HANDLE_SLOTS - 1] of TFATWriteRef; WriteRefs : array[0..FAT_OPEN_HANDLE_SLOTS - 1] of TFATWriteRef;
end; end;
{ Exclusive cluster bound, constrained by both data area and FAT capacity. }
function FAT32ClusterLimit(br : PBootRecord) : uint32;
implementation 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. end.
File diff suppressed because it is too large. Load diff
@@ -86,7 +86,7 @@ procedure set_bootable(partition_table : PPartition_table);
begin begin
push_trace('driver.storage.vol.mbr.set_bootable'); push_trace('driver.storage.vol.mbr.set_bootable');
//set the bootble bit in attributes //set the bootble bit in attributes
partition_table^.attributes := (partition_table^.attributes and $80); partition_table^.attributes := (partition_table^.attributes or $80);
end; end;
{ Check a partitions bootable bit } { Check a partitions bootable bit }
@@ -105,7 +105,7 @@ begin
partition_table^.LBA_start := address; partition_table^.LBA_start := address;
partition_table^.sector_count := sectorSize; partition_table^.sector_count := sectorSize;
partition_table^.CHS_start := LBA_2_CHS(address); 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'); push_trace('driver.storage.vol.mbr.setup_partition.end');
end; end;
File diff suppressed because it is too large. Load diff
+4
View File
@@ -12,6 +12,7 @@ implementation
uses uses
core.strings, core.strings,
app.diskutil,
driver.bus.usb.types, driver.bus.usb.types,
driver.bus.usb.core, driver.bus.usb.core,
driver.bus.usb.uhci, driver.bus.usb.uhci,
@@ -32,6 +33,7 @@ uses
core.ds.prio, core.ds.prio,
driver.storage.vfs, driver.storage.vfs,
driver.storage.test, driver.storage.test,
driver.storage.metatest,
core.enc.fnv1a, core.enc.fnv1a,
core.enc.djb2, core.enc.djb2,
core.ds.bloom, core.ds.bloom,
@@ -46,6 +48,7 @@ procedure runAllTests();
begin begin
{ Run unit tests } { Run unit tests }
core.strings.UnitTest; core.strings.UnitTest;
app.diskutil.UnitTest;
driver.bus.usb.types.UnitTest; driver.bus.usb.types.UnitTest;
driver.bus.usb.core.UnitTest; driver.bus.usb.core.UnitTest;
driver.bus.usb.uhci.UnitTest; driver.bus.usb.uhci.UnitTest;
@@ -66,6 +69,7 @@ begin
core.ds.prio.UnitTest; core.ds.prio.UnitTest;
driver.storage.vfs.UnitTest; driver.storage.vfs.UnitTest;
driver.storage.test.UnitTest; driver.storage.test.UnitTest;
driver.storage.metatest.UnitTest;
core.enc.fnv1a.UnitTest; core.enc.fnv1a.UnitTest;
core.enc.djb2.UnitTest; core.enc.djb2.UnitTest;
core.ds.bloom.UnitTest; core.ds.bloom.UnitTest;