1 parent
096db148d0
commit
7e99bc2db1
1 file changed
+42
-11
@@ -61,6 +61,7 @@ var
|
|||||||
function readFat(volume : PStorage_Volume; cluster : uint32; bootRecord : PBootRecord) : uint32; forward;
|
function readFat(volume : PStorage_Volume; cluster : uint32; bootRecord : PBootRecord) : uint32; forward;
|
||||||
procedure writeFat(volume : PStorage_Volume; cluster : uint32; value : uint32; bootRecord : PBootRecord); forward;
|
procedure writeFat(volume : PStorage_Volume; cluster : uint32; value : uint32; bootRecord : PBootRecord); forward;
|
||||||
procedure fatFreeClusterChain(volume : PStorage_Volume; info : PFATVolumeInfo; startCluster : uint32); 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;
|
function isEndOfChain(value : uint32) : boolean;
|
||||||
begin
|
begin
|
||||||
@@ -1657,6 +1658,7 @@ var
|
|||||||
tempRun : PFATTempRun;
|
tempRun : PFATTempRun;
|
||||||
i : uint32;
|
i : uint32;
|
||||||
lastTail : uint32;
|
lastTail : uint32;
|
||||||
|
prevLastCluster : uint32;
|
||||||
begin
|
begin
|
||||||
FAT32EnsureCapacityForWrite := eNone;
|
FAT32EnsureCapacityForWrite := eNone;
|
||||||
if (ofi = nil) or (ofi^.VolumeInfo = nil) then begin
|
if (ofi = nil) or (ofi^.VolumeInfo = nil) then begin
|
||||||
@@ -1696,6 +1698,10 @@ begin
|
|||||||
if fatFindContiguousFreeRange(ofi^.Volume, ofi^.VolumeInfo, extraClusters, firstNew) then begin
|
if fatFindContiguousFreeRange(ofi^.Volume, ofi^.VolumeInfo, extraClusters, firstNew) then begin
|
||||||
fatLinkContiguousRange(ofi^.Volume, ofi^.VolumeInfo, lastCluster, firstNew, extraClusters, lastTail);
|
fatLinkContiguousRange(ofi^.Volume, ofi^.VolumeInfo, lastCluster, firstNew, extraClusters, lastTail);
|
||||||
if not runMapAppend(ofi^.RunMap, firstNew, extraClusters) then begin
|
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;
|
FAT32EnsureCapacityForWrite := eOutOfMemory;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@@ -1709,10 +1715,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
for i := 0 to LL_Size(tempRuns) - 1 do begin
|
for i := 0 to LL_Size(tempRuns) - 1 do begin
|
||||||
tempRun := PFATTempRun(LL_Get(tempRuns, i));
|
tempRun := PFATTempRun(LL_Get(tempRuns, i));
|
||||||
|
prevLastCluster := lastCluster;
|
||||||
fatLinkContiguousRange(ofi^.Volume, ofi^.VolumeInfo, lastCluster,
|
fatLinkContiguousRange(ofi^.Volume, ofi^.VolumeInfo, lastCluster,
|
||||||
tempRun^.StartCluster, tempRun^.ClusterCount, lastTail);
|
tempRun^.StartCluster, tempRun^.ClusterCount, lastTail);
|
||||||
lastCluster := lastTail;
|
lastCluster := lastTail;
|
||||||
if not runMapAppend(ofi^.RunMap, tempRun^.StartCluster, tempRun^.ClusterCount) then begin
|
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);
|
LL_Free(tempRuns);
|
||||||
FAT32EnsureCapacityForWrite := eOutOfMemory;
|
FAT32EnsureCapacityForWrite := eOutOfMemory;
|
||||||
exit;
|
exit;
|
||||||
@@ -1810,6 +1827,13 @@ begin
|
|||||||
ofi^.DirLoc.ParentCluster := parentCluster;
|
ofi^.DirLoc.ParentCluster := parentCluster;
|
||||||
|
|
||||||
sectorBuf := puint32(kalloc(info^.BootRecord.sectorSize));
|
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 sectorBuf <> nil then begin
|
||||||
if locateDirEntry(volume, info, parentCluster, cleanName, extPart, ofi^.DirLoc, sectorBuf) then begin
|
if locateDirEntry(volume, info, parentCluster, cleanName, extPart, ofi^.DirLoc, sectorBuf) then begin
|
||||||
ofi^.Exists := true;
|
ofi^.Exists := true;
|
||||||
@@ -1836,7 +1860,6 @@ end;
|
|||||||
procedure FAT32CloseFile(ctx : pointer);
|
procedure FAT32CloseFile(ctx : pointer);
|
||||||
var
|
var
|
||||||
ofi : PFATOpenFile;
|
ofi : PFATOpenFile;
|
||||||
sectorBuf : puint32;
|
|
||||||
rawDir : PDirectory;
|
rawDir : PDirectory;
|
||||||
keepClusters : uint32;
|
keepClusters : uint32;
|
||||||
walked : uint32;
|
walked : uint32;
|
||||||
@@ -1910,16 +1933,14 @@ begin
|
|||||||
if ofi^.FatDirty and (ofi^.Volume <> nil) then
|
if ofi^.FatDirty and (ofi^.Volume <> nil) then
|
||||||
FAT32Flush(ofi^.Volume);
|
FAT32Flush(ofi^.Volume);
|
||||||
|
|
||||||
if ofi^.MetaDirty and ofi^.DirLoc.Valid then begin
|
{ Use the already-allocated ScratchSector (same size as a disk sector) to avoid
|
||||||
sectorBuf := puint32(kalloc(ofi^.VolumeInfo^.BootRecord.sectorSize));
|
a kalloc in close; an allocation failure here would silently lose metadata. }
|
||||||
if sectorBuf <> nil then begin
|
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, sectorBuf);
|
driver.storage.mgr.storage_read(ofi^.Volume^.device, ofi^.DirLoc.SectorLBA, 1, ofi^.ScratchSector);
|
||||||
rawDir := @PDirectory(sectorBuf)[ofi^.DirLoc.EntryIdx];
|
rawDir := @PDirectory(ofi^.ScratchSector)[ofi^.DirLoc.EntryIdx];
|
||||||
rawDir^.byteSize := ofi^.ByteSize;
|
rawDir^.byteSize := ofi^.ByteSize;
|
||||||
setDirFirstCluster(rawDir, ofi^.FirstCluster);
|
setDirFirstCluster(rawDir, ofi^.FirstCluster);
|
||||||
driver.storage.mgr.storage_write(ofi^.Volume^.device, ofi^.DirLoc.SectorLBA, 1, sectorBuf);
|
driver.storage.mgr.storage_write(ofi^.Volume^.device, ofi^.DirLoc.SectorLBA, 1, ofi^.ScratchSector);
|
||||||
kfree(sectorBuf);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
runMapFree(ofi^.RunMap);
|
runMapFree(ofi^.RunMap);
|
||||||
@@ -2070,13 +2091,14 @@ begin
|
|||||||
statusOut := eNone;
|
statusOut := eNone;
|
||||||
end;
|
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
|
var
|
||||||
buffer : puint32;
|
buffer : puint32;
|
||||||
ds : uint32;
|
ds : uint32;
|
||||||
clusterLBA : uint32;
|
clusterLBA : uint32;
|
||||||
dir : PDirectory;
|
dir : PDirectory;
|
||||||
begin
|
begin
|
||||||
|
fatInitDirectoryCluster := false;
|
||||||
if (volume = nil) or (info = nil) or (cluster < 2) then exit;
|
if (volume = nil) or (info = nil) or (cluster < 2) then exit;
|
||||||
buffer := puint32(kalloc(info^.BootRecord.sectorSize));
|
buffer := puint32(kalloc(info^.BootRecord.sectorSize));
|
||||||
if buffer = nil then exit;
|
if buffer = nil then exit;
|
||||||
@@ -2113,6 +2135,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
kfree(buffer);
|
kfree(buffer);
|
||||||
|
fatInitDirectoryCluster := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function FAT32ReadDirectory(volume : PStorage_Volume; directory : pchar; statusOut : puint32) : PLinkedListBase;
|
function FAT32ReadDirectory(volume : PStorage_Volume; directory : pchar; statusOut : puint32) : PLinkedListBase;
|
||||||
@@ -2300,7 +2323,15 @@ begin
|
|||||||
LL_Free(tempRuns);
|
LL_Free(tempRuns);
|
||||||
end;
|
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];
|
rawDir := @PDirectory(sectorBuf)[loc.EntryIdx];
|
||||||
memset(uint32(rawDir), 0, sizeof(TDirectory));
|
memset(uint32(rawDir), 0, sizeof(TDirectory));
|
||||||
|
|||||||
Reference in new issue
Block a user