Skip to content

Commit 6691f48

Browse files
committedSep 17, 2022
[#63] Saving in parallel thread (Part 8: Fixed crash when insufficient amount of space on disk)
1 parent 19589ce commit 6691f48

File tree

8 files changed

+57
-16
lines changed

8 files changed

+57
-16
lines changed
 

‎Main/src/Dsk5.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ formatError: ::SetLastError(ERROR_BAD_FORMAT);
220220
CFile f;
221221
if (const TStdWinError err=CreateImageForWriting(lpszPathName,f))
222222
return err;
223+
if (GetCurrentDiskFreeSpace()<sizeof(TDiskInfo))
224+
return ERROR_DISK_FULL;
223225
f.Write(&diskInfo,sizeof(TDiskInfo));
224226
const PTrackInfo *ppti=tracks;
225227
if (params.rev5){
@@ -228,8 +230,11 @@ formatError: ::SetLastError(ERROR_BAD_FORMAT);
228230
for( BYTE track=0,*pOffset256=diskInfo.rev5_trackOffsets256; track<DSK_REV5_TRACKS_MAX; pOffset256++,ppti++,ap.UpdateProgress(++track) )
229231
if (ap.Cancelled)
230232
return ERROR_CANCELLED;
231-
else if (const BYTE tmp=*pOffset256)
232-
f.Write(*ppti,tmp<<8);
233+
else if (const DWORD tmp=*pOffset256<<8)
234+
if (GetCurrentDiskFreeSpace()<tmp)
235+
return ERROR_DISK_FULL;
236+
else
237+
f.Write(*ppti,tmp);
233238
}else{
234239
// standard DSK
235240
bool mayLeadToIncompatibilityIssues=false; // assumption (none Track contains assets that could potentially lead to unreadability in randomly selected emulator)
@@ -238,6 +243,8 @@ formatError: ::SetLastError(ERROR_BAD_FORMAT);
238243
for( THead head=diskInfo.nHeads; head--; ){
239244
const TTrackInfo *const ti=*ppti++;
240245
WORD trackLength=sizeof(TTrackInfo)+__getTrackLength256__(ti);
246+
if (GetCurrentDiskFreeSpace()<diskInfo.std_trackLength)
247+
return ERROR_DISK_FULL;
241248
f.Write( ti, trackLength );
242249
if (trackLength<diskInfo.std_trackLength){
243250
for( static constexpr BYTE Zero=0; trackLength++<diskInfo.std_trackLength; f.Write(&Zero,1) );

‎Main/src/Image.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,15 @@ namespace Medium{
334334
return (PImage)CMainWindow::CTdiTemplate::pSingleInstance->__getDocument__();
335335
}
336336

337+
DWORD CImage::GetCurrentDiskFreeSpace(){
338+
// determines and returns number of free Bytes on current working disk (nullptr below); this function to be used during Image saving to avoid exceptions (for can't use try-catch blocks in "MFC4.2" release!)
339+
DWORD nSectorsPerCluster,nBytesPerSector,nFreeClusters,nAllClusters;
340+
if (!::GetDiskFreeSpace( nullptr, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nAllClusters ))
341+
return 0;
342+
const auto nFreeBytes=(ULONGLONG)nSectorsPerCluster*nBytesPerSector*nFreeClusters;
343+
return nFreeBytes<ULONG_MAX ? nFreeBytes : ULONG_MAX;
344+
}
345+
337346
TStdWinError CImage::OpenImageForReading(LPCTSTR fileName,CFile &f){
338347
// True <=> File successfully opened for reading, otherwise False
339348
CFileException e;

‎Main/src/Image.h

+1
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@
251251
void Patch();
252252
void OnCloseDocument() override sealed;
253253
protected:
254+
static DWORD GetCurrentDiskFreeSpace();
254255
static TStdWinError OpenImageForReading(LPCTSTR fileName,CFile &f);
255256
static TStdWinError OpenImageForReadingAndWriting(LPCTSTR fileName,CFile &f);
256257
static TStdWinError CreateImageForWriting(LPCTSTR fileName,CFile &f);

‎Main/src/ImageRaw.cpp

+9-4
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,11 @@
106106
return TRUE;
107107
}
108108

109-
void CImageRaw::__saveTrackToCurrentPositionInFile__(CFile *pfOtherThanCurrentFile,TPhysicalAddress chs){
110-
// saves Track defined by the {Cylinder,Head} pair in PhysicalAddress to the current position in the open file; after saving, the position in the file will advance immediately "after" the just saved Track
109+
TStdWinError CImageRaw::SaveTrackToCurrentPositionInFile(CFile *pfOtherThanCurrentFile,TPhysicalAddress chs){
110+
// saves Track defined by the {Cylinder,Head} pair in PhysicalAddress to the current position in the open file, returning Windows standard i/o error; after saving, the position in the file will advance immediately "after" the just saved Track
111111
for( TSector s=0; s<nSectors; s++ ){
112+
if (GetCurrentDiskFreeSpace()<sectorLength)
113+
return ERROR_DISK_FULL;
112114
chs.sectorId.sector=firstSectorNumber+s;
113115
const PCSectorData bufferedData=__getBufferedSectorData__(chs.cylinder,chs.head,&chs.sectorId);
114116
if (!pfOtherThanCurrentFile){
@@ -128,6 +130,7 @@
128130
pfOtherThanCurrentFile->Write( buffer, f.Read(buffer,sectorLength) );
129131
}
130132
}
133+
return ERROR_SUCCESS;
131134
}
132135

133136
TStdWinError CImageRaw::SaveAllModifiedTracks(LPCTSTR lpszPathName,CActionProgress &ap){
@@ -148,14 +151,16 @@
148151
for( chs.cylinder=0; chs.cylinder<nCylinders; chs.cylinder++ )
149152
for( chs.sectorId.cylinder=chs.cylinder,chs.head=0; chs.head<nHeads; chs.head++,ap.IncrementProgress() ){
150153
chs.sectorId.side=sideMap[chs.head];
151-
__saveTrackToCurrentPositionInFile__( savingToCurrentFile?nullptr:&fTmp, chs );
154+
if (const TStdWinError err=SaveTrackToCurrentPositionInFile( savingToCurrentFile?nullptr:&fTmp, chs ))
155+
return err;
152156
}
153157
break;
154158
case TTrackScheme::BY_SIDES:
155159
for( chs.head=0; chs.head<nHeads; chs.head++ )
156160
for( chs.sectorId.side=sideMap[chs.head],chs.cylinder=0; chs.cylinder<nCylinders; chs.cylinder++,ap.IncrementProgress() ){
157161
chs.sectorId.cylinder=chs.cylinder;
158-
__saveTrackToCurrentPositionInFile__( savingToCurrentFile?nullptr:&fTmp, chs );
162+
if (const TStdWinError err=SaveTrackToCurrentPositionInFile( savingToCurrentFile?nullptr:&fTmp, chs ))
163+
return err;
159164
}
160165
break;
161166
default:

‎Main/src/ImageRaw.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
bool IsKnownSector(TCylinder cyl,THead head,RCSectorId id) const;
1212
PSectorData __getBufferedSectorData__(TCylinder cyl,THead head,PCSectorId sectorId) const;
13-
void __saveTrackToCurrentPositionInFile__(CFile *pfOtherThanCurrentFile,TPhysicalAddress chs);
13+
TStdWinError SaveTrackToCurrentPositionInFile(CFile *pfOtherThanCurrentFile,TPhysicalAddress chs);
1414
protected:
1515
TTrackScheme trackAccessScheme;
1616
Utils::CCallocPtr<TSide,THead> explicitSides; // non-Null = Side numbers explicitly provided by user

‎Main/src/KryoFluxStreams.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@
133133
if (!f.Open( GetStreamFileName(cyl,head), CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareExclusive, &e ))
134134
return e.m_cause;
135135
if (const auto data=Utils::MakeCallocPtr<BYTE>(KF_BUFFER_CAPACITY)){
136-
f.Write( data, TrackToStream(*pit,data) );
136+
const DWORD nTrackBytes=TrackToStream(*pit,data);
137+
if (GetCurrentDiskFreeSpace()<nTrackBytes)
138+
return ERROR_DISK_FULL;
139+
f.Write( data, nTrackBytes );
137140
pit->modified=false;
138141
}else
139142
return ERROR_NOT_ENOUGH_MEMORY;

‎Main/src/SCL.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,24 @@
6666
TSclHeader header;
6767
::lstrcpyA( header.id, HEADER_SINCLAIR );
6868
header.nFiles=boot->nFiles;
69+
if (GetCurrentDiskFreeSpace()<sizeof(header))
70+
return ERROR_DISK_FULL;
6971
f.Write(&header,sizeof(header));
7072
// - saving Directory
7173
CTRDOS503 *const trdos=(CTRDOS503 *)dos;
7274
CTRDOS503::PDirectoryEntry directory[TRDOS503_FILE_COUNT_MAX],*pde=directory;
75+
if (GetCurrentDiskFreeSpace()<n*sizeof(TSclDirectoryItem))
76+
return ERROR_DISK_FULL;
7377
for( BYTE n=trdos->__getDirectory__(directory); n--; f.Write(*pde++,sizeof(TSclDirectoryItem)) );
7478
// - saving each File's data
7579
{ const Utils::CVarTempReset<CDos::TGetFileSizeOptions> gfso0( trdos->getFileSizeDefaultOption, CDos::TGetFileSizeOptions::SizeOnDisk ); // exporting whole Sectors instead of just reported File length
7680
BYTE buf[65536];
77-
for( pde=directory; header.nFiles--; )
78-
f.Write(buf,
79-
trdos->ExportFile( *pde++, &CMemFile(buf,sizeof(buf)), sizeof(buf), nullptr )
80-
);
81+
for( pde=directory; header.nFiles--; ){
82+
const DWORD fileLength=trdos->ExportFile( *pde++, &CMemFile(buf,sizeof(buf)), sizeof(buf), nullptr );
83+
if (GetCurrentDiskFreeSpace()<fileLength)
84+
return ERROR_DISK_FULL;
85+
f.Write( buf, fileLength );
86+
}
8187
m_bModified=FALSE;
8288
} // - reopening the Image's underlying file
8389
f.Close();

‎Main/src/SCP.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,12 @@ formatError: ::SetLastError(ERROR_BAD_FORMAT);
202202
pit->FlushSectorBuffers(); // convert all modifications into flux transitions
203203
if (const DWORD trackLength=TrackToStream( *pit, CMemFile(buffer,SCP_BUFFER_CAPACITY), cylFile, head, bStreamAdjusted )){
204204
// conversion of the Track to SuperCardPro stream succeeded?
205+
const LONG capacity=((TTrackDataHeader *)buffer.get())->GetFullTrackCapacityInBytes( mp, header );
206+
if (GetCurrentDiskFreeSpace()<capacity)
207+
return ERROR_DISK_FULL;
205208
// . success thanks to adjustments to overcome SuperCard Pro limitations?
206209
header.flags.normalized|=bStreamAdjusted;
207210
// . search for sufficiently big gap
208-
const LONG capacity=((TTrackDataHeader *)buffer.get())->GetFullTrackCapacityInBytes( mp, header );
209211
tdhOffsets[cylFile][head]=fTargetLength; // assumption (no gap big enough to contain this Track, so must extend the file)
210212
for( auto it=contentLayout.begin(); it!=contentLayout.end(); it++ )
211213
if (it->second<0 && it->second<=-capacity){ // a gap that can contain the Track
@@ -233,11 +235,14 @@ formatError: ::SetLastError(ERROR_BAD_FORMAT);
233235
pit->FlushSectorBuffers(); // convert all modifications into flux transitions
234236
if (const DWORD trackLength=TrackToStream( *pit, CMemFile(buffer,SCP_BUFFER_CAPACITY), cylFile, head, bStreamAdjusted )){
235237
// conversion of the Track to SuperCardPro stream succeeded?
238+
const LONG capacity=((TTrackDataHeader *)buffer.get())->GetFullTrackCapacityInBytes( mp, header );
239+
if (GetCurrentDiskFreeSpace()<capacity)
240+
return ERROR_DISK_FULL;
236241
// . success thanks to adjustments to overcome SuperCard Pro limitations?
237242
header.flags.normalized|=bStreamAdjusted;
238243
// . append Track to file
239244
fTarget.SetLength( // make reserve so that the Track can expand upon different data
240-
fTargetLength + ((TTrackDataHeader *)buffer.get())->GetFullTrackCapacityInBytes( mp, header )
245+
fTargetLength + capacity
241246
);
242247
fTarget.Seek(
243248
tdhOffsets[cylFile][head] = fTargetLength,
@@ -252,8 +257,11 @@ formatError: ::SetLastError(ERROR_BAD_FORMAT);
252257
if (!tdh.Read( f, cylFile, head, header.nAvailableRevolutions ))
253258
return ERROR_INVALID_BLOCK; // read invalid TrackDataHeader structure
254259
f.Seek( tdhOffset, CFile::begin ); // seek back to the TrackDataHeader
260+
const DWORD capacity=tdh.GetFullTrackCapacityInBytes( mp, header );
261+
if (GetCurrentDiskFreeSpace()<capacity)
262+
return ERROR_DISK_FULL;
255263
fTarget.SetLength( // make reserve so that the Track can expand upon different data
256-
fTargetLength + tdh.GetFullTrackCapacityInBytes( mp, header )
264+
fTargetLength + capacity
257265
);
258266
fTarget.Seek( // append Track to file
259267
tdhOffsets[cylFile][head] = fTargetLength,
@@ -277,6 +285,8 @@ formatError: ::SetLastError(ERROR_BAD_FORMAT);
277285
}*/
278286
// - save Offsets
279287
fTarget.Seek( sizeof(header)+header.flags.extended*0x70, CFile::begin );
288+
if (GetCurrentDiskFreeSpace()<sizeof(tdhOffsets))
289+
return ERROR_DISK_FULL;
280290
fTarget.Write( tdhOffsets, sizeof(tdhOffsets) );
281291
// - update Header
282292
header.signatureAndRevision=THeader().signatureAndRevision;
@@ -322,7 +332,7 @@ formatError: ::SetLastError(ERROR_BAD_FORMAT);
322332
}while (fTarget.GetPosition()<fTarget.GetLength());
323333
}
324334
fTarget.SeekToBegin();
325-
fTarget.Write( &header, sizeof(header) );
335+
fTarget.Write( &header, sizeof(header) ); // no need to test free space on disk - we would already fail somewhere above
326336
m_bModified=FALSE;
327337
// - reopening Image's underlying file
328338
if (f.m_hFile!=CFile::hFileNull)

0 commit comments

Comments
 (0)
Please sign in to comment.