fat
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-03-24 18:10:04 +00:00
parent 096db148d0
commit 7e99bc2db1
@@ -61,6 +61,7 @@ var
function readFat(volume : PStorage_Volume; cluster : uint32; bootRecord : PBootRecord) : uint32; forward;
procedure writeFat(volume : PStorage_Volume; cluster : uint32; value : uint32; bootRecord : PBootRecord); forward;
procedure fatFreeClusterChain(volume : PStorage_Volume; info : PFATVolumeInfo; startCluster : uint32); forward;
function fatInitDirectoryCluster(volume : PStorage_Volume; info : PFATVolumeInfo; cluster : uint32; parentCluster : uint32) : boolean; forward;
function isEndOfChain(value : uint32) : boolean;
begin
@@ -1650,13 +1651,14 @@ var
needClusters : uint32;
targetClusters : uint32;
reserve : uint32;
extraClusters : uint32;
lastCluster : uint32;
firstNew : uint32;
tempRuns : PLinkedListBase;
tempRun : PFATTempRun;
i : uint32;
lastTail : uint32;
extraClusters : uint32;
lastCluster : uint32;
firstNew : uint32;
tempRuns : PLinkedListBase;
tempRun : PFATTempRun;
i : uint32;
lastTail : uint32;
prevLastCluster : uint32;
begin
FAT32EnsureCapacityForWrite := eNone;
if (ofi = nil) or (ofi^.VolumeInfo = nil) then begin
@@ -1696,6 +1698,10 @@ begin
if fatFindContiguousFreeRange(ofi^.Volume, ofi^.VolumeInfo, extraClusters, firstNew) then begin
fatLinkContiguousRange(ofi^.Volume, ofi^.VolumeInfo, lastCluster, firstNew, extraClusters, lastTail);
if not runMapAppend(ofi^.RunMap, firstNew, extraClusters) then begin
{ Undo: free the newly linked clusters and restore the previous chain tail to EOC }
fatFreeClusterChain(ofi^.Volume, ofi^.VolumeInfo, firstNew);
if lastCluster >= 2 then
writeFat(ofi^.Volume, lastCluster, $0FFFFFF8, @ofi^.VolumeInfo^.BootRecord);
FAT32EnsureCapacityForWrite := eOutOfMemory;
exit;
end;
@@ -1709,10 +1715,21 @@ begin
end;
for i := 0 to LL_Size(tempRuns) - 1 do begin
tempRun := PFATTempRun(LL_Get(tempRuns, i));
prevLastCluster := lastCluster;
fatLinkContiguousRange(ofi^.Volume, ofi^.VolumeInfo, lastCluster,
tempRun^.StartCluster, tempRun^.ClusterCount, lastTail);
lastCluster := lastTail;
if not runMapAppend(ofi^.RunMap, tempRun^.StartCluster, tempRun^.ClusterCount) then begin
{ Undo: free the current run and restore the previous tail to EOC }
fatFreeClusterChain(ofi^.Volume, ofi^.VolumeInfo, tempRun^.StartCluster);
if prevLastCluster >= 2 then
writeFat(ofi^.Volume, prevLastCluster, $0FFFFFF8, @ofi^.VolumeInfo^.BootRecord);
{ Sync AllocClusters with what actually made it into the RunMap }
ofi^.AllocClusters := ofi^.RunMap.TotalClusters;
if ofi^.AllocClusters > 0 then begin
ofi^.FatDirty := true;
ofi^.MetaDirty := true;
end;
LL_Free(tempRuns);
FAT32EnsureCapacityForWrite := eOutOfMemory;
exit;
@@ -1810,6 +1827,13 @@ begin
ofi^.DirLoc.ParentCluster := parentCluster;
sectorBuf := puint32(kalloc(info^.BootRecord.sectorSize));
if (sectorBuf = nil) and (info^.BootRecord.sectorSize > 0) then begin
{ OOM: cannot probe the directory — fail rather than silently treating an existing file as new }
if namePart <> nil then kfree(void(namePart));
if extPart <> nil then kfree(void(extPart));
FAT32CloseFile(ofi);
exit;
end;
if sectorBuf <> nil then begin
if locateDirEntry(volume, info, parentCluster, cleanName, extPart, ofi^.DirLoc, sectorBuf) then begin
ofi^.Exists := true;
@@ -1836,7 +1860,6 @@ end;
procedure FAT32CloseFile(ctx : pointer);
var
ofi : PFATOpenFile;
sectorBuf : puint32;
rawDir : PDirectory;
keepClusters : uint32;
walked : uint32;
@@ -1910,16 +1933,14 @@ begin
if ofi^.FatDirty and (ofi^.Volume <> nil) then
FAT32Flush(ofi^.Volume);
if ofi^.MetaDirty and ofi^.DirLoc.Valid then begin
sectorBuf := puint32(kalloc(ofi^.VolumeInfo^.BootRecord.sectorSize));
if sectorBuf <> nil then begin
driver.storage.mgr.storage_read(ofi^.Volume^.device, ofi^.DirLoc.SectorLBA, 1, sectorBuf);
rawDir := @PDirectory(sectorBuf)[ofi^.DirLoc.EntryIdx];
rawDir^.byteSize := ofi^.ByteSize;
setDirFirstCluster(rawDir, ofi^.FirstCluster);
driver.storage.mgr.storage_write(ofi^.Volume^.device, ofi^.DirLoc.SectorLBA, 1, sectorBuf);
kfree(sectorBuf);
end;
{ Use the already-allocated ScratchSector (same size as a disk sector) to avoid
a kalloc in close; an allocation failure here would silently lose metadata. }
if ofi^.MetaDirty and ofi^.DirLoc.Valid and (ofi^.ScratchSector <> nil) then begin
driver.storage.mgr.storage_read(ofi^.Volume^.device, ofi^.DirLoc.SectorLBA, 1, ofi^.ScratchSector);
rawDir := @PDirectory(ofi^.ScratchSector)[ofi^.DirLoc.EntryIdx];
rawDir^.byteSize := ofi^.ByteSize;
setDirFirstCluster(rawDir, ofi^.FirstCluster);
driver.storage.mgr.storage_write(ofi^.Volume^.device, ofi^.DirLoc.SectorLBA, 1, ofi^.ScratchSector);
end;
runMapFree(ofi^.RunMap);
@@ -2070,13 +2091,14 @@ begin
statusOut := eNone;
end;
procedure fatInitDirectoryCluster(volume : PStorage_Volume; info : PFATVolumeInfo; cluster : uint32; parentCluster : uint32);
function fatInitDirectoryCluster(volume : PStorage_Volume; info : PFATVolumeInfo; cluster : uint32; parentCluster : uint32) : boolean;
var
buffer : puint32;
ds : uint32;
clusterLBA : uint32;
dir : PDirectory;
begin
fatInitDirectoryCluster := false;
if (volume = nil) or (info = nil) or (cluster < 2) then exit;
buffer := puint32(kalloc(info^.BootRecord.sectorSize));
if buffer = nil then exit;
@@ -2113,6 +2135,7 @@ begin
end;
kfree(buffer);
fatInitDirectoryCluster := true;
end;
function FAT32ReadDirectory(volume : PStorage_Volume; directory : pchar; statusOut : puint32) : PLinkedListBase;
@@ -2300,7 +2323,15 @@ begin
LL_Free(tempRuns);
end;
fatInitDirectoryCluster(volume, info, cluster, parentCluster);
if not fatInitDirectoryCluster(volume, info, cluster, parentCluster) then begin
{ OOM in fatInitDirectoryCluster: free the allocated cluster and bail out }
fatFreeClusterChain(volume, info, cluster);
if statusOut <> nil then statusOut^ := ord(eOutOfMemory);
kfree(sectorBuf);
if namePart <> nil then kfree(void(namePart));
if extPart <> nil then kfree(void(extPart));
exit;
end;
rawDir := @PDirectory(sectorBuf)[loc.EntryIdx];
memset(uint32(rawDir), 0, sizeof(TDirectory));