1
0
Fork 0

Use record size of 128 if it is 0 in the FCB when calling INT 21 AH=23 (fixes bug #433).

Set record size to 128 if it is 0 in the FCB when calling any FCB read/write function (ripsaw).
Fixes for acad 10:
- Add missing reference counting when the file is already open when calling FCB_Open, so that acad which uses FCBs and normal handles on the same file works better.
- Remove FCBs being added to the PSP filetable and rewrite most functions to support this change. This way acad won't run out of temporary (fcb) files when low on memory.


Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3962
This commit is contained in:
Peter Veenstra 2016-02-09 14:12:05 +00:00
parent 26dd1635b5
commit 59805112d9
3 changed files with 72 additions and 60 deletions

View file

@ -110,19 +110,19 @@ enum { HAND_NONE=0,HAND_FILE,HAND_DEVICE};
/* Routines for File Class */
void DOS_SetupFiles (void);
bool DOS_ReadFile(Bit16u handle,Bit8u * data,Bit16u * amount);
bool DOS_WriteFile(Bit16u handle,Bit8u * data,Bit16u * amount);
bool DOS_SeekFile(Bit16u handle,Bit32u * pos,Bit32u type);
bool DOS_CloseFile(Bit16u handle);
bool DOS_ReadFile(Bit16u handle,Bit8u * data,Bit16u * amount, bool fcb = false);
bool DOS_WriteFile(Bit16u handle,Bit8u * data,Bit16u * amount,bool fcb = false);
bool DOS_SeekFile(Bit16u handle,Bit32u * pos,Bit32u type,bool fcb = false);
bool DOS_CloseFile(Bit16u handle,bool fcb = false);
bool DOS_FlushFile(Bit16u handle);
bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry);
bool DOS_ForceDuplicateEntry(Bit16u entry,Bit16u newentry);
bool DOS_GetFileDate(Bit16u entry, Bit16u* otime, Bit16u* odate);
/* Routines for Drive Class */
bool DOS_OpenFile(char const * name,Bit8u flags,Bit16u * entry);
bool DOS_OpenFile(char const * name,Bit8u flags,Bit16u * entry,bool fcb = false);
bool DOS_OpenFileExtended(char const * name, Bit16u flags, Bit16u createAttr, Bit16u action, Bit16u *entry, Bit16u* status);
bool DOS_CreateFile(char const * name,Bit16u attribute,Bit16u * entry);
bool DOS_CreateFile(char const * name,Bit16u attribute,Bit16u * entry, bool fcb = false);
bool DOS_UnlinkFile(char const * const name);
bool DOS_FindFirst(char *search,Bit16u attr,bool fcb_findfirst=false);
bool DOS_FindNext(void);
@ -501,6 +501,7 @@ public:
void GetRecord(Bit16u & _cur_block,Bit8u & _cur_rec);
void SetRecord(Bit16u _cur_block,Bit8u _cur_rec);
void GetSeqData(Bit8u & _fhandle,Bit16u & _rec_size);
void SetSeqData(Bit8u _fhandle,Bit16u _rec_size);
void GetRandom(Bit32u & _random);
void SetRandom(Bit32u _random);
Bit8u GetDrive(void);
@ -529,6 +530,8 @@ private:
Bit8u sft_entries;
Bit8u share_attributes;
Bit8u extra_info;
/* Maybe swap file_handle and sft_entries now that fcbs
* aren't stored in the psp filetable anymore */
Bit8u file_handle;
Bit8u reserved[4];
/* end */

View file

@ -435,6 +435,10 @@ void DOS_FCB::GetSeqData(Bit8u & _fhandle,Bit16u & _rec_size) {
_rec_size=(Bit16u)sGet(sFCB,rec_size);
}
void DOS_FCB::SetSeqData(Bit8u _fhandle,Bit16u _rec_size) {
sSave(sFCB,file_handle,_fhandle);
sSave(sFCB,rec_size,_rec_size);
}
void DOS_FCB::GetRandom(Bit32u & _random) {
_random=sGet(sFCB,rndm);
@ -454,14 +458,13 @@ void DOS_FCB::FileOpen(Bit8u _fhandle) {
sSave(sFCB,cur_block,0);
sSave(sFCB,rec_size,128);
// sSave(sFCB,rndm,0); // breaks Jewels of darkness.
Bit8u temp = RealHandle(_fhandle);
Bit32u size = 0;
Files[temp]->Seek(&size,DOS_SEEK_END);
Files[_fhandle]->Seek(&size,DOS_SEEK_END);
sSave(sFCB,filesize,size);
size = 0;
Files[temp]->Seek(&size,DOS_SEEK_SET);
sSave(sFCB,time,Files[temp]->time);
sSave(sFCB,date,Files[temp]->date);
Files[_fhandle]->Seek(&size,DOS_SEEK_SET);
sSave(sFCB,time,Files[_fhandle]->time);
sSave(sFCB,date,Files[_fhandle]->date);
}
bool DOS_FCB::Valid() {

View file

@ -365,8 +365,8 @@ bool DOS_FindNext(void) {
}
bool DOS_ReadFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
Bit32u handle=RealHandle(entry);
bool DOS_ReadFile(Bit16u entry,Bit8u * data,Bit16u * amount,bool fcb) {
Bit32u handle = fcb?entry:RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
@ -387,8 +387,8 @@ bool DOS_ReadFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
return ret;
}
bool DOS_WriteFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
Bit32u handle=RealHandle(entry);
bool DOS_WriteFile(Bit16u entry,Bit8u * data,Bit16u * amount,bool fcb) {
Bit32u handle = fcb?entry:RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
@ -409,8 +409,8 @@ bool DOS_WriteFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
return ret;
}
bool DOS_SeekFile(Bit16u entry,Bit32u * pos,Bit32u type) {
Bit32u handle=RealHandle(entry);
bool DOS_SeekFile(Bit16u entry,Bit32u * pos,Bit32u type,bool fcb) {
Bit32u handle = fcb?entry:RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
@ -422,8 +422,8 @@ bool DOS_SeekFile(Bit16u entry,Bit32u * pos,Bit32u type) {
return Files[handle]->Seek(pos,type);
}
bool DOS_CloseFile(Bit16u entry) {
Bit32u handle=RealHandle(entry);
bool DOS_CloseFile(Bit16u entry, bool fcb) {
Bit32u handle = fcb?entry:RealHandle(entry);
if (handle>=DOS_FILES) {
DOS_SetError(DOSERR_INVALID_HANDLE);
return false;
@ -435,8 +435,10 @@ bool DOS_CloseFile(Bit16u entry) {
if (Files[handle]->IsOpen()) {
Files[handle]->Close();
}
DOS_PSP psp(dos.psp());
psp.SetFileHandle(entry,0xff);
if (!fcb) psp.SetFileHandle(entry,0xff);
if (Files[handle]->RemoveRef()<=0) {
delete Files[handle];
Files[handle]=0;
@ -473,7 +475,7 @@ static bool PathExists(char const * const name) {
}
bool DOS_CreateFile(char const * name,Bit16u attributes,Bit16u * entry) {
bool DOS_CreateFile(char const * name,Bit16u attributes,Bit16u * entry,bool fcb) {
// Creation of a device is the same as opening it
// Tc201 installer
if (DOS_FindDevice(name) != DOS_DEVICES)
@ -496,7 +498,7 @@ bool DOS_CreateFile(char const * name,Bit16u attributes,Bit16u * entry) {
return false;
}
/* We have a position in the main table now find one in the psp table */
*entry = psp.FindFreeFileEntry();
*entry = fcb?handle:psp.FindFreeFileEntry();
if (*entry==0xff) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
return false;
@ -510,7 +512,7 @@ bool DOS_CreateFile(char const * name,Bit16u attributes,Bit16u * entry) {
if (foundit) {
Files[handle]->SetDrive(drive);
Files[handle]->AddRef();
psp.SetFileHandle(*entry,handle);
if (!fcb) psp.SetFileHandle(*entry,handle);
return true;
} else {
if(!PathExists(name)) DOS_SetError(DOSERR_PATH_NOT_FOUND);
@ -519,7 +521,7 @@ bool DOS_CreateFile(char const * name,Bit16u attributes,Bit16u * entry) {
}
}
bool DOS_OpenFile(char const * name,Bit8u flags,Bit16u * entry) {
bool DOS_OpenFile(char const * name,Bit8u flags,Bit16u * entry,bool fcb) {
/* First check for devices */
if (flags>2) LOG(LOG_FILES,LOG_ERROR)("Special file open command %X file %s",flags,name);
else LOG(LOG_FILES,LOG_NORMAL)("file open command %X file %s",flags,name);
@ -552,7 +554,7 @@ bool DOS_OpenFile(char const * name,Bit8u flags,Bit16u * entry) {
return false;
}
/* We have a position in the main table now find one in the psp table */
*entry = psp.FindFreeFileEntry();
*entry = fcb?handle:psp.FindFreeFileEntry();
if (*entry==0xff) {
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
@ -567,7 +569,7 @@ bool DOS_OpenFile(char const * name,Bit8u flags,Bit16u * entry) {
}
if (exists || device ) {
Files[handle]->AddRef();
psp.SetFileHandle(*entry,handle);
if (!fcb) psp.SetFileHandle(*entry,handle);
return true;
} else {
//Test if file exists, but opened in read-write mode (and writeprotected)
@ -959,7 +961,7 @@ bool DOS_FCBCreate(Bit16u seg,Bit16u offset) {
Bit8u attr = DOS_ATTR_ARCHIVE;
fcb.GetAttr(attr);
if (!attr) attr = DOS_ATTR_ARCHIVE; //Better safe than sorry
if (!DOS_CreateFile(shortname,attr,&handle)) return false;
if (!DOS_CreateFile(shortname,attr,&handle,true)) return false;
fcb.FileOpen((Bit8u)handle);
return true;
}
@ -975,21 +977,15 @@ bool DOS_FCBOpen(Bit16u seg,Bit16u offset) {
if (!DOS_MakeName(shortname,fullname,&drive)) return false;
/* Check, if file is already opened */
for (Bit8u i=0;i<DOS_FILES;i++) {
DOS_PSP psp(dos.psp());
for (Bit8u i = 0;i < DOS_FILES;i++) {
if (Files[i] && Files[i]->IsOpen() && Files[i]->IsName(fullname)) {
handle = psp.FindEntryByHandle(i);
if (handle==0xFF) {
// This shouldnt happen
LOG(LOG_FILES,LOG_ERROR)("DOS: File %s is opened but has no psp entry.",shortname);
return false;
}
fcb.FileOpen((Bit8u)handle);
Files[i]->AddRef();
fcb.FileOpen(i);
return true;
}
}
if (!DOS_OpenFile(shortname,OPEN_READWRITE,&handle)) return false;
if (!DOS_OpenFile(shortname,OPEN_READWRITE,&handle,true)) return false;
fcb.FileOpen((Bit8u)handle);
return true;
}
@ -999,7 +995,7 @@ bool DOS_FCBClose(Bit16u seg,Bit16u offset) {
if(!fcb.Valid()) return false;
Bit8u fhandle;
fcb.FileClose(fhandle);
DOS_CloseFile(fhandle);
DOS_CloseFile(fhandle,true);
return true;
}
@ -1033,11 +1029,15 @@ Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset,Bit16u recno) {
LOG(LOG_FCB,LOG_WARN)("Reopened closed FCB");
fcb.GetSeqData(fhandle,rec_size);
}
if (rec_size == 0) {
rec_size = 128;
fcb.SetSeqData(fhandle,rec_size);
}
fcb.GetRecord(cur_block,cur_rec);
Bit32u pos=((cur_block*128)+cur_rec)*rec_size;
if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET)) return FCB_READ_NODATA;
if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET,true)) return FCB_READ_NODATA;
Bit16u toread=rec_size;
if (!DOS_ReadFile(fhandle,dos_copybuf,&toread)) return FCB_READ_NODATA;
if (!DOS_ReadFile(fhandle,dos_copybuf,&toread,true)) return FCB_READ_NODATA;
if (toread==0) return FCB_READ_NODATA;
if (toread < rec_size) { //Zero pad copybuffer to rec_size
Bitu i = toread;
@ -1060,12 +1060,16 @@ Bit8u DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno) {
LOG(LOG_FCB,LOG_WARN)("Reopened closed FCB");
fcb.GetSeqData(fhandle,rec_size);
}
if (rec_size == 0) {
rec_size = 128;
fcb.SetSeqData(fhandle,rec_size);
}
fcb.GetRecord(cur_block,cur_rec);
Bit32u pos=((cur_block*128)+cur_rec)*rec_size;
if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET)) return FCB_ERR_WRITE;
if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET,true)) return FCB_ERR_WRITE;
MEM_BlockRead(Real2Phys(dos.dta())+recno*rec_size,dos_copybuf,rec_size);
Bit16u towrite=rec_size;
if (!DOS_WriteFile(fhandle,dos_copybuf,&towrite)) return FCB_ERR_WRITE;
if (!DOS_WriteFile(fhandle,dos_copybuf,&towrite,true)) return FCB_ERR_WRITE;
Bit32u size;Bit16u date,time;
fcb.GetSizeDateTime(size,date,time);
if (pos+towrite>size) size=pos+towrite;
@ -1077,9 +1081,8 @@ Bit8u DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno) {
Bit16u min = (Bit16u)((seconds % 3600)/60);
Bit16u sec = (Bit16u)(seconds % 60);
time = DOS_PackTime(hour,min,sec);
Bit8u temp=RealHandle(fhandle);
Files[temp]->time=time;
Files[temp]->date=date;
Files[fhandle]->time = time;
Files[fhandle]->date = date;
fcb.SetSizeDateTime(size,date,time);
if (++cur_rec>127) { cur_block++;cur_rec=0; }
fcb.SetRecord(cur_block,cur_rec);
@ -1092,9 +1095,9 @@ Bit8u DOS_FCBIncreaseSize(Bit16u seg,Bit16u offset) {
fcb.GetSeqData(fhandle,rec_size);
fcb.GetRecord(cur_block,cur_rec);
Bit32u pos=((cur_block*128)+cur_rec)*rec_size;
if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET)) return FCB_ERR_WRITE;
if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET,true)) return FCB_ERR_WRITE;
Bit16u towrite=0;
if (!DOS_WriteFile(fhandle,dos_copybuf,&towrite)) return FCB_ERR_WRITE;
if (!DOS_WriteFile(fhandle,dos_copybuf,&towrite,true)) return FCB_ERR_WRITE;
Bit32u size;Bit16u date,time;
fcb.GetSizeDateTime(size,date,time);
if (pos+towrite>size) size=pos+towrite;
@ -1106,9 +1109,8 @@ Bit8u DOS_FCBIncreaseSize(Bit16u seg,Bit16u offset) {
Bit16u min = (Bit16u)((seconds % 3600)/60);
Bit16u sec = (Bit16u)(seconds % 60);
time = DOS_PackTime(hour,min,sec);
Bit8u temp=RealHandle(fhandle);
Files[temp]->time=time;
Files[temp]->date=date;
Files[fhandle]->time = time;
Files[fhandle]->date = date;
fcb.SetSizeDateTime(size,date,time);
fcb.SetRecord(cur_block,cur_rec);
return FCB_SUCCESS;
@ -1178,14 +1180,18 @@ Bit8u DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u * numRec,bool restore)
}
bool DOS_FCBGetFileSize(Bit16u seg,Bit16u offset) {
char shortname[DOS_PATHLENGTH];Bit16u entry;Bit8u handle;Bit16u rec_size;
char shortname[DOS_PATHLENGTH];Bit16u entry;
DOS_FCB fcb(seg,offset);
fcb.GetName(shortname);
if (!DOS_OpenFile(shortname,OPEN_READ,&entry)) return false;
handle = RealHandle(entry);
if (!DOS_OpenFile(shortname,OPEN_READ,&entry,true)) return false;
Bit32u size = 0;
Files[handle]->Seek(&size,DOS_SEEK_END);
DOS_CloseFile(entry);fcb.GetSeqData(handle,rec_size);
Files[entry]->Seek(&size,DOS_SEEK_END);
DOS_CloseFile(entry,true);
Bit8u handle; Bit16u rec_size;
fcb.GetSeqData(handle,rec_size);
if (rec_size == 0) rec_size = 128; //Use default if missing.
Bit32u random=(size/rec_size);
if (size % rec_size) random++;
fcb.SetRandom(random);
@ -1212,7 +1218,7 @@ bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset){
nextfile = DOS_FCBFindNext(seg,offset);
}
dos.dta(old_dta); /*Restore dta */
return return_value;
return return_value;
}
bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset){
@ -1231,12 +1237,12 @@ bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset){
for (Bit8u i=0;i<DOS_FILES;i++) {
if (Files[i] && Files[i]->IsOpen() && Files[i]->IsName(fullname)) {
Bit16u handle = psp.FindEntryByHandle(i);
//(more than once maybe)
if (handle == 0xFF) {
// This shouldnt happen
LOG(LOG_FILES,LOG_ERROR)("DOS: File %s is opened but has no psp entry.",oldname);
return false;
DOS_CloseFile(i,true);
} else {
DOS_CloseFile(handle);
}
DOS_CloseFile(handle);
}
}