diff options
author | ripsaw8080 <ripsaw8080@users.sourceforge.net> | 2022-05-29 03:39:15 +0300 |
---|---|---|
committer | kcgen <kcgen@users.noreply.github.com> | 2022-05-29 03:40:38 +0300 |
commit | bf4a482ec600a74bf7823ec1789c964ab5d266c7 (patch) | |
tree | 174e4addf200d9b956c0ad0df19260654ed6a7d5 | |
parent | 749183e6322137b33eee78333d68d7a611fbe4be (diff) | |
parent | d40affc717e7430037a7a3fcb03f3f1daeaf2530 (diff) |
Merge 'svn/trunk' r4475-r4477kc/merge-r4477
r4475:
- Specified path can be invalid if filename is a device. Fixes
installer for World Series of Poker.
r4476:
- Fix "Invalid Access Code" error when opening files. Preserve
last error code when no error occurs.
r4477:
- Support BIOS access with multiple images. Fixes some
mutli-floppy installers: Dark Seed, Master of Magic, et al.
- Implement INT 25h and INT 26h. Fixes some installers: Dark
Seed, Gods, et al.
- Allow low-level hacks for local drive HDD when floppy
image(s) mounted. Fixes installing Amberstar from floppy
images.
- Use real pointer when writing faked sector contents.
- Prevent problematic condition: booting floppy image files
when floppy image(s) mounted.
- FAT drive improvements regarding zero-length truncation of
files.
- Update Drive Parameter Table only when necessary.
-rw-r--r-- | include/drives.h | 4 | ||||
-rw-r--r-- | src/dos/dos.cpp | 49 | ||||
-rw-r--r-- | src/dos/dos_devices.cpp | 10 | ||||
-rw-r--r-- | src/dos/dos_files.cpp | 16 | ||||
-rw-r--r-- | src/dos/drive_fat.cpp | 23 | ||||
-rw-r--r-- | src/dos/drives.cpp | 17 | ||||
-rw-r--r-- | src/dos/program_boot.cpp | 6 | ||||
-rw-r--r-- | src/dos/program_imgmount.cpp | 16 | ||||
-rw-r--r-- | src/ints/bios_disk.cpp | 13 |
9 files changed, 121 insertions, 33 deletions
diff --git a/include/drives.h b/include/drives.h index aee341c47..51f5ff543 100644 --- a/include/drives.h +++ b/include/drives.h @@ -190,6 +190,7 @@ public: uint8_t readSector(uint32_t sectnum, void * data); uint8_t writeSector(uint32_t sectnum, void * data); uint32_t getAbsoluteSectFromBytePos(uint32_t startClustNum, uint32_t bytePos); + uint32_t getSectorCount(); uint32_t getSectorSize(void); uint32_t getClusterSize(void); uint32_t getAbsoluteSectFromChain(uint32_t startClustNum, uint32_t logicalSector); @@ -201,6 +202,8 @@ public: bool directoryChange(uint32_t dirClustNumber, direntry *useEntry, int32_t entNum); std::shared_ptr<imageDisk> loadedDisk; bool created_successfully; + uint32_t partSectOff; + private: uint32_t getClusterValue(uint32_t clustNum); void setClusterValue(uint32_t clustNum, uint32_t clustValue); @@ -217,7 +220,6 @@ private: bool readonly; uint8_t fattype; uint32_t CountOfClusters; - uint32_t partSectOff; uint32_t firstDataSector; uint32_t firstRootDirSect; diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index 977b9e266..0f297d32c 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -26,6 +26,7 @@ #include "bios.h" #include "callback.h" +#include "drives.h" #include "mem.h" #include "regs.h" #include "serialport.h" @@ -1377,16 +1378,55 @@ static Bitu DOS_27Handler(void) { return CBRET_NONE; } -static Bitu DOS_25Handler(void) { +static uint16_t DOS_SectorAccess(const bool read) +{ + auto drive = static_cast<fatDrive *>(Drives[reg_al]); + auto bufferSeg = SegValue(ds); + auto bufferOff = reg_bx; + auto sectorCnt = reg_cx; + auto sectorNum = static_cast<uint32_t>(reg_dx) + drive->partSectOff; + auto sectorEnd = drive->getSectorCount() + drive->partSectOff; + + if (sectorCnt == 0xffff) { // large partition form + bufferSeg = real_readw(SegValue(ds), reg_bx + 8); + bufferOff = real_readw(SegValue(ds), reg_bx + 6); + sectorCnt = real_readw(SegValue(ds), reg_bx + 4); + sectorNum = real_readd(SegValue(ds), reg_bx + 0) + drive->partSectOff; + } else if (sectorEnd > 0xffff) + return 0x0207; // must use large partition form + + uint8_t sectorBuf[512]; + while (sectorCnt--) { + if (sectorNum >= sectorEnd) + return 0x0408; // sector not found + if (read) { + if (drive->readSector(sectorNum++, §orBuf)) + return 0x0408; + for (auto §or_byte : sectorBuf) + real_writeb(bufferSeg, bufferOff++, sector_byte); + } else { + for (auto §or_byte : sectorBuf) + sector_byte = real_readb(bufferSeg, bufferOff++); + if (drive->writeSector(sectorNum++, §orBuf)) + return 0x0408; + } + } + return 0; +} + +static Bitu DOS_25Handler(void) +{ if (reg_al >= DOS_DRIVES || !Drives[reg_al] || Drives[reg_al]->isRemovable()) { reg_ax = 0x8002; SETFLAGBIT(CF,true); + } else if (strncmp(Drives[reg_al]->GetInfo(), "fatDrive", 8) == 0) { + reg_ax = DOS_SectorAccess(true); + SETFLAGBIT(CF, reg_ax != 0); } else { if (reg_cx == 1 && reg_dx == 0) { if (reg_al >= 2) { - PhysPt ptr = PhysMake(SegValue(ds),reg_bx); // write some BPB data into buffer for MicroProse installers - mem_writew(ptr+0x1c,0x3f); // hidden sectors + real_writew(SegValue(ds), reg_bx + 0x1c, 0x3f); // hidden sectors } } else { LOG(LOG_DOSMISC,LOG_NORMAL)("int 25 called but not as disk detection drive %u",reg_al); @@ -1401,6 +1441,9 @@ static Bitu DOS_26Handler(void) { if (reg_al >= DOS_DRIVES || !Drives[reg_al] || Drives[reg_al]->isRemovable()) { reg_ax = 0x8002; SETFLAGBIT(CF,true); + } else if (strncmp(Drives[reg_al]->GetInfo(), "fatDrive", 8) == 0) { + reg_ax = DOS_SectorAccess(false); + SETFLAGBIT(CF, reg_ax != 0); } else { SETFLAGBIT(CF,false); reg_ax = 0; diff --git a/src/dos/dos_devices.cpp b/src/dos/dos_devices.cpp index 8c279d5fe..aae2a2b2b 100644 --- a/src/dos/dos_devices.cpp +++ b/src/dos/dos_devices.cpp @@ -346,10 +346,12 @@ uint8_t DOS_FindDevice(char const * name) { char* name_part = strrchr(fullname,'\\'); if(name_part) { *name_part++ = 0; - //Check validity of leading directory. - if(!Drives[drive]->TestDir(fullname)) return DOS_DEVICES; - } else name_part = fullname; - + // Check validity of leading directory. + // if(!Drives[drive]->TestDir(fullname)) return + // DOS_DEVICES; //can be invalid + } else + name_part = fullname; + char* dot = strrchr(name_part,'.'); if(dot) *dot = 0; //no ext checking diff --git a/src/dos/dos_files.cpp b/src/dos/dos_files.cpp index 7356b42a4..656f0bf33 100644 --- a/src/dos/dos_files.cpp +++ b/src/dos/dos_files.cpp @@ -573,11 +573,14 @@ bool DOS_OpenFile(char const * name,uint8_t flags,uint16_t * entry,bool fcb) { if (device) { Files[handle]=new DOS_Device(*Devices[devnum]); } else { - exists=Drives[drive]->FileOpen(&Files[handle],fullname,flags); + const auto old_errorcode = dos.errorcode; + dos.errorcode = 0; + exists = Drives[drive]->FileOpen(&Files[handle], fullname, flags); if (exists) Files[handle]->SetDrive(drive); - else if (dos.errorcode == DOSERR_ACCESS_CODE_INVALID) + if (dos.errorcode) return false; + dos.errorcode = old_errorcode; } if (exists || device ) { Files[handle]->AddRef(); @@ -798,7 +801,8 @@ bool DOS_CreateTempFile(char * const name,uint16_t * entry) { tempname++; } } - dos.errorcode=0; + const auto old_errorcode = dos.errorcode; + dos.errorcode = 0; static const auto randomize_letter = CreateRandomizer<char>('A', 'Z'); do { @@ -808,8 +812,12 @@ bool DOS_CreateTempFile(char * const name,uint16_t * entry) { } tempname[8]=0; } while (DOS_FileExists(name)); + DOS_CreateFile(name,0,entry); - if (dos.errorcode) return false; + if (dos.errorcode) + return false; + + dos.errorcode = old_errorcode; return true; } diff --git a/src/dos/drive_fat.cpp b/src/dos/drive_fat.cpp index c69eb6de3..c306a0304 100644 --- a/src/dos/drive_fat.cpp +++ b/src/dos/drive_fat.cpp @@ -171,7 +171,10 @@ bool fatFile::Write(uint8_t * data, uint16_t *size) { if(seekpos < filelength && *size == 0) { /* Truncate file to current position */ - myDrive->deleteClustChain(firstCluster, seekpos); + if (firstCluster != 0) + myDrive->deleteClustChain(firstCluster, seekpos); + if (seekpos == 0) + firstCluster = 0; filelength = seekpos; goto finalizeWrite; } @@ -554,7 +557,16 @@ uint8_t fatDrive::writeSector(uint32_t sectnum, void * data) { return loadedDisk->Write_Sector(head, cylinder, sector, data); } -uint32_t fatDrive::getSectorSize(void) { +uint32_t fatDrive::getSectorCount() +{ + if (bootbuffer.totalsectorcount != 0) + return check_cast<uint32_t>(bootbuffer.totalsectorcount); + else + return bootbuffer.totalsecdword; +} + +uint32_t fatDrive::getSectorSize(void) +{ return bootbuffer.bytespersector; } @@ -989,9 +1001,12 @@ bool fatDrive::FileCreate(DOS_File **file, char *name, uint16_t attributes) { /* Check if file already exists */ if(getFileDirEntry(name, &fileEntry, &dirClust, &subEntry)) { /* Truncate file */ - fileEntry.entrysize=0; + if (fileEntry.loFirstClust != 0) { + deleteClustChain(fileEntry.loFirstClust, 0); + fileEntry.loFirstClust = 0; + } + fileEntry.entrysize = 0; directoryChange(dirClust, &fileEntry, subEntry); - if(fileEntry.loFirstClust != 0) deleteClustChain(fileEntry.loFirstClust, 0); } else { /* Can we even get the name of the file itself? */ if(!getEntryName(name, &dirName[0])) return false; diff --git a/src/dos/drives.cpp b/src/dos/drives.cpp index 5120471fa..a526b4b9b 100644 --- a/src/dos/drives.cpp +++ b/src/dos/drives.cpp @@ -15,12 +15,13 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - #include "drives.h" +#include <string_view> + +#include "bios_disk.h" #include "ide.h" #include "string_utils.h" -#include <string_view> extern char sfn[DOS_NAMELENGTH_ASCII]; @@ -264,7 +265,17 @@ void DriveManager::CycleDisks(int requested_drive, bool notify) currentDisk = (currentDisk + 1) % numDisks; DOS_Drive* newDisk = driveInfos[drive].disks[currentDisk]; driveInfos[drive].currentDisk = currentDisk; - + if (drive < MAX_DISK_IMAGES && imageDiskList[drive] != nullptr) { + if (strncmp(newDisk->GetInfo(), "fatDrive", 8) == 0) { + imageDiskList[drive] = reinterpret_cast<fatDrive *>(newDisk)->loadedDisk; + } else { + imageDiskList[drive].reset(reinterpret_cast<imageDisk *>(newDisk)); + } + if ((drive == 2 || drive == 3) && imageDiskList[drive]->hardDrive) { + updateDPT(); + } + } + // copy working directory, acquire system resources and finally switch to next drive strcpy(newDisk->curdir, oldDisk->curdir); newDisk->Activate(); diff --git a/src/dos/program_boot.cpp b/src/dos/program_boot.cpp index 4bd811c12..643359498 100644 --- a/src/dos/program_boot.cpp +++ b/src/dos/program_boot.cpp @@ -222,6 +222,11 @@ void BOOT::Run(void) continue; } + if (imageDiskList[0] != nullptr || imageDiskList[1] != NULL) { + WriteOut(MSG_Get("PROGRAM_BOOT_IMAGE_MOUNTED")); + return; + } + if (i >= MAX_SWAPPABLE_DISKS) { return; // TODO give a warning. } @@ -520,6 +525,7 @@ void BOOT::AddMessages() { "\033[34;1mIMGMOUNT\033[0m command.\n\n" "Type \033[34;1mBOOT /?\033[0m for the syntax of this command.\033[0m\n"); MSG_Add("PROGRAM_BOOT_UNABLE","Unable to boot off of drive %c"); + MSG_Add("PROGRAM_BOOT_IMAGE_MOUNTED", "Floppy image(s) already mounted.\n"); MSG_Add("PROGRAM_BOOT_IMAGE_OPEN","Opening image file: %s\n"); MSG_Add("PROGRAM_BOOT_IMAGE_NOT_OPEN","Cannot open %s"); MSG_Add("PROGRAM_BOOT_BOOT","Booting from drive %c...\n"); diff --git a/src/dos/program_imgmount.cpp b/src/dos/program_imgmount.cpp index 20990c6b0..d449a8e72 100644 --- a/src/dos/program_imgmount.cpp +++ b/src/dos/program_imgmount.cpp @@ -383,14 +383,12 @@ void IMGMOUNT::Run(void) { } WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_2"), drive, tmp.c_str()); - if (paths.size() == 1) { - auto *newdrive = static_cast<fatDrive*>(imgDisks[0]); - if (('A' <= drive && drive <= 'B' && !(newdrive->loadedDisk->hardDrive)) || - ('C' <= drive && drive <= 'D' && newdrive->loadedDisk->hardDrive)) { - const size_t idx = drive_index(drive); - imageDiskList[idx] = newdrive->loadedDisk; - updateDPT(); - } + auto *newdrive = static_cast<fatDrive*>(imgDisks[0]); + if (('A' <= drive && drive <= 'B' && !(newdrive->loadedDisk->hardDrive)) || + ('C' <= drive && drive <= 'D' && newdrive->loadedDisk->hardDrive)) { + const size_t idx = drive_index(drive); + imageDiskList[idx] = newdrive->loadedDisk; + updateDPT(); } } else if (fstype=="iso") { if (Drives[drive_index(drive)]) { @@ -474,7 +472,7 @@ void IMGMOUNT::Run(void) { if (hdd) newImage->Set_Geometry(sizes[2],sizes[3],sizes[1],sizes[0]); imageDiskList[drive - '0'].reset(newImage); - updateDPT(); + if ((drive == '2' || drive == '3') && hdd) updateDPT(); WriteOut(MSG_Get("PROGRAM_IMGMOUNT_MOUNT_NUMBER"),drive - '0',temp_line.c_str()); } diff --git a/src/ints/bios_disk.cpp b/src/ints/bios_disk.cpp index 0bc94d94e..538836b83 100644 --- a/src/ints/bios_disk.cpp +++ b/src/ints/bios_disk.cpp @@ -297,7 +297,7 @@ static uint8_t GetDosDriveNumber(uint8_t biosNum) { } static bool driveInactive(uint8_t driveNum) { - if(driveNum>=(2 + MAX_HDD_IMAGES)) { + if (driveNum >= MAX_DISK_IMAGES) { LOG(LOG_BIOS,LOG_ERROR)("Disk %d non-existent", driveNum); last_status = 0x01; CALLBACK_SCF(true); @@ -380,7 +380,7 @@ static Bitu INT13_DiskHandler(void) { CALLBACK_SCF(true); return CBRET_NONE; } - if (!any_images) { + if (drivenum < MAX_DISK_IMAGES && imageDiskList[drivenum] == nullptr) { if (drivenum >= DOS_DRIVES || !Drives[drivenum] || Drives[drivenum]->isRemovable()) { reg_ah = 0x01; CALLBACK_SCF(true); @@ -389,10 +389,13 @@ static Bitu INT13_DiskHandler(void) { // Inherit the Earth cdrom and Amberstar use it as a disk test if (((reg_dl&0x80)==0x80) && (reg_dh==0) && ((reg_cl&0x3f)==1)) { if (reg_ch==0) { - PhysPt ptr = PhysMake(SegValue(es),reg_bx); // write some MBR data into buffer for Amberstar installer - mem_writeb(ptr+0x1be,0x80); // first partition is active - mem_writeb(ptr+0x1c2,0x06); // first partition is FAT16B + real_writeb(SegValue(es), + reg_bx + 0x1be, + 0x80); // first partition is active + real_writeb(SegValue(es), + reg_bx + 0x1c2, + 0x06); // first partition is FAT16B } reg_ah = 0; CALLBACK_SCF(false); |