Port storage and filesystems to x86_64 with stable device ownership
This commit is contained in:
1 parent
a27d9cb39d
commit
f8911ccdec
24 files changed
+1139
-703
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -28,8 +28,7 @@ uses
|
|||||||
core.ds.lists,
|
core.ds.lists,
|
||||||
memory.heap,
|
memory.heap,
|
||||||
driver.bus.pci,
|
driver.bus.pci,
|
||||||
core.util, arch.x86.util,
|
core.util;
|
||||||
arch.x86.memory.virtual;
|
|
||||||
|
|
||||||
const
|
const
|
||||||
AHCI_CONTROLLER_MODE = $80000000;
|
AHCI_CONTROLLER_MODE = $80000000;
|
||||||
@@ -278,6 +277,7 @@ type
|
|||||||
device_type : TDeviceType;
|
device_type : TDeviceType;
|
||||||
ata_info : TIdentResponse;
|
ata_info : TIdentResponse;
|
||||||
supportsNCQ : boolean;
|
supportsNCQ : boolean;
|
||||||
|
supports64BitDMA: boolean;
|
||||||
queueDepth : uint32; { safe active depth for this device }
|
queueDepth : uint32; { safe active depth for this device }
|
||||||
slotCount : uint32; { controller slot count from CAP.NCS + 1 }
|
slotCount : uint32; { controller slot count from CAP.NCS + 1 }
|
||||||
command_list : PHBA_CMD_HEADER;
|
command_list : PHBA_CMD_HEADER;
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -62,7 +62,7 @@ implementation
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
driver.storage.vfs, driver.storage.types, memory.heap, core.strings,
|
driver.storage.vfs, driver.storage.types, memory.heap, core.strings,
|
||||||
core.strings.helpers, debug.tracer, io.syslog, core.util, arch.x86.util;
|
core.strings.helpers, debug.tracer, io.syslog, core.util, arch.platform.cpu;
|
||||||
|
|
||||||
type
|
type
|
||||||
THandlerEntry = record
|
THandlerEntry = record
|
||||||
@@ -124,7 +124,7 @@ begin
|
|||||||
Handlers[i].Used := true;
|
Handlers[i].Used := true;
|
||||||
Handlers[i].Kind := hkMagic;
|
Handlers[i].Kind := hkMagic;
|
||||||
Handlers[i].MagicLen := magicLen;
|
Handlers[i].MagicLen := magicLen;
|
||||||
memcpy(uint32(magic), uint32(@Handlers[i].Magic[0]), magicLen);
|
memcpy(PtrUInt(magic), PtrUInt(@Handlers[i].Magic[0]), magicLen);
|
||||||
copyName(@Handlers[i].Name[0], name, 16);
|
copyName(@Handlers[i].Name[0], name, 16);
|
||||||
Handlers[i].Handler := handler;
|
Handlers[i].Handler := handler;
|
||||||
inc(HandlerCount);
|
inc(HandlerCount);
|
||||||
@@ -149,7 +149,7 @@ begin
|
|||||||
if not Handlers[i].Used then begin
|
if not Handlers[i].Used then begin
|
||||||
Handlers[i].Used := true;
|
Handlers[i].Used := true;
|
||||||
Handlers[i].Kind := hkExtension;
|
Handlers[i].Kind := hkExtension;
|
||||||
memcpy(uint32(extList), uint32(@Handlers[i].ExtList[0]), len);
|
memcpy(PtrUInt(extList), PtrUInt(@Handlers[i].ExtList[0]), len);
|
||||||
Handlers[i].ExtList[len] := #0;
|
Handlers[i].ExtList[len] := #0;
|
||||||
copyName(@Handlers[i].Name[0], name, 16);
|
copyName(@Handlers[i].Name[0], name, 16);
|
||||||
Handlers[i].Handler := handler;
|
Handlers[i].Handler := handler;
|
||||||
@@ -224,7 +224,7 @@ begin
|
|||||||
fh := driver.storage.vfs.OpenFile(absPath, omRead, @err);
|
fh := driver.storage.vfs.OpenFile(absPath, omRead, @err);
|
||||||
if fh = 0 then exit;
|
if fh = 0 then exit;
|
||||||
|
|
||||||
memset(uint32(@headerBuf[0]), 0, MAX_MAGIC_LEN);
|
memset(PtrUInt(@headerBuf[0]), 0, MAX_MAGIC_LEN);
|
||||||
bytesRead := driver.storage.vfs.ReadFile(fh, 0, @headerBuf[0], MAX_MAGIC_LEN);
|
bytesRead := driver.storage.vfs.ReadFile(fh, 0, @headerBuf[0], MAX_MAGIC_LEN);
|
||||||
driver.storage.vfs.CloseFile(fh);
|
driver.storage.vfs.CloseFile(fh);
|
||||||
|
|
||||||
|
|||||||
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
@@ -0,0 +1,140 @@
|
|||||||
|
// Copyright 2026 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.
|
||||||
|
|
||||||
|
{ Path syntax shared by VFS and boot consumers; no volume or driver access.
|
||||||
|
Returned strings are caller-owned. Normalization is lexical, not symlink
|
||||||
|
resolution, and never climbs above the root. }
|
||||||
|
unit driver.storage.path;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
function absolute(path, baseDir: pchar): pchar;
|
||||||
|
function normalize(path: pchar): pchar;
|
||||||
|
procedure UnitTest;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses core.strings, core.util, memory.heap, arch.platform.diagnostics;
|
||||||
|
|
||||||
|
function absolute(path, baseDir: pchar): pchar;
|
||||||
|
var
|
||||||
|
pathLen, baseLen, separator: uint32;
|
||||||
|
result: pchar;
|
||||||
|
begin
|
||||||
|
absolute := nil;
|
||||||
|
if path = nil then begin
|
||||||
|
absolute := stringCopy('/');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
if path[0] = '/' then begin
|
||||||
|
absolute := stringCopy(path);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
if (baseDir = nil) or (baseDir[0] = #0) then baseDir := '/';
|
||||||
|
pathLen := StringSize(path);
|
||||||
|
baseLen := StringSize(baseDir);
|
||||||
|
separator := 0;
|
||||||
|
if baseDir[baseLen - 1] <> '/' then separator := 1;
|
||||||
|
if pathLen >= High(uint32) - separator then exit;
|
||||||
|
if baseLen >= High(uint32) - pathLen - separator then exit;
|
||||||
|
|
||||||
|
result := stringNew(baseLen + separator + pathLen);
|
||||||
|
if result = nil then exit;
|
||||||
|
memcpy(PtrUInt(baseDir), PtrUInt(result), baseLen);
|
||||||
|
if separator <> 0 then result[baseLen] := '/';
|
||||||
|
memcpy(PtrUInt(path), PtrUInt(result) + baseLen + separator, pathLen);
|
||||||
|
absolute := result;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function normalize(path: pchar): pchar;
|
||||||
|
var
|
||||||
|
length, readPos, start, count, used: uint32;
|
||||||
|
result: pchar;
|
||||||
|
begin
|
||||||
|
normalize := nil;
|
||||||
|
if path = nil then path := '';
|
||||||
|
length := StringSize(path);
|
||||||
|
if length >= High(uint32) - 1 then exit;
|
||||||
|
result := stringNew(length + 1);
|
||||||
|
if result = nil then exit;
|
||||||
|
result[0] := '/';
|
||||||
|
used := 1;
|
||||||
|
readPos := 0;
|
||||||
|
|
||||||
|
while readPos < length do begin
|
||||||
|
if path[readPos] = '/' then begin
|
||||||
|
inc(readPos);
|
||||||
|
continue;
|
||||||
|
end;
|
||||||
|
start := readPos;
|
||||||
|
while (readPos < length) and (path[readPos] <> '/') do inc(readPos);
|
||||||
|
count := readPos - start;
|
||||||
|
if (count = 1) and (path[start] = '.') then continue;
|
||||||
|
if (count = 2) and (path[start] = '.') and (path[start + 1] = '.') then begin
|
||||||
|
while (used > 1) and (result[used - 1] <> '/') do dec(used);
|
||||||
|
if used > 1 then dec(used);
|
||||||
|
end else begin
|
||||||
|
if used > 1 then begin
|
||||||
|
result[used] := '/';
|
||||||
|
inc(used);
|
||||||
|
end;
|
||||||
|
memcpy(PtrUInt(path) + start, PtrUInt(result) + used, count);
|
||||||
|
inc(used, count);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
result[used] := #0;
|
||||||
|
normalize := result;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure UnitTest;
|
||||||
|
var
|
||||||
|
passed, failed: uint32;
|
||||||
|
beforeFree: SizeUInt;
|
||||||
|
|
||||||
|
procedure Check(actual, expected: pchar);
|
||||||
|
begin
|
||||||
|
if StringEquals(actual, expected) then
|
||||||
|
inc(passed)
|
||||||
|
else begin
|
||||||
|
inc(failed);
|
||||||
|
log('PATH', 'FAIL: path result');
|
||||||
|
end;
|
||||||
|
kfree(void(actual));
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
passed := 0;
|
||||||
|
failed := 0;
|
||||||
|
beforeFree := lmm_total_free;
|
||||||
|
Check(absolute('file', '/disk'), '/disk/file');
|
||||||
|
Check(absolute('file', '/disk/'), '/disk/file');
|
||||||
|
Check(absolute('/file', '/disk'), '/file');
|
||||||
|
Check(absolute('file', ''), '/file');
|
||||||
|
Check(absolute('file', nil), '/file');
|
||||||
|
Check(absolute(nil, '/disk'), '/');
|
||||||
|
Check(absolute('', '/disk'), '/disk/');
|
||||||
|
Check(normalize('/a//b/./c/../..'), '/a');
|
||||||
|
Check(normalize('../../a/..'), '/');
|
||||||
|
Check(normalize('/a/../b/../c'), '/c');
|
||||||
|
Check(normalize('a/b/'), '/a/b');
|
||||||
|
Check(normalize('/.../.hidden'), '/.../.hidden');
|
||||||
|
Check(normalize(''), '/');
|
||||||
|
Check(normalize(nil), '/');
|
||||||
|
if lmm_total_free = beforeFree then
|
||||||
|
inc(passed)
|
||||||
|
else begin
|
||||||
|
inc(failed);
|
||||||
|
log('PATH', 'FAIL: path allocation accounting');
|
||||||
|
end;
|
||||||
|
testSummary('PATH', 'PATH_TESTS_PASSED', 'PATH_TESTS_FAILED', passed, failed);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
@@ -275,7 +275,7 @@ type
|
|||||||
TStorage_Device = record
|
TStorage_Device = record
|
||||||
id : uint8;
|
id : uint8;
|
||||||
controller : TControllerType;
|
controller : TControllerType;
|
||||||
controllerId0 : uint32;
|
controllerId0 : PtrUInt;
|
||||||
writable : boolean;
|
writable : boolean;
|
||||||
removed : boolean; { true if device was hot-unplugged }
|
removed : boolean; { true if device was hot-unplugged }
|
||||||
volumes : PDList;
|
volumes : PDList;
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -32,7 +32,7 @@ uses
|
|||||||
core.strings,
|
core.strings,
|
||||||
io.stdio,
|
io.stdio,
|
||||||
debug.tracer,
|
debug.tracer,
|
||||||
core.util, arch.x86.util;
|
core.util, arch.platform.cpu;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ var
|
|||||||
begin
|
begin
|
||||||
|
|
||||||
buffer := puint32(kalloc(disk^.sectorSize))
|
buffer := puint32(kalloc(disk^.sectorSize))
|
||||||
memset(uint32(buffer), 0, disk^.sectorSize);
|
memset(PtrUInt(buffer), 0, disk^.sectorSize);
|
||||||
PFilesystemRecord := PFilesystemRecord(buffer);
|
PFilesystemRecord := PFilesystemRecord(buffer);
|
||||||
|
|
||||||
filesystemRecord^.magicNumber := $A2F2;
|
filesystemRecord^.magicNumber := $A2F2;
|
||||||
@@ -102,7 +102,7 @@ begin
|
|||||||
//filesystemRecord.volumeLabel := config^
|
//filesystemRecord.volumeLabel := config^
|
||||||
|
|
||||||
driver.storage.mgr.storage_write(disk, start, 1, buffer);
|
driver.storage.mgr.storage_write(disk, start, 1, buffer);
|
||||||
memset(uint32(buffer), 0, disk^.sectorSize);
|
memset(PtrUInt(buffer), 0, disk^.sectorSize);
|
||||||
|
|
||||||
fileEntry := PFileEntry(buffer)[0];
|
fileEntry := PFileEntry(buffer)[0];
|
||||||
fileEntry^.filename := thisArray;
|
fileEntry^.filename := thisArray;
|
||||||
|
|||||||
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
File diff suppressed because it is too large.
Load diff
@@ -14,7 +14,7 @@ uses driver.storage.fs.ext2.types, driver.storage.fs.ext2.core,
|
|||||||
function ValidateLabel(text : pchar; var normalized : TVolumeLabel) : TError;
|
function ValidateLabel(text : pchar; var normalized : TVolumeLabel) : TError;
|
||||||
var i : uint32;
|
var i : uint32;
|
||||||
begin
|
begin
|
||||||
memset(uint32(@normalized),0,sizeof(normalized));
|
memset(PtrUInt(@normalized),0,sizeof(normalized));
|
||||||
ValidateLabel:=eInvalidArgument; if text=nil then exit;
|
ValidateLabel:=eInvalidArgument; if text=nil then exit;
|
||||||
i:=0;
|
i:=0;
|
||||||
while (i<16) and (text[i]<>char(0)) do begin
|
while (i<16) and (text[i]<>char(0)) do begin
|
||||||
@@ -29,7 +29,7 @@ function Geometry(volume : PStorage_Volume; sectors, start : uint32; config : PF
|
|||||||
var g, count, minimum, perBlock, tables, reserve : uint32; labelText : TVolumeLabel;
|
var g, count, minimum, perBlock, tables, reserve : uint32; labelText : TVolumeLabel;
|
||||||
begin
|
begin
|
||||||
Geometry:=eInvalidArgument;
|
Geometry:=eInvalidArgument;
|
||||||
memset(uint32(@v),0,sizeof(v));
|
memset(PtrUInt(@v),0,sizeof(v));
|
||||||
if volume=nil then exit;
|
if volume=nil then exit;
|
||||||
if volume^.device=nil then exit;
|
if volume^.device=nil then exit;
|
||||||
if not volume^.device^.writable then begin Geometry:=eReadOnly; exit; end;
|
if not volume^.device^.writable then begin Geometry:=eReadOnly; exit; end;
|
||||||
@@ -98,7 +98,7 @@ begin
|
|||||||
if err<>eNone then begin kfree(void(v)); FormatVolume:=err; exit; end;
|
if err<>eNone then begin kfree(void(v)); FormatVolume:=err; exit; end;
|
||||||
op:=PExt2Op(kalloc(sizeof(TExt2Op)));
|
op:=PExt2Op(kalloc(sizeof(TExt2Op)));
|
||||||
if op=nil then begin kfree(void(v)); exit; end;
|
if op=nil then begin kfree(void(v)); exit; end;
|
||||||
memset(uint32(op),0,sizeof(TExt2Op)); op^.V:=v;
|
memset(PtrUInt(op),0,sizeof(TExt2Op)); op^.V:=v;
|
||||||
v^.Super:=puint8(kalloc(1024)); v^.Groups:=puint8(kalloc(v^.GDTBlocks*v^.BlockSize));
|
v^.Super:=puint8(kalloc(1024)); v^.Groups:=puint8(kalloc(v^.GDTBlocks*v^.BlockSize));
|
||||||
op^.Scratch:=puint8(kalloc(v^.BlockSize));
|
op^.Scratch:=puint8(kalloc(v^.BlockSize));
|
||||||
if (v^.Super=nil) or (v^.Groups=nil) or (op^.Scratch=nil) then begin
|
if (v^.Super=nil) or (v^.Groups=nil) or (op^.Scratch=nil) then begin
|
||||||
@@ -106,7 +106,7 @@ begin
|
|||||||
if op^.Scratch<>nil then kfree(void(op^.Scratch));
|
if op^.Scratch<>nil then kfree(void(op^.Scratch));
|
||||||
kfree(void(op)); kfree(void(v)); exit;
|
kfree(void(op)); kfree(void(v)); exit;
|
||||||
end;
|
end;
|
||||||
memset(uint32(v^.Super),0,1024); memset(uint32(v^.Groups),0,v^.GDTBlocks*v^.BlockSize);
|
memset(PtrUInt(v^.Super),0,1024); memset(PtrUInt(v^.Groups),0,v^.GDTBlocks*v^.BlockSize);
|
||||||
Put32(v^.Super,0,v^.InodeCount); Put32(v^.Super,4,v^.BlockCount);
|
Put32(v^.Super,0,v^.InodeCount); Put32(v^.Super,4,v^.BlockCount);
|
||||||
Put32(v^.Super,16,v^.InodeCount-10); Put32(v^.Super,20,v^.FirstBlock);
|
Put32(v^.Super,16,v^.InodeCount-10); Put32(v^.Super,20,v^.FirstBlock);
|
||||||
i:=0; if v^.BlockSize=2048 then i:=1 else if v^.BlockSize=4096 then i:=2;
|
i:=0; if v^.BlockSize=2048 then i:=1 else if v^.BlockSize=4096 then i:=2;
|
||||||
@@ -120,13 +120,13 @@ begin
|
|||||||
v^.Super[110]:=(v^.Super[110] and $0F) or $40;
|
v^.Super[110]:=(v^.Super[110] and $0F) or $40;
|
||||||
v^.Super[112]:=(v^.Super[112] and $3F) or $80;
|
v^.Super[112]:=(v^.Super[112] and $3F) or $80;
|
||||||
if config<>nil then if (config^.Flags and FS_FORMAT_PARAM_LABEL)<>0 then
|
if config<>nil then if (config^.Flags and FS_FORMAT_PARAM_LABEL)<>0 then
|
||||||
memcpy(uint32(@config^.LabelText[0]),uint32(v^.Super)+120,11);
|
memcpy(PtrUInt(@config^.LabelText[0]),PtrUInt(v^.Super)+120,11);
|
||||||
tables:=v^.InodesPerGroup div (v^.BlockSize div 128); freeBlocks:=0; rootBlock:=0;
|
tables:=v^.InodesPerGroup div (v^.BlockSize div 128); freeBlocks:=0; rootBlock:=0;
|
||||||
for g:=0 to v^.GroupCount-1 do begin
|
for g:=0 to v^.GroupCount-1 do begin
|
||||||
first:=v^.FirstBlock+g*v^.BlocksPerGroup; count:=v^.BlockCount-first;
|
first:=v^.FirstBlock+g*v^.BlocksPerGroup; count:=v^.BlockCount-first;
|
||||||
if count>v^.BlocksPerGroup then count:=v^.BlocksPerGroup;
|
if count>v^.BlocksPerGroup then count:=v^.BlocksPerGroup;
|
||||||
reserve:=0; if HasSuper(g,1) then reserve:=1+v^.GDTBlocks;
|
reserve:=0; if HasSuper(g,1) then reserve:=1+v^.GDTBlocks;
|
||||||
d:=PExt2Group(uint32(v^.Groups)+g*32);
|
d:=PExt2Group(PtrUInt(v^.Groups)+g*32);
|
||||||
d^.BlockBitmap:=first+reserve; d^.InodeBitmap:=first+reserve+1; d^.InodeTable:=first+reserve+2;
|
d^.BlockBitmap:=first+reserve; d^.InodeBitmap:=first+reserve+1; d^.InodeTable:=first+reserve+2;
|
||||||
used:=reserve+2+tables;
|
used:=reserve+2+tables;
|
||||||
d^.FreeInodes:=v^.InodesPerGroup;
|
d^.FreeInodes:=v^.InodesPerGroup;
|
||||||
@@ -135,42 +135,42 @@ begin
|
|||||||
end;
|
end;
|
||||||
Put32(v^.Super,12,freeBlocks);
|
Put32(v^.Super,12,freeBlocks);
|
||||||
{ Invalidate the primary signature before writing metadata. Publish it last. }
|
{ Invalidate the primary signature before writing metadata. Publish it last. }
|
||||||
memset(uint32(op^.Scratch),0,v^.BlockSize);
|
memset(PtrUInt(op^.Scratch),0,v^.BlockSize);
|
||||||
op^.Error:=storage_write(volume^.device,start+2,2,puint32(op^.Scratch));
|
op^.Error:=storage_write(volume^.device,start+2,2,puint32(op^.Scratch));
|
||||||
g:=0;
|
g:=0;
|
||||||
while (g<v^.GroupCount) and (op^.Error=eNone) do begin
|
while (g<v^.GroupCount) and (op^.Error=eNone) do begin
|
||||||
first:=v^.FirstBlock+g*v^.BlocksPerGroup; count:=v^.BlockCount-first;
|
first:=v^.FirstBlock+g*v^.BlocksPerGroup; count:=v^.BlockCount-first;
|
||||||
if count>v^.BlocksPerGroup then count:=v^.BlocksPerGroup;
|
if count>v^.BlocksPerGroup then count:=v^.BlocksPerGroup;
|
||||||
d:=PExt2Group(uint32(v^.Groups)+g*32); used:=count-d^.FreeBlocks;
|
d:=PExt2Group(PtrUInt(v^.Groups)+g*32); used:=count-d^.FreeBlocks;
|
||||||
memset(uint32(op^.Scratch),$FF,v^.BlockSize);
|
memset(PtrUInt(op^.Scratch),$FF,v^.BlockSize);
|
||||||
for bit:=used to count-1 do op^.Scratch[bit div 8]:=op^.Scratch[bit div 8] and not (1 shl (bit mod 8));
|
for bit:=used to count-1 do op^.Scratch[bit div 8]:=op^.Scratch[bit div 8] and not (1 shl (bit mod 8));
|
||||||
WriteBlock(op,d^.BlockBitmap,op^.Scratch);
|
WriteBlock(op,d^.BlockBitmap,op^.Scratch);
|
||||||
memset(uint32(op^.Scratch),$FF,v^.BlockSize);
|
memset(PtrUInt(op^.Scratch),$FF,v^.BlockSize);
|
||||||
used:=0; if g=0 then used:=10;
|
used:=0; if g=0 then used:=10;
|
||||||
for bit:=used to v^.InodesPerGroup-1 do op^.Scratch[bit div 8]:=op^.Scratch[bit div 8] and not (1 shl (bit mod 8));
|
for bit:=used to v^.InodesPerGroup-1 do op^.Scratch[bit div 8]:=op^.Scratch[bit div 8] and not (1 shl (bit mod 8));
|
||||||
WriteBlock(op,d^.InodeBitmap,op^.Scratch);
|
WriteBlock(op,d^.InodeBitmap,op^.Scratch);
|
||||||
memset(uint32(op^.Scratch),0,v^.BlockSize);
|
memset(PtrUInt(op^.Scratch),0,v^.BlockSize);
|
||||||
for i:=0 to tables-1 do begin
|
for i:=0 to tables-1 do begin
|
||||||
if not WriteBlock(op,d^.InodeTable+i,op^.Scratch) then break;
|
if not WriteBlock(op,d^.InodeTable+i,op^.Scratch) then break;
|
||||||
end;
|
end;
|
||||||
if HasSuper(g,1) then begin
|
if HasSuper(g,1) then begin
|
||||||
for i:=0 to v^.GDTBlocks-1 do
|
for i:=0 to v^.GDTBlocks-1 do
|
||||||
if not WriteBlock(op,first+1+i,pointer(uint32(v^.Groups)+i*v^.BlockSize)) then break;
|
if not WriteBlock(op,first+1+i,pointer(PtrUInt(v^.Groups)+i*v^.BlockSize)) then break;
|
||||||
if g<>0 then begin
|
if g<>0 then begin
|
||||||
memset(uint32(op^.Scratch),0,v^.BlockSize);
|
memset(PtrUInt(op^.Scratch),0,v^.BlockSize);
|
||||||
memcpy(uint32(v^.Super),uint32(op^.Scratch),1024); Put16(op^.Scratch,90,g);
|
memcpy(PtrUInt(v^.Super),PtrUInt(op^.Scratch),1024); Put16(op^.Scratch,90,g);
|
||||||
WriteBlock(op,first,op^.Scratch);
|
WriteBlock(op,first,op^.Scratch);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
Inc(g);
|
Inc(g);
|
||||||
end;
|
end;
|
||||||
if op^.Error=eNone then begin
|
if op^.Error=eNone then begin
|
||||||
memset(uint32(op^.Scratch),0,v^.BlockSize);
|
memset(PtrUInt(op^.Scratch),0,v^.BlockSize);
|
||||||
inode:=PExt2Inode(uint32(op^.Scratch)+128);
|
inode:=PExt2Inode(PtrUInt(op^.Scratch)+128);
|
||||||
inode^.Mode:=EXT2_DIR or $1ED; inode^.Size:=v^.BlockSize; inode^.Links:=2;
|
inode^.Mode:=EXT2_DIR or $1ED; inode^.Size:=v^.BlockSize; inode^.Links:=2;
|
||||||
inode^.Sectors:=v^.SectorsPerBlock; inode^.Blocks[0]:=rootBlock;
|
inode^.Sectors:=v^.SectorsPerBlock; inode^.Blocks[0]:=rootBlock;
|
||||||
WriteBlock(op,PExt2Group(v^.Groups)^.InodeTable,op^.Scratch);
|
WriteBlock(op,PExt2Group(v^.Groups)^.InodeTable,op^.Scratch);
|
||||||
memset(uint32(op^.Scratch),0,v^.BlockSize);
|
memset(PtrUInt(op^.Scratch),0,v^.BlockSize);
|
||||||
Put32(op^.Scratch,0,2); Put16(op^.Scratch,4,12); op^.Scratch[6]:=1; op^.Scratch[7]:=2; op^.Scratch[8]:=ord('.');
|
Put32(op^.Scratch,0,2); Put16(op^.Scratch,4,12); op^.Scratch[6]:=1; op^.Scratch[7]:=2; op^.Scratch[8]:=ord('.');
|
||||||
Put32(op^.Scratch,12,2); Put16(op^.Scratch,16,v^.BlockSize-12); op^.Scratch[18]:=2; op^.Scratch[19]:=2;
|
Put32(op^.Scratch,12,2); Put16(op^.Scratch,16,v^.BlockSize-12); op^.Scratch[18]:=2; op^.Scratch[19]:=2;
|
||||||
op^.Scratch[20]:=ord('.'); op^.Scratch[21]:=ord('.');
|
op^.Scratch[20]:=ord('.'); op^.Scratch[21]:=ord('.');
|
||||||
@@ -188,14 +188,14 @@ begin
|
|||||||
SetLabel:=ValidateLabel(text,labelText); if SetLabel<>eNone then exit;
|
SetLabel:=ValidateLabel(text,labelText); if SetLabel<>eNone then exit;
|
||||||
op:=BeginOp(volume); if op=nil then begin SetLabel:=eOutOfMemory; exit; end;
|
op:=BeginOp(volume); if op=nil then begin SetLabel:=eOutOfMemory; exit; end;
|
||||||
if BeginMutation(op) then begin
|
if BeginMutation(op) then begin
|
||||||
memcpy(uint32(@labelText),uint32(op^.V^.Super)+120,16);
|
memcpy(PtrUInt(@labelText),PtrUInt(op^.V^.Super)+120,16);
|
||||||
for g:=1 to op^.V^.GroupCount-1 do if HasSuper(g,Get32(op^.V^.Super,100)) then begin
|
for g:=1 to op^.V^.GroupCount-1 do if HasSuper(g,Get32(op^.V^.Super,100)) then begin
|
||||||
first:=op^.V^.FirstBlock+g*op^.V^.BlocksPerGroup;
|
first:=op^.V^.FirstBlock+g*op^.V^.BlocksPerGroup;
|
||||||
if not ReadBlock(op,first,op^.Scratch) then break;
|
if not ReadBlock(op,first,op^.Scratch) then break;
|
||||||
memcpy(uint32(@labelText),uint32(op^.Scratch)+120,16);
|
memcpy(PtrUInt(@labelText),PtrUInt(op^.Scratch)+120,16);
|
||||||
if not WriteBlock(op,first,op^.Scratch) then break;
|
if not WriteBlock(op,first,op^.Scratch) then break;
|
||||||
end;
|
end;
|
||||||
if FinishMutation(op) then memcpy(uint32(@labelText),uint32(@volume^.labelText),sizeof(labelText));
|
if FinishMutation(op) then memcpy(PtrUInt(@labelText),PtrUInt(@volume^.labelText),sizeof(labelText));
|
||||||
end;
|
end;
|
||||||
SetLabel:=op^.Error; EndOp(op);
|
SetLabel:=op^.Error; EndOp(op);
|
||||||
end;
|
end;
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
unit driver.storage.fs.ext2;
|
unit driver.storage.fs.ext2;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
uses driver.storage.types;
|
uses arch.platform.cpu, driver.storage.types;
|
||||||
|
procedure StartWorker;
|
||||||
procedure init;
|
procedure init;
|
||||||
procedure ReleaseVolume(volume : PStorage_Volume);
|
procedure ReleaseVolume(volume : PStorage_Volume);
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses boot.mgr, driver.storage.fs.mgr, driver.storage.vol.mgr,
|
uses driver.storage.fs.mgr, driver.storage.vol.mgr,
|
||||||
driver.storage.fs.ext2.types, driver.storage.fs.ext2.core,
|
driver.storage.fs.ext2.types, driver.storage.fs.ext2.core,
|
||||||
driver.storage.fs.ext2.format, memory.heap, core.util, core.strings,
|
driver.storage.fs.ext2.format, memory.heap, core.util, core.strings,
|
||||||
proc.mgr, proc.types;
|
proc.mgr, proc.types;
|
||||||
@@ -62,15 +63,17 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure WorkLoop(pctx : PProcessContext);
|
procedure WorkLoop(pctx : PProcessContext);
|
||||||
var work : PWork; done : uint32; error : TError; callback : TIOCallback; data : pointer;
|
var
|
||||||
|
savedIRQ: PtrUInt;
|
||||||
|
work : PWork; done : uint32; error : TError; callback : TIOCallback; data : pointer;
|
||||||
begin
|
begin
|
||||||
while true do begin
|
while true do begin
|
||||||
asm pushf; cli end;
|
savedIRQ := arch.platform.cpu.lock;
|
||||||
work:=head;
|
work:=head;
|
||||||
if work<>nil then begin
|
if work<>nil then begin
|
||||||
head:=work^.Next; if head=nil then tail:=nil; Dec(queued);
|
head:=work^.Next; if head=nil then tail:=nil; Dec(queued);
|
||||||
end else pctx^.State:=psAwaiting;
|
end else pctx^.State:=psAwaiting;
|
||||||
asm popf end;
|
arch.platform.cpu.unlock(savedIRQ);
|
||||||
if work=nil then begin
|
if work=nil then begin
|
||||||
{ Queue publication wakes the worker under the same CLI section.
|
{ Queue publication wakes the worker under the same CLI section.
|
||||||
No per-I/O process, IRQ continuation, or volatile spin is needed. }
|
No per-I/O process, IRQ continuation, or volatile spin is needed. }
|
||||||
@@ -92,7 +95,9 @@ begin worker:=proc.mgr.create('ext2.io',@WorkLoop,nil,1); end;
|
|||||||
procedure QueueTransfer(volume : PStorage_Volume; directory, name : pchar; offset : uint32;
|
procedure QueueTransfer(volume : PStorage_Volume; directory, name : pchar; offset : uint32;
|
||||||
buffer : puint32; count : uint32; ctx : pointer; completed : puint32;
|
buffer : puint32; count : uint32; ctx : pointer; completed : puint32;
|
||||||
callback : TIOCallback; data : pointer; writing : boolean);
|
callback : TIOCallback; data : pointer; writing : boolean);
|
||||||
var work : PWork; error : TError;
|
var
|
||||||
|
savedIRQ: PtrUInt;
|
||||||
|
work : PWork; error : TError;
|
||||||
begin
|
begin
|
||||||
if completed<>nil then completed^:=0;
|
if completed<>nil then completed^:=0;
|
||||||
error:=eNone;
|
error:=eNone;
|
||||||
@@ -101,7 +106,7 @@ begin
|
|||||||
if error<>eNone then begin if callback<>nil then callback(error,data); exit; end;
|
if error<>eNone then begin if callback<>nil then callback(error,data); exit; end;
|
||||||
work:=PWork(kalloc(sizeof(TWork)));
|
work:=PWork(kalloc(sizeof(TWork)));
|
||||||
if work=nil then begin if callback<>nil then callback(eOutOfMemory,data); exit; end;
|
if work=nil then begin if callback<>nil then callback(eOutOfMemory,data); exit; end;
|
||||||
memset(uint32(work),0,sizeof(TWork));
|
memset(PtrUInt(work),0,sizeof(TWork));
|
||||||
if ctx=nil then begin
|
if ctx=nil then begin
|
||||||
if (directory=nil) or (name=nil) then error:=eInvalidArgument else begin
|
if (directory=nil) or (name=nil) then error:=eInvalidArgument else begin
|
||||||
work^.Directory:=stringCopy(directory); work^.Name:=stringCopy(name);
|
work^.Directory:=stringCopy(directory); work^.Name:=stringCopy(name);
|
||||||
@@ -112,13 +117,13 @@ begin
|
|||||||
work^.Volume:=volume; work^.FileCtx:=PExt2File(ctx); work^.Offset:=offset;
|
work^.Volume:=volume; work^.FileCtx:=PExt2File(ctx); work^.Offset:=offset;
|
||||||
work^.Buffer:=buffer; work^.Count:=count; work^.Completed:=completed;
|
work^.Buffer:=buffer; work^.Count:=count; work^.Completed:=completed;
|
||||||
work^.Writing:=writing; work^.Callback:=callback; work^.CallbackData:=data;
|
work^.Writing:=writing; work^.Callback:=callback; work^.CallbackData:=data;
|
||||||
asm pushf; cli end;
|
savedIRQ := arch.platform.cpu.lock;
|
||||||
if queued>=64 then error:=eQueueFull else begin
|
if queued>=64 then error:=eQueueFull else begin
|
||||||
if tail=nil then head:=work else tail^.Next:=work;
|
if tail=nil then head:=work else tail^.Next:=work;
|
||||||
tail:=work; Inc(queued);
|
tail:=work; Inc(queued);
|
||||||
if worker^.State=psAwaiting then worker^.State:=psReady;
|
if worker^.State=psAwaiting then worker^.State:=psReady;
|
||||||
end;
|
end;
|
||||||
asm popf end;
|
arch.platform.cpu.unlock(savedIRQ);
|
||||||
if error<>eNone then begin FreeWork(work); if callback<>nil then callback(error,data); end;
|
if error<>eNone then begin FreeWork(work); if callback<>nil then callback(error,data); end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -177,7 +182,7 @@ var volume : PStorage_Volume;
|
|||||||
begin
|
begin
|
||||||
if device=nil then exit;
|
if device=nil then exit;
|
||||||
volume:=PStorage_Volume(kalloc(sizeof(TStorage_Volume))); if volume=nil then exit;
|
volume:=PStorage_Volume(kalloc(sizeof(TStorage_Volume))); if volume=nil then exit;
|
||||||
memset(uint32(volume),0,sizeof(TStorage_Volume));
|
memset(PtrUInt(volume),0,sizeof(TStorage_Volume));
|
||||||
volume^.device:=device; volume^.sectorCount:=device^.maxSectorCount; volume^.sectorSize:=device^.sectorSize;
|
volume^.device:=device; volume^.sectorCount:=device^.maxSectorCount; volume^.sectorSize:=device^.sectorSize;
|
||||||
if Identify(volume) then begin
|
if Identify(volume) then begin
|
||||||
volume^.filesystem:=@filesystem;
|
volume^.filesystem:=@filesystem;
|
||||||
@@ -187,7 +192,7 @@ end;
|
|||||||
|
|
||||||
procedure init;
|
procedure init;
|
||||||
begin
|
begin
|
||||||
memset(uint32(@filesystem),0,sizeof(filesystem));
|
memset(PtrUInt(@filesystem),0,sizeof(filesystem));
|
||||||
filesystem.sName:='EXT2'; filesystem.system_id:=$83;
|
filesystem.sName:='EXT2'; filesystem.system_id:=$83;
|
||||||
filesystem.identifyCallback:=@Identify; filesystem.detectCallback:=@Detect;
|
filesystem.identifyCallback:=@Identify; filesystem.detectCallback:=@Detect;
|
||||||
filesystem.validateFormat:=@ValidateFormat; filesystem.createCallback:=@FormatVolume;
|
filesystem.validateFormat:=@ValidateFormat; filesystem.createCallback:=@FormatVolume;
|
||||||
@@ -203,7 +208,4 @@ begin
|
|||||||
driver.storage.fs.mgr.register_filesystem(@filesystem);
|
driver.storage.fs.mgr.register_filesystem(@filesystem);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
initialization
|
|
||||||
boot.mgr.registerBoot('driver.storage.fs.ext2',@init,'Ext2 Filesystem','driver.storage.fs.mgr');
|
|
||||||
boot.mgr.registerBoot('driver.storage.ext2.worker',@StartWorker,'Ext2 I/O Worker','proc.mgr');
|
|
||||||
end.
|
end.
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -14,7 +14,7 @@ function normalize_label(text : pchar; var normalized : TVolumeLabel) : TError;
|
|||||||
var i, n, first : uint32; c : char;
|
var i, n, first : uint32; c : char;
|
||||||
begin
|
begin
|
||||||
normalize_label := eInvalidArgument;
|
normalize_label := eInvalidArgument;
|
||||||
memset(uint32(@normalized[0]), 0, sizeof(normalized));
|
memset(PtrUInt(@normalized[0]), 0, sizeof(normalized));
|
||||||
if text = nil then exit;
|
if text = nil then exit;
|
||||||
n := 0;
|
n := 0;
|
||||||
while (n < 12) and (text[n] <> #0) do Inc(n);
|
while (n < 12) and (text[n] <> #0) do Inc(n);
|
||||||
@@ -37,7 +37,7 @@ end;
|
|||||||
procedure unpack_label(src : pchar; var dest : TVolumeLabel);
|
procedure unpack_label(src : pchar; var dest : TVolumeLabel);
|
||||||
var n, i : uint32;
|
var n, i : uint32;
|
||||||
begin
|
begin
|
||||||
memset(uint32(@dest[0]), 0, sizeof(dest));
|
memset(PtrUInt(@dest[0]), 0, sizeof(dest));
|
||||||
n := 11; while (n > 0) and ((src[n-1] = ' ') or (src[n-1] = #0)) do Dec(n);
|
n := 11; while (n > 0) and ((src[n-1] = ' ') or (src[n-1] = #0)) do Dec(n);
|
||||||
for i := 0 to 10 do if i < n then dest[i] := src[i];
|
for i := 0 to 10 do if i < n then dest[i] := src[i];
|
||||||
end;
|
end;
|
||||||
@@ -62,7 +62,7 @@ begin
|
|||||||
br := PBootRecord(buffer); lim := FAT32ClusterLimit(br);
|
br := PBootRecord(buffer); lim := FAT32ClusterLimit(br);
|
||||||
if (lim <= 2) or (br^.manySectors = 0) or (br^.manySectors > volume^.sectorCount) or
|
if (lim <= 2) or (br^.manySectors = 0) or (br^.manySectors > volume^.sectorCount) or
|
||||||
(br^.rootCluster < 2) or (br^.rootCluster >= lim) or
|
(br^.rootCluster < 2) or (br^.rootCluster >= lim) or
|
||||||
(puint16(uint32(buffer)+510)^ <> $AA55) then load_boot := eCorruptFilesystem;
|
(puint16(PtrUInt(buffer)+510)^ <> $AA55) then load_boot := eCorruptFilesystem;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Bounded walk of the root FAT chain. A label is authoritative when present.
|
{ Bounded walk of the root FAT chain. A label is authoritative when present.
|
||||||
@@ -113,12 +113,12 @@ var mem, boot, scratch : puint32; sector, offset, i : uint32; found, noName : bo
|
|||||||
begin
|
begin
|
||||||
mem := puint32(kalloc(1024));
|
mem := puint32(kalloc(1024));
|
||||||
if mem = nil then begin read_label := eOutOfMemory; exit; end;
|
if mem = nil then begin read_label := eOutOfMemory; exit; end;
|
||||||
boot := mem; scratch := puint32(uint32(mem)+512);
|
boot := mem; scratch := puint32(PtrUInt(mem)+512);
|
||||||
read_label := load_boot(volume,boot);
|
read_label := load_boot(volume,boot);
|
||||||
if read_label = eNone then begin
|
if read_label = eNone then begin
|
||||||
read_label := locate_label(volume,PBootRecord(boot),scratch,sector,offset,found);
|
read_label := locate_label(volume,PBootRecord(boot),scratch,sector,offset,found);
|
||||||
if read_label = eNone then begin
|
if read_label = eNone then begin
|
||||||
if found then unpack_label(pchar(uint32(scratch)+offset),value)
|
if found then unpack_label(pchar(PtrUInt(scratch)+offset),value)
|
||||||
else begin
|
else begin
|
||||||
unpack_label(pchar(@PBootRecord(boot)^.volumeLabel[0]),value);
|
unpack_label(pchar(@PBootRecord(boot)^.volumeLabel[0]),value);
|
||||||
noName := true;
|
noName := true;
|
||||||
@@ -142,8 +142,8 @@ begin
|
|||||||
if not volume^.device^.writable then begin write_label := eReadOnly; exit; end;
|
if not volume^.device^.writable then begin write_label := eReadOnly; exit; end;
|
||||||
mem := puint32(kalloc(5*512));
|
mem := puint32(kalloc(5*512));
|
||||||
if mem = nil then begin write_label := eOutOfMemory; exit; end;
|
if mem = nil then begin write_label := eOutOfMemory; exit; end;
|
||||||
boot := mem; scratch := puint32(uint32(mem)+512); rootOld := puint32(uint32(mem)+1024);
|
boot := mem; scratch := puint32(PtrUInt(mem)+512); rootOld := puint32(PtrUInt(mem)+1024);
|
||||||
backupOld := puint32(uint32(mem)+1536); bootOld := puint32(uint32(mem)+2048);
|
backupOld := puint32(PtrUInt(mem)+1536); bootOld := puint32(PtrUInt(mem)+2048);
|
||||||
bootWritten := false; backupWritten := false; rootWritten := false; backup := 0;
|
bootWritten := false; backupWritten := false; rootWritten := false; backup := 0;
|
||||||
repeat
|
repeat
|
||||||
write_label := load_boot(volume,boot); if write_label <> eNone then break;
|
write_label := load_boot(volume,boot); if write_label <> eNone then break;
|
||||||
@@ -153,17 +153,17 @@ begin
|
|||||||
if (sector = 0) and (value[0] <> #0) then begin write_label := eDiskFull; break; end;
|
if (sector = 0) and (value[0] <> #0) then begin write_label := eDiskFull; break; end;
|
||||||
if sector <> 0 then begin
|
if sector <> 0 then begin
|
||||||
write_label := storage_read(volume^.device,sector,1,scratch); if write_label <> eNone then break;
|
write_label := storage_read(volume^.device,sector,1,scratch); if write_label <> eNone then break;
|
||||||
memcpy(uint32(scratch),uint32(rootOld),512);
|
memcpy(PtrUInt(scratch),PtrUInt(rootOld),512);
|
||||||
entry := PDirectory(uint32(scratch)+offset);
|
entry := PDirectory(PtrUInt(scratch)+offset);
|
||||||
if value[0] = #0 then begin
|
if value[0] = #0 then begin
|
||||||
if found then entry^.fileName[0] := char($E5);
|
if found then entry^.fileName[0] := char($E5);
|
||||||
end else begin
|
end else begin
|
||||||
if entry^.fileName[0] = #0 then begin
|
if entry^.fileName[0] = #0 then begin
|
||||||
{ Retain an end marker after a newly inserted label. }
|
{ Retain an end marker after a newly inserted label. }
|
||||||
if offset = 480 then begin write_label := eDiskFull; break; end;
|
if offset = 480 then begin write_label := eDiskFull; break; end;
|
||||||
puint8(uint32(entry)+32)^ := 0;
|
puint8(PtrUInt(entry)+32)^ := 0;
|
||||||
end;
|
end;
|
||||||
memset(uint32(entry),0,32); pack_label(@value[0],@entry^.fileName[0]); entry^.attributes := $08;
|
memset(PtrUInt(entry),0,32); pack_label(@value[0],@entry^.fileName[0]); entry^.attributes := $08;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
if (br^.backupCluster <> 0) and (br^.backupCluster <> $FFFF) then begin
|
if (br^.backupCluster <> 0) and (br^.backupCluster <> $FFFF) then begin
|
||||||
@@ -171,7 +171,7 @@ begin
|
|||||||
backup := volume^.sectorStart+br^.backupCluster;
|
backup := volume^.sectorStart+br^.backupCluster;
|
||||||
write_label := storage_read(volume^.device,backup,1,backupOld); if write_label <> eNone then break;
|
write_label := storage_read(volume^.device,backup,1,backupOld); if write_label <> eNone then break;
|
||||||
end;
|
end;
|
||||||
memcpy(uint32(boot),uint32(bootOld),512);
|
memcpy(PtrUInt(boot),PtrUInt(bootOld),512);
|
||||||
if value[0] = #0 then pack_label('NO NAME',pchar(@br^.volumeLabel[0]))
|
if value[0] = #0 then pack_label('NO NAME',pchar(@br^.volumeLabel[0]))
|
||||||
else pack_label(@value[0],pchar(@br^.volumeLabel[0]));
|
else pack_label(@value[0],pchar(@br^.volumeLabel[0]));
|
||||||
bootWritten := true;
|
bootWritten := true;
|
||||||
@@ -180,7 +180,7 @@ begin
|
|||||||
bootWritten := true;
|
bootWritten := true;
|
||||||
if backup <> 0 then begin
|
if backup <> 0 then begin
|
||||||
{ Preserve backup-specific bytes; only update its label. }
|
{ Preserve backup-specific bytes; only update its label. }
|
||||||
memcpy(uint32(backupOld),uint32(boot),512);
|
memcpy(PtrUInt(backupOld),PtrUInt(boot),512);
|
||||||
if value[0] = #0 then pack_label('NO NAME',pchar(@br^.volumeLabel[0]))
|
if value[0] = #0 then pack_label('NO NAME',pchar(@br^.volumeLabel[0]))
|
||||||
else pack_label(@value[0],pchar(@br^.volumeLabel[0]));
|
else pack_label(@value[0],pchar(@br^.volumeLabel[0]));
|
||||||
backupWritten := true;
|
backupWritten := true;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ unit driver.storage.fs.fat32;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
boot.mgr,
|
|
||||||
driver.storage.fs.mgr,
|
driver.storage.fs.mgr,
|
||||||
driver.storage.types;
|
driver.storage.types;
|
||||||
|
|
||||||
@@ -31,7 +30,7 @@ end;
|
|||||||
procedure init;
|
procedure init;
|
||||||
begin
|
begin
|
||||||
io.syslog.logln('FAT32', 'init: registering FAT32 filesystem');
|
io.syslog.logln('FAT32', 'init: registering FAT32 filesystem');
|
||||||
memset(uint32(@filesystem), 0, sizeof(TFilesystem));
|
memset(PtrUInt(@filesystem), 0, sizeof(TFilesystem));
|
||||||
filesystem.sName := 'FAT32';
|
filesystem.sName := 'FAT32';
|
||||||
filesystem.system_id := $0B;
|
filesystem.system_id := $0B;
|
||||||
filesystem.readDirCallback := @FAT32ReadDirectory;
|
filesystem.readDirCallback := @FAT32ReadDirectory;
|
||||||
@@ -61,7 +60,4 @@ begin
|
|||||||
driver.storage.fs.mgr.register_filesystem(@filesystem);
|
driver.storage.fs.mgr.register_filesystem(@filesystem);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
initialization
|
|
||||||
boot.mgr.registerBoot('driver.storage.fs.fat32', @init, 'FAT32 Filesystem', 'driver.storage.fs.mgr');
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
Loaded 20 of 24 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user