dosbox-x/src/dos/drive_virtual.cpp
Jaak Ristioja 39906a9399
Add override keyword, clean up virtual keyword
Also removed virtual and override keywords from destructors which already
override.
2024-03-21 21:45:16 +02:00

717 lines
25 KiB
C++

/*
* Copyright (C) 2002-2021 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "dosbox.h"
#include "dos_inc.h"
#include "drives.h"
#include "logging.h"
#include "support.h"
#include "control.h"
#include "cross.h"
#include "regs.h"
extern bool gbk, isDBCSCP(), isKanji1_gbk(uint8_t chr), shiftjis_lead_byte(int c);
struct VFILE_Block {
const char * name;
const char * lname;
uint8_t * data;
uint32_t size;
uint16_t date;
uint16_t time;
unsigned int onpos;
bool isdir;
bool hidden;
bool intprog;
VFILE_Block * next;
};
#define MAX_VFILES 500
unsigned int vfpos=1, lfn_id[256];
bool internal_program = false, skipintprog = false;
char sfn[DOS_NAMELENGTH_ASCII],vfnames[MAX_VFILES][CROSS_LEN],vfsnames[MAX_VFILES][DOS_NAMELENGTH_ASCII];
static VFILE_Block * first_file, * lfn_search[256], * parent_dir = NULL;
extern int lfn_filefind_handle;
extern bool filename_not_8x3(const char *n), filename_not_strict_8x3(const char *n);
extern void Add_VFiles(bool usecp), PROGRAMS_Shutdown(void);
extern char * DBCS_upcase(char * str);
std::string hidefiles="";
/* Generate 8.3 names from LFNs, with tilde usage (from ~1 to ~999999). */
void GenerateSFN(char *lfn, unsigned int k, unsigned int &i, unsigned int &t) {
char *n=lfn;
if (t>strlen(n)||k==1||k==10||k==100||k==1000||k==10000||k==100000) {
i=0;
*sfn=0;
while (*n == '.'||*n == ' ') n++;
while (strlen(n)&&(*(n+strlen(n)-1)=='.'||*(n+strlen(n)-1)==' ')) *(n+strlen(n)-1)=0;
bool lead = false;
unsigned int m = k<10?6u:(k<100?5u:(k<1000?4u:(k<10000?3u:(k<100000?2u:1u))));
while (*n != 0 && *n != '.' && i < m) {
if (*n == ' ') {
n++;
lead = false;
continue;
}
if (!lead && ((IS_PC98_ARCH && shiftjis_lead_byte(*n & 0xFF)) || (isDBCSCP() && isKanji1_gbk(*n & 0xFF)))) {
if (i==m-1) break;
sfn[i++]=*(n++);
lead = true;
} else if (*n=='"'||*n=='+'||*n=='='||*n==','||*n==';'||*n==':'||*n=='<'||*n=='>'||((*n=='['||*n==']'||*n=='|'||*n=='\\')&&(!lead||((dos.loaded_codepage==936||IS_PDOSV)&&!gbk)))||*n=='?'||*n=='*') {
sfn[i++]='_';
n++;
lead = false;
} else {
sfn[i++]=lead?*n:toupper(*n);
n++;
lead = false;
}
}
sfn[i++]='~';
t=i;
} else
i=t;
if (k<10)
sfn[i++]='0'+k;
else if (k<100) {
sfn[i++]='0'+(k/10);
sfn[i++]='0'+(k%10);
} else if (k<1000) {
sfn[i++]='0'+(k/100);
sfn[i++]='0'+((k%100)/10);
sfn[i++]='0'+(k%10);
} else if (k<10000) {
sfn[i++]='0'+(k/1000);
sfn[i++]='0'+((k%1000)/100);
sfn[i++]='0'+((k%100)/10);
sfn[i++]='0'+(k%10);
} else if (k<100000) {
sfn[i++]='0'+(k/10000);
sfn[i++]='0'+((k%10000)/1000);
sfn[i++]='0'+((k%1000)/100);
sfn[i++]='0'+((k%100)/10);
sfn[i++]='0'+(k%10);
} else {
sfn[i++]='0'+(k/100000);
sfn[i++]='0'+((k%100000)/10000);
sfn[i++]='0'+((k%10000)/1000);
sfn[i++]='0'+((k%1000)/100);
sfn[i++]='0'+((k%100)/10);
sfn[i++]='0'+(k%10);
}
if (t>strlen(n)||k==1||k==10||k==100||k==1000||k==10000||k==100000) {
char *p=strrchr(n, '.');
if (p!=NULL) {
sfn[i++]='.';
n=p+1;
while (*n == '.') n++;
int j=0;
bool lead = false;
while (*n != 0 && j++<3) {
if (*n == ' ') {
n++;
lead = false;
continue;
}
if (!lead && ((IS_PC98_ARCH && shiftjis_lead_byte(*n & 0xFF)) || (isDBCSCP() && isKanji1_gbk(*n & 0xFF)))) {
if (j==3) break;
sfn[i++]=*(n++);
lead = true;
} else if (*n=='"'||*n=='+'||*n=='='||*n==','||*n==';'||*n==':'||*n=='<'||*n=='>'||((*n=='['||*n==']'||*n=='|'||*n=='\\')&&(!lead||((dos.loaded_codepage==936||IS_PDOSV)&&!gbk)))||*n=='?'||*n=='*') {
sfn[i++]='_';
n++;
lead = false;
} else {
sfn[i++]=lead?*n:toupper(*n);
n++;
lead = false;
}
}
}
sfn[i++]=0;
}
}
char* VFILE_Generate_SFN(const char *name, unsigned int onpos) {
if (!filename_not_8x3(name)) {
strcpy(sfn, name);
DBCS_upcase(sfn);
return sfn;
}
char lfn[LFN_NAMELENGTH+1];
if (name==NULL||!*name) return NULL;
if (strlen(name)>LFN_NAMELENGTH) {
strncpy(lfn, name, LFN_NAMELENGTH);
lfn[LFN_NAMELENGTH]=0;
} else
strcpy(lfn, name);
if (!strlen(lfn)) return NULL;
unsigned int k=1, i, t=1000000;
const VFILE_Block* cur_file;
while (k<1000000) {
GenerateSFN(lfn, k, i, t);
cur_file = first_file;
bool found=false;
while (cur_file) {
if (onpos==cur_file->onpos&&(strcasecmp(sfn,cur_file->name)==0||(uselfn&&strcasecmp(sfn,cur_file->lname)==0))) {found=true;break;}
cur_file=cur_file->next;
}
if (!found) return sfn;
k++;
}
return 0;
}
void VFILE_Shutdown(void) {
LOG(LOG_DOSMISC,LOG_DEBUG)("Shutting down VFILE system");
if (parent_dir != NULL) {
delete parent_dir;
parent_dir = NULL;
}
while (first_file != NULL) {
VFILE_Block *n = first_file->next;
delete first_file;
first_file = n;
}
vfpos=1;
}
void VFILE_RegisterBuiltinFileBlob(const struct BuiltinFileBlob &b, const char *dir) {
VFILE_Register(b.recommended_file_name, (uint8_t*)b.data, (uint32_t)b.length, dir);
}
uint16_t fztime=0, fzdate=0;
void VFILE_Register(const char * name,uint8_t * data,uint32_t size,const char *dir) {
if (vfpos>=MAX_VFILES) return;
std::istringstream in(hidefiles);
bool hidden=false;
bool isdir=!strcmp(dir,"/")||!strcmp(name,".")||!strcmp(name,"..");
unsigned int onpos=0;
char fullname[CROSS_LEN], fullsname[CROSS_LEN];
if (strlen(dir)>2&&dir[0]=='/'&&dir[strlen(dir)-1]=='/') {
for (unsigned int i=1; i<vfpos; i++)
if (!strcasecmp((std::string(vfsnames[i])+"/").c_str(), dir+1)||!strcasecmp((std::string(vfnames[i])+"/").c_str(), dir+1)) {
onpos=i;
break;
}
if (onpos==0) return;
}
const VFILE_Block* cur_file = first_file;
while (cur_file) {
if (onpos==cur_file->onpos&&(strcasecmp(name,cur_file->name)==0||(uselfn&&strcasecmp(name,cur_file->name)==0))) return;
cur_file=cur_file->next;
}
std::string sname=filename_not_strict_8x3(name)?VFILE_Generate_SFN(name,onpos):name;
if (in) for (std::string file; in >> file; ) {
if (strlen(dir)>2&&dir[0]=='/'&&dir[strlen(dir)-1]=='/') {
strncpy(fullname, dir+1, strlen(dir)-2);
*(fullname+strlen(dir)-2)=0;
strcat(fullname, "\\");
strcpy(fullsname, "\\");
strcat(fullsname, sname.c_str());
strcat(fullname, name);
} else {
strcpy(fullname, name);
strcpy(fullsname, sname.c_str());
}
if (!strcasecmp(fullname,file.c_str())||!strcasecmp(("\""+std::string(fullname)+"\"").c_str(),file.c_str())
|| !strcasecmp(fullsname,file.c_str())||!strcasecmp(("\""+std::string(fullsname)+"\"").c_str(),file.c_str()))
return;
if (!strcasecmp(("/"+std::string(fullname)).c_str(),file.c_str())||!strcasecmp(("/\""+std::string(fullname)+"\"").c_str(),file.c_str())
|| !strcasecmp(("/"+std::string(fullsname)).c_str(),file.c_str())||!strcasecmp(("/\""+std::string(fullsname)+"\"").c_str(),file.c_str())) {
hidden=true;
break;
}
}
strcpy(vfnames[vfpos],name);
strcpy(vfsnames[vfpos],sname.c_str());
if (!strlen(trim(vfnames[vfpos]))||!strlen(trim(vfsnames[vfpos]))) return;
VFILE_Block * new_file=new VFILE_Block;
new_file->name=vfsnames[vfpos];
new_file->lname=vfnames[vfpos];
vfpos++;
new_file->intprog = internal_program;
new_file->data=data;
new_file->size=size;
new_file->date=fztime||fzdate?fzdate:DOS_PackDate(2002,10,1);
new_file->time=fztime||fzdate?fztime:DOS_PackTime(12,34,56);
new_file->onpos=onpos;
new_file->isdir=isdir;
new_file->hidden=hidden;
new_file->next=first_file;
first_file=new_file;
}
void VFILE_Remove(const char *name,const char *dir = "") {
unsigned int onpos=0;
if (*dir) {
for (unsigned int i=1; i<vfpos; i++)
if (!strcasecmp(vfsnames[i], dir)||!strcasecmp(vfnames[i], dir)) {
onpos=i;
break;
}
if (onpos==0) return;
}
VFILE_Block * chan=first_file;
VFILE_Block * * where=&first_file;
while (chan) {
if (onpos==chan->onpos && (strcmp(name,chan->name) == 0 || strcmp(name,chan->lname) == 0)) {
*where = chan->next;
if(chan == first_file) first_file = chan->next;
delete chan;
return;
}
where=&chan->next;
chan=chan->next;
}
}
uint32_t VFILE_GetCPIData(const char *filename, std::vector<uint8_t> &cpibuf) {
if (!*filename) return 0;
unsigned int onpos=0;
for (unsigned int i=1; i<vfpos; i++)
if (!strcasecmp(vfsnames[i], "CPI")||!strcasecmp(vfnames[i], "CPI")) {
onpos=i;
break;
}
if (onpos==0) return 0;
VFILE_Block * chan=first_file;
while (chan) {
if (onpos==chan->onpos && (strcmp(filename,chan->name) == 0 || strcmp(filename,chan->lname) == 0)) {
if (chan->size>65535) return 0;
for (size_t bct=0; bct<chan->size; bct++) cpibuf.push_back(chan->data[bct]);
return chan->size;
}
chan=chan->next;
}
return 0;
}
class Virtual_File : public DOS_File {
public:
Virtual_File(uint8_t * in_data,uint32_t in_size);
bool Read(uint8_t * data,uint16_t * size) override;
bool Write(const uint8_t * data,uint16_t * size) override;
bool Seek(uint32_t * new_pos,uint32_t type) override;
bool Close() override;
uint16_t GetInformation(void) override;
private:
uint32_t file_size;
uint32_t file_pos = 0;
uint8_t * file_data;
};
Virtual_File::Virtual_File(uint8_t* in_data, uint32_t in_size) : file_size(in_size), file_data(in_data) {
date=DOS_PackDate(2002,10,1);
time=DOS_PackTime(12,34,56);
open=true;
}
bool Virtual_File::Read(uint8_t * data,uint16_t * size) {
uint32_t left=file_size-file_pos;
if (left<=*size) {
memcpy(data,&file_data[file_pos],left);
*size=(uint16_t)left;
} else {
memcpy(data,&file_data[file_pos],*size);
}
file_pos+=*size;
return true;
}
bool Virtual_File::Write(const uint8_t * data,uint16_t * size){
(void)data;//UNUSED
(void)size;//UNUSED
/* Not really writable */
return false;
}
bool Virtual_File::Seek(uint32_t * new_pos,uint32_t type){
switch (type) {
case DOS_SEEK_SET:
if (*new_pos<=file_size) file_pos=*new_pos;
else return false;
break;
case DOS_SEEK_CUR:
if ((*new_pos+file_pos)<=file_size) file_pos=*new_pos+file_pos;
else return false;
break;
case DOS_SEEK_END:
if (*new_pos<=file_size) file_pos=file_size-*new_pos;
else return false;
break;
}
*new_pos=file_pos;
return true;
}
bool Virtual_File::Close(){
return true;
}
uint16_t Virtual_File::GetInformation(void) {
return DeviceInfoFlags::NotWritten; // read-only drive
}
Virtual_Drive::Virtual_Drive() {
strcpy(info,"Internal Virtual Drive");
for (int i=0; i<256; i++) {lfn_id[i] = 0;lfn_search[i] = 0;}
const Section_prop * section=static_cast<Section_prop *>(control->GetSection("dos"));
hidefiles = section->Get_string("drive z hide files");
if (parent_dir == NULL) parent_dir = new VFILE_Block;
}
bool Virtual_Drive::FileOpen(DOS_File * * file,const char * name,uint32_t flags) {
if (*name == 0) {
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
/* Scan through the internal list of files */
const VFILE_Block* cur_file = first_file;
while (cur_file) {
unsigned int onpos=cur_file->onpos;
if (strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||(uselfn&&
(strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0))) {
/* We have a match */
*file=new Virtual_File(cur_file->data,cur_file->size);
(*file)->SetName(cur_file->name);
(*file)->flags=flags;
return true;
}
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::FileCreate(DOS_File * * file,const char * name,uint16_t attributes) {
(void)file;//UNUSED
(void)name;//UNUSED
(void)attributes;//UNUSED
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
bool Virtual_Drive::FileUnlink(const char * name) {
if (*name == 0) {
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
const VFILE_Block* cur_file = first_file;
while (cur_file) {
unsigned int onpos=cur_file->onpos;
if (strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||(uselfn&&
(strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0))) {
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::RemoveDir(const char * dir) {
(void)dir;//UNUSED
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
bool Virtual_Drive::MakeDir(const char * dir) {
(void)dir;//UNUSED
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
bool Virtual_Drive::TestDir(const char * dir) {
if (!dir[0]) return true; //root directory
const VFILE_Block* cur_file = first_file;
while (cur_file) {
if (cur_file->isdir&&(!strcasecmp(cur_file->name, dir)||!strcasecmp(cur_file->lname, dir))) return true;
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::FileStat(const char* name, FileStat_Block * const stat_block){
const VFILE_Block* cur_file = first_file;
while (cur_file) {
unsigned int onpos=cur_file->onpos;
if (strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||(uselfn&&
(strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0))) {
stat_block->attr=cur_file->isdir?(cur_file->hidden?DOS_ATTR_DIRECTORY|DOS_ATTR_HIDDEN:DOS_ATTR_DIRECTORY):(cur_file->hidden?DOS_ATTR_ARCHIVE|DOS_ATTR_HIDDEN:DOS_ATTR_ARCHIVE);
stat_block->size=cur_file->size;
stat_block->date=DOS_PackDate(2002,10,1);
stat_block->time=DOS_PackTime(12,34,56);
return true;
}
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::FileExists(const char* name){
const VFILE_Block* cur_file = first_file;
while (cur_file) {
unsigned int onpos=cur_file->onpos;
if (strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||(uselfn&&
(strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0)))
return !cur_file->isdir;
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::FindFirst(const char * _dir,DOS_DTA & dta,bool fcb_findfirst) {
unsigned int onpos=0;
if (*_dir) {
if (FileExists(_dir)) {
DOS_SetError(DOSERR_FILE_NOT_FOUND);
return false;
}
for (unsigned int i=1; i<vfpos; i++) {
if (!strcasecmp(vfsnames[i], _dir)||!strcasecmp(vfnames[i], _dir)) {
onpos=i;
break;
}
}
if (!onpos) {
DOS_SetError(DOSERR_PATH_NOT_FOUND);
return false;
}
}
uint8_t attr;char pattern[CROSS_LEN];
dta.GetSearchParams(attr,pattern,false);
if (lfn_filefind_handle>=LFN_FILEFIND_MAX) {
dta.SetDirID(onpos);
search_file=(attr & DOS_ATTR_DIRECTORY) && onpos>0?parent_dir:first_file;
} else {
lfn_id[lfn_filefind_handle]=onpos;
lfn_search[lfn_filefind_handle]=(attr & DOS_ATTR_DIRECTORY) && onpos>0?parent_dir:first_file;
}
if (attr == DOS_ATTR_VOLUME) {
dta.SetResult(GetLabel(),GetLabel(),0,0,0,0,DOS_ATTR_VOLUME);
return true;
} else if ((attr & DOS_ATTR_DIRECTORY) && onpos>0) {
if (WildFileCmp(".",pattern)) {
dta.SetResult(".",".",0,0,DOS_PackDate(2002,10,1),DOS_PackTime(12,34,56),DOS_ATTR_DIRECTORY);
return true;
}
} else if ((attr & DOS_ATTR_VOLUME) && !fcb_findfirst) {
if (WildFileCmp(GetLabel(),pattern)) {
dta.SetResult(GetLabel(),GetLabel(),0,0,0,0,DOS_ATTR_VOLUME);
return true;
}
}
return FindNext(dta);
}
bool Virtual_Drive::FindNext(DOS_DTA & dta) {
uint8_t attr;char pattern[CROSS_LEN];
dta.GetSearchParams(attr,pattern,false);
unsigned int pos=lfn_filefind_handle>=LFN_FILEFIND_MAX?dta.GetDirID():lfn_id[lfn_filefind_handle];
if ((lfn_filefind_handle>=LFN_FILEFIND_MAX&&search_file==parent_dir) || (lfn_filefind_handle<LFN_FILEFIND_MAX&&lfn_search[lfn_filefind_handle]==parent_dir)) {
bool cmp=WildFileCmp("..",pattern);
if (cmp) dta.SetResult("..","..",0,0,DOS_PackDate(2002,10,1),DOS_PackTime(12,34,56),DOS_ATTR_DIRECTORY);
if (lfn_filefind_handle>=LFN_FILEFIND_MAX)
search_file=first_file;
else
lfn_search[lfn_filefind_handle]=first_file;
if (cmp) return true;
}
if (lfn_filefind_handle>=LFN_FILEFIND_MAX)
while (search_file) {
if (!(skipintprog && search_file->intprog) && pos==search_file->onpos&&((attr & DOS_ATTR_DIRECTORY)||!search_file->isdir)&&(WildFileCmp(search_file->name,pattern)||LWildFileCmp(search_file->lname,pattern))) {
dta.SetResult(search_file->name,search_file->lname,search_file->size,0,search_file->date,search_file->time,search_file->isdir?(search_file->hidden?DOS_ATTR_DIRECTORY|DOS_ATTR_HIDDEN:DOS_ATTR_DIRECTORY):(search_file->hidden?DOS_ATTR_ARCHIVE|DOS_ATTR_HIDDEN:DOS_ATTR_ARCHIVE));
search_file=search_file->next;
return true;
}
search_file=search_file->next;
}
else
while (lfn_search[lfn_filefind_handle]) {
if (!(skipintprog && search_file->intprog) && pos==lfn_search[lfn_filefind_handle]->onpos&&((attr & DOS_ATTR_DIRECTORY)||!lfn_search[lfn_filefind_handle]->isdir)&&(WildFileCmp(lfn_search[lfn_filefind_handle]->name,pattern)||LWildFileCmp(lfn_search[lfn_filefind_handle]->lname,pattern))) {
dta.SetResult(lfn_search[lfn_filefind_handle]->name,lfn_search[lfn_filefind_handle]->lname,lfn_search[lfn_filefind_handle]->size,0,lfn_search[lfn_filefind_handle]->date,lfn_search[lfn_filefind_handle]->time,lfn_search[lfn_filefind_handle]->isdir?(lfn_search[lfn_filefind_handle]->hidden?DOS_ATTR_DIRECTORY|DOS_ATTR_HIDDEN:DOS_ATTR_DIRECTORY):(lfn_search[lfn_filefind_handle]->hidden?DOS_ATTR_ARCHIVE|DOS_ATTR_HIDDEN:DOS_ATTR_ARCHIVE));
lfn_search[lfn_filefind_handle]=lfn_search[lfn_filefind_handle]->next;
return true;
}
lfn_search[lfn_filefind_handle]=lfn_search[lfn_filefind_handle]->next;
}
if (lfn_filefind_handle<LFN_FILEFIND_MAX) {
lfn_id[lfn_filefind_handle]=0;
lfn_search[lfn_filefind_handle]=0;
}
DOS_SetError(DOSERR_NO_MORE_FILES);
return false;
}
bool Virtual_Drive::SetFileAttr(const char * name,uint16_t attr) {
(void)attr;//UNUSED
if (*name == 0) {
DOS_SetError(DOSERR_ACCESS_DENIED);
return true;
}
const VFILE_Block* cur_file = first_file;
while (cur_file) {
unsigned int onpos=cur_file->onpos;
if (strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||(uselfn&&
(strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0))) {
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
cur_file=cur_file->next;
}
DOS_SetError(DOSERR_FILE_NOT_FOUND);
return false;
}
bool Virtual_Drive::GetFileAttr(const char * name,uint16_t * attr) {
if (*name == 0) {
*attr=DOS_ATTR_DIRECTORY;
return true;
}
const VFILE_Block* cur_file = first_file;
while (cur_file) {
unsigned int onpos=cur_file->onpos;
if (strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||(uselfn&&
(strcasecmp(name,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||
strcasecmp(name,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0))) {
*attr = cur_file->isdir?(cur_file->hidden?DOS_ATTR_DIRECTORY|DOS_ATTR_HIDDEN:DOS_ATTR_DIRECTORY):(cur_file->hidden?DOS_ATTR_ARCHIVE|DOS_ATTR_HIDDEN:DOS_ATTR_ARCHIVE); //Maybe readonly ?
return true;
}
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::GetFileAttrEx(char* name, struct stat *status) {
(void)name;
(void)status;
return false;
}
unsigned long Virtual_Drive::GetCompressedSize(char* name) {
(void)name;
return 0;
}
#if defined (WIN32)
HANDLE Virtual_Drive::CreateOpenFile(const char* name) {
(void)name;
DOS_SetError(1);
return INVALID_HANDLE_VALUE;
}
#endif
bool Virtual_Drive::Rename(const char * oldname,const char * newname) {
if (*oldname == 0 || *newname == 0) {
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
const VFILE_Block* cur_file = first_file;
while (cur_file) {
unsigned int onpos=cur_file->onpos;
if (strcasecmp(oldname,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||(uselfn&&
(strcasecmp(oldname,(std::string(onpos?vfsnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0||
strcasecmp(oldname,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->name).c_str())==0||
strcasecmp(oldname,(std::string(onpos?vfnames[onpos]+std::string(1, '\\'):"")+cur_file->lname).c_str())==0))) {
DOS_SetError(DOSERR_ACCESS_DENIED);
return false;
}
cur_file=cur_file->next;
}
return false;
}
bool Virtual_Drive::AllocationInfo(uint16_t * _bytes_sector,uint8_t * _sectors_cluster,uint16_t * _total_clusters,uint16_t * _free_clusters) {
*_bytes_sector=512;
*_sectors_cluster=32;
*_total_clusters=32765; // total size is always 500 mb
*_free_clusters=0; // nothing free here
return true;
}
uint8_t Virtual_Drive::GetMediaByte(void) {
return 0xF8;
}
bool Virtual_Drive::isRemote(void) {
const Section_prop * section=static_cast<Section_prop *>(control->GetSection("dos"));
const char * opt = section->Get_string("drive z is remote");
if (!strcmp(opt,"1") || !strcmp(opt,"true")) {
return true;
}
else if (!strcmp(opt,"0") || !strcmp(opt,"false")) {
return false;
}
char psp_name[9];
DOS_MCB psp_mcb(dos.psp()-1);
psp_mcb.GetFileName(psp_name);
if (!strcmp(psp_name, "SCANDISK") || !strcmp(psp_name, "CHKDSK")) {
/* Check for SCANDISK.EXE (or CHKDSK.EXE) and return true (Wengier) */
return true;
}
/* Automatically detect if called by SCANDISK.EXE even if it is renamed (tested with the program from MS-DOS 6.20 to Windows ME) */
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)
return true;
return false;
}
bool Virtual_Drive::isRemovable(void) {
return false;
}
Bits Virtual_Drive::UnMount(void) {
return 1;
}
char const* Virtual_Drive::GetLabel(void) {
return "DOSBOX-X";
}
void Virtual_Drive::EmptyCache(void) {
while (first_file != NULL) {
VFILE_Block *n = first_file->next;
delete first_file;
first_file = n;
}
vfpos=1;
PROGRAMS_Shutdown();
Add_VFiles(true);
}