DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/dos/drive_virtual.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 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <time.h>
00023 #include "dosbox.h"
00024 #include "dos_inc.h"
00025 #include "drives.h"
00026 #include "support.h"
00027 #include "control.h"
00028 #include "cross.h"
00029 #include "regs.h"
00030 
00031 struct VFILE_Block {
00032         const char * name;
00033         const char * lname;
00034         Bit8u * data;
00035         Bit32u size;
00036         Bit16u date;
00037         Bit16u time;
00038         VFILE_Block * next;
00039 };
00040 
00041 extern int lfn_filefind_handle;
00042 static VFILE_Block * first_file, * lfn_search[256];
00043 
00044 void VFILE_Shutdown(void) {
00045         LOG(LOG_MISC,LOG_DEBUG)("Shutting down VFILE system");
00046 
00047         while (first_file != NULL) {
00048                 VFILE_Block *n = first_file->next;
00049                 delete first_file;
00050                 first_file = n;
00051         }
00052 }
00053 
00054 void VFILE_RegisterBuiltinFileBlob(const struct BuiltinFileBlob &b) {
00055         VFILE_Register(b.recommended_file_name, (Bit8u*)b.data, (Bit32u)b.length);
00056 }
00057 
00058 void VFILE_Register(const char * name,Bit8u * data,Bit32u size) {
00059         VFILE_Block * new_file=new VFILE_Block;
00060         new_file->name=name;
00061         new_file->lname=name;
00062         new_file->data=data;
00063         new_file->size=size;
00064         new_file->date=DOS_PackDate(2002,10,1);
00065         new_file->time=DOS_PackTime(12,34,56);
00066         new_file->next=first_file;
00067         first_file=new_file;
00068 }
00069 
00070 void VFILE_Remove(const char *name) {
00071         VFILE_Block * chan=first_file;
00072         VFILE_Block * * where=&first_file;
00073         while (chan) {
00074                 if (strcmp(name,chan->name) == 0) {
00075                         *where = chan->next;
00076                         if(chan == first_file) first_file = chan->next;
00077                         delete chan;
00078                         return;
00079                 }
00080                 where=&chan->next;
00081                 chan=chan->next;
00082         }
00083 }
00084 
00085 class Virtual_File : public DOS_File {
00086 public:
00087         Virtual_File(Bit8u * in_data,Bit32u in_size);
00088         bool Read(Bit8u * data,Bit16u * size);
00089         bool Write(const Bit8u * data,Bit16u * size);
00090         bool Seek(Bit32u * new_pos,Bit32u type);
00091         bool Close();
00092         Bit16u GetInformation(void);
00093 private:
00094         Bit32u file_size;
00095     Bit32u file_pos = 0;
00096         Bit8u * file_data;
00097 };
00098 
00099 
00100 Virtual_File::Virtual_File(Bit8u* in_data, Bit32u in_size) : file_size(in_size), file_data(in_data) {
00101         date=DOS_PackDate(2002,10,1);
00102         time=DOS_PackTime(12,34,56);
00103         open=true;
00104 }
00105 
00106 bool Virtual_File::Read(Bit8u * data,Bit16u * size) {
00107         Bit32u left=file_size-file_pos;
00108         if (left<=*size) { 
00109                 memcpy(data,&file_data[file_pos],left);
00110                 *size=(Bit16u)left;
00111         } else {
00112                 memcpy(data,&file_data[file_pos],*size);
00113         }
00114         file_pos+=*size;
00115         return true;
00116 }
00117 
00118 bool Virtual_File::Write(const Bit8u * data,Bit16u * size){
00119     (void)data;//UNUSED
00120     (void)size;//UNUSED
00121         /* Not really writable */
00122         return false;
00123 }
00124 
00125 bool Virtual_File::Seek(Bit32u * new_pos,Bit32u type){
00126         switch (type) {
00127         case DOS_SEEK_SET:
00128                 if (*new_pos<=file_size) file_pos=*new_pos;
00129                 else return false;
00130                 break;
00131         case DOS_SEEK_CUR:
00132                 if ((*new_pos+file_pos)<=file_size) file_pos=*new_pos+file_pos;
00133                 else return false;
00134                 break;
00135         case DOS_SEEK_END:
00136                 if (*new_pos<=file_size) file_pos=file_size-*new_pos;
00137                 else return false;
00138                 break;
00139         }
00140         *new_pos=file_pos;
00141         return true;
00142 }
00143 
00144 bool Virtual_File::Close(){
00145         return true;
00146 }
00147 
00148 
00149 Bit16u Virtual_File::GetInformation(void) {
00150         return 0x40;    // read-only drive
00151 }
00152 
00153 
00154 Virtual_Drive::Virtual_Drive() {
00155         strcpy(info,"Internal Virtual Drive");
00156         for (int i=0; i<256; i++) lfn_search[i] = 0;
00157 }
00158 
00159 
00160 bool Virtual_Drive::FileOpen(DOS_File * * file,const char * name,Bit32u flags) {
00161 /* Scan through the internal list of files */
00162     const VFILE_Block* cur_file = first_file;
00163         while (cur_file) {
00164                 if (strcasecmp(name,cur_file->name)==0) {
00165                 /* We have a match */
00166                         *file=new Virtual_File(cur_file->data,cur_file->size);
00167                         (*file)->flags=flags;
00168                         return true;
00169                 }
00170                 cur_file=cur_file->next;
00171         }
00172         return false;
00173 }
00174 
00175 bool Virtual_Drive::FileCreate(DOS_File * * file,const char * name,Bit16u attributes) {
00176     (void)file;//UNUSED
00177     (void)name;//UNUSED
00178     (void)attributes;//UNUSED
00179         return false;
00180 }
00181 
00182 bool Virtual_Drive::FileUnlink(const char * name) {
00183     const VFILE_Block* cur_file = first_file;
00184         while (cur_file) {
00185                 if (strcasecmp(name,cur_file->name)==0) {
00186                         DOS_SetError(DOSERR_ACCESS_DENIED);
00187                         return false;
00188                 }
00189                 cur_file=cur_file->next;
00190         }
00191         return false;
00192 }
00193 
00194 bool Virtual_Drive::RemoveDir(const char * dir) {
00195     (void)dir;//UNUSED
00196         return false;
00197 }
00198 
00199 bool Virtual_Drive::MakeDir(const char * dir) {
00200     (void)dir;//UNUSED
00201         return false;
00202 }
00203 
00204 bool Virtual_Drive::TestDir(const char * dir) {
00205         if (!dir[0]) return true;               //only valid dir is the empty dir
00206         return false;
00207 }
00208 
00209 bool Virtual_Drive::FileStat(const char* name, FileStat_Block * const stat_block){
00210     const VFILE_Block* cur_file = first_file;
00211         while (cur_file) {
00212                 if (strcasecmp(name,cur_file->name)==0) {
00213                         stat_block->attr=DOS_ATTR_ARCHIVE;
00214                         stat_block->size=cur_file->size;
00215                         stat_block->date=DOS_PackDate(2002,10,1);
00216                         stat_block->time=DOS_PackTime(12,34,56);
00217                         return true;
00218                 }
00219                 cur_file=cur_file->next;
00220         }
00221         return false;
00222 }
00223 
00224 bool Virtual_Drive::FileExists(const char* name){
00225     const VFILE_Block* cur_file = first_file;
00226         while (cur_file) {
00227                 if (strcasecmp(name,cur_file->name)==0) return true;
00228                 cur_file=cur_file->next;
00229         }
00230         return false;
00231 }
00232 
00233 bool Virtual_Drive::FindFirst(const char * _dir,DOS_DTA & dta,bool fcb_findfirst) {
00234     (void)_dir;//UNUSED
00235         if (lfn_filefind_handle>=LFN_FILEFIND_MAX)
00236                 search_file=first_file;
00237         else
00238                 lfn_search[lfn_filefind_handle]=first_file;
00239         Bit8u attr;char pattern[CROSS_LEN];
00240     dta.GetSearchParams(attr,pattern,uselfn);
00241         if (attr == DOS_ATTR_VOLUME) {
00242                 dta.SetResult(GetLabel(),GetLabel(),0,0,0,DOS_ATTR_VOLUME);
00243                 return true;
00244         } else if ((attr & DOS_ATTR_VOLUME) && !fcb_findfirst) {
00245                 if (WildFileCmp(GetLabel(),pattern)) {
00246                         dta.SetResult(GetLabel(),GetLabel(),0,0,0,DOS_ATTR_VOLUME);
00247                         return true;
00248                 }
00249         }
00250         return FindNext(dta);
00251 }
00252 
00253 bool Virtual_Drive::FindNext(DOS_DTA & dta) {   Bit8u attr;char pattern[CROSS_LEN];
00254     dta.GetSearchParams(attr,pattern,uselfn);
00255         if (lfn_filefind_handle>=LFN_FILEFIND_MAX)
00256                 while (search_file) {
00257                         if (WildFileCmp(search_file->name,pattern)) {
00258                                 dta.SetResult(search_file->name,search_file->lname,search_file->size,search_file->date,search_file->time,DOS_ATTR_ARCHIVE);
00259                                 search_file=search_file->next;
00260                                 return true;
00261                         }
00262                         search_file=search_file->next;
00263                 }
00264         else
00265                 while (lfn_search[lfn_filefind_handle]) {
00266                         if (WildFileCmp(lfn_search[lfn_filefind_handle]->name,pattern)) {
00267                                 dta.SetResult(lfn_search[lfn_filefind_handle]->name,lfn_search[lfn_filefind_handle]->lname,lfn_search[lfn_filefind_handle]->size,lfn_search[lfn_filefind_handle]->date,lfn_search[lfn_filefind_handle]->time,DOS_ATTR_ARCHIVE);
00268                                 lfn_search[lfn_filefind_handle]=lfn_search[lfn_filefind_handle]->next;
00269                                 return true;
00270                         }
00271                         lfn_search[lfn_filefind_handle]=lfn_search[lfn_filefind_handle]->next;
00272                 }
00273         DOS_SetError(DOSERR_NO_MORE_FILES);
00274         return false;
00275 }
00276 
00277 bool Virtual_Drive::SetFileAttr(const char * name,Bit16u attr) {
00278     (void)name;
00279     (void)attr;
00280         return false;
00281 }
00282 
00283 bool Virtual_Drive::GetFileAttr(const char * name,Bit16u * attr) {
00284     const VFILE_Block* cur_file = first_file;
00285         while (cur_file) {
00286                 if (strcasecmp(name,cur_file->name)==0) { 
00287                         *attr = DOS_ATTR_ARCHIVE;       //Maybe readonly ?
00288                         return true;
00289                 }
00290                 cur_file=cur_file->next;
00291         }
00292         return false;
00293 }
00294 
00295 bool Virtual_Drive::GetFileAttrEx(char* name, struct stat *status) {
00296     (void)name;
00297     (void)status;
00298         return false;
00299 }
00300 
00301 unsigned long Virtual_Drive::GetCompressedSize(char* name) {
00302     (void)name;
00303         return 0;
00304 }
00305 
00306 #if defined (WIN32)
00307 HANDLE Virtual_Drive::CreateOpenFile(const char* name) {
00308     (void)name;
00309         DOS_SetError(1);
00310         return INVALID_HANDLE_VALUE;
00311 }
00312 #endif
00313 
00314 bool Virtual_Drive::Rename(const char * oldname,const char * newname) {
00315     (void)newname;//UNUSED
00316     const VFILE_Block* cur_file = first_file;
00317         while (cur_file) {
00318                 if (strcasecmp(oldname,cur_file->name)==0) {
00319                         DOS_SetError(DOSERR_ACCESS_DENIED);
00320                         return false;
00321                 }
00322                 cur_file=cur_file->next;
00323         }
00324         return false;
00325 }
00326 
00327 bool Virtual_Drive::AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) {
00328         *_bytes_sector=512;
00329         *_sectors_cluster=32;
00330         *_total_clusters=32765; // total size is always 500 mb
00331         *_free_clusters=0;              // nothing free here
00332         return true;
00333 }
00334 
00335 Bit8u Virtual_Drive::GetMediaByte(void) {
00336         return 0xF8;
00337 }
00338 
00339 bool Virtual_Drive::isRemote(void) {
00340     const Section_prop * section=static_cast<Section_prop *>(control->GetSection("dos"));
00341     const char * opt = section->Get_string("drive z is remote");
00342 
00343     if (!strcmp(opt,"1") || !strcmp(opt,"true")) {
00344         return true;
00345     }
00346     else if (!strcmp(opt,"0") || !strcmp(opt,"false")) {
00347         return false;
00348     }
00349         char psp_name[9];
00350         DOS_MCB psp_mcb(dos.psp()-1);
00351         psp_mcb.GetFileName(psp_name);
00352         if (strcmp(psp_name, "SCANDISK") == 0) {
00353                 /* Check for SCANDISK.EXE and return true (Wengier) */
00354                 return true;
00355         }
00356         /* Automatically detect if called by SCANDISK.EXE even if it is renamed (tested with the program from MS-DOS 6.20 to Windows ME) */
00357     if (dos.version.major >= 5 && reg_sp >=0x4000 && mem_readw(SegPhys(ss)+reg_sp)/0x100 == 0x1 && mem_readw(SegPhys(ss)+reg_sp+2)/0x100 >= 0xB && mem_readw(SegPhys(ss)+reg_sp+2)/0x100 <= 0x12)
00358                 return true;
00359 
00360         return false;
00361 }
00362 
00363 bool Virtual_Drive::isRemovable(void) {
00364         return false;
00365 }
00366 
00367 Bits Virtual_Drive::UnMount(void) {
00368         return 1;
00369 }
00370 
00371 char const* Virtual_Drive::GetLabel(void) {
00372         return "DOSBOX-X";
00373 }