mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-09 11:51:09 +08:00
FAT driver: Recalculate FAT structure placement when the guest changes the BPB, allow mounting an unformatted partition as a FAT drive letter in a way that allows FORMAT.COM to later make a valid filesystem
This commit is contained in:
parent
c08ce26926
commit
41f94f776f
12
CHANGELOG
12
CHANGELOG
@ -12,6 +12,18 @@ Next version:
|
||||
file would attempt to mount the .bat file, not the disk image.
|
||||
- IMGMAKE: If -nofs and -bat was specified, the generated .bat file
|
||||
will refer to "IMGMAKE 2" instead of "IMGMAKE C"
|
||||
- DOS FAT driver: When the guest sends in a new BIOS Parameter Block,
|
||||
recalculate the disk locations and FAT type properly instead of
|
||||
assuming that FORMAT.COM is using the same format already present.
|
||||
- DOS FAT driver: If the partition is unformatted and looks as if
|
||||
freshly written by FDISK, then instead of failing to mount, mount
|
||||
the partition instead as an unformatted partition and fail file
|
||||
I/O until a BPB is set and the partition formatted by FORMAT.COM.
|
||||
This matches MS-DOS behavior and it makes it possible to mount an
|
||||
image, FDISK it, restart, FORMAT.COM the unformatted partition,
|
||||
and end up with a working drive letter (just like MS-DOS). So far
|
||||
verified against MS-DOS 6.22 and Windows 98 versions of FDISK,
|
||||
FORMAT, SYS, and SCANDISK.
|
||||
|
||||
2023.09.01
|
||||
- Disable by default message confirmation after snapshot and AVI video
|
||||
|
@ -598,6 +598,7 @@ uint32_t fatFile::GetSeekPos() {
|
||||
}
|
||||
|
||||
uint32_t fatDrive::getClustFirstSect(uint32_t clustNum) {
|
||||
if (unformatted) return 0;
|
||||
return ((clustNum - 2) * BPB.v.BPB_SecPerClus) + firstDataSector;
|
||||
}
|
||||
|
||||
@ -607,6 +608,8 @@ uint32_t fatDrive::getClusterValue(uint32_t clustNum) {
|
||||
uint32_t fatentoff;
|
||||
uint32_t clustValue=0;
|
||||
|
||||
if (unformatted) return 0xFFFFFFFFu;
|
||||
|
||||
switch(fattype) {
|
||||
case FAT12:
|
||||
fatoffset = clustNum + (clustNum / 2);
|
||||
@ -669,6 +672,8 @@ void fatDrive::setClusterValue(uint32_t clustNum, uint32_t clustValue) {
|
||||
uint32_t fatsectnum;
|
||||
uint32_t fatentoff;
|
||||
|
||||
if (unformatted) return;
|
||||
|
||||
switch(fattype) {
|
||||
case FAT12:
|
||||
fatoffset = clustNum + (clustNum / 2);
|
||||
@ -740,6 +745,8 @@ void fatDrive::setClusterValue(uint32_t clustNum, uint32_t clustValue) {
|
||||
}
|
||||
|
||||
bool fatDrive::getEntryName(const char *fullname, char *entname) {
|
||||
if (unformatted) return false;
|
||||
|
||||
char dirtoken[DOS_PATHLENGTH];
|
||||
|
||||
char * findDir;
|
||||
@ -772,6 +779,8 @@ bool fatDrive::getEntryName(const char *fullname, char *entname) {
|
||||
}
|
||||
|
||||
void fatDrive::UpdateBootVolumeLabel(const char *label) {
|
||||
if (unformatted) return;
|
||||
|
||||
FAT_BootSector bootbuffer = {};
|
||||
|
||||
if (BPB.v.BPB_BootSig == 0x28 || BPB.v.BPB_BootSig == 0x29) {
|
||||
@ -794,6 +803,8 @@ void fatDrive::UpdateBootVolumeLabel(const char *label) {
|
||||
}
|
||||
|
||||
void fatDrive::SetLabel(const char *label, bool /*iscdrom*/, bool /*updatable*/) {
|
||||
if (unformatted) return;
|
||||
|
||||
direntry sectbuf[MAX_DIRENTS_PER_SECTOR]; /* 16 directory entries per 512 byte sector */
|
||||
uint32_t dirClustNumber;
|
||||
uint32_t logentsector; /* Logical entry sector */
|
||||
@ -903,6 +914,8 @@ nextfile:
|
||||
* first call the clear() method before calling. After the call, copy off the value because the next call to FindNextInternal
|
||||
* by any part of this code will obliterate the result with a new result. */
|
||||
bool fatDrive::getFileDirEntry(char const * const filename, direntry * useEntry, uint32_t * dirClust, uint32_t * subEntry,bool dirOk) {
|
||||
if (unformatted) return false;
|
||||
|
||||
size_t len = strlen(filename);
|
||||
char dirtoken[DOS_PATHLENGTH];
|
||||
uint32_t currentClust = 0; /* FAT12/FAT16 root directory */
|
||||
@ -966,6 +979,8 @@ bool fatDrive::getFileDirEntry(char const * const filename, direntry * useEntry,
|
||||
}
|
||||
|
||||
bool fatDrive::getDirClustNum(const char *dir, uint32_t *clustNum, bool parDir) {
|
||||
if (unformatted) return false;
|
||||
|
||||
uint32_t len = (uint32_t)strlen(dir);
|
||||
char dirtoken[DOS_PATHLENGTH];
|
||||
direntry foundEntry;
|
||||
@ -1077,14 +1092,17 @@ uint32_t fatDrive::getSectorSize(void) {
|
||||
}
|
||||
|
||||
uint32_t fatDrive::getClusterSize(void) {
|
||||
if (unformatted) return 0;
|
||||
return (unsigned int)BPB.v.BPB_SecPerClus * (unsigned int)BPB.v.BPB_BytsPerSec;
|
||||
}
|
||||
|
||||
uint32_t fatDrive::getAbsoluteSectFromBytePos(uint32_t startClustNum, uint32_t bytePos,clusterChainMemory *ccm) {
|
||||
if (unformatted) return 0;
|
||||
return getAbsoluteSectFromChain(startClustNum, bytePos / BPB.v.BPB_BytsPerSec,ccm);
|
||||
}
|
||||
|
||||
bool fatDrive::iseofFAT(const uint32_t cv) const {
|
||||
if (unformatted) return true;
|
||||
switch(fattype) {
|
||||
case FAT12: return cv < 2 || cv >= 0xff8;
|
||||
case FAT16: return cv < 2 || cv >= 0xfff8;
|
||||
@ -1096,6 +1114,7 @@ bool fatDrive::iseofFAT(const uint32_t cv) const {
|
||||
}
|
||||
|
||||
uint32_t fatDrive::getAbsoluteSectFromChain(uint32_t startClustNum, uint32_t logicalSector,clusterChainMemory *ccm) {
|
||||
if (unformatted) return 0;
|
||||
uint32_t targClust = (uint32_t)(logicalSector / BPB.v.BPB_SecPerClus);
|
||||
uint32_t sectClust = (uint32_t)(logicalSector % BPB.v.BPB_SecPerClus);
|
||||
uint32_t indxClust = (uint32_t)0;
|
||||
@ -1147,6 +1166,7 @@ uint32_t fatDrive::getAbsoluteSectFromChain(uint32_t startClustNum, uint32_t log
|
||||
}
|
||||
|
||||
void fatDrive::deleteClustChain(uint32_t startCluster, uint32_t bytePos) {
|
||||
if (unformatted) return;
|
||||
if (startCluster < 2) return; /* do not corrupt the FAT media ID. The file has no chain. Do nothing. */
|
||||
|
||||
uint32_t clustSize = getClusterSize();
|
||||
@ -1226,6 +1246,7 @@ void fatDrive::deleteClustChain(uint32_t startCluster, uint32_t bytePos) {
|
||||
}
|
||||
|
||||
uint32_t fatDrive::appendCluster(uint32_t startCluster) {
|
||||
if (unformatted) return 0;
|
||||
if (startCluster < 2) return 0; /* do not corrupt the FAT media ID. The file has no chain. Do nothing. */
|
||||
|
||||
uint32_t currentClust = startCluster;
|
||||
@ -1270,6 +1291,7 @@ uint32_t fatDrive::appendCluster(uint32_t startCluster) {
|
||||
}
|
||||
|
||||
bool fatDrive::allocateCluster(uint32_t useCluster, uint32_t prevCluster) {
|
||||
if (unformatted) return false;
|
||||
|
||||
/* Can't allocate cluster #0 */
|
||||
if(useCluster == 0) return false;
|
||||
@ -1506,7 +1528,7 @@ void fatDrive::UpdateDPB(unsigned char dos_drive) {
|
||||
void fatDrive::fatDriveInit(const char *sysFilename, uint32_t bytesector, uint32_t cylsector, uint32_t headscyl, uint32_t cylinders, uint64_t filesize, const std::vector<std::string> &options) {
|
||||
uint32_t startSector = 0,countSector = 0;
|
||||
bool pc98_512_to_1024_allow = false;
|
||||
int opt_partition_index = -1;
|
||||
int opt_partition_index = -1;
|
||||
bool is_hdd = (filesize > 2880);
|
||||
|
||||
physToLogAdj = 0;
|
||||
@ -1517,29 +1539,29 @@ void fatDrive::fatDriveInit(const char *sysFilename, uint32_t bytesector, uint32
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &opt : options) {
|
||||
size_t equ = opt.find_first_of('=');
|
||||
std::string name,value;
|
||||
for (const auto &opt : options) {
|
||||
size_t equ = opt.find_first_of('=');
|
||||
std::string name,value;
|
||||
|
||||
if (equ != std::string::npos) {
|
||||
name = opt.substr(0,equ);
|
||||
value = opt.substr(equ+1);
|
||||
}
|
||||
else {
|
||||
name = opt;
|
||||
value.clear();
|
||||
}
|
||||
if (equ != std::string::npos) {
|
||||
name = opt.substr(0,equ);
|
||||
value = opt.substr(equ+1);
|
||||
}
|
||||
else {
|
||||
name = opt;
|
||||
value.clear();
|
||||
}
|
||||
|
||||
if (name == "partidx") {
|
||||
if (!value.empty())
|
||||
opt_partition_index = (int)atol(value.c_str());
|
||||
}
|
||||
else {
|
||||
LOG(LOG_DOSMISC,LOG_DEBUG)("FAT: option '%s' = '%s' ignored, unknown",name.c_str(),value.c_str());
|
||||
}
|
||||
if (name == "partidx") {
|
||||
if (!value.empty())
|
||||
opt_partition_index = (int)atol(value.c_str());
|
||||
}
|
||||
else {
|
||||
LOG(LOG_DOSMISC,LOG_DEBUG)("FAT: option '%s' = '%s' ignored, unknown",name.c_str(),value.c_str());
|
||||
}
|
||||
|
||||
// LOG_MSG("'%s' = '%s'",name.c_str(),value.c_str());
|
||||
}
|
||||
// LOG_MSG("'%s' = '%s'",name.c_str(),value.c_str());
|
||||
}
|
||||
|
||||
loadedDisk->Addref();
|
||||
bool isipl1 = false;
|
||||
@ -1701,15 +1723,144 @@ void fatDrive::fatDriveInit(const char *sysFilename, uint32_t bytesector, uint32
|
||||
loadedDisk->Read_AbsoluteSector(0+partSectOff,&bootbuffer);
|
||||
|
||||
/* If the sector is full of 0xF6, the partition is brand new and was just created with Microsoft FDISK.EXE (Windows 98 behavior)
|
||||
* and therefore there is NO FAT filesystem here. We'll go farther and check if all bytes are just the same. */
|
||||
{
|
||||
* and therefore there is NO FAT filesystem here. We'll go farther and check if all bytes are just the same.
|
||||
*
|
||||
* MS-DOS behavior is to let the drive letter appear, but any attempt to access it results in errors like "invalid media type" until
|
||||
* you run FORMAT.COM on it, which will then set up the filesystem and allow it to work. */
|
||||
if (partSectOff != 0) { /* hard drives only */
|
||||
unsigned int i=1;
|
||||
|
||||
while (i < 128 && ((uint8_t*)(&bootbuffer))[0] == ((uint8_t*)(&bootbuffer))[i]) i++;
|
||||
|
||||
if (i == 128) {
|
||||
LOG_MSG("Boot sector appears to have been created by FDISK.EXE but not formatted");
|
||||
created_successfully = false;
|
||||
LOG_MSG("Boot sector appears to have been created by FDISK.EXE but not formatted. Allowing mount but filesystem access will not work until formatted.");
|
||||
|
||||
sector_size = loadedDisk->getSectSize();
|
||||
firstRootDirSect = 0;
|
||||
CountOfClusters = 0;
|
||||
firstDataSector = 0;
|
||||
unformatted = true;
|
||||
|
||||
cwdDirCluster = 0;
|
||||
|
||||
memset(fatSectBuffer,0,1024);
|
||||
curFatSect = 0xffffffff;
|
||||
|
||||
strcpy(info, "fatDrive ");
|
||||
strcat(info, wpcolon&&strlen(sysFilename)>1&&sysFilename[0]==':'?sysFilename+1:sysFilename);
|
||||
|
||||
/* NTS: Real MS-DOS behavior is that an unformatted partition is inaccessible but INT 21h AX=440Dh CX=0x0860 (Get Device Parameters)
|
||||
* has a ready-made BPB for use in formatting the partition. FORMAT.COM then formats the filesystem based on the MS-DOS kernel's
|
||||
* recommended BPB. It's not FORMAT.COM that decides the layout it is MS-DOS itself. */
|
||||
uint64_t part_sectors;
|
||||
|
||||
if (partSectOff != 0 && partSectSize != 0) {
|
||||
part_sectors = partSectSize;
|
||||
}
|
||||
else {
|
||||
part_sectors = GetSectorCount();
|
||||
}
|
||||
|
||||
/* If the partition is 1GB or larger and emulating MS-DOS 7.10 or higher, default FAT32 */
|
||||
if ((part_sectors*uint64_t(sector_size)) >= (1000ull*2048ull) && (dos.version.major > 7 || (dos.version.major == 7 && dos.version.minor >= 10))) {
|
||||
BPB.v32.BPB_BytsPerSec = sector_size;
|
||||
BPB.v32.BPB_SecPerClus = 8; // 4096 byte clusters
|
||||
BPB.v32.BPB_RsvdSecCnt = 32;
|
||||
BPB.v32.BPB_NumFATs = 2;
|
||||
BPB.v32.BPB_RootEntCnt = 0;
|
||||
BPB.v32.BPB_TotSec16 = 0;
|
||||
BPB.v32.BPB_Media = 0xF8;
|
||||
BPB.v32.BPB_SecPerTrk = loadedDisk->sectors;
|
||||
BPB.v32.BPB_NumHeads = loadedDisk->heads;
|
||||
BPB.v32.BPB_HiddSec = partSectOff;
|
||||
BPB.v32.BPB_TotSec32 = part_sectors;
|
||||
BPB.v32.BPB_ExtFlags = 0;
|
||||
BPB.v32.BPB_FSVer = 0;
|
||||
BPB.v32.BPB_RootClus = 2;
|
||||
BPB.v32.BPB_FSInfo = 0;
|
||||
BPB.v32.BPB_BkBootSec = 0;
|
||||
|
||||
while (BPB.v32.BPB_SecPerClus < 64 && (part_sectors / uint64_t(BPB.v32.BPB_SecPerClus)) > uint64_t(0x880000u))
|
||||
BPB.v32.BPB_SecPerClus *= 2u;
|
||||
|
||||
/* Get size of root dir in sectors */
|
||||
uint32_t DataSectors;
|
||||
|
||||
DataSectors = (Bitu)BPB.v32.BPB_TotSec32 - ((Bitu)BPB.v32.BPB_RsvdSecCnt + ((Bitu)BPB.v32.BPB_NumFATs * (Bitu)BPB.v32.BPB_FATSz32));
|
||||
CountOfClusters = DataSectors / BPB.v32.BPB_SecPerClus;
|
||||
|
||||
BPB.v32.BPB_FATSz32 = uint32_t((CountOfClusters * 4ull) + uint64_t(sector_size) - 1ull) / uint64_t(sector_size);
|
||||
|
||||
assert(CountOfClusters >= 0xFFF8);
|
||||
|
||||
assert(BPB.is_fat32());
|
||||
fattype = FAT32;
|
||||
}
|
||||
else {
|
||||
BPB.v.BPB_BytsPerSec = sector_size;
|
||||
BPB.v.BPB_SecPerClus = 1; // 512 byte clusters
|
||||
BPB.v.BPB_RsvdSecCnt = 1;
|
||||
BPB.v.BPB_NumFATs = 2;
|
||||
BPB.v.BPB_RootEntCnt = 96;
|
||||
if (part_sectors > 65535ul) {
|
||||
BPB.v.BPB_TotSec16 = 0;
|
||||
BPB.v.BPB_TotSec32 = part_sectors;
|
||||
}
|
||||
else {
|
||||
BPB.v.BPB_TotSec16 = part_sectors;
|
||||
BPB.v.BPB_TotSec32 = 0;
|
||||
}
|
||||
BPB.v.BPB_Media = 0xF8;
|
||||
BPB.v.BPB_SecPerTrk = loadedDisk->sectors;
|
||||
BPB.v.BPB_NumHeads = loadedDisk->heads;
|
||||
BPB.v.BPB_HiddSec = partSectOff;
|
||||
|
||||
if ((part_sectors*uint64_t(sector_size)) >= (31ull*1024ull*1024ull)) { // 31MB
|
||||
fattype = FAT16;
|
||||
while (BPB.v.BPB_SecPerClus < 32 && (part_sectors / uint64_t(BPB.v.BPB_SecPerClus)) > uint64_t(0x8800u))
|
||||
BPB.v.BPB_SecPerClus *= 2u;
|
||||
}
|
||||
else {
|
||||
fattype = FAT12;
|
||||
while (BPB.v.BPB_SecPerClus < 64 && (part_sectors / uint64_t(BPB.v.BPB_SecPerClus)) > uint64_t(0x880u))
|
||||
BPB.v.BPB_SecPerClus *= 2u;
|
||||
}
|
||||
|
||||
/* Get size of root dir in sectors */
|
||||
uint32_t RootDirSectors;
|
||||
uint32_t DataSectors;
|
||||
|
||||
RootDirSectors = ((BPB.v.BPB_RootEntCnt * 32u) + (BPB.v.BPB_BytsPerSec - 1u)) / BPB.v.BPB_BytsPerSec;
|
||||
|
||||
if (BPB.v.BPB_TotSec16 != 0)
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec16 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
else
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
|
||||
CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
|
||||
|
||||
if (fattype == FAT16)
|
||||
BPB.v.BPB_FATSz16 = uint32_t((CountOfClusters * 2ull) + uint64_t(sector_size) - 1ull) / uint64_t(sector_size);
|
||||
else
|
||||
BPB.v.BPB_FATSz16 = uint32_t((((CountOfClusters+1ull)/2ull) * 3ull) + uint64_t(sector_size) - 1ull) / uint64_t(sector_size);
|
||||
|
||||
if (BPB.v.BPB_TotSec16 != 0)
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec16 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
else
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
|
||||
|
||||
if (fattype == FAT12) {
|
||||
assert(CountOfClusters < 0xFF8);
|
||||
}
|
||||
else if (fattype == FAT16) {
|
||||
assert(CountOfClusters < 0xFFF8);
|
||||
assert(CountOfClusters >= 0xFF8);
|
||||
}
|
||||
|
||||
assert(!BPB.is_fat32());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1793,9 +1944,9 @@ void fatDrive::fatDriveInit(const char *sysFilename, uint32_t bytesector, uint32
|
||||
|
||||
/* DEBUG */
|
||||
LOG(LOG_DOSMISC,LOG_DEBUG)("FAT: BPB says %u sectors/track %u heads %u bytes/sector",
|
||||
BPB.v.BPB_SecPerTrk,
|
||||
BPB.v.BPB_NumHeads,
|
||||
BPB.v.BPB_BytsPerSec);
|
||||
BPB.v.BPB_SecPerTrk,
|
||||
BPB.v.BPB_NumHeads,
|
||||
BPB.v.BPB_BytsPerSec);
|
||||
|
||||
/* NTS: PC-98 floppies (the 1024 byte/sector format) do not have magic bytes */
|
||||
if (fatDrive::getSectSize() == 512 && !IS_PC98_ARCH) {
|
||||
@ -1808,35 +1959,35 @@ void fatDrive::fatDriveInit(const char *sysFilename, uint32_t bytesector, uint32
|
||||
}
|
||||
}
|
||||
|
||||
/* NTS: Some HDI images of PC-98 games do in fact have BPB_NumHeads == 0. Some like "Amaranth 5" have BPB_SecPerTrk == 0 too! */
|
||||
if (!IS_PC98_ARCH) {
|
||||
/* a clue that we're not really looking at FAT is invalid or weird values in the boot sector */
|
||||
if (BPB.v.BPB_SecPerTrk == 0 || (BPB.v.BPB_SecPerTrk > ((filesize <= 3000) ? 40 : 255)) ||
|
||||
(BPB.v.BPB_NumHeads > ((filesize <= 3000) ? 64 : 255))) {
|
||||
LOG_MSG("Rejecting image, boot sector has weird values not consistent with FAT filesystem");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* NTS: Some HDI images of PC-98 games do in fact have BPB_NumHeads == 0. Some like "Amaranth 5" have BPB_SecPerTrk == 0 too! */
|
||||
if (!IS_PC98_ARCH) {
|
||||
/* a clue that we're not really looking at FAT is invalid or weird values in the boot sector */
|
||||
if (BPB.v.BPB_SecPerTrk == 0 || (BPB.v.BPB_SecPerTrk > ((filesize <= 3000) ? 40 : 255)) ||
|
||||
(BPB.v.BPB_NumHeads > ((filesize <= 3000) ? 64 : 255))) {
|
||||
LOG_MSG("Rejecting image, boot sector has weird values not consistent with FAT filesystem");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* work at this point in logical sectors */
|
||||
/* work at this point in logical sectors */
|
||||
sector_size = loadedDisk->getSectSize();
|
||||
|
||||
/* Many HDI images indicate a disk format of 256 or 512 bytes per sector combined with a FAT filesystem
|
||||
* that indicates 1024 bytes per sector. */
|
||||
if (pc98_512_to_1024_allow &&
|
||||
BPB.v.BPB_BytsPerSec != fatDrive::getSectSize() &&
|
||||
BPB.v.BPB_BytsPerSec > fatDrive::getSectSize() &&
|
||||
(BPB.v.BPB_BytsPerSec % fatDrive::getSectSize()) == 0) {
|
||||
unsigned int ratioshift = 1;
|
||||
/* Many HDI images indicate a disk format of 256 or 512 bytes per sector combined with a FAT filesystem
|
||||
* that indicates 1024 bytes per sector. */
|
||||
if (pc98_512_to_1024_allow &&
|
||||
BPB.v.BPB_BytsPerSec != fatDrive::getSectSize() &&
|
||||
BPB.v.BPB_BytsPerSec > fatDrive::getSectSize() &&
|
||||
(BPB.v.BPB_BytsPerSec % fatDrive::getSectSize()) == 0) {
|
||||
unsigned int ratioshift = 1;
|
||||
|
||||
while ((unsigned int)(BPB.v.BPB_BytsPerSec >> ratioshift) > fatDrive::getSectSize())
|
||||
ratioshift++;
|
||||
while ((unsigned int)(BPB.v.BPB_BytsPerSec >> ratioshift) > fatDrive::getSectSize())
|
||||
ratioshift++;
|
||||
|
||||
unsigned int ratio = 1u << ratioshift;
|
||||
unsigned int ratio = 1u << ratioshift;
|
||||
|
||||
LOG_MSG("Disk indicates %u bytes/sector, FAT filesystem indicates %u bytes/sector. Ratio=%u:1 shift=%u",
|
||||
fatDrive::getSectSize(),BPB.v.BPB_BytsPerSec,ratio,ratioshift);
|
||||
LOG_MSG("Disk indicates %u bytes/sector, FAT filesystem indicates %u bytes/sector. Ratio=%u:1 shift=%u",
|
||||
fatDrive::getSectSize(),BPB.v.BPB_BytsPerSec,ratio,ratioshift);
|
||||
|
||||
if ((unsigned int)(BPB.v.BPB_BytsPerSec >> ratioshift) == fatDrive::getSectSize()) {
|
||||
assert(ratio >= 2);
|
||||
@ -1854,18 +2005,18 @@ void fatDrive::fatDriveInit(const char *sysFilename, uint32_t bytesector, uint32
|
||||
}
|
||||
|
||||
/* Sanity checks */
|
||||
/* NTS: DOSBox-X *does* support non-standard sector sizes, though not in IBM PC mode and not through INT 13h.
|
||||
* In DOSBox-X INT 13h emulation will enforce the standard (512 byte) sector size.
|
||||
* In PC-98 mode mounting disk images requires "non-standard" sector sizes because PC-98 floppies (other
|
||||
* than ones formatted 1.44MB) generally use 1024 bytes/sector and MAY use 128 or 256 bytes per sector. */
|
||||
/* NTS: Loosen geometry checks for PC-98 mode, for two reasons. One, is that the geometry check will fail
|
||||
* when logical vs physical sector translation is involved, since it is apparently common for PC-98 HDI
|
||||
* images to be formatted with 256, 512, 1024, or in rare cases even 2048 bytes per sector, yet the FAT
|
||||
* file format will report a sector size that is a power of 2 multiple of the disk sector size. The
|
||||
* most common appears to be 512 byte/sector HDI images formatted with 1024 byte/sector FAT filesystems.
|
||||
*
|
||||
* Second, there are some HDI images that are valid yet the FAT filesystem reports a head count of 0
|
||||
* for some reason (Touhou Project) */
|
||||
/* NTS: DOSBox-X *does* support non-standard sector sizes, though not in IBM PC mode and not through INT 13h.
|
||||
* In DOSBox-X INT 13h emulation will enforce the standard (512 byte) sector size.
|
||||
* In PC-98 mode mounting disk images requires "non-standard" sector sizes because PC-98 floppies (other
|
||||
* than ones formatted 1.44MB) generally use 1024 bytes/sector and MAY use 128 or 256 bytes per sector. */
|
||||
/* NTS: Loosen geometry checks for PC-98 mode, for two reasons. One, is that the geometry check will fail
|
||||
* when logical vs physical sector translation is involved, since it is apparently common for PC-98 HDI
|
||||
* images to be formatted with 256, 512, 1024, or in rare cases even 2048 bytes per sector, yet the FAT
|
||||
* file format will report a sector size that is a power of 2 multiple of the disk sector size. The
|
||||
* most common appears to be 512 byte/sector HDI images formatted with 1024 byte/sector FAT filesystems.
|
||||
*
|
||||
* Second, there are some HDI images that are valid yet the FAT filesystem reports a head count of 0
|
||||
* for some reason (Touhou Project) */
|
||||
if ((BPB.v.BPB_SecPerClus == 0) ||
|
||||
(BPB.v.BPB_NumFATs == 0) ||
|
||||
(BPB.v.BPB_NumHeads == 0 && !IS_PC98_ARCH) ||
|
||||
@ -1882,53 +2033,53 @@ void fatDrive::fatDriveInit(const char *sysFilename, uint32_t bytesector, uint32
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sanity check: Root directory count is nonzero if FAT16/FAT12, or is zero if FAT32 */
|
||||
if (BPB.is_fat32()) {
|
||||
if (BPB.v.BPB_RootEntCnt != 0) {
|
||||
LOG_MSG("Sanity check fail: Root directory count != 0 and not FAT32");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BPB.v.BPB_RootEntCnt == 0) {
|
||||
LOG_MSG("Sanity check fail: Root directory count == 0 and not FAT32");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Sanity check: Root directory count is nonzero if FAT16/FAT12, or is zero if FAT32 */
|
||||
if (BPB.is_fat32()) {
|
||||
if (BPB.v.BPB_RootEntCnt != 0) {
|
||||
LOG_MSG("Sanity check fail: Root directory count != 0 and not FAT32");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BPB.v.BPB_RootEntCnt == 0) {
|
||||
LOG_MSG("Sanity check fail: Root directory count == 0 and not FAT32");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* too much of this code assumes 512 bytes per sector or more.
|
||||
* MS-DOS itself as I understand it relies on bytes per sector being a power of 2.
|
||||
* this is to protect against errant FAT structures and to help prep this code
|
||||
* later to work with the 1024 bytes/sector used by PC-98 floppy formats.
|
||||
* When done, this code should be able to then handle the FDI/FDD images
|
||||
* PC-98 games are normally distributed in on the internet.
|
||||
*
|
||||
* The value "128" comes from the smallest sector size possible on the floppy
|
||||
* controller of MS-DOS based systems. */
|
||||
/* NTS: Power of 2 test: A number is a power of 2 if (x & (x - 1)) == 0
|
||||
*
|
||||
* 15 15 & 14 01111 AND 01110 RESULT: 01110 (15)
|
||||
* 16 16 & 15 10000 AND 01111 RESULT: 00000 (0)
|
||||
* 17 17 & 16 10001 AND 10000 RESULT: 10000 (16) */
|
||||
if (BPB.v.BPB_BytsPerSec < 128 || BPB.v.BPB_BytsPerSec > SECTOR_SIZE_MAX ||
|
||||
(BPB.v.BPB_BytsPerSec & (BPB.v.BPB_BytsPerSec - 1)) != 0/*not a power of 2*/) {
|
||||
LOG_MSG("FAT bytes/sector value %u not supported",BPB.v.BPB_BytsPerSec);
|
||||
/* too much of this code assumes 512 bytes per sector or more.
|
||||
* MS-DOS itself as I understand it relies on bytes per sector being a power of 2.
|
||||
* this is to protect against errant FAT structures and to help prep this code
|
||||
* later to work with the 1024 bytes/sector used by PC-98 floppy formats.
|
||||
* When done, this code should be able to then handle the FDI/FDD images
|
||||
* PC-98 games are normally distributed in on the internet.
|
||||
*
|
||||
* The value "128" comes from the smallest sector size possible on the floppy
|
||||
* controller of MS-DOS based systems. */
|
||||
/* NTS: Power of 2 test: A number is a power of 2 if (x & (x - 1)) == 0
|
||||
*
|
||||
* 15 15 & 14 01111 AND 01110 RESULT: 01110 (15)
|
||||
* 16 16 & 15 10000 AND 01111 RESULT: 00000 (0)
|
||||
* 17 17 & 16 10001 AND 10000 RESULT: 10000 (16) */
|
||||
if (BPB.v.BPB_BytsPerSec < 128 || BPB.v.BPB_BytsPerSec > SECTOR_SIZE_MAX ||
|
||||
(BPB.v.BPB_BytsPerSec & (BPB.v.BPB_BytsPerSec - 1)) != 0/*not a power of 2*/) {
|
||||
LOG_MSG("FAT bytes/sector value %u not supported",BPB.v.BPB_BytsPerSec);
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* another fault of this code is that it assumes the sector size of the medium matches
|
||||
* the BPB_BytsPerSec value of the MS-DOS filesystem. if they don't match, problems
|
||||
* will result. */
|
||||
if (BPB.v.BPB_BytsPerSec != fatDrive::getSectSize()) {
|
||||
LOG_MSG("FAT bytes/sector %u does not match disk image bytes/sector %u",
|
||||
(unsigned int)BPB.v.BPB_BytsPerSec,
|
||||
(unsigned int)fatDrive::getSectSize());
|
||||
/* another fault of this code is that it assumes the sector size of the medium matches
|
||||
* the BPB_BytsPerSec value of the MS-DOS filesystem. if they don't match, problems
|
||||
* will result. */
|
||||
if (BPB.v.BPB_BytsPerSec != fatDrive::getSectSize()) {
|
||||
LOG_MSG("FAT bytes/sector %u does not match disk image bytes/sector %u",
|
||||
(unsigned int)BPB.v.BPB_BytsPerSec,
|
||||
(unsigned int)fatDrive::getSectSize());
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Filesystem must be contiguous to use absolute sectors, otherwise CHS will be used */
|
||||
absolute = IS_PC98_ARCH || ((BPB.v.BPB_NumHeads == headscyl) && (BPB.v.BPB_SecPerTrk == cylsector));
|
||||
@ -1940,53 +2091,53 @@ void fatDrive::fatDriveInit(const char *sysFilename, uint32_t bytesector, uint32
|
||||
uint32_t RootDirSectors;
|
||||
uint32_t DataSectors;
|
||||
|
||||
if (BPB.is_fat32()) {
|
||||
/* FAT32 requires use of TotSec32, TotSec16 must be zero. */
|
||||
if (BPB.v.BPB_TotSec32 == 0) {
|
||||
LOG_MSG("BPB_TotSec32 == 0 and FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
if (BPB.v32.BPB_RootClus < 2) {
|
||||
LOG_MSG("BPB_RootClus == 0 and FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
if (BPB.v.BPB_FATSz16 != 0) {
|
||||
LOG_MSG("BPB_FATSz16 != 0 and FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
if (BPB.v32.BPB_FATSz32 == 0) {
|
||||
LOG_MSG("BPB_FATSz32 == 0 and FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
if (BPB.is_fat32()) {
|
||||
/* FAT32 requires use of TotSec32, TotSec16 must be zero. */
|
||||
if (BPB.v.BPB_TotSec32 == 0) {
|
||||
LOG_MSG("BPB_TotSec32 == 0 and FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
if (BPB.v32.BPB_RootClus < 2) {
|
||||
LOG_MSG("BPB_RootClus == 0 and FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
if (BPB.v.BPB_FATSz16 != 0) {
|
||||
LOG_MSG("BPB_FATSz16 != 0 and FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
if (BPB.v32.BPB_FATSz32 == 0) {
|
||||
LOG_MSG("BPB_FATSz32 == 0 and FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
|
||||
RootDirSectors = 0; /* FAT32 root directory has it's own allocation chain, instead of a fixed location */
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v32.BPB_FATSz32) + (Bitu)RootDirSectors);
|
||||
CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
|
||||
firstDataSector = ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v32.BPB_FATSz32) + (Bitu)RootDirSectors) + (Bitu)partSectOff;
|
||||
firstRootDirSect = 0;
|
||||
}
|
||||
else {
|
||||
if (BPB.v.BPB_FATSz16 == 0) {
|
||||
LOG_MSG("BPB_FATSz16 == 0 and not FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
RootDirSectors = 0; /* FAT32 root directory has it's own allocation chain, instead of a fixed location */
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v32.BPB_FATSz32) + (Bitu)RootDirSectors);
|
||||
CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
|
||||
firstDataSector = ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v32.BPB_FATSz32) + (Bitu)RootDirSectors) + (Bitu)partSectOff;
|
||||
firstRootDirSect = 0;
|
||||
}
|
||||
else {
|
||||
if (BPB.v.BPB_FATSz16 == 0) {
|
||||
LOG_MSG("BPB_FATSz16 == 0 and not FAT32 BPB, not valid");
|
||||
created_successfully = false;
|
||||
return;
|
||||
}
|
||||
|
||||
RootDirSectors = ((BPB.v.BPB_RootEntCnt * 32u) + (BPB.v.BPB_BytsPerSec - 1u)) / BPB.v.BPB_BytsPerSec;
|
||||
RootDirSectors = ((BPB.v.BPB_RootEntCnt * 32u) + (BPB.v.BPB_BytsPerSec - 1u)) / BPB.v.BPB_BytsPerSec;
|
||||
|
||||
if (BPB.v.BPB_TotSec16 != 0)
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec16 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
else
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
if (BPB.v.BPB_TotSec16 != 0)
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec16 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
else
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
|
||||
CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
|
||||
firstDataSector = ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors) + (Bitu)partSectOff;
|
||||
firstRootDirSect = (Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)partSectOff;
|
||||
}
|
||||
CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
|
||||
firstDataSector = ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors) + (Bitu)partSectOff;
|
||||
firstRootDirSect = (Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)partSectOff;
|
||||
}
|
||||
|
||||
if(CountOfClusters < 4085) {
|
||||
/* Volume is FAT12 */
|
||||
@ -2027,6 +2178,8 @@ bool fatDrive::AllocationInfo32(uint32_t * _bytes_sector,uint32_t * _sectors_clu
|
||||
uint32_t countFree = 0;
|
||||
uint32_t i;
|
||||
|
||||
if (unformatted) return false;
|
||||
|
||||
for(i=0;i<CountOfClusters;i++) {
|
||||
if(!getClusterValue(i+2))
|
||||
countFree++;
|
||||
@ -2041,6 +2194,8 @@ bool fatDrive::AllocationInfo32(uint32_t * _bytes_sector,uint32_t * _sectors_clu
|
||||
}
|
||||
|
||||
bool fatDrive::AllocationInfo(uint16_t *_bytes_sector, uint8_t *_sectors_cluster, uint16_t *_total_clusters, uint16_t *_free_clusters) {
|
||||
if (unformatted) return false;
|
||||
|
||||
if (BPB.is_fat32()) {
|
||||
uint32_t bytes32,sectors32,clusters32,free32;
|
||||
if (AllocationInfo32(&bytes32,§ors32,&clusters32,&free32) &&
|
||||
@ -2070,6 +2225,9 @@ bool fatDrive::AllocationInfo(uint16_t *_bytes_sector, uint8_t *_sectors_cluster
|
||||
|
||||
uint32_t fatDrive::getFirstFreeClust(void) {
|
||||
uint32_t i;
|
||||
|
||||
if (unformatted) return 0;
|
||||
|
||||
for(i=searchFreeCluster;i<CountOfClusters;i++) {
|
||||
if(!getClusterValue(i+2)) return ((searchFreeCluster=i)+2);
|
||||
}
|
||||
@ -2095,6 +2253,7 @@ const FAT_BootSector::bpb_union_t &fatDrive::GetBPB(void) { return BPB; }
|
||||
|
||||
void fatDrive::SetBPB(const FAT_BootSector::bpb_union_t &bpb) {
|
||||
if (readonly) return;
|
||||
unformatted = false;
|
||||
BPB.v.BPB_BytsPerSec = bpb.v.BPB_BytsPerSec;
|
||||
BPB.v.BPB_SecPerClus = bpb.v.BPB_SecPerClus;
|
||||
BPB.v.BPB_RsvdSecCnt = bpb.v.BPB_RsvdSecCnt;
|
||||
@ -2132,16 +2291,54 @@ void fatDrive::SetBPB(const FAT_BootSector::bpb_union_t &bpb) {
|
||||
BPB.v32.BPB_BkBootSec = bpb.v32.BPB_BkBootSec;
|
||||
}
|
||||
|
||||
FAT_BootSector bootbuffer = {};
|
||||
loadedDisk->Read_AbsoluteSector(0+partSectOff,&bootbuffer);
|
||||
FAT_BootSector bootbuffer = {};
|
||||
loadedDisk->Read_AbsoluteSector(0+partSectOff,&bootbuffer);
|
||||
if (BPB.is_fat32()) bootbuffer.bpb.v32=BPB.v32;
|
||||
bootbuffer.bpb.v=BPB.v;
|
||||
loadedDisk->Write_AbsoluteSector(0+partSectOff,&bootbuffer);
|
||||
loadedDisk->Write_AbsoluteSector(0+partSectOff,&bootbuffer);
|
||||
|
||||
/* Get size of root dir in sectors */
|
||||
uint32_t RootDirSectors;
|
||||
uint32_t DataSectors;
|
||||
|
||||
if (BPB.is_fat32()) {
|
||||
RootDirSectors = 0; /* FAT32 root directory has it's own allocation chain, instead of a fixed location */
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v32.BPB_FATSz32) + (Bitu)RootDirSectors);
|
||||
CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
|
||||
firstDataSector = ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v32.BPB_FATSz32) + (Bitu)RootDirSectors) + (Bitu)partSectOff;
|
||||
firstRootDirSect = 0;
|
||||
}
|
||||
else {
|
||||
RootDirSectors = ((BPB.v.BPB_RootEntCnt * 32u) + (BPB.v.BPB_BytsPerSec - 1u)) / BPB.v.BPB_BytsPerSec;
|
||||
|
||||
if (BPB.v.BPB_TotSec16 != 0)
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec16 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
else
|
||||
DataSectors = (Bitu)BPB.v.BPB_TotSec32 - ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors);
|
||||
|
||||
CountOfClusters = DataSectors / BPB.v.BPB_SecPerClus;
|
||||
firstDataSector = ((Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)RootDirSectors) + (Bitu)partSectOff;
|
||||
firstRootDirSect = (Bitu)BPB.v.BPB_RsvdSecCnt + ((Bitu)BPB.v.BPB_NumFATs * (Bitu)BPB.v.BPB_FATSz16) + (Bitu)partSectOff;
|
||||
}
|
||||
|
||||
if(CountOfClusters < 4085) {
|
||||
/* Volume is FAT12 */
|
||||
LOG_MSG("Mounted FAT volume is now FAT12 with %d clusters", CountOfClusters);
|
||||
fattype = FAT12;
|
||||
} else if (CountOfClusters < 65525 || !bpb.is_fat32()) {
|
||||
LOG_MSG("Mounted FAT volume is now FAT16 with %d clusters", CountOfClusters);
|
||||
fattype = FAT16;
|
||||
} else {
|
||||
LOG_MSG("Mounted FAT volume is now FAT32 with %d clusters", CountOfClusters);
|
||||
fattype = FAT32;
|
||||
}
|
||||
}
|
||||
|
||||
bool fatDrive::FileCreate(DOS_File **file, const char *name, uint16_t attributes) {
|
||||
const char *lfn = NULL;
|
||||
|
||||
if (unformatted) return false;
|
||||
|
||||
if (readonly) {
|
||||
DOS_SetError(DOSERR_WRITE_PROTECTED);
|
||||
return false;
|
||||
@ -2243,6 +2440,8 @@ bool fatDrive::FileCreate(DOS_File **file, const char *name, uint16_t attributes
|
||||
}
|
||||
|
||||
bool fatDrive::FileExists(const char *name) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry fileEntry = {};
|
||||
uint32_t dummy1, dummy2;
|
||||
uint16_t save_errorcode = dos.errorcode;
|
||||
@ -2252,6 +2451,8 @@ bool fatDrive::FileExists(const char *name) {
|
||||
}
|
||||
|
||||
bool fatDrive::FileOpen(DOS_File **file, const char *name, uint32_t flags) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry fileEntry = {};
|
||||
uint32_t dirClust, subEntry;
|
||||
|
||||
@ -2280,6 +2481,8 @@ bool fatDrive::FileStat(const char * /*name*/, FileStat_Block *const /*stat_bloc
|
||||
}
|
||||
|
||||
bool fatDrive::FileUnlink(const char * name) {
|
||||
if (unformatted) return false;
|
||||
|
||||
if (readonly) {
|
||||
DOS_SetError(DOSERR_WRITE_PROTECTED);
|
||||
return false;
|
||||
@ -2327,6 +2530,8 @@ bool fatDrive::FileUnlink(const char * name) {
|
||||
}
|
||||
|
||||
bool fatDrive::FindFirst(const char *_dir, DOS_DTA &dta,bool fcb_findfirst) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry dummyClust = {};
|
||||
|
||||
// volume label searches always affect root directory, no matter the current directory, at least with FCBs
|
||||
@ -2414,6 +2619,8 @@ static void copyDirEntry(const direntry *src, direntry *dst) {
|
||||
}
|
||||
|
||||
bool fatDrive::FindNextInternal(uint32_t dirClustNumber, DOS_DTA &dta, direntry *foundEntry) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry sectbuf[MAX_DIRENTS_PER_SECTOR]; /* 16 directory entries per 512 byte sector */
|
||||
uint32_t logentsector; /* Logical entry sector */
|
||||
uint32_t entryoffset; /* Index offset within sector */
|
||||
@ -2676,6 +2883,8 @@ nextfile:
|
||||
}
|
||||
|
||||
bool fatDrive::FindNext(DOS_DTA &dta) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry dummyClust = {};
|
||||
|
||||
return FindNextInternal(lfn_filefind_handle>=LFN_FILEFIND_MAX?dta.GetDirIDCluster():(dnum[lfn_filefind_handle]?dnum[lfn_filefind_handle]:0), dta, &dummyClust);
|
||||
@ -2683,6 +2892,8 @@ bool fatDrive::FindNext(DOS_DTA &dta) {
|
||||
|
||||
|
||||
bool fatDrive::SetFileAttr(const char *name, uint16_t attr) {
|
||||
if (unformatted) return false;
|
||||
|
||||
if (readonly) {
|
||||
DOS_SetError(DOSERR_WRITE_PROTECTED);
|
||||
return false;
|
||||
@ -2706,6 +2917,8 @@ bool fatDrive::SetFileAttr(const char *name, uint16_t attr) {
|
||||
}
|
||||
|
||||
bool fatDrive::GetFileAttr(const char *name, uint16_t *attr) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry fileEntry = {};
|
||||
uint32_t dirClust, subEntry;
|
||||
|
||||
@ -2748,6 +2961,8 @@ unsigned long fatDrive::GetSerial() {
|
||||
}
|
||||
|
||||
bool fatDrive::directoryBrowse(uint32_t dirClustNumber, direntry *useEntry, int32_t entNum, int32_t start/*=0*/) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry sectbuf[MAX_DIRENTS_PER_SECTOR]; /* 16 directory entries per 512 byte sector */
|
||||
uint32_t tmpsector;
|
||||
|
||||
@ -2783,6 +2998,8 @@ bool fatDrive::directoryBrowse(uint32_t dirClustNumber, direntry *useEntry, int3
|
||||
}
|
||||
|
||||
bool fatDrive::directoryChange(uint32_t dirClustNumber, const direntry *useEntry, int32_t entNum) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry sectbuf[MAX_DIRENTS_PER_SECTOR]; /* 16 directory entries per 512 byte sector */
|
||||
uint32_t tmpsector = 0;
|
||||
|
||||
@ -2817,6 +3034,8 @@ bool fatDrive::directoryChange(uint32_t dirClustNumber, const direntry *useEntry
|
||||
}
|
||||
|
||||
bool fatDrive::addDirectoryEntry(uint32_t dirClustNumber, const direntry& useEntry,const char *lfn) {
|
||||
if (unformatted) return false;
|
||||
|
||||
direntry sectbuf[MAX_DIRENTS_PER_SECTOR]; /* 16 directory entries per 512 byte sector */
|
||||
uint32_t tmpsector;
|
||||
uint16_t dirPos = 0;
|
||||
@ -2977,6 +3196,8 @@ void fatDrive::zeroOutCluster(uint32_t clustNumber) {
|
||||
}
|
||||
|
||||
bool fatDrive::MakeDir(const char *dir) {
|
||||
if (unformatted) return false;
|
||||
|
||||
const char *lfn = NULL;
|
||||
|
||||
if (readonly) {
|
||||
@ -3080,6 +3301,8 @@ bool fatDrive::MakeDir(const char *dir) {
|
||||
}
|
||||
|
||||
bool fatDrive::RemoveDir(const char *dir) {
|
||||
if (unformatted) return false;
|
||||
|
||||
if (readonly) {
|
||||
DOS_SetError(DOSERR_WRITE_PROTECTED);
|
||||
return false;
|
||||
@ -3149,6 +3372,8 @@ bool fatDrive::RemoveDir(const char *dir) {
|
||||
}
|
||||
|
||||
bool fatDrive::Rename(const char * oldname, const char * newname) {
|
||||
if (unformatted) return false;
|
||||
|
||||
const char *lfn = NULL;
|
||||
|
||||
if (readonly) {
|
||||
@ -3235,6 +3460,8 @@ bool fatDrive::Rename(const char * oldname, const char * newname) {
|
||||
}
|
||||
|
||||
bool fatDrive::TestDir(const char *dir) {
|
||||
if (unformatted) return false;
|
||||
|
||||
uint32_t dummyClust;
|
||||
|
||||
/* root directory is directory */
|
||||
@ -3244,14 +3471,17 @@ bool fatDrive::TestDir(const char *dir) {
|
||||
}
|
||||
|
||||
uint32_t fatDrive::GetPartitionOffset(void) {
|
||||
if (unformatted) return 0;
|
||||
return partSectOff;
|
||||
}
|
||||
|
||||
uint32_t fatDrive::GetFirstClusterOffset(void) {
|
||||
if (unformatted) return 0;
|
||||
return firstDataSector - partSectOff;
|
||||
}
|
||||
|
||||
uint32_t fatDrive::GetHighestClusterNumber(void) {
|
||||
if (unformatted) return 0;
|
||||
return CountOfClusters + 1ul;
|
||||
}
|
||||
|
||||
|
@ -519,6 +519,8 @@ public:
|
||||
virtual uint32_t GetPartitionOffset(void);
|
||||
virtual uint32_t GetFirstClusterOffset(void);
|
||||
virtual uint32_t GetHighestClusterNumber(void);
|
||||
|
||||
bool unformatted = false;
|
||||
};
|
||||
|
||||
PhysPt DOS_Get_DPB(unsigned int dos_drive);
|
||||
|
Loading…
x
Reference in New Issue
Block a user