mirror of
https://github.com/joncampbell123/dosbox-x.git
synced 2025-05-08 19:32:39 +08:00
717 lines
25 KiB
C++
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);
|
|
} |