2021-02-06 09:39:32 +01:00
|
|
|
/*
|
2021-02-06 16:06:31 +01:00
|
|
|
* Copyright (C) 2002-2019 The DOSBox Team
|
2021-02-06 09:39:32 +01:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2021-02-06 16:06:31 +01:00
|
|
|
* 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.
|
2021-02-06 09:39:32 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "dosbox.h"
|
|
|
|
#include "dos_inc.h"
|
|
|
|
#include "drives.h"
|
|
|
|
#include "support.h"
|
|
|
|
#include "cross.h"
|
|
|
|
#include "inout.h"
|
|
|
|
|
|
|
|
|
|
|
|
bool localDrive::FileCreate(DOS_File * * file,char * name,Bit16u /*attributes*/) {
|
|
|
|
//TODO Maybe care for attributes but not likely
|
|
|
|
char newname[CROSS_LEN];
|
|
|
|
strcpy(newname,basedir);
|
|
|
|
strcat(newname,name);
|
|
|
|
CROSS_FILENAME(newname);
|
|
|
|
char* temp_name = dirCache.GetExpandName(newname); //Can only be used in till a new drive_cache action is preformed */
|
|
|
|
/* Test if file exists (so we need to truncate it). don't add to dirCache then */
|
2021-02-06 16:06:31 +01:00
|
|
|
bool existing_file = false;
|
2021-02-06 09:39:32 +01:00
|
|
|
|
2021-02-06 16:06:31 +01:00
|
|
|
FILE * test = fopen_wrap(temp_name,"rb+");
|
2021-02-06 09:39:32 +01:00
|
|
|
if(test) {
|
|
|
|
fclose(test);
|
|
|
|
existing_file=true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-02-06 16:06:31 +01:00
|
|
|
FILE * hand = fopen_wrap(temp_name,"wb+");
|
2021-02-06 09:39:32 +01:00
|
|
|
if (!hand){
|
|
|
|
LOG_MSG("Warning: file creation failed: %s",newname);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!existing_file) dirCache.AddEntry(newname, true);
|
|
|
|
/* Make the 16 bit device information */
|
|
|
|
*file=new localFile(name,hand);
|
|
|
|
(*file)->flags=OPEN_READWRITE;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) {
|
|
|
|
const char* type;
|
|
|
|
switch (flags&0xf) {
|
|
|
|
case OPEN_READ: type = "rb" ; break;
|
|
|
|
case OPEN_WRITE: type = "rb+"; break;
|
|
|
|
case OPEN_READWRITE: type = "rb+"; break;
|
|
|
|
case OPEN_READ_NO_MOD: type = "rb" ; break; //No modification of dates. LORD4.07 uses this
|
|
|
|
default:
|
|
|
|
DOS_SetError(DOSERR_ACCESS_CODE_INVALID);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
char newname[CROSS_LEN];
|
|
|
|
strcpy(newname,basedir);
|
|
|
|
strcat(newname,name);
|
|
|
|
CROSS_FILENAME(newname);
|
|
|
|
dirCache.ExpandName(newname);
|
|
|
|
|
|
|
|
//Flush the buffer of handles for the same file. (Betrayal in Antara)
|
|
|
|
Bit8u i,drive=DOS_DRIVES;
|
|
|
|
localFile *lfp;
|
|
|
|
for (i=0;i<DOS_DRIVES;i++) {
|
|
|
|
if (Drives[i]==this) {
|
|
|
|
drive=i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i=0;i<DOS_FILES;i++) {
|
|
|
|
if (Files[i] && Files[i]->IsOpen() && Files[i]->GetDrive()==drive && Files[i]->IsName(name)) {
|
|
|
|
lfp=dynamic_cast<localFile*>(Files[i]);
|
|
|
|
if (lfp) lfp->Flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-06 16:06:31 +01:00
|
|
|
FILE * hand = fopen_wrap(newname,type);
|
2021-02-06 09:39:32 +01:00
|
|
|
// Bit32u err=errno;
|
|
|
|
if (!hand) {
|
|
|
|
if((flags&0xf) != OPEN_READ) {
|
2021-02-06 16:06:31 +01:00
|
|
|
FILE * hmm = fopen_wrap(newname,"rb");
|
2021-02-06 09:39:32 +01:00
|
|
|
if (hmm) {
|
|
|
|
fclose(hmm);
|
|
|
|
LOG_MSG("Warning: file %s exists and failed to open in write mode.\nPlease Remove write-protection",newname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*file=new localFile(name,hand);
|
|
|
|
(*file)->flags=flags; //for the inheritance flag and maybe check for others.
|
|
|
|
// (*file)->SetFileName(newname);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE * localDrive::GetSystemFilePtr(char const * const name, char const * const type) {
|
|
|
|
|
|
|
|
char newname[CROSS_LEN];
|
|
|
|
strcpy(newname,basedir);
|
|
|
|
strcat(newname,name);
|
|
|
|
CROSS_FILENAME(newname);
|
|
|
|
dirCache.ExpandName(newname);
|
|
|
|
|
2021-02-06 16:06:31 +01:00
|
|
|
return fopen_wrap(newname,type);
|
2021-02-06 09:39:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::GetSystemFilename(char *sysName, char const * const dosName) {
|
|
|
|
|
|
|
|
strcpy(sysName, basedir);
|
|
|
|
strcat(sysName, dosName);
|
|
|
|
CROSS_FILENAME(sysName);
|
|
|
|
dirCache.ExpandName(sysName);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::FileUnlink(char * name) {
|
|
|
|
char newname[CROSS_LEN];
|
|
|
|
strcpy(newname,basedir);
|
|
|
|
strcat(newname,name);
|
|
|
|
CROSS_FILENAME(newname);
|
|
|
|
char *fullname = dirCache.GetExpandName(newname);
|
|
|
|
if (unlink(fullname)) {
|
|
|
|
//Unlink failed for some reason try finding it.
|
|
|
|
struct stat buffer;
|
|
|
|
if(stat(fullname,&buffer)) return false; // File not found.
|
|
|
|
|
2021-02-06 16:06:31 +01:00
|
|
|
FILE* file_writable = fopen_wrap(fullname,"rb+");
|
2021-02-06 09:39:32 +01:00
|
|
|
if(!file_writable) return false; //No acces ? ERROR MESSAGE NOT SET. FIXME ?
|
|
|
|
fclose(file_writable);
|
|
|
|
|
|
|
|
//File exists and can technically be deleted, nevertheless it failed.
|
|
|
|
//This means that the file is probably open by some process.
|
|
|
|
//See if We have it open.
|
|
|
|
bool found_file = false;
|
|
|
|
for(Bitu i = 0;i < DOS_FILES;i++){
|
|
|
|
if(Files[i] && Files[i]->IsName(name)) {
|
|
|
|
Bitu max = DOS_FILES;
|
|
|
|
while(Files[i]->IsOpen() && max--) {
|
|
|
|
Files[i]->Close();
|
|
|
|
if (Files[i]->RemoveRef()<=0) break;
|
|
|
|
}
|
|
|
|
found_file=true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!found_file) return false;
|
|
|
|
if (!unlink(fullname)) {
|
|
|
|
dirCache.DeleteEntry(newname);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
dirCache.DeleteEntry(newname);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst) {
|
|
|
|
char tempDir[CROSS_LEN];
|
|
|
|
strcpy(tempDir,basedir);
|
|
|
|
strcat(tempDir,_dir);
|
|
|
|
CROSS_FILENAME(tempDir);
|
|
|
|
|
|
|
|
if (allocation.mediaid==0xF0 ) {
|
|
|
|
EmptyCache(); //rescan floppie-content on each findfirst
|
|
|
|
}
|
|
|
|
|
|
|
|
char end[2]={CROSS_FILESPLIT,0};
|
|
|
|
if (tempDir[strlen(tempDir)-1]!=CROSS_FILESPLIT) strcat(tempDir,end);
|
|
|
|
|
|
|
|
Bit16u id;
|
|
|
|
if (!dirCache.FindFirst(tempDir,id)) {
|
|
|
|
DOS_SetError(DOSERR_PATH_NOT_FOUND);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
strcpy(srchInfo[id].srch_dir,tempDir);
|
|
|
|
dta.SetDirID(id);
|
|
|
|
|
|
|
|
Bit8u sAttr;
|
|
|
|
dta.GetSearchParams(sAttr,tempDir);
|
|
|
|
|
|
|
|
if (this->isRemote() && this->isRemovable()) {
|
|
|
|
// cdroms behave a bit different than regular drives
|
|
|
|
if (sAttr == DOS_ATTR_VOLUME) {
|
|
|
|
dta.SetResult(dirCache.GetLabel(),0,0,0,DOS_ATTR_VOLUME);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (sAttr == DOS_ATTR_VOLUME) {
|
|
|
|
if ( strcmp(dirCache.GetLabel(), "") == 0 ) {
|
|
|
|
// LOG(LOG_DOSMISC,LOG_ERROR)("DRIVELABEL REQUESTED: none present, returned NOLABEL");
|
|
|
|
// dta.SetResult("NO_LABEL",0,0,0,DOS_ATTR_VOLUME);
|
|
|
|
// return true;
|
|
|
|
DOS_SetError(DOSERR_NO_MORE_FILES);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
dta.SetResult(dirCache.GetLabel(),0,0,0,DOS_ATTR_VOLUME);
|
|
|
|
return true;
|
|
|
|
} else if ((sAttr & DOS_ATTR_VOLUME) && (*_dir == 0) && !fcb_findfirst) {
|
|
|
|
//should check for a valid leading directory instead of 0
|
|
|
|
//exists==true if the volume label matches the searchmask and the path is valid
|
|
|
|
if (WildFileCmp(dirCache.GetLabel(),tempDir)) {
|
|
|
|
dta.SetResult(dirCache.GetLabel(),0,0,0,DOS_ATTR_VOLUME);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FindNext(dta);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::FindNext(DOS_DTA & dta) {
|
|
|
|
|
|
|
|
char * dir_ent;
|
|
|
|
struct stat stat_block;
|
|
|
|
char full_name[CROSS_LEN];
|
|
|
|
char dir_entcopy[CROSS_LEN];
|
|
|
|
|
|
|
|
Bit8u srch_attr;char srch_pattern[DOS_NAMELENGTH_ASCII];
|
|
|
|
Bit8u find_attr;
|
|
|
|
|
|
|
|
dta.GetSearchParams(srch_attr,srch_pattern);
|
|
|
|
Bit16u id = dta.GetDirID();
|
|
|
|
|
|
|
|
again:
|
|
|
|
if (!dirCache.FindNext(id,dir_ent)) {
|
|
|
|
DOS_SetError(DOSERR_NO_MORE_FILES);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(!WildFileCmp(dir_ent,srch_pattern)) goto again;
|
|
|
|
|
|
|
|
strcpy(full_name,srchInfo[id].srch_dir);
|
|
|
|
strcat(full_name,dir_ent);
|
|
|
|
|
|
|
|
//GetExpandName might indirectly destroy dir_ent (by caching in a new directory
|
|
|
|
//and due to its design dir_ent might be lost.)
|
|
|
|
//Copying dir_ent first
|
|
|
|
strcpy(dir_entcopy,dir_ent);
|
|
|
|
if (stat(dirCache.GetExpandName(full_name),&stat_block)!=0) {
|
|
|
|
goto again;//No symlinks and such
|
|
|
|
}
|
|
|
|
|
|
|
|
if(stat_block.st_mode & S_IFDIR) find_attr=DOS_ATTR_DIRECTORY;
|
|
|
|
else find_attr=DOS_ATTR_ARCHIVE;
|
|
|
|
if (~srch_attr & find_attr & (DOS_ATTR_DIRECTORY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM)) goto again;
|
|
|
|
|
|
|
|
/*file is okay, setup everything to be copied in DTA Block */
|
|
|
|
char find_name[DOS_NAMELENGTH_ASCII];Bit16u find_date,find_time;Bit32u find_size;
|
|
|
|
|
|
|
|
if(strlen(dir_entcopy)<DOS_NAMELENGTH_ASCII){
|
|
|
|
strcpy(find_name,dir_entcopy);
|
|
|
|
upcase(find_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
find_size=(Bit32u) stat_block.st_size;
|
|
|
|
struct tm *time;
|
|
|
|
if((time=localtime(&stat_block.st_mtime))!=0){
|
|
|
|
find_date=DOS_PackDate((Bit16u)(time->tm_year+1900),(Bit16u)(time->tm_mon+1),(Bit16u)time->tm_mday);
|
|
|
|
find_time=DOS_PackTime((Bit16u)time->tm_hour,(Bit16u)time->tm_min,(Bit16u)time->tm_sec);
|
|
|
|
} else {
|
|
|
|
find_time=6;
|
|
|
|
find_date=4;
|
|
|
|
}
|
|
|
|
dta.SetResult(find_name,find_size,find_date,find_time,find_attr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::GetFileAttr(char * name,Bit16u * attr) {
|
|
|
|
char newname[CROSS_LEN];
|
|
|
|
strcpy(newname,basedir);
|
|
|
|
strcat(newname,name);
|
|
|
|
CROSS_FILENAME(newname);
|
|
|
|
dirCache.ExpandName(newname);
|
|
|
|
|
|
|
|
struct stat status;
|
|
|
|
if (stat(newname,&status)==0) {
|
|
|
|
*attr=DOS_ATTR_ARCHIVE;
|
|
|
|
if(status.st_mode & S_IFDIR) *attr|=DOS_ATTR_DIRECTORY;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
*attr=0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::MakeDir(char * dir) {
|
|
|
|
char newdir[CROSS_LEN];
|
|
|
|
strcpy(newdir,basedir);
|
|
|
|
strcat(newdir,dir);
|
|
|
|
CROSS_FILENAME(newdir);
|
|
|
|
#if defined (WIN32) /* MS Visual C++ */
|
|
|
|
int temp=mkdir(dirCache.GetExpandName(newdir));
|
|
|
|
#else
|
|
|
|
int temp=mkdir(dirCache.GetExpandName(newdir),0700);
|
|
|
|
#endif
|
|
|
|
if (temp==0) dirCache.CacheOut(newdir,true);
|
|
|
|
|
|
|
|
return (temp==0);// || ((temp!=0) && (errno==EEXIST));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::RemoveDir(char * dir) {
|
|
|
|
char newdir[CROSS_LEN];
|
|
|
|
strcpy(newdir,basedir);
|
|
|
|
strcat(newdir,dir);
|
|
|
|
CROSS_FILENAME(newdir);
|
|
|
|
int temp=rmdir(dirCache.GetExpandName(newdir));
|
|
|
|
if (temp==0) dirCache.DeleteEntry(newdir,true);
|
|
|
|
return (temp==0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::TestDir(char * dir) {
|
|
|
|
char newdir[CROSS_LEN];
|
|
|
|
strcpy(newdir,basedir);
|
|
|
|
strcat(newdir,dir);
|
|
|
|
CROSS_FILENAME(newdir);
|
|
|
|
dirCache.ExpandName(newdir);
|
|
|
|
// Skip directory test, if "\"
|
|
|
|
size_t len = strlen(newdir);
|
|
|
|
if (len && (newdir[len-1]!='\\')) {
|
|
|
|
// It has to be a directory !
|
|
|
|
struct stat test;
|
|
|
|
if (stat(newdir,&test)) return false;
|
|
|
|
if ((test.st_mode & S_IFDIR)==0) return false;
|
|
|
|
};
|
|
|
|
int temp=access(newdir,F_OK);
|
|
|
|
return (temp==0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::Rename(char * oldname,char * newname) {
|
|
|
|
char newold[CROSS_LEN];
|
|
|
|
strcpy(newold,basedir);
|
|
|
|
strcat(newold,oldname);
|
|
|
|
CROSS_FILENAME(newold);
|
|
|
|
dirCache.ExpandName(newold);
|
|
|
|
|
|
|
|
char newnew[CROSS_LEN];
|
|
|
|
strcpy(newnew,basedir);
|
|
|
|
strcat(newnew,newname);
|
|
|
|
CROSS_FILENAME(newnew);
|
|
|
|
int temp=rename(newold,dirCache.GetExpandName(newnew));
|
|
|
|
if (temp==0) dirCache.CacheOut(newnew);
|
|
|
|
return (temp==0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) {
|
|
|
|
*_bytes_sector=allocation.bytes_sector;
|
|
|
|
*_sectors_cluster=allocation.sectors_cluster;
|
|
|
|
*_total_clusters=allocation.total_clusters;
|
|
|
|
*_free_clusters=allocation.free_clusters;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::FileExists(const char* name) {
|
|
|
|
char newname[CROSS_LEN];
|
|
|
|
strcpy(newname,basedir);
|
|
|
|
strcat(newname,name);
|
|
|
|
CROSS_FILENAME(newname);
|
|
|
|
dirCache.ExpandName(newname);
|
|
|
|
struct stat temp_stat;
|
|
|
|
if(stat(newname,&temp_stat)!=0) return false;
|
|
|
|
if(temp_stat.st_mode & S_IFDIR) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::FileStat(const char* name, FileStat_Block * const stat_block) {
|
|
|
|
char newname[CROSS_LEN];
|
|
|
|
strcpy(newname,basedir);
|
|
|
|
strcat(newname,name);
|
|
|
|
CROSS_FILENAME(newname);
|
|
|
|
dirCache.ExpandName(newname);
|
|
|
|
struct stat temp_stat;
|
|
|
|
if(stat(newname,&temp_stat)!=0) return false;
|
|
|
|
/* Convert the stat to a FileStat */
|
|
|
|
struct tm *time;
|
|
|
|
if((time=localtime(&temp_stat.st_mtime))!=0) {
|
|
|
|
stat_block->time=DOS_PackTime((Bit16u)time->tm_hour,(Bit16u)time->tm_min,(Bit16u)time->tm_sec);
|
|
|
|
stat_block->date=DOS_PackDate((Bit16u)(time->tm_year+1900),(Bit16u)(time->tm_mon+1),(Bit16u)time->tm_mday);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
}
|
|
|
|
stat_block->size=(Bit32u)temp_stat.st_size;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Bit8u localDrive::GetMediaByte(void) {
|
|
|
|
return allocation.mediaid;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::isRemote(void) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localDrive::isRemovable(void) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bits localDrive::UnMount(void) {
|
|
|
|
delete this;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
localDrive::localDrive(const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid) {
|
|
|
|
strcpy(basedir,startdir);
|
|
|
|
sprintf(info,"local directory %s",startdir);
|
|
|
|
allocation.bytes_sector=_bytes_sector;
|
|
|
|
allocation.sectors_cluster=_sectors_cluster;
|
|
|
|
allocation.total_clusters=_total_clusters;
|
|
|
|
allocation.free_clusters=_free_clusters;
|
|
|
|
allocation.mediaid=_mediaid;
|
|
|
|
|
|
|
|
dirCache.SetBaseDir(basedir);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//TODO Maybe use fflush, but that seemed to fuck up in visual c
|
|
|
|
bool localFile::Read(Bit8u * data,Bit16u * size) {
|
|
|
|
if ((this->flags & 0xf) == OPEN_WRITE) { // check if file opened in write-only mode
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (last_action==WRITE) fseek(fhandle,ftell(fhandle),SEEK_SET);
|
|
|
|
last_action=READ;
|
|
|
|
*size=(Bit16u)fread(data,1,*size,fhandle);
|
|
|
|
/* Fake harddrive motion. Inspector Gadget with soundblaster compatible */
|
|
|
|
/* Same for Igor */
|
|
|
|
/* hardrive motion => unmask irq 2. Only do it when it's masked as unmasking is realitively heavy to emulate */
|
|
|
|
Bit8u mask = IO_Read(0x21);
|
|
|
|
if(mask & 0x4 ) IO_Write(0x21,mask&0xfb);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localFile::Write(Bit8u * data,Bit16u * size) {
|
2021-02-06 16:06:31 +01:00
|
|
|
Bit32u lastflags = this->flags & 0xf;
|
|
|
|
if (lastflags == OPEN_READ || lastflags == OPEN_READ_NO_MOD) { // check if file opened in read-only mode
|
2021-02-06 09:39:32 +01:00
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (last_action==READ) fseek(fhandle,ftell(fhandle),SEEK_SET);
|
|
|
|
last_action=WRITE;
|
|
|
|
if(*size==0){
|
|
|
|
return (!ftruncate(fileno(fhandle),ftell(fhandle)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*size=(Bit16u)fwrite(data,1,*size,fhandle);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localFile::Seek(Bit32u * pos,Bit32u type) {
|
|
|
|
int seektype;
|
|
|
|
switch (type) {
|
|
|
|
case DOS_SEEK_SET:seektype=SEEK_SET;break;
|
|
|
|
case DOS_SEEK_CUR:seektype=SEEK_CUR;break;
|
|
|
|
case DOS_SEEK_END:seektype=SEEK_END;break;
|
|
|
|
default:
|
|
|
|
//TODO Give some doserrorcode;
|
|
|
|
return false;//ERROR
|
|
|
|
}
|
|
|
|
int ret=fseek(fhandle,*reinterpret_cast<Bit32s*>(pos),seektype);
|
|
|
|
if (ret!=0) {
|
|
|
|
// Out of file range, pretend everythings ok
|
|
|
|
// and move file pointer top end of file... ?! (Black Thorne)
|
|
|
|
fseek(fhandle,0,SEEK_END);
|
|
|
|
};
|
|
|
|
#if 0
|
|
|
|
fpos_t temppos;
|
|
|
|
fgetpos(fhandle,&temppos);
|
|
|
|
Bit32u * fake_pos=(Bit32u*)&temppos;
|
|
|
|
*pos=*fake_pos;
|
|
|
|
#endif
|
|
|
|
*pos=(Bit32u)ftell(fhandle);
|
|
|
|
last_action=NONE;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localFile::Close() {
|
|
|
|
// only close if one reference left
|
|
|
|
if (refCtr==1) {
|
|
|
|
if(fhandle) fclose(fhandle);
|
|
|
|
fhandle = 0;
|
|
|
|
open = false;
|
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bit16u localFile::GetInformation(void) {
|
|
|
|
return read_only_medium?0x40:0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
localFile::localFile(const char* _name, FILE * handle) {
|
|
|
|
fhandle=handle;
|
|
|
|
open=true;
|
|
|
|
UpdateDateTimeFromHost();
|
|
|
|
|
|
|
|
attr=DOS_ATTR_ARCHIVE;
|
|
|
|
last_action=NONE;
|
|
|
|
read_only_medium=false;
|
|
|
|
|
|
|
|
name=0;
|
|
|
|
SetName(_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void localFile::FlagReadOnlyMedium(void) {
|
|
|
|
read_only_medium = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool localFile::UpdateDateTimeFromHost(void) {
|
|
|
|
if(!open) return false;
|
|
|
|
struct stat temp_stat;
|
|
|
|
fstat(fileno(fhandle),&temp_stat);
|
|
|
|
struct tm * ltime;
|
|
|
|
if((ltime=localtime(&temp_stat.st_mtime))!=0) {
|
|
|
|
time=DOS_PackTime((Bit16u)ltime->tm_hour,(Bit16u)ltime->tm_min,(Bit16u)ltime->tm_sec);
|
|
|
|
date=DOS_PackDate((Bit16u)(ltime->tm_year+1900),(Bit16u)(ltime->tm_mon+1),(Bit16u)ltime->tm_mday);
|
|
|
|
} else {
|
|
|
|
time=1;date=1;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void localFile::Flush(void) {
|
|
|
|
if (last_action==WRITE) {
|
|
|
|
fseek(fhandle,ftell(fhandle),SEEK_SET);
|
|
|
|
last_action=NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ********************************************
|
|
|
|
// CDROM DRIVE
|
|
|
|
// ********************************************
|
|
|
|
|
|
|
|
int MSCDEX_RemoveDrive(char driveLetter);
|
|
|
|
int MSCDEX_AddDrive(char driveLetter, const char* physicalPath, Bit8u& subUnit);
|
|
|
|
bool MSCDEX_HasMediaChanged(Bit8u subUnit);
|
|
|
|
bool MSCDEX_GetVolumeName(Bit8u subUnit, char* name);
|
|
|
|
|
|
|
|
|
|
|
|
cdromDrive::cdromDrive(const char driveLetter, const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid, int& error)
|
2021-02-06 16:06:31 +01:00
|
|
|
:localDrive(startdir,_bytes_sector,_sectors_cluster,_total_clusters,_free_clusters,_mediaid),
|
|
|
|
subUnit(0),
|
|
|
|
driveLetter('\0')
|
|
|
|
{
|
2021-02-06 09:39:32 +01:00
|
|
|
// Init mscdex
|
|
|
|
error = MSCDEX_AddDrive(driveLetter,startdir,subUnit);
|
|
|
|
strcpy(info, "CDRom ");
|
|
|
|
strcat(info, startdir);
|
|
|
|
this->driveLetter = driveLetter;
|
|
|
|
// Get Volume Label
|
|
|
|
char name[32];
|
|
|
|
if (MSCDEX_GetVolumeName(subUnit,name)) dirCache.SetLabel(name,true,true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) {
|
|
|
|
if ((flags&0xf)==OPEN_READWRITE) {
|
|
|
|
flags &= ~OPEN_READWRITE;
|
|
|
|
} else if ((flags&0xf)==OPEN_WRITE) {
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool retcode = localDrive::FileOpen(file,name,flags);
|
|
|
|
if(retcode) (dynamic_cast<localFile*>(*file))->FlagReadOnlyMedium();
|
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::FileCreate(DOS_File * * /*file*/,char * /*name*/,Bit16u /*attributes*/) {
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::FileUnlink(char * /*name*/) {
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::RemoveDir(char * /*dir*/) {
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::MakeDir(char * /*dir*/) {
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::Rename(char * /*oldname*/,char * /*newname*/) {
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::GetFileAttr(char * name,Bit16u * attr) {
|
|
|
|
bool result = localDrive::GetFileAttr(name,attr);
|
|
|
|
if (result) *attr |= DOS_ATTR_READ_ONLY;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::FindFirst(char * _dir,DOS_DTA & dta,bool /*fcb_findfirst*/) {
|
|
|
|
// If media has changed, reInit drivecache.
|
|
|
|
if (MSCDEX_HasMediaChanged(subUnit)) {
|
|
|
|
dirCache.EmptyCache();
|
|
|
|
// Get Volume Label
|
|
|
|
char name[32];
|
|
|
|
if (MSCDEX_GetVolumeName(subUnit,name)) dirCache.SetLabel(name,true,true);
|
|
|
|
}
|
|
|
|
return localDrive::FindFirst(_dir,dta);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cdromDrive::SetDir(const char* path) {
|
|
|
|
// If media has changed, reInit drivecache.
|
|
|
|
if (MSCDEX_HasMediaChanged(subUnit)) {
|
|
|
|
dirCache.EmptyCache();
|
|
|
|
// Get Volume Label
|
|
|
|
char name[32];
|
|
|
|
if (MSCDEX_GetVolumeName(subUnit,name)) dirCache.SetLabel(name,true,true);
|
|
|
|
}
|
|
|
|
localDrive::SetDir(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::isRemote(void) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cdromDrive::isRemovable(void) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bits cdromDrive::UnMount(void) {
|
|
|
|
if(MSCDEX_RemoveDrive(driveLetter)) {
|
|
|
|
delete this;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|