DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/dos/drives.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include "dosbox.h"
00021 #include "dos_system.h"
00022 #include "drives.h"
00023 #include "setup.h"
00024 #include "mapper.h"
00025 #include "support.h"
00026 #include "control.h"
00027 
00028 bool wild_match(char *haystack, char *needle) {
00029         size_t max, i;
00030     for (; *needle != '\0'; ++needle) {
00031         switch (*needle) {
00032         case '?':
00033             if (*haystack == '\0')
00034                 return false;
00035             ++haystack;
00036             break;
00037         case '*':
00038             if (needle[1] == '\0')
00039                 return true;
00040             max = strlen(haystack);
00041             for (i = 0; i < max; i++)
00042                 if (wild_match(haystack + i, needle + 1))
00043                     return true;
00044             return false;
00045         default:
00046             if (toupper(*haystack) != *needle)
00047                 return false;
00048             ++haystack;
00049         }
00050     }
00051     return *haystack == '\0';
00052 }
00053 
00054 bool WildFileCmp(const char * file, const char * wild) 
00055 {
00056         char file_name[9];
00057         char file_ext[4];
00058     char wild_name[10];
00059     char wild_ext[5];
00060         const char * find_ext;
00061         Bitu r;
00062 
00063     for (r=0;r<9;r++) {
00064         file_name[r]=0;
00065         wild_name[r]=0;
00066     }
00067     wild_name[9]=0;
00068     for (r=0;r<4;r++) {
00069         file_ext[r]=0;
00070         wild_ext[r]=0;
00071     }
00072     wild_ext[4]=0;
00073 
00074         find_ext=strrchr(file,'.');
00075         if (find_ext) {
00076                 Bitu size=(Bitu)(find_ext-file);
00077                 if (size>8) size=8;
00078                 memcpy(file_name,file,size);
00079                 find_ext++;
00080                 memcpy(file_ext,find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); 
00081         } else {
00082                 memcpy(file_name,file,(strlen(file) > 8) ? 8 : strlen(file));
00083         }
00084         upcase(file_name);upcase(file_ext);
00085         find_ext=strrchr(wild,'.');
00086         if (find_ext) {
00087                 Bitu size=(Bitu)(find_ext-wild);
00088                 if (size>9) size=9;
00089                 memcpy(wild_name,wild,size);
00090                 find_ext++;
00091                 memcpy(wild_ext,find_ext,(strlen(find_ext)>4) ? 4 : strlen(find_ext));
00092         } else {
00093                 memcpy(wild_name,wild,(strlen(wild) > 9) ? 9 : strlen(wild));
00094         }
00095         upcase(wild_name);upcase(wild_ext);
00096         /* Names are right do some checking */
00097         if (uselfn&&strchr(wild_name, '*')) {
00098                 if (strchr(wild,'.')) {
00099                         if (!wild_match(file_name, wild_name)) return false;
00100                         goto checkext;
00101                 } else
00102                         return wild_match((char *)file, wild_name);
00103         } else {
00104                 r=0;
00105                 while (r<8) {
00106                         if (wild_name[r]=='*') goto checkext;
00107                         if (wild_name[r]!='?' && wild_name[r]!=file_name[r]) return false;
00108                         r++;
00109                 }
00110                 if (wild_name[r]&&wild_name[r]!='*') return false;
00111         }
00112 checkext:
00113         if (uselfn&&strchr(wild_ext, '*'))
00114                 return wild_match(file_ext, wild_ext);
00115         else {
00116                 r=0;
00117                 while (r<3) {
00118                         if (wild_ext[r]=='*') return true;
00119                         if (wild_ext[r]!='?' && wild_ext[r]!=file_ext[r]) return false;
00120                         r++;
00121                 }
00122                 if (wild_ext[r]&&wild_ext[r]!='*') return false;
00123                 return true;
00124         }
00125 }
00126 
00127 bool LWildFileCmp(const char * file, const char * wild)
00128 {
00129     if (!uselfn||*file == 0) return false;
00130     char file_name[256];
00131     char file_ext[256];
00132     char wild_name[256];
00133     char wild_ext[256];
00134     const char * find_ext;
00135     Bitu r;
00136 
00137     for (r=0;r<256;r++) {
00138       file_name[r]=0;
00139       wild_name[r]=0;
00140     }
00141     for (r=0;r<256;r++) {
00142       file_ext[r]=0;
00143       wild_ext[r]=0;
00144     }
00145 
00146     Bitu size,elen;
00147     find_ext=strrchr(file,'.');
00148     if (find_ext) {
00149             size=(Bitu)(find_ext-file);
00150             if (size>255) size=255;
00151             memcpy(file_name,file,size);
00152             find_ext++;
00153             elen=strlen(find_ext);
00154             memcpy(file_ext,find_ext,(strlen(find_ext)>255) ? 255 : strlen(find_ext));
00155     } else {
00156             size=strlen(file);
00157             elen=0;
00158             memcpy(file_name,file,(strlen(file) > 255) ? 255 : strlen(file));
00159     }
00160     upcase(file_name);upcase(file_ext);
00161     char nwild[LFN_NAMELENGTH+2];
00162     strcpy(nwild,wild);
00163     if (strrchr(nwild,'*')&&strrchr(nwild,'.')==NULL) strcat(nwild,".*");
00164     find_ext=strrchr(nwild,'.');
00165     if (find_ext) {
00166             Bitu size=(Bitu)(find_ext-nwild);
00167             if (size>255) size=255;
00168             memcpy(wild_name,nwild,size);
00169             find_ext++;
00170             memcpy(wild_ext,find_ext,(strlen(find_ext)>255) ? 255 : strlen(find_ext));
00171     } else {
00172             memcpy(wild_name,nwild,(strlen(nwild) > 255) ? 255 : strlen(nwild));
00173     }
00174     upcase(wild_name);upcase(wild_ext);
00175     /* Names are right do some checking */
00176         if (strchr(wild_name, '*')) {
00177                 if (strchr(wild,'.')) {
00178                         if (!wild_match(file_name, wild_name)) return false;
00179                         goto checkext;
00180                 } else
00181                         return wild_match((char *)file, wild_name);
00182         } else {
00183                 r=0;
00184                 while (r<size) {
00185                                 if (wild_name[r]=='*') goto checkext;
00186                                 if (wild_name[r]!='?' && wild_name[r]!=file_name[r]) return false;
00187                                 r++;
00188                 }
00189                 if (wild_name[r]&&wild_name[r]!='*') return false;
00190         }
00191 checkext:
00192         if (strchr(wild_ext, '*'))
00193                 return wild_match(file_ext, wild_ext);
00194         else {
00195                 r=0;
00196                 while (r<elen) {
00197                                 if (wild_ext[r]=='*') return true;
00198                                 if (wild_ext[r]!='?' && wild_ext[r]!=file_ext[r]) return false;
00199                                 r++;
00200                 }
00201                 if (wild_ext[r]&&wild_ext[r]!='*') return false;
00202                 return true;
00203         }
00204 }
00205 
00206 void Set_Label(char const * const input, char * const output, bool cdrom) {
00207     /* I don't know what MSCDEX.EXE does but don't put dots in the 11-char volume label for non-CD-ROM drives */
00208     if (!cdrom) {
00209         Bitu togo     = 11;
00210         Bitu vnamePos = 0;
00211         Bitu labelPos = 0;
00212 
00213         while (togo > 0) {
00214             if (input[vnamePos]==0) break;
00215             //Another mscdex quirk. Label is not always uppercase. (Daggerfall)
00216             output[labelPos] = toupper(input[vnamePos]);
00217             labelPos++;
00218             vnamePos++;
00219             togo--;
00220         }
00221         output[labelPos] = 0;
00222         return;
00223     }
00224 
00225         Bitu togo     = 8;
00226         Bitu vnamePos = 0;
00227         Bitu labelPos = 0;
00228         bool point    = false;
00229 
00230         //spacepadding the filenamepart to include spaces after the terminating zero is more closely to the specs. (not doing this now)
00231         // HELLO\0' '' '
00232 
00233         while (togo > 0) {
00234                 if (input[vnamePos]==0) break;
00235                 if (!point && (input[vnamePos]=='.')) { togo=4; point=true; }
00236 
00237                 output[labelPos] = input[vnamePos];
00238 
00239                 labelPos++; vnamePos++;
00240                 togo--;
00241                 if ((togo==0) && !point) {
00242                         if (input[vnamePos]=='.') vnamePos++;
00243                         output[labelPos]='.'; labelPos++; point=true; togo=3;
00244                 }
00245         }
00246         output[labelPos]=0;
00247 
00248         //Remove trailing dot. except when on cdrom and filename is exactly 8 (9 including the dot) letters. MSCDEX feature/bug (fifa96 cdrom detection)
00249         if((labelPos > 0) && (output[labelPos-1] == '.') && !(cdrom && labelPos ==9))
00250                 output[labelPos-1] = 0;
00251 }
00252 
00253 
00254 
00255 DOS_Drive::DOS_Drive() {
00256     nocachedir=false;
00257     readonly=false;
00258         curdir[0]=0;
00259         info[0]=0;
00260 }
00261 
00262 const char * DOS_Drive::GetInfo(void) {
00263         return info;
00264 }
00265 
00266 // static members variables
00267 int DriveManager::currentDrive;
00268 DriveManager::DriveInfo DriveManager::driveInfos[26];
00269 
00270 void DriveManager::AppendDisk(int drive, DOS_Drive* disk) {
00271         driveInfos[drive].disks.push_back(disk);
00272 }
00273 
00274 void DriveManager::InitializeDrive(int drive) {
00275         currentDrive = drive;
00276         DriveInfo& driveInfo = driveInfos[currentDrive];
00277         if (driveInfo.disks.size() > 0) {
00278                 driveInfo.currentDisk = 0;
00279                 DOS_Drive* disk = driveInfo.disks[driveInfo.currentDisk];
00280                 Drives[currentDrive] = disk;
00281                 if (driveInfo.disks.size() > 1) disk->Activate();
00282         disk->UpdateDPB(currentDrive);
00283     }
00284 }
00285 
00286 /*
00287 void DriveManager::CycleDrive(bool pressed) {
00288         if (!pressed) return;
00289                 
00290         // do one round through all drives or stop at the next drive with multiple disks
00291         int oldDrive = currentDrive;
00292         do {
00293                 currentDrive = (currentDrive + 1) % DOS_DRIVES;
00294                 int numDisks = driveInfos[currentDrive].disks.size();
00295                 if (numDisks > 1) break;
00296         } while (currentDrive != oldDrive);
00297 }
00298 
00299 void DriveManager::CycleDisk(bool pressed) {
00300         if (!pressed) return;
00301         
00302         int numDisks = driveInfos[currentDrive].disks.size();
00303         if (numDisks > 1) {
00304                 // cycle disk
00305                 int currentDisk = driveInfos[currentDrive].currentDisk;
00306                 DOS_Drive* oldDisk = driveInfos[currentDrive].disks[currentDisk];
00307                 currentDisk = (currentDisk + 1) % numDisks;             
00308                 DOS_Drive* newDisk = driveInfos[currentDrive].disks[currentDisk];
00309                 driveInfos[currentDrive].currentDisk = currentDisk;
00310                 
00311                 // copy working directory, acquire system resources and finally switch to next drive            
00312                 strcpy(newDisk->curdir, oldDisk->curdir);
00313                 newDisk->Activate();
00314                 Drives[currentDrive] = newDisk;
00315         }
00316 }
00317 */
00318 
00319 void DriveManager::CycleDisks(int drive, bool notify) {
00320         unsigned int numDisks = (unsigned int)driveInfos[drive].disks.size();
00321         if (numDisks > 1) {
00322                 // cycle disk
00323                 unsigned int currentDisk = (unsigned int)driveInfos[drive].currentDisk;
00324         const DOS_Drive* oldDisk = driveInfos[drive].disks[(unsigned int)currentDisk];
00325                 currentDisk = ((unsigned int)currentDisk + 1u) % (unsigned int)numDisks;
00326                 DOS_Drive* newDisk = driveInfos[drive].disks[currentDisk];
00327                 driveInfos[drive].currentDisk = currentDisk;
00328                 
00329                 // copy working directory, acquire system resources and finally switch to next drive            
00330                 strcpy(newDisk->curdir, oldDisk->curdir);
00331                 newDisk->Activate();
00332         newDisk->UpdateDPB(currentDrive);
00333                 Drives[drive] = newDisk;
00334                 if (notify) LOG_MSG("Drive %c: disk %d of %d now active", 'A'+drive, currentDisk+1, numDisks);
00335         }
00336 }
00337 
00338 void DriveManager::CycleAllDisks(void) {
00339         for (int idrive=0; idrive<2; idrive++) CycleDisks(idrive, true); /* Cycle all DISKS meaning A: and B: */
00340 }
00341 
00342 void DriveManager::CycleAllCDs(void) {
00343         for (unsigned int idrive=2; idrive<DOS_DRIVES; idrive++) { /* Cycle all CDs in C: D: ... Z: */
00344                 unsigned int numDisks = (unsigned int)driveInfos[idrive].disks.size();
00345                 if (numDisks > 1) {
00346                         // cycle disk
00347                         unsigned int currentDisk = driveInfos[idrive].currentDisk;
00348             const DOS_Drive* oldDisk = driveInfos[idrive].disks[currentDisk];
00349                         currentDisk = ((unsigned int)currentDisk + 1u) % (unsigned int)numDisks;                
00350                         DOS_Drive* newDisk = driveInfos[idrive].disks[currentDisk];
00351                         driveInfos[idrive].currentDisk = currentDisk;
00352                         
00353                         // copy working directory, acquire system resources and finally switch to next drive            
00354                         strcpy(newDisk->curdir, oldDisk->curdir);
00355                         newDisk->Activate();
00356             newDisk->UpdateDPB(currentDrive);
00357             Drives[idrive] = newDisk;
00358                         LOG_MSG("Drive %c: disk %d of %d now active", 'A'+idrive, currentDisk+1, numDisks);
00359                 }
00360         }
00361 }
00362 
00363 int DriveManager::UnmountDrive(int drive) {
00364         int result = 0;
00365         // unmanaged drive
00366         if (driveInfos[drive].disks.size() == 0) {
00367                 result = (int)Drives[drive]->UnMount();
00368         } else {
00369                 // managed drive
00370                 unsigned int currentDisk = driveInfos[drive].currentDisk;
00371                 result = (int)driveInfos[drive].disks[currentDisk]->UnMount();
00372                 // only delete on success, current disk set to NULL because of UnMount
00373                 if (result == 0) {
00374                         driveInfos[drive].disks[currentDisk] = NULL;
00375                         for (unsigned int i = 0; i < (unsigned int)driveInfos[drive].disks.size(); i++) {
00376                                 delete driveInfos[drive].disks[i];
00377                         }
00378                         driveInfos[drive].disks.clear();
00379                 }
00380         }
00381         
00382         return result;
00383 }
00384 
00385 bool drivemanager_init = false;
00386 bool int13_extensions_enable = true;
00387 
00388 void DriveManager::Init(Section* s) {
00389     const Section_prop* section = static_cast<Section_prop*>(s);
00390 
00391         drivemanager_init = true;
00392 
00393         int13_extensions_enable = section->Get_bool("int 13 extensions");
00394         
00395         // setup driveInfos structure
00396         currentDrive = 0;
00397         for(int i = 0; i < DOS_DRIVES; i++) {
00398                 driveInfos[i].currentDisk = 0;
00399         }
00400         
00401 //      MAPPER_AddHandler(&CycleDisk, MK_f3, MMOD1, "cycledisk", "Cycle Disk");
00402 //      MAPPER_AddHandler(&CycleDrive, MK_f3, MMOD2, "cycledrive", "Cycle Drv");
00403 }
00404 
00405 void DRIVES_Startup(Section *s) {
00406     (void)s;//UNUSED
00407         if (!drivemanager_init) {
00408                 LOG(LOG_MISC,LOG_DEBUG)("Initializing drive system");
00409                 DriveManager::Init(control->GetSection("dos"));
00410         }
00411 }
00412 
00413 void DRIVES_Init() {
00414         LOG(LOG_MISC,LOG_DEBUG)("Initializing OOS drives");
00415 
00416         // TODO: DOS kernel exit, reset, guest booting handler
00417 }
00418 
00419 char * DOS_Drive::GetBaseDir(void) {
00420         return info + 16;
00421 }
00422 
00423 // save state support
00424 void DOS_Drive::SaveState( std::ostream& stream )
00425 {
00426         // - pure data
00427         WRITE_POD( &curdir, curdir );
00428         WRITE_POD( &info, info );
00429 }
00430 
00431 void DOS_Drive::LoadState( std::istream& stream )
00432 {
00433         // - pure data
00434         READ_POD( &curdir, curdir );
00435         READ_POD( &info, info );
00436 }
00437 
00438 void DriveManager::SaveState( std::ostream& stream )
00439 {
00440         // - pure data
00441         WRITE_POD( &currentDrive, currentDrive );
00442 }
00443 
00444 void DriveManager::LoadState( std::istream& stream )
00445 {
00446         // - pure data
00447         READ_POD( &currentDrive, currentDrive );
00448 }
00449 
00450 void POD_Save_DOS_DriveManager( std::ostream& stream )
00451 {
00452         DriveManager::SaveState(stream);
00453 }
00454 
00455 void POD_Load_DOS_DriveManager( std::istream& stream )
00456 {
00457         DriveManager::LoadState(stream);
00458 }