Merge branch 'joncampbell123:master' into master

This commit is contained in:
Robert 2022-07-05 19:38:45 +02:00 committed by GitHub
commit 846599c3b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1023 additions and 44 deletions

View File

@ -1,5 +1,16 @@
0.84.2
-
- Added support for auto-converting non-image drives
(such as mounted local drives) to disk images, so
that they will be visible when booting into guest
systems. A config option "convertdrivefat" (in
[dosbox] section) is added to toggle this setting,
or you can toggle via BOOT command's -convertfat
and -noconvertfat options. There is also a config
option "drive z convert image" (in [dos] section)
to control if to convert virtual drive Z:. Much of
the code is imported from DOSBox Pure. (Wengier)
- Fixed display of total file size in DIR command
when the file sizes are very large. (Wengier)
0.84.1
- Added dosbox(-x).conf option to enable workaround
for errant DOS programs that set the TF (trap flag)

View File

@ -10,7 +10,7 @@
<category>Emulation</category>
</categories>
<releases>
<release version="@PACKAGE_VERSION@" date="2022-7-1"/>
<release version="@PACKAGE_VERSION@" date="2022-7-3"/>
</releases>
<screenshots>
<screenshot type="default">

View File

@ -396,6 +396,7 @@ debuggerrun = debugger
# If set to "relative", the value of MOUNT -freesize will change relative to the specified value.
# If set to "fixed" (="false"), the value of MOUNT -freesize will be a fixed one to be reported all the time.
# Possible values: true, false, fixed, relative, cap, 2, 1, 0.
# convertdrivefat: If set, DOSBox-X will auto-convert mounted non-FAT drives (such as local drives) to FAT format for use with guest systems.
#DOSBOX-X-ADV:# leading colon write protect image: If set, BOOT and IMGMOUNT commands will put an image file name with a leading colon (:) in write-protect mode.
#DOSBOX-X-ADV:# locking disk image mount: If set, BOOT and IMGMOUNT commands will try to lock the mounted disk image files. As a result, you cannot
#DOSBOX-X-ADV:# mount the same disk image files in read/write mode at the same time as this can cause possible disk corruptions.
@ -495,6 +496,7 @@ memsize = 16
#DOSBOX-X-ADV:memalias = 0
nocachedir = false
freesizecap = cap
convertdrivefat = true
#DOSBOX-X-ADV:leading colon write protect image = true
#DOSBOX-X-ADV:locking disk image mount = true
#DOSBOX-X-ADV:unmask keyboard on int 16 read = true
@ -2069,6 +2071,7 @@ timeout = 0
#DOSBOX-X-ADV:# Set this option to true to prevent SCANDISK.EXE from attempting scan and repair drive Z:
#DOSBOX-X-ADV:# which is impossible since Z: is a virtual drive not backed by a disk filesystem.
#DOSBOX-X-ADV:# Possible values: true, false, 1, 0, auto.
#DOSBOX-X-ADV:# drive z convert fat: If set, DOSBox-X will automatically convert the Z drive into disk image as well when "convertdrivefat" is set.
#DOSBOX-X-ADV:# drive z expand path: If set, DOSBox-X will automatically expand the %PATH% environment variable to include the subdirectories on the Z drive.
#DOSBOX-X-ADV:# drive z hide files: The files or directories listed here (separated by space) will be either hidden or removed from the Z drive.
#DOSBOX-X-ADV:# Files with leading forward slashes (e.g. "/DEBUG\BIOSTEST.COM") will become hidden files (DIR /A will list them).
@ -2251,7 +2254,7 @@ timeout = 0
# dos clipboard api: If set, DOS APIs for communications with the Windows clipboard will be enabled for shared clipboard communications.
#DOSBOX-X-ADV-SEE:#
#DOSBOX-X-ADV-SEE:# Advanced options (see full configuration reference file [dosbox-x.reference.full.conf] for more details):
#DOSBOX-X-ADV-SEE:# -> badcommandhandler; hma allow reservation; special operation file prefix; drive z is remote; drive z expand path; drive z hide files; hidenonrepresentable; hma minimum allocation; dos sda size; hma free space; cpm compatibility mode; minimum dos initial private segment; minimum mcb segment; enable dummy device mcb; maximum environment block size on exec; additional environment block size on exec; enable a20 on windows init; zero memory on xms memory allocation; vcpi; unmask timer on disk io; zero int 67h if no ems; zero unused int 68h; emm386 startup active; zero memory on ems memory allocation; ems system handle memory size; ems system handle on even megabyte; umb start; umb end; kernel allocation in umb; keep umb on boot; keep private area on boot; private area in umb; autoa20fix; autoloadfix; startincon; int33 hide host cursor if interrupt subroutine; int33 hide host cursor when polling; int33 disable cell granularity; int 13 disk change detect; int 13 extensions; biosps2; int15 wait force unmask irq; int15 mouse callback does not preserve registers; filenamechar; collating and uppercase; con device use int 16h to detect keyboard input; zero memory on int 21h memory allocation
#DOSBOX-X-ADV-SEE:# -> badcommandhandler; hma allow reservation; special operation file prefix; drive z is remote; drive z convert fat; drive z expand path; drive z hide files; hidenonrepresentable; hma minimum allocation; dos sda size; hma free space; cpm compatibility mode; minimum dos initial private segment; minimum mcb segment; enable dummy device mcb; maximum environment block size on exec; additional environment block size on exec; enable a20 on windows init; zero memory on xms memory allocation; vcpi; unmask timer on disk io; zero int 67h if no ems; zero unused int 68h; emm386 startup active; zero memory on ems memory allocation; ems system handle memory size; ems system handle on even megabyte; umb start; umb end; kernel allocation in umb; keep umb on boot; keep private area on boot; private area in umb; autoa20fix; autoloadfix; startincon; int33 hide host cursor if interrupt subroutine; int33 hide host cursor when polling; int33 disable cell granularity; int 13 disk change detect; int 13 extensions; biosps2; int15 wait force unmask irq; int15 mouse callback does not preserve registers; filenamechar; collating and uppercase; con device use int 16h to detect keyboard input; zero memory on int 21h memory allocation
#DOSBOX-X-ADV-SEE:#
xms = true
xms handles = 0
@ -2263,6 +2266,7 @@ hard drive data rate limit = -1
floppy drive data rate limit = -1
#DOSBOX-X-ADV:special operation file prefix = .DB
#DOSBOX-X-ADV:drive z is remote = auto
#DOSBOX-X-ADV:drive z convert fat = false
#DOSBOX-X-ADV:drive z expand path = true
#DOSBOX-X-ADV:drive z hide files = /TEXTUTIL\25.COM /TEXTUTIL\28.COM /TEXTUTIL\50.COM
#DOSBOX-X-ADV:hidenonrepresentable = true

View File

@ -192,6 +192,7 @@ debuggerrun = debugger
# If set to "relative", the value of MOUNT -freesize will change relative to the specified value.
# If set to "fixed" (="false"), the value of MOUNT -freesize will be a fixed one to be reported all the time.
# Possible values: true, false, fixed, relative, cap, 2, 1, 0.
# convertdrivefat: If set, DOSBox-X will auto-convert mounted non-FAT drives (such as local drives) to FAT format for use with guest systems.
#
# Advanced options (see full configuration reference file [dosbox-x.reference.full.conf] for more details):
# -> disable graphical splash; allow quit after warning; keyboard hook; weitek; bochs debug port e9; compresssaveparts; show recorded filename; skip encoding unchanged frames; capture chroma format; capture format; shell environment size; private area size; turn off a20 gate on boot; cbus bus clock; isa bus clock; pci bus clock; call binary on reset; unhandled irq handler; call binary on boot; ibm rom basic; rom bios allocation max; rom bios minimum size; irq delay ns; iodelay; iodelay16; iodelay32; acpi; acpi rsd ptr location; acpi sci irq; acpi iobase; acpi reserved size; memsizekb; dos mem limit; isa memory hole at 512kb; reboot delay; memalias; leading colon write protect image; locking disk image mount; unmask keyboard on int 16 read; int16 keyboard polling undocumented cf behavior; allow port 92 reset; enable port 92; enable 1st dma controller; enable 2nd dma controller; allow dma address decrement; enable 128k capable 16-bit dma; enable dma extra page registers; dma page registers write-only; cascade interrupt never in service; cascade interrupt ignore in service; enable slave pic; enable pc nmi mask; allow more than 640kb base memory; enable pci bus
@ -222,6 +223,7 @@ a20 = mask
memsize = 16
nocachedir = false
freesizecap = cap
convertdrivefat = true
[render]
# frameskip: How many frames DOSBox-X skips before drawing one.
@ -1086,7 +1088,7 @@ timeout = 0
# dos clipboard api: If set, DOS APIs for communications with the Windows clipboard will be enabled for shared clipboard communications.
#
# Advanced options (see full configuration reference file [dosbox-x.reference.full.conf] for more details):
# -> badcommandhandler; hma allow reservation; special operation file prefix; drive z is remote; drive z expand path; drive z hide files; hidenonrepresentable; hma minimum allocation; dos sda size; hma free space; cpm compatibility mode; minimum dos initial private segment; minimum mcb segment; enable dummy device mcb; maximum environment block size on exec; additional environment block size on exec; enable a20 on windows init; zero memory on xms memory allocation; vcpi; unmask timer on disk io; zero int 67h if no ems; zero unused int 68h; emm386 startup active; zero memory on ems memory allocation; ems system handle memory size; ems system handle on even megabyte; umb start; umb end; kernel allocation in umb; keep umb on boot; keep private area on boot; private area in umb; autoa20fix; autoloadfix; startincon; int33 hide host cursor if interrupt subroutine; int33 hide host cursor when polling; int33 disable cell granularity; int 13 disk change detect; int 13 extensions; biosps2; int15 wait force unmask irq; int15 mouse callback does not preserve registers; filenamechar; collating and uppercase; con device use int 16h to detect keyboard input; zero memory on int 21h memory allocation
# -> badcommandhandler; hma allow reservation; special operation file prefix; drive z is remote; drive z convert fat; drive z expand path; drive z hide files; hidenonrepresentable; hma minimum allocation; dos sda size; hma free space; cpm compatibility mode; minimum dos initial private segment; minimum mcb segment; enable dummy device mcb; maximum environment block size on exec; additional environment block size on exec; enable a20 on windows init; zero memory on xms memory allocation; vcpi; unmask timer on disk io; zero int 67h if no ems; zero unused int 68h; emm386 startup active; zero memory on ems memory allocation; ems system handle memory size; ems system handle on even megabyte; umb start; umb end; kernel allocation in umb; keep umb on boot; keep private area on boot; private area in umb; autoa20fix; autoloadfix; startincon; int33 hide host cursor if interrupt subroutine; int33 hide host cursor when polling; int33 disable cell granularity; int 13 disk change detect; int 13 extensions; biosps2; int15 wait force unmask irq; int15 mouse callback does not preserve registers; filenamechar; collating and uppercase; con device use int 16h to detect keyboard input; zero memory on int 21h memory allocation
#
xms = true
xms handles = 0

View File

@ -388,6 +388,7 @@ debuggerrun = debugger
# If set to "relative", the value of MOUNT -freesize will change relative to the specified value.
# If set to "fixed" (="false"), the value of MOUNT -freesize will be a fixed one to be reported all the time.
# Possible values: true, false, fixed, relative, cap, 2, 1, 0.
# convertdrivefat: If set, DOSBox-X will auto-convert mounted non-FAT drives (such as local drives) to FAT format for use with guest systems.
# leading colon write protect image: If set, BOOT and IMGMOUNT commands will put an image file name with a leading colon (:) in write-protect mode.
# locking disk image mount: If set, BOOT and IMGMOUNT commands will try to lock the mounted disk image files. As a result, you cannot
# mount the same disk image files in read/write mode at the same time as this can cause possible disk corruptions.
@ -483,6 +484,7 @@ reboot delay = -1
memalias = 0
nocachedir = false
freesizecap = cap
convertdrivefat = true
leading colon write protect image = true
locking disk image mount = true
unmask keyboard on int 16 read = true
@ -2013,6 +2015,7 @@ timeout = 0
# Set this option to true to prevent SCANDISK.EXE from attempting scan and repair drive Z:
# which is impossible since Z: is a virtual drive not backed by a disk filesystem.
# Possible values: true, false, 1, 0, auto.
# drive z convert fat: If set, DOSBox-X will automatically convert the Z drive into disk image as well when "convertdrivefat" is set.
# drive z expand path: If set, DOSBox-X will automatically expand the %PATH% environment variable to include the subdirectories on the Z drive.
# drive z hide files: The files or directories listed here (separated by space) will be either hidden or removed from the Z drive.
# Files with leading forward slashes (e.g. "/DEBUG\BIOSTEST.COM") will become hidden files (DIR /A will list them).
@ -2203,6 +2206,7 @@ hard drive data rate limit = -1
floppy drive data rate limit = -1
special operation file prefix = .DB
drive z is remote = auto
drive z convert fat = false
drive z expand path = true
drive z hide files = /TEXTUTIL\25.COM /TEXTUTIL\28.COM /TEXTUTIL\50.COM
hidenonrepresentable = true

View File

@ -65,9 +65,12 @@ class imageDisk {
virtual void Get_Geometry(uint32_t * getHeads, uint32_t *getCyl, uint32_t *getSect, uint32_t *getSectSize);
virtual uint8_t GetBiosType(void);
virtual uint32_t getSectSize(void);
imageDisk(class DOS_Drive *useDrive);
imageDisk(FILE *imgFile, const char *imgName, uint32_t imgSizeK, bool isHardDisk);
imageDisk(FILE* diskimg, const char* diskName, uint32_t cylinders, uint32_t heads, uint32_t sectors, uint32_t sector_size, bool hardDrive);
virtual ~imageDisk() { if(diskimg != NULL) { fclose(diskimg); diskimg=NULL; } };
virtual ~imageDisk();
void Set_GeometryForHardDisk();
struct fatFromDOSDrive* ffdd = NULL;
IMAGE_TYPE class_id = ID_BASE;
std::string diskname;
@ -91,6 +94,7 @@ class imageDisk {
private:
volatile int refcount = 0;
std::vector<bool> partition_in_use; /* used by FAT driver to prevent mounting a partition twice */
uint64_t current_fpos;
public:
int Addref() {

View File

@ -1,4 +1,4 @@
/*auto-generated*/
#define UPDATED_STR "Jul 1, 2022 2:43:23pm"
#define GIT_COMMIT_HASH "644ab8a"
#define UPDATED_STR "Jul 3, 2022 11:03:27pm"
#define GIT_COMMIT_HASH "e73255c"
#define COPYRIGHT_END_YEAR "2022"

View File

@ -332,7 +332,6 @@ public:
virtual void closedir(void *handle) { (void)handle; };
virtual bool read_directory_first(void *handle, char* entry_name, char* entry_sname, bool& is_directory) { (void)handle; (void)entry_name; (void)entry_sname; (void)is_directory; return false; };
virtual bool read_directory_next(void *handle, char* entry_name, char* entry_sname, bool& is_directory) { (void)handle; (void)entry_name; (void)entry_sname; (void)is_directory; return false; };
virtual const char * GetInfo(void);
char * GetBaseDir(void);

View File

@ -99,6 +99,7 @@ bool Mouse_Vertical = false;
bool force_nocachedir = false;
bool lockmount = true;
bool wpcolon = true;
bool convertimg = true;
bool startcmd = false;
bool startwait = true;
bool startquiet = false;
@ -107,7 +108,7 @@ bool mountwarning = true;
bool qmount = false;
bool nowarn = false;
bool CodePageHostToGuestUTF8(char *d/*CROSS_LEN*/,const char *s/*CROSS_LEN*/), CodePageHostToGuestUTF16(char *d/*CROSS_LEN*/,const uint16_t *s/*CROSS_LEN*/);
extern bool addovl, addipx, addne2k, prepared, inshell, usecon, uao, morelen, mountfro[26], mountiro[26], resetcolor, staycolors;
extern bool addovl, addipx, addne2k, prepared, inshell, usecon, uao, morelen, mountfro[26], mountiro[26], resetcolor, staycolors, internal_program;
extern bool clear_screen(), OpenGL_using(void), DOS_SetAnsiAttr(uint8_t attr);
extern int lastcp, FileDirExistCP(const char *name), FileDirExistUTF8(std::string &localname, const char *name);
extern uint8_t DOS_GetAnsiAttr(void);
@ -1846,6 +1847,7 @@ public:
bool bios_boot = false;
bool swaponedrive = false;
bool force = false;
int convimg = -1;
int quiet = 0;
//Hack To allow long commandlines
@ -1874,6 +1876,12 @@ public:
if (cmd->FindExist("-force",true))
force = true;
if (cmd->FindExist("-convertfat",true))
convimg = 1;
if (cmd->FindExist("-noconvertfat",true))
convimg = 0;
if (cmd->FindString("-bios",bios,true))
bios_boot = true;
@ -2490,10 +2498,44 @@ public:
return;
}
char msg[512] = {0};
const uint8_t page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
if ((convimg == 1 || (convertimg && convimg == -1 && !IS_PC98_ARCH))) { // PC-98 image not supported yet
unsigned int drv = 2, nextdrv = 2;
for (unsigned int d=2;d<DOS_DRIVES+2;d++) {
if (d==DOS_DRIVES) drv=0;
else if (d==DOS_DRIVES+1) drv=1;
else drv=d;
if (Drives[drv] && strncmp(Drives[drv]->GetInfo(), "fatDrive ", 9) && strncmp(Drives[drv]->GetInfo(), "isoDrive ", 9)) {
if (drv==ZDRIVE_NUM && !static_cast<Section_prop *>(control->GetSection("dos"))->Get_bool("drive z convert fat")) continue;
while (imageDiskList[nextdrv]) nextdrv++;
if (nextdrv>=MAX_DISK_IMAGES) break;
if (quiet<2) {
size_t len = strlen(msg);
if (!len) strcat(msg, CURSOR_POS_COL(page)>0?"\r\n":"");
strcat(msg, "Converting drive ");
strcat(msg, std::string(1, 'A'+drv).c_str());
strcat(msg, ": to FAT...\r\n");
LOG_MSG("%s", msg+len);
if (!quiet) {
uint16_t s = (uint16_t)strlen(msg);
DOS_WriteFile(STDERR,(uint8_t*)msg,&s);
*msg = 0;
}
}
imageDiskList[nextdrv] = new imageDisk(Drives[drv]);
if (imageDiskList[nextdrv]) {
bool ide_slave = false;
signed char ide_index = -1;
IDE_Auto(ide_index,ide_slave);
IDE_Hard_Disk_Attach((signed char)ide_index, ide_slave, nextdrv);
}
}
}
}
if (quiet<2) {
char msg[30];
const uint8_t page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE);
strcpy(msg, CURSOR_POS_COL(page)>0?"\r\n":"");
if (!strlen(msg)) strcat(msg, CURSOR_POS_COL(page)>0?"\r\n":"");
strcat(msg, "Booting from drive ");
strcat(msg, std::string(1, drive).c_str());
strcat(msg, "...\r\n");
@ -8283,8 +8325,10 @@ void Add_VFiles(bool usecp) {
PROGRAMS_MakeFile("CONFIG.COM",CONFIG_ProgramStart,"/SYSTEM/");
PROGRAMS_MakeFile("COUNTRY.COM",COUNTRY_ProgramStart,"/SYSTEM/");
PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart);
internal_program = true;
if (usecp) VFILE_Register("AUTOEXEC.BAT",(uint8_t *)autoexec_data,(uint32_t)strlen(autoexec_data));
if (prepared) VFILE_Register("CONFIG.SYS",(uint8_t *)config_data,(uint32_t)strlen(config_data));
internal_program = false;
PROGRAMS_MakeFile("RE-DOS.COM",REDOS_ProgramStart,"/SYSTEM/");
PROGRAMS_MakeFile("RESCAN.COM",RESCAN_ProgramStart,"/SYSTEM/");
#if defined(WIN32) && !defined(HX_DOS) || defined(LINUX) || defined(MACOSX)

View File

@ -633,4 +633,3 @@ void isoDrive::GetLongName(const char* ident, char* lfindName) {
strcpy(lfindName,ident);
}

View File

@ -1402,6 +1402,7 @@ bool localDrive::FileOpen(DOS_File * * file,const char * name,uint32_t flags) {
break;
}
}
if (!dos_kernel_disabled)
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]);
@ -2283,7 +2284,6 @@ bool localDrive::FileStat(const char* name, FileStat_Block * const stat_block) {
return true;
}
uint8_t localDrive::GetMediaByte(void) {
return allocation.mediaid;
}

View File

@ -593,6 +593,7 @@ bool Overlay_Drive::FileOpen(DOS_File * * file,const char * name,uint32_t flags)
break;
}
}
if (!dos_kernel_disabled)
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]);

View File

@ -41,13 +41,14 @@ struct VFILE_Block {
unsigned int onpos;
bool isdir;
bool hidden;
bool intprog;
VFILE_Block * next;
};
#define MAX_VFILES 500
unsigned int vfpos=1, lfn_id[256];
char ondirs[MAX_VFILES][CROSS_LEN],sfn[DOS_NAMELENGTH_ASCII];
char vfnames[MAX_VFILES][CROSS_LEN],vfsnames[MAX_VFILES][DOS_NAMELENGTH_ASCII];
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;
@ -249,7 +250,8 @@ void VFILE_Register(const char * name,uint8_t * data,uint32_t size,const char *d
VFILE_Block * new_file=new VFILE_Block;
new_file->name=vfsnames[vfpos];
new_file->lname=vfnames[vfpos];
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);
@ -550,7 +552,7 @@ bool Virtual_Drive::FindNext(DOS_DTA & dta) {
if (lfn_filefind_handle>=LFN_FILEFIND_MAX)
while (search_file) {
if (pos==search_file->onpos&&((attr & DOS_ATTR_DIRECTORY)||!search_file->isdir)&&(WildFileCmp(search_file->name,pattern)||LWildFileCmp(search_file->lname,pattern))) {
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,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;
@ -559,7 +561,7 @@ bool Virtual_Drive::FindNext(DOS_DTA & dta) {
}
else
while (lfn_search[lfn_filefind_handle]) {
if (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))) {
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,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;

View File

@ -99,7 +99,6 @@ public:
virtual void remove_special_file_from_disk(const char* dosname, const char* operation);
virtual std::string create_filename_of_special_operation(const char* dosname, const char* operation, bool expand);
virtual bool add_special_file_to_disk(const char* dosname, const char* operation, uint16_t value, bool isdir);
virtual void EmptyCache(void) { dirCache.EmptyCache(); };
virtual void MediaChange() {};
const char* getBasedir() {return basedir;};
@ -681,7 +680,7 @@ private:
bool GetNextDirEntry(const int dirIteratorHandle, isoDirEntry* de);
void FreeDirIterator(const int dirIterator);
bool ReadCachedSector(uint8_t** buffer, const uint32_t sector);
void GetLongName(const char* ident, char* lfindName);
void GetLongName(const char* ident, char* lfindName);
struct DirIterator {
bool valid;

View File

@ -124,6 +124,7 @@ static void CheckX86ExtensionsSupport()
extern void GFX_SetTitle(int32_t cycles, int frameskip, Bits timing, bool paused);
extern void AddSaveStateMapper(), AddMessages(), JFONT_Init(), J3_SetType(std::string type, std::string back, std::string text);
extern bool force_nocachedir;
extern bool convertimg;
extern bool wpcolon;
extern bool lockmount;
extern bool clearline;
@ -793,9 +794,8 @@ void DOSBOX_InitTickLoop() {
void Init_VGABIOS() {
long rom_sz = 0;
FILE *rom_fp = NULL;
Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosbox"));
Section_prop *video_section = static_cast<Section_prop *>(control->GetSection("video"));
assert(section != NULL && video_section != NULL);
assert(video_section != NULL);
if (IS_PC98_ARCH) {
// There IS no VGA BIOS, this is PC-98 mode!
@ -812,14 +812,6 @@ void Init_VGABIOS() {
// We can remove this once the device callout system is in place.
assert(MemBase != NULL);
force_nocachedir = section->Get_bool("nocachedir");
std::string freesizestr = section->Get_string("freesizecap");
if (freesizestr == "fixed" || freesizestr == "false" || freesizestr == "0") freesizecap = 0;
else if (freesizestr == "relative" || freesizestr == "2") freesizecap = 2;
else freesizecap = 1;
wpcolon = section->Get_bool("leading colon write protect image");
lockmount = section->Get_bool("locking disk image mount");
VGA_BIOS_use_rom = video_section->Get_bool("vga bios use rom image");
VGA_BIOS_rom = video_section->Get_string("vga bios rom image");
@ -1036,6 +1028,15 @@ void DOSBOX_RealInit() {
// TODO: should be parsed by motherboard emulation
allow_port_92_reset = section->Get_bool("allow port 92 reset");
force_nocachedir = section->Get_bool("nocachedir");
std::string freesizestr = section->Get_string("freesizecap");
if (freesizestr == "fixed" || freesizestr == "false" || freesizestr == "0") freesizecap = 0;
else if (freesizestr == "relative" || freesizestr == "2") freesizecap = 2;
else freesizecap = 1;
convertimg = section->Get_bool("convertdrivefat");
wpcolon = section->Get_bool("leading colon write protect image");
lockmount = section->Get_bool("locking disk image mount");
// CGA/EGA/VGA-specific
extern unsigned char vga_p3da_undefined_bits;
vga_p3da_undefined_bits = (unsigned char)static_cast<Section_prop *>(control->GetSection("video"))->Get_hex("vga 3da undefined bits");
@ -1791,6 +1792,10 @@ void DOSBOX_SetupConfigSections(void) {
"If set to \"fixed\" (=\"false\"), the value of MOUNT -freesize will be a fixed one to be reported all the time.");
Pstring->SetBasic(true);
Pbool = secprop->Add_bool("convertdrivefat",Property::Changeable::WhenIdle,true);
Pbool->Set_help("If set, DOSBox-X will auto-convert mounted non-FAT drives (such as local drives) to FAT format for use with guest systems.");
Pbool->SetBasic(true);
Pbool = secprop->Add_bool("leading colon write protect image",Property::Changeable::WhenIdle,true);
Pbool->Set_help("If set, BOOT and IMGMOUNT commands will put an image file name with a leading colon (:) in write-protect mode.");
@ -4100,6 +4105,9 @@ void DOSBOX_SetupConfigSections(void) {
"Set this option to true to prevent SCANDISK.EXE from attempting scan and repair drive Z:\n"
"which is impossible since Z: is a virtual drive not backed by a disk filesystem.");
Pbool = secprop->Add_bool("drive z convert fat",Property::Changeable::WhenIdle,false);
Pbool->Set_help("If set, DOSBox-X will automatically convert the Z drive into disk image as well when \"convertdrivefat\" is set.");
Pbool = secprop->Add_bool("drive z expand path",Property::Changeable::WhenIdle,true);
Pbool->Set_help("If set, DOSBox-X will automatically expand the %PATH% environment variable to include the subdirectories on the Z drive.");

View File

@ -73,7 +73,7 @@ bool tonoime = false, enableime = false;
bool usesystemcursor = false, rtl = false, selmark = false;
bool mountfro[26], mountiro[26];
bool OpenGL_using(void), Direct3D_using(void);
void DOSBox_SetSysMenu(void), GFX_OpenGLRedrawScreen(void), InitFontHandle(void), DOSV_FillScreen(void), SetWindowTransparency(int trans);
void DOSBox_SetSysMenu(void), GFX_OpenGLRedrawScreen(void), InitFontHandle(void), DOSV_FillScreen(void), Add_VFiles(bool usecp), SetWindowTransparency(int trans);
void MenuBrowseProgramFile(void), OutputSettingMenuUpdate(void), aspect_ratio_menu(void), update_pc98_clock_pit_menu(void), AllocCallback1(void), AllocCallback2(void), ToggleMenu(bool pressed);
int Reflect_Menu(void);
@ -9190,12 +9190,14 @@ fresh_boot:
Voodoo_Output_Enable(false);
grGlideShutdown();
/* shutdown DOSBox-X's virtual drive Z */
VFILE_Shutdown();
/* shutdown the programs */
PROGRAMS_Shutdown(); /* FIXME: Is this safe? Or will this cause use-after-free bug? */
Add_VFiles(false);
/* remove environment variables for some components */
DOS_UninstallMisc();
SBLASTER_DOS_Shutdown();

View File

@ -34,9 +34,850 @@
#endif
extern int bootdrive;
extern bool int13_disk_change_detect_enable;
extern unsigned long freec;
extern bool int13_disk_change_detect_enable, skipintprog, rsize;
extern bool int13_extensions_enable, bootguest, bootvm, use_quick_reboot;
#define STATIC_ASSERTM(A,B) static_assertion_##A##_##B
#define STATIC_ASSERTN(A,B) STATIC_ASSERTM(A,B)
#define STATIC_ASSERT(cond) typedef char STATIC_ASSERTN(__LINE__,__COUNTER__)[(cond)?1:-1]
uint32_t DriveCalculateCRC32(const uint8_t *ptr, size_t len, uint32_t crc)
{
// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/
static const uint32_t s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
uint32_t crcu32 = (uint32_t)~crc;
while (len--) { uint8_t b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; }
return ~crcu32;
}
void DriveFileIterator(DOS_Drive* drv, void(*func)(const char* path, bool is_dir, uint32_t size, uint16_t date, uint16_t time, uint8_t attr, Bitu data), Bitu data)
{
if (!drv) return;
struct Iter
{
static void ParseDir(DOS_Drive* drv, const std::string& dir, std::vector<std::string>& dirs, void(*func)(const char* path, bool is_dir, uint32_t size, uint16_t date, uint16_t time, uint8_t attr, Bitu data), Bitu data)
{
size_t dirlen = dir.length();
if (dirlen + DOS_NAMELENGTH >= DOS_PATHLENGTH) return;
char full_path[DOS_PATHLENGTH+4];
if (dirlen)
{
memcpy(full_path, &dir[0], dirlen);
full_path[dirlen++] = '\\';
}
full_path[dirlen] = '\0';
RealPt save_dta = dos.dta();
dos.dta(dos.tables.tempdta);
DOS_DTA dta(dos.dta());
dta.SetupSearch(255, (uint8_t)(0xffff & ~DOS_ATTR_VOLUME), (char*)"*.*");
for (bool more = drv->FindFirst((char*)dir.c_str(), dta); more; more = drv->FindNext(dta))
{
char dta_name[DOS_NAMELENGTH_ASCII], lname[LFN_NAMELENGTH+1]; uint32_t dta_size; uint16_t dta_date, dta_time; uint8_t dta_attr;
dta.GetResult(dta_name, lname, dta_size, dta_date, dta_time, dta_attr);
strcpy(full_path + dirlen, dta_name);
bool is_dir = !!(dta_attr & DOS_ATTR_DIRECTORY);
//if (is_dir) printf("[%s] [%s] %s (size: %u - date: %u - time: %u - attr: %u)\n", (const char*)data, (dta_attr == 8 ? "V" : (is_dir ? "D" : "F")), full_path, dta_size, dta_date, dta_time, dta_attr);
if (dta_name[0] == '.' && dta_name[dta_name[1] == '.' ? 2 : 1] == '\0') continue;
if (is_dir) dirs.emplace_back(full_path);
func(full_path, is_dir, dta_size, dta_date, dta_time, dta_attr, data);
}
dos.dta(save_dta);
}
};
std::vector<std::string> dirs;
dirs.emplace_back("");
std::string dir;
while (dirs.size())
{
std::swap(dirs.back(), dir);
dirs.pop_back();
Iter::ParseDir(drv, dir.c_str(), dirs, func, data);
}
}
template <typename TVal> struct StringToPointerHashMap
{
StringToPointerHashMap() : len(0), maxlen(0), keys(NULL), vals(NULL) { }
~StringToPointerHashMap() { free(keys); free(vals); }
static uint32_t Hash(const char* str, uint32_t str_limit = 0xFFFF, uint32_t hash_init = (uint32_t)0x811c9dc5)
{
for (const char* e = str + str_limit; *str && str != e;)
hash_init = ((hash_init * (uint32_t)0x01000193) ^ (uint32_t)*(str++));
return hash_init;
}
TVal* Get(const char* str, uint32_t str_limit = 0xFFFF, uint32_t hash_init = (uint32_t)0x811c9dc5) const
{
if (len == 0) return NULL;
for (uint32_t key0 = Hash(str, str_limit, hash_init), key = (key0 ? key0 : 1), i = key;; i++)
{
if (keys[i &= maxlen] == key) return vals[i];
if (!keys[i]) return NULL;
}
}
void Put(const char* str, TVal* val, uint32_t str_limit = 0xFFFF, uint32_t hash_init = (uint32_t)0x811c9dc5)
{
if (len * 2 >= maxlen) Grow();
for (uint32_t key0 = Hash(str, str_limit, hash_init), key = (key0 ? key0 : 1), i = key;; i++)
{
if (!keys[i &= maxlen]) { len++; keys[i] = key; vals[i] = val; return; }
if (keys[i] == key) { vals[i] = val; return; }
}
}
bool Remove(const char* str, uint32_t str_limit = 0xFFFF, uint32_t hash_init = (uint32_t)0x811c9dc5)
{
if (len == 0) return false;
for (uint32_t key0 = Hash(str, str_limit, hash_init), key = (key0 ? key0 : 1), i = key;; i++)
{
if (keys[i &= maxlen] == key)
{
keys[i] = 0;
len--;
while ((key = keys[i = (i + 1) & maxlen]) != 0)
{
for (uint32_t j = key;; j++)
{
if (keys[j &= maxlen] == key) break;
if (!keys[j]) { keys[i] = 0; keys[j] = key; vals[j] = vals[i]; break; }
}
}
return true;
}
if (!keys[i]) return false;
}
}
void Clear() { memset(keys, len = 0, (maxlen + 1) * sizeof(uint32_t)); }
uint32_t Len() const { return len; }
uint32_t Capacity() const { return (maxlen ? maxlen + 1 : 0); }
TVal* GetAtIndex(uint32_t idx) const { return (keys[idx] ? vals[idx] : NULL); }
struct Iterator
{
Iterator(StringToPointerHashMap<TVal>& _map, uint32_t _index) : map(_map), index(_index - 1) { this->operator++(); }
StringToPointerHashMap<TVal>& map;
uint32_t index;
TVal* operator *() const { return map.vals[index]; }
bool operator ==(const Iterator &other) const { return index == other.index; }
bool operator !=(const Iterator &other) const { return index != other.index; }
Iterator& operator ++()
{
if (!map.maxlen) { index = 0; return *this; }
if (++index > map.maxlen) index = map.maxlen + 1;
while (index <= map.maxlen && !map.keys[index]) index++;
return *this;
}
};
Iterator begin() { return Iterator(*this, 0); }
Iterator end() { return Iterator(*this, (maxlen ? maxlen + 1 : 0)); }
private:
uint32_t len, maxlen, *keys;
TVal** vals;
void Grow()
{
uint32_t oldMax = maxlen, oldCap = (maxlen ? oldMax + 1 : 0), *oldKeys = keys;
TVal **oldVals = vals;
maxlen = (maxlen ? maxlen * 2 + 1 : 15);
keys = (uint32_t*)calloc(maxlen + 1, sizeof(uint32_t));
vals = (TVal**)malloc((maxlen + 1) * sizeof(TVal*));
for (uint32_t i = 0; i != oldCap; i++)
{
if (!oldKeys[i]) continue;
for (uint32_t key = oldKeys[i], j = key;; j++)
{
if (!keys[j &= maxlen]) { keys[j] = key; vals[j] = oldVals[i]; break; }
}
}
free(oldKeys);
free(oldVals);
}
// not copyable
StringToPointerHashMap(const StringToPointerHashMap&);
StringToPointerHashMap& operator=(const StringToPointerHashMap&);
};
#ifdef _MSC_VER
#pragma pack (1)
#endif
struct bootstrap {
uint8_t nearjmp[3];
uint8_t oemname[8];
uint8_t bytespersector[2];
uint8_t sectorspercluster;
uint16_t reservedsectors;
uint8_t fatcopies;
uint16_t rootdirentries;
uint16_t totalsectorcount;
uint8_t mediadescriptor;
uint16_t sectorsperfat;
uint16_t sectorspertrack;
uint16_t headcount;
uint32_t hiddensectorcount;
uint32_t totalsecdword;
uint8_t bootcode[474];
uint8_t magic1; /* 0x55 */
uint8_t magic2; /* 0xaa */
} GCC_ATTRIBUTE(packed);
struct lfndirentry {
uint8_t ord;
uint8_t name1[10];
uint8_t attrib;
uint8_t type;
uint8_t chksum;
uint8_t name2[12];
uint16_t loFirstClust;
uint8_t name3[4];
char* Name(int j) { return (char*)(j < 5 ? name1 + j*2 : j < 11 ? name2 + (j-5)*2 : name3 + (j-11)*2); }
} GCC_ATTRIBUTE(packed);
#ifdef _MSC_VER
#pragma pack ()
#endif
STATIC_ASSERT(sizeof(direntry) == sizeof(lfndirentry));
enum
{
DOS_ATTR_LONG_NAME = (DOS_ATTR_READ_ONLY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM | DOS_ATTR_VOLUME),
DOS_ATTR_LONG_NAME_MASK = (DOS_ATTR_READ_ONLY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM | DOS_ATTR_VOLUME | DOS_ATTR_DIRECTORY | DOS_ATTR_ARCHIVE),
DOS_ATTR_PENDING_SHORT_NAME = 0x80,
};
struct fatFromDOSDrive
{
DOS_Drive* drive;
enum ffddDefs : uint32_t
{
BYTESPERSECTOR = 512,
HEADCOUNT = 240, // needs to be >128 to fit 4GB into CHS
SECTORSPERTRACK = 63,
SECT_MBR = 0,
SECT_BOOT = 32,
CACHECOUNT = 256,
KEEPOPENCOUNT = 8,
NULL_CURSOR = (uint32_t)-1,
};
partTable mbr;
bootstrap bootsec;
uint8_t fsinfosec[BYTESPERSECTOR];
uint32_t sectorsPerCluster;
bool isFAT32, readOnly, tomany = false;
struct ffddFile { char path[DOS_PATHLENGTH+1]; uint32_t firstSect; };
std::vector<direntry> root, dirs;
std::vector<ffddFile> files;
std::vector<uint32_t> fileAtSector;
std::vector<uint8_t> fat;
uint32_t sect_disk_end, sect_files_end, sect_files_start, sect_dirs_start, sect_root_start, sect_fat2_start, sect_fat1_start;
struct ffddBuf { uint8_t data[BYTESPERSECTOR]; };
struct ffddSec { uint32_t cursor = NULL_CURSOR; };
std::vector<ffddBuf> diffSectorBufs;
std::vector<ffddSec> diffSectors;
std::vector<uint32_t> diffFreeCursors;
std::string savePath;
FILE* saveFile = NULL;
uint32_t saveEndCursor = 0;
uint8_t cacheSectorData[CACHECOUNT][BYTESPERSECTOR];
uint32_t cacheSectorNumber[CACHECOUNT];
DOS_File* openFiles[KEEPOPENCOUNT];
uint32_t openIndex[KEEPOPENCOUNT];
uint32_t openCursor = 0;
~fatFromDOSDrive()
{
if (saveFile)
fclose(saveFile);
for (DOS_File* df : openFiles)
if (df) { df->Close(); delete df; }
}
fatFromDOSDrive(DOS_Drive* drv) : drive(drv)
{
cacheSectorNumber[0] = 1; // must not state that sector 0 is already cached
memset(&cacheSectorNumber[1], 0, sizeof(cacheSectorNumber) - sizeof(cacheSectorNumber[0]));
memset(openFiles, 0, sizeof(openFiles));
struct Iter
{
static void SetFAT(fatFromDOSDrive& ffdd, size_t idx, uint32_t val)
{
while (idx >= ffdd.fat.size() / (ffdd.isFAT32 ? 4 : 2))
{
ffdd.fat.resize(ffdd.fat.size() + BYTESPERSECTOR);
memset(&ffdd.fat[ffdd.fat.size() - BYTESPERSECTOR], 0, BYTESPERSECTOR);
}
if (ffdd.isFAT32)
var_write((uint32_t * const)&ffdd.fat[idx * 4], (const uint32_t)val);
else
var_write((uint16_t * const)&ffdd.fat[idx * 2], (const uint16_t)val);
}
static direntry* AddDirEntry(fatFromDOSDrive& ffdd, bool useFAT16Root, size_t& diridx)
{
const uint32_t entriesPerCluster = ffdd.sectorsPerCluster * BYTESPERSECTOR / sizeof(direntry);
if (!useFAT16Root && (diridx % entriesPerCluster) == 0)
{
// link fat (was set to 0xFFFF before but now we knew the chain continues)
if (diridx) SetFAT(ffdd, 2 + (diridx - 1) / entriesPerCluster, (uint32_t)(2 + ffdd.dirs.size() / entriesPerCluster));
diridx = ffdd.dirs.size();
ffdd.dirs.resize(diridx + entriesPerCluster);
memset(&ffdd.dirs[diridx], 0, sizeof(direntry) * entriesPerCluster);
SetFAT(ffdd, 2 + diridx / entriesPerCluster, (uint32_t)0xFFFFFFFF); // set as last cluster in chain for now
}
else if (useFAT16Root && diridx && (diridx % 512) == 0)
{
// this actually should never be larger than 512 for some FAT16 drivers
ffdd.root.resize(diridx + 512);
memset(&ffdd.root[diridx], 0, sizeof(direntry) * 512);
}
return &(!useFAT16Root ? ffdd.dirs : ffdd.root)[diridx++];
}
static void ParseDir(fatFromDOSDrive& ffdd, char* dir, const StringToPointerHashMap<void>* filter, int dirlen = 0, uint16_t parentFirstCluster = 0)
{
if (ffdd.tomany) return;
const bool useFAT16Root = (!dirlen && !ffdd.isFAT32), readOnly = ffdd.readOnly;
const size_t firstidx = (!useFAT16Root ? ffdd.dirs.size() : 0);
const uint32_t sectorsPerCluster = ffdd.sectorsPerCluster, bytesPerCluster = sectorsPerCluster * BYTESPERSECTOR, entriesPerCluster = bytesPerCluster / sizeof(direntry);
const uint16_t myFirstCluster = (dirlen ? (uint16_t)(2 + firstidx / entriesPerCluster) : (uint16_t)0) ;
char finddir[DOS_PATHLENGTH+4];
memcpy(finddir, dir, dirlen); // because FindFirst can modify this...
finddir[dirlen] = '\0';
if (dirlen) dir[dirlen++] = '\\';
size_t diridx = 0;
RealPt save_dta = dos.dta();
dos.dta(dos.tables.tempdta);
DOS_DTA dta(dos.dta());
dta.SetupSearch(255, 0xFF, (char*)"*.*");
skipintprog = true;
for (bool more = ffdd.drive->FindFirst(finddir, dta); more; more = ffdd.drive->FindNext(dta))
{
char dta_name[DOS_NAMELENGTH_ASCII], lname[LFN_NAMELENGTH+1]; uint32_t dta_size; uint16_t dta_date, dta_time; uint8_t dta_attr;
dta.GetResult(dta_name, lname, dta_size, dta_date, dta_time, dta_attr);
//LOG_MSG("dta_name %s lname %s\n", dta_name, lname);
const char *fend = dta_name + strlen(dta_name);
const bool dot = (dta_name[0] == '.' && dta_name[1] == '\0'), dotdot = (dta_name[0] == '.' && dta_name[1] == '.' && dta_name[2] == '\0');
if (!dirlen && (dot || dotdot)) continue; // root shouldn't have dot entries (yet localDrive does...)
ffddFile f;
memcpy(f.path, dir, dirlen);
memcpy(f.path + dirlen, dta_name, fend - dta_name + 1);
if (filter && filter->Get(f.path)) continue;
const bool isLongFileName = (!dot && !dotdot && !(dta_attr & DOS_ATTR_VOLUME));
if (isLongFileName)
{
size_t lfnlen = strlen(lname);
const char *lfn_end = lname + lfnlen;
for (size_t i = 0, lfnblocks = (lfnlen + 12) / 13; i != lfnblocks; i++)
{
lfndirentry* le = (lfndirentry*)AddDirEntry(ffdd, useFAT16Root, diridx);
le->ord = (uint8_t)((lfnblocks - i)|(i == 0 ? 0x40 : 0x0));
le->attrib = DOS_ATTR_LONG_NAME;
le->type = 0;
le->loFirstClust = 0;
const char* plfn = lname + (lfnblocks - i - 1) * 13;
for (int j = 0; j != 13; j++, plfn++)
{
char* p = le->Name(j);
if (plfn > lfn_end) { p[0] = p[1] = (char)0xFF; }
else if (plfn == lfn_end) { p[0] = p[1] = 0; }
else { p[0] = *plfn; p[1] = 0; }
}
}
}
const char *fext = (dot || dotdot ? NULL : strrchr(dta_name, '.'));
direntry* e = AddDirEntry(ffdd, useFAT16Root, diridx);
memset(e->entryname, ' ', sizeof(e->entryname));
memcpy(e->entryname, dta_name, (fext ? fext : fend) - dta_name);
if (fext++) memcpy(e->entryname + 8, fext, fend - fext);
e->attrib = dta_attr | (readOnly ? DOS_ATTR_READ_ONLY : 0) | (isLongFileName ? DOS_ATTR_PENDING_SHORT_NAME : 0);
if (dos.version.major >= 7) {
var_write(&e->crtTime, dta_time); // create date/time is DOS 7.0 and up only
var_write(&e->crtDate, dta_date); // create date/time is DOS 7.0 and up only
}
var_write(&e->accessDate, dta_date);
var_write(&e->modTime, dta_time);
var_write(&e->modDate, dta_date);
if (dot)
{
e->attrib |= DOS_ATTR_DIRECTORY; // make sure
var_write(&e->loFirstClust, myFirstCluster);
}
else if (dotdot)
{
e->attrib |= DOS_ATTR_DIRECTORY; // make sure
var_write(&e->loFirstClust, parentFirstCluster);
}
else if (dta_attr & DOS_ATTR_VOLUME)
{
if ((dirlen || (e->attrib & DOS_ATTR_DIRECTORY) || dta_size)) {
if (!strcmp(trim((char *)e->entryname), "DOSBOX-X")) continue;
LOG_MSG("Invalid volume entry - %s\n", e->entryname);
}
}
else if (!(dta_attr & DOS_ATTR_DIRECTORY))
{
var_write(&e->entrysize, dta_size);
uint32_t fileIdx = (uint32_t)ffdd.files.size();
ffdd.files.push_back(f);
uint32_t numSects = (dta_size + bytesPerCluster - 1) / bytesPerCluster * sectorsPerCluster;
try {
ffdd.fileAtSector.resize(ffdd.fileAtSector.size() + numSects, fileIdx);
} catch (...) {
LOG_MSG("Too many sectors needed, will discard remaining files (from %s)", lname);
ffdd.tomany = ffdd.readOnly = true;
var_write((uint32_t *const)&ffdd.fsinfosec[488], (const uint32_t)0x0);
break;
}
}
}
skipintprog = false;
dos.dta(save_dta);
if (dirlen && diridx < firstidx + 2) {
LOG_MSG("Directory need at least . and .. entries - %s\n", finddir);
return;
}
// Now fill out the subdirectories (can't be done above because only one dos.dta can run simultaneously
std::vector<direntry>& entries = (!useFAT16Root ? ffdd.dirs : ffdd.root);
for (size_t ei = firstidx; ei != diridx; ei++)
{
direntry& e = entries[ei];
uint8_t* entryname = e.entryname;
int totlen = dirlen;
if (e.attrib & DOS_ATTR_DIRECTORY) // copy name before modifying SFN
{
if (entryname[0] == '.' && entryname[entryname[1] == '.' ? 2 : 1] == ' ') continue;
for (int i = 0; i != 8 && entryname[i] != ' '; i++) dir[totlen++] = entryname[i];
if (entryname[8] != ' ') dir[totlen++] = '.';
for (int i = 8; i != 11 && entryname[i] != ' '; i++) dir[totlen++] = entryname[i];
}
if (e.attrib & DOS_ATTR_PENDING_SHORT_NAME) // convert LFN to SFN
{
memset(entryname, ' ', sizeof(e.entryname));
int ni = 0, niext = 0, lossy = 0;
for (lfndirentry* le = (lfndirentry*)&e; le-- == (lfndirentry*)&e || !(le[1].ord & 0x40);)
{
for (int j = 0; j != 13; j++)
{
char c = *le->Name(j);
if (c == '\0') { lossy |= (niext && ni - niext > 3); break; }
if (c == '.') { if (ni > 8) { memset(entryname+8, ' ', 3); ni = 8; } if (!ni || niext) { lossy = 1; } niext = ni; continue; }
if (c == ' ' || ni == 11 || (ni == 8 && !niext)) { lossy = 1; continue; }
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { }
else if (c >= 'a' && c <= 'z') { c ^= 0x20; }
else if (strchr("$%'-_@~`!(){}^#&", c)) { }
else { lossy = 1; c = '_'; }
entryname[ni++] = (uint8_t)c;
}
}
if (niext && niext != 8)
for (int i = 2; i >= 0; i--)
entryname[8+i] = entryname[niext+i], entryname[niext+i] = ' ';
if (niext && niext <= 4 && ni - niext > 3)
for (int i = niext + 3; i != 8; i++)
entryname[i] = ' ';
if (lossy)
{
if (!niext) niext = ni;
for (int i = 1; i <= 999999; i++)
{
int taillen = (i<=9?2:i<=99?3:i<=999?4:i<=9999?5:i<=99999?6:7);
char* ptr = (char*)&entryname[niext + taillen > 8 ? 8 : niext + taillen];
for (int j = i; j; j /= 10) *--ptr = '0'+(j%10);
*--ptr = '~';
bool conflict = false;
for (size_t e2 = firstidx; e2 != diridx; e2++)
if (!(entries[e2].attrib & (DOS_ATTR_VOLUME|DOS_ATTR_PENDING_SHORT_NAME)) && !memcmp(entryname, entries[e2].entryname, sizeof(e.entryname)))
{ conflict = true; break; }
if (!conflict) break;
}
}
uint8_t chksum = 0;
for (int i = 0; i != 11;) chksum = (chksum >> 1) + (chksum << 7) + entryname[i++];
for (lfndirentry* le = (lfndirentry*)&e; le-- == (lfndirentry*)&e || !(le[1].ord & 0x40);) le->chksum = chksum;
e.attrib &= ~DOS_ATTR_PENDING_SHORT_NAME;
}
if (e.attrib & DOS_ATTR_DIRECTORY) // this reallocates ffdd.dirs so do this last
{
var_write(&e.loFirstClust, (const uint16_t)(2 + ffdd.dirs.size() / entriesPerCluster));
ParseDir(ffdd, dir, filter, totlen, myFirstCluster);
}
}
}
struct SumInfo { uint64_t used_bytes; const StringToPointerHashMap<void>* filter; };
static void SumFileSize(const char* path, bool is_dir, uint32_t size, uint16_t, uint16_t, uint8_t, Bitu data)
{
if (!((SumInfo*)data)->filter || !((SumInfo*)data)->filter->Get(path))
((SumInfo*)data)->used_bytes += (size + (32*1024-1)) / (32*1024) * (32*1024); // count as 32 kb clusters
}
};
Iter::SumInfo sum = { 0, NULL };
Bitu freeSpace = 0, freeSpaceMB = 0;
uint32_t free_clusters = 0;
uint16_t drv_bytes_sector; uint8_t drv_sectors_cluster; uint16_t drv_total_clusters, drv_free_clusters;
rsize=true;
freec=0;
drv->AllocationInfo(&drv_bytes_sector, &drv_sectors_cluster, &drv_total_clusters, &drv_free_clusters);
free_clusters = freec?freec:drv_free_clusters;
freeSpace = (Bitu)drv_bytes_sector * (Bitu)drv_sectors_cluster * (Bitu)(freec?freec:free_clusters);
freeSpaceMB = freeSpace / (1024*1024);
rsize=false;
DriveFileIterator(drv, Iter::SumFileSize, (Bitu)&sum);
readOnly = (free_clusters == 0);
tomany = false;
const uint32_t addFreeMB = (readOnly ? 0 : freeSpaceMB), totalMB = (uint32_t)(sum.used_bytes / (1024*1024)) + addFreeMB + 1;
if (totalMB >= 3072) { isFAT32 = true; sectorsPerCluster = 64; } // 32 kb clusters ( 98304 ~ FAT entries)
else if (totalMB >= 2048) { isFAT32 = true; sectorsPerCluster = 32; } // 16 kb clusters (131072 ~ 196608 FAT entries)
else if (totalMB >= 384) { isFAT32 = false; sectorsPerCluster = 64; } // 32 kb clusters ( 12288 ~ 65504 FAT entries)
else if (totalMB >= 192) { isFAT32 = false; sectorsPerCluster = 32; } // 16 kb clusters ( 12288 ~ 24576 FAT entries)
else if (totalMB >= 96) { isFAT32 = false; sectorsPerCluster = 16; } // 8 kb clusters ( 12288 ~ 24576 FAT entries)
else if (totalMB >= 48) { isFAT32 = false; sectorsPerCluster = 8; } // 4 kb clusters ( 12288 ~ 24576 FAT entries)
else if (totalMB >= 8) { isFAT32 = false; sectorsPerCluster = 4; } // 4 kb clusters ( 4096 ~ 24576 FAT entries)
else { isFAT32 = false; sectorsPerCluster = 1; } // 2 kb clusters ( ~ 16383 FAT entries)
// mediadescriptor in very first byte of FAT table
Iter::SetFAT(*this, 0, (uint32_t)0xFFFFFF8);
Iter::SetFAT(*this, 1, (uint32_t)0xFFFFFFF);
if (!isFAT32)
{
// this actually should never be anything but 512 for some FAT16 drivers
root.resize(512);
memset(&root[0], 0, sizeof(direntry) * 512);
}
char dirbuf[DOS_PATHLENGTH+4];
Iter::ParseDir(*this, dirbuf, NULL);
const uint32_t bytesPerCluster = sectorsPerCluster * BYTESPERSECTOR;
const uint32_t entriesPerCluster = bytesPerCluster / sizeof(direntry);
uint32_t fileCluster = (uint32_t)(2 + dirs.size() / entriesPerCluster);
for (uint32_t fileSect = 0, rootOrDir = 0; rootOrDir != 2; rootOrDir++)
{
for (direntry& e : (rootOrDir ? dirs : root))
{
if (!e.entrysize || (e.attrib & DOS_ATTR_LONG_NAME_MASK) == DOS_ATTR_LONG_NAME) continue;
var_write(&e.hiFirstClust, (const uint16_t)(fileCluster >> 16));
var_write(&e.loFirstClust, (const uint16_t)(fileCluster));
// Write FAT link chain
uint32_t numClusters = (var_read(&e.entrysize) + bytesPerCluster - 1) / bytesPerCluster;
for (uint32_t i = fileCluster, iEnd = i + numClusters - 1; i != iEnd; i++) Iter::SetFAT(*this, i, i + 1);
Iter::SetFAT(*this, fileCluster + numClusters - 1, (uint32_t)0xFFFFFFF);
files[fileAtSector[fileSect]].firstSect = fileSect;
fileCluster += numClusters;
fileSect += numClusters * sectorsPerCluster;
}
}
// Add at least one page after the last file or FAT spec minimume to make ScanDisk happy (even on read-only disks)
const uint32_t FATWidth = (isFAT32 ? 4 : 2), FATPageClusters = BYTESPERSECTOR / FATWidth, FATMinCluster = (isFAT32 ? 65525 : 4085) + FATPageClusters;
const uint32_t addFreeClusters = ((addFreeMB * (1024*1024/BYTESPERSECTOR)) + sectorsPerCluster - 1) / sectorsPerCluster;
const uint32_t targetClusters = fileCluster + (addFreeClusters < FATPageClusters ? FATPageClusters : addFreeClusters);
Iter::SetFAT(*this, (targetClusters < FATMinCluster ? FATMinCluster : targetClusters) - 1, 0);
const uint32_t totalClusters = (uint32_t)(fat.size() / FATWidth); // as set by Iter::SetFAT
// on read-only disks, fill up the end of the FAT table with "Bad sector in cluster or reserved cluster" markers
if (readOnly)
for (uint32_t cluster = fileCluster; cluster != totalClusters; cluster++)
Iter::SetFAT(*this, cluster, 0xFFFFFF7);
const uint32_t sectorsPerFat = (uint32_t)(fat.size() / BYTESPERSECTOR);
const uint16_t reservedSectors = (isFAT32 ? 32 : 1);
const uint32_t partSize = totalClusters * sectorsPerCluster + reservedSectors;
sect_fat1_start = SECT_BOOT + reservedSectors;
sect_fat2_start = sect_fat1_start + sectorsPerFat;
sect_root_start = sect_fat2_start + sectorsPerFat;
sect_dirs_start = sect_root_start + ((root.size() * sizeof(direntry) + BYTESPERSECTOR - 1) / BYTESPERSECTOR);
sect_files_start = sect_dirs_start + ((dirs.size() * sizeof(direntry) + BYTESPERSECTOR - 1) / BYTESPERSECTOR);
sect_files_end = sect_files_start + fileAtSector.size();
sect_disk_end = SECT_BOOT + partSize;
assert(sect_disk_end >= sect_files_end);
for (ffddFile& f : files)
f.firstSect += sect_files_start;
uint32_t serial = 0;
if (!serial)
{
serial = DriveCalculateCRC32(&fat[0], fat.size(), 0);
if (root.size()) serial = DriveCalculateCRC32((uint8_t*)&root[0], root.size() * sizeof(direntry), serial);
if (dirs.size()) serial = DriveCalculateCRC32((uint8_t*)&dirs[0], dirs.size() * sizeof(direntry), serial);
}
memset(&mbr, 0, sizeof(mbr));
var_write((uint32_t *)&mbr.booter[440], serial); //4 byte disk serial number
var_write(&mbr.pentry[0].bootflag, 0x80); //Active bootable
if ((sect_disk_end - 1) / (HEADCOUNT * SECTORSPERTRACK) > 0x3FF)
{
mbr.pentry[0].beginchs[0] = mbr.pentry[0].beginchs[1] = mbr.pentry[0].beginchs[2] = 0;
mbr.pentry[0].endchs[0] = mbr.pentry[0].endchs[1] = mbr.pentry[0].endchs[2] = 0;
}
else
{
chs_write(mbr.pentry[0].beginchs, SECT_BOOT);
chs_write(mbr.pentry[0].endchs, sect_disk_end - 1);
}
var_write(&mbr.pentry[0].absSectStart, SECT_BOOT);
var_write(&mbr.pentry[0].partSize, partSize);
mbr.magic1 = 0x55; mbr.magic2 = 0xaa;
memset(&bootsec, 0, sizeof(bootsec));
memcpy(bootsec.nearjmp, "\xEB\x3C\x90", sizeof(bootsec.nearjmp));
memcpy(bootsec.oemname, "MSWIN4.1", sizeof(bootsec.oemname));
var_write((uint16_t *const)&bootsec.bytespersector, (const uint16_t)BYTESPERSECTOR);
var_write(&bootsec.sectorspercluster, sectorsPerCluster);
var_write(&bootsec.reservedsectors, reservedSectors);
var_write(&bootsec.fatcopies, 2);
var_write(&bootsec.totalsectorcount, 0); // 16 bit field is 0, actual value is in totalsecdword
var_write(&bootsec.mediadescriptor, 0xF8); //also in FAT[0]
var_write(&bootsec.sectorspertrack, SECTORSPERTRACK);
var_write(&bootsec.headcount, HEADCOUNT);
var_write(&bootsec.hiddensectorcount, SECT_BOOT);
var_write(&bootsec.totalsecdword, partSize);
bootsec.magic1 = 0x55; bootsec.magic2 = 0xaa;
if (!isFAT32) // FAT16
{
var_write(&mbr.pentry[0].parttype, 0x04); //FAT16
var_write((uint16_t *const)&bootsec.rootdirentries, (const uint16_t)root.size());
var_write((uint16_t *const)&bootsec.sectorsperfat, (const uint16_t)sectorsPerFat);
bootsec.bootcode[0] = 0x80; //Physical drive (harddisk) flag
bootsec.bootcode[2] = 0x29; //Extended boot signature
var_write((uint32_t *const)&bootsec.bootcode[3], (const uint32_t)(serial + 1)); //4 byte partition serial number
memcpy(&bootsec.bootcode[7], "NO NAME ", 11); // volume label
memcpy(&bootsec.bootcode[18], "FAT16 ", 8); // file system string name
}
else // FAT32
{
var_write(&mbr.pentry[0].parttype, 0x0C); //FAT32
var_write((uint32_t *const)&bootsec.bootcode[0], sectorsPerFat);
var_write((uint32_t *const)&bootsec.bootcode[8], (const uint32_t)2); // First cluster number of the root directory
var_write((uint16_t *const)&bootsec.bootcode[12], (const uint16_t)1); // Sector of FSInfo structure in offset from top of the FAT32 volume
var_write((uint16_t *const)&bootsec.bootcode[14], (const uint16_t)6); // Sector of backup boot sector in offset from top of the FAT32 volume
bootsec.bootcode[28] = 0x80; //Physical drive (harddisk) flag
bootsec.bootcode[30] = 0x29; //Extended boot signature
var_write((uint32_t *const)&bootsec.bootcode[31], (const uint32_t)(serial + 1)); //4 byte partition serial number
memcpy(&bootsec.bootcode[35], "NO NAME ", 11); // volume label
memcpy(&bootsec.bootcode[46], "FAT32 ", 8); // file system string name
memset(fsinfosec, 0, sizeof(fsinfosec));
var_write((uint32_t *const)&fsinfosec[0], (const uint32_t)0x41615252); //lead signature
var_write((uint32_t *const)&fsinfosec[484], (const uint32_t)0x61417272); //Another signature
Bitu freeclusters = (Bitu)freeSpace / (BYTESPERSECTOR * sectorsPerCluster);
var_write((uint32_t *const)&fsinfosec[488], (const uint32_t)(readOnly ? 0x0 : (freeclusters < 0xFFFFFFFF ? freeclusters : 0xFFFFFFFF))); //last known free cluster count (all FF is unknown)
var_write((uint32_t *const)&fsinfosec[492], (const uint32_t)0xFFFFFFFF); //the cluster number at which the driver should start looking for free clusters (all FF is unknown)
var_write((uint32_t *const)&fsinfosec[508], (const uint32_t)0xAA550000); //ending signature
}
}
static void chs_write(uint8_t* chs, uint32_t lba)
{
uint32_t cylinder = lba / (HEADCOUNT * SECTORSPERTRACK);
uint32_t head = (lba / SECTORSPERTRACK) % HEADCOUNT;
uint32_t sector = (lba % SECTORSPERTRACK) + 1;
if (head > 0xFF || sector > 0x3F || cylinder > 0x3FF)
LOG_MSG("Warning: Invalid CHS data - %X, %X, %X\n", head, sector, cylinder);
chs[0] = (uint8_t)(head & 0xFF);
chs[1] = (uint8_t)((sector & 0x3F) | ((cylinder >> 8) & 0x3));
chs[2] = (uint8_t)(cylinder & 0xFF);
}
uint8_t WriteSector(uint32_t sectnum, const void* data)
{
if (sectnum >= sect_disk_end) return 1;
if (sectnum == SECT_MBR)
{
// Windows 9x writes the disk timestamp into the booter area on startup.
// Just copy that part over so it doesn't get treated as a difference that needs to be stored.
memcpy(mbr.booter, data, sizeof(mbr.booter));
}
if (readOnly) return 0; // just return without error to avoid bluescreens in Windows 9x
if (sectnum >= diffSectors.size()) diffSectors.resize(sectnum + 128);
uint32_t *cursor_ptr = &diffSectors[sectnum].cursor, cursor_val = *cursor_ptr;
int is_different;
uint8_t filebuf[BYTESPERSECTOR];
void* unmodified = GetUnmodifiedSector(sectnum, filebuf);
if (!unmodified)
{
is_different = false; // to be equal it must be filled with zeroes
for (uint64_t* p = (uint64_t*)data, *pEnd = p + (BYTESPERSECTOR / sizeof(uint64_t)); p != pEnd; p++)
if (*p) { is_different = true; break; }
}
else is_different = memcmp(unmodified, data, BYTESPERSECTOR);
if (is_different)
{
if (!saveFile && !savePath.empty())
{
saveFile = fopen(savePath.c_str(), "wb+");
if (saveFile) { fwrite("FFDD\x1", 5, 1, saveFile); saveEndCursor = 5; };
savePath.clear();
}
if (cursor_val == NULL_CURSOR && diffFreeCursors.size())
{
*cursor_ptr = cursor_val = diffFreeCursors.back();
diffFreeCursors.pop_back();
}
if (saveFile)
{
if (cursor_val == NULL_CURSOR)
{
uint32_t sectnumval;
var_write(&sectnumval, sectnum);
*cursor_ptr = cursor_val = saveEndCursor;
saveEndCursor += sizeof(sectnumval) + BYTESPERSECTOR;
fseeko64(saveFile, cursor_val, SEEK_SET);
fwrite(&sectnumval, sizeof(sectnumval), 1, saveFile);
}
else
fseeko64(saveFile, cursor_val + sizeof(sectnum), SEEK_SET);
fwrite(data, BYTESPERSECTOR, 1, saveFile);
}
else
{
if (cursor_val == NULL_CURSOR)
{
*cursor_ptr = cursor_val = (uint32_t)diffSectorBufs.size();
diffSectorBufs.resize(cursor_val + 1);
}
memcpy(diffSectorBufs[cursor_val].data, data, BYTESPERSECTOR);
}
cacheSectorNumber[sectnum % CACHECOUNT] = (uint32_t)-1; // invalidate cache
}
else if (cursor_val != NULL_CURSOR)
{
if (saveFile)
{
// mark sector in diff file as free
uint32_t sectnumval = 0xFFFFFFFF;
fseeko64(saveFile, cursor_val, SEEK_SET);
fwrite(&sectnumval, sizeof(sectnumval), 1, saveFile);
}
diffFreeCursors.push_back(cursor_val);
*cursor_ptr = NULL_CURSOR;
cacheSectorNumber[sectnum % CACHECOUNT] = (uint32_t)-1; // invalidate cache
}
return 0;
}
void* GetUnmodifiedSector(uint32_t sectnum, void* filebuf)
{
if (sectnum >= sect_files_end) {}
else if (sectnum >= sect_files_start)
{
uint32_t idx = fileAtSector[sectnum - sect_files_start];
ffddFile& f = files[idx];
DOS_File* df = NULL;
for (uint32_t i = 0; i != KEEPOPENCOUNT; i++)
if (openIndex[i] == idx && openFiles[i])
{ df = openFiles[i]; break; }
if (!df)
{
openCursor = (openCursor + 1) % KEEPOPENCOUNT;
DOS_File*& cachedf = openFiles[openCursor];
if (cachedf)
{
cachedf->Close();
delete cachedf;
cachedf = NULL;
}
bool res = drive->FileOpen(&df, f.path, OPEN_READ) ;
if (res)
{
df->AddRef();
cachedf = df;
openIndex[openCursor] = idx;
}
else return NULL;
}
if (df)
{
uint32_t pos = (sectnum - f.firstSect) * BYTESPERSECTOR;
uint16_t read = (uint16_t)BYTESPERSECTOR;
df->Seek(&pos, DOS_SEEK_SET);
if (!df->Read((uint8_t*)filebuf, &read)) { read = 0; assert(0); }
if (read != BYTESPERSECTOR)
memset((uint8_t*)filebuf + read, 0, BYTESPERSECTOR - read);
return filebuf;
}
}
else if (sectnum >= sect_dirs_start) return &dirs[(sectnum - sect_dirs_start) * (BYTESPERSECTOR / sizeof(direntry))];
else if (sectnum >= sect_root_start) return &root[(sectnum - sect_root_start) * (BYTESPERSECTOR / sizeof(direntry))];
else if (sectnum >= sect_fat2_start) return &fat[(sectnum - sect_fat2_start) * BYTESPERSECTOR];
else if (sectnum >= sect_fat1_start) return &fat[(sectnum - sect_fat1_start) * BYTESPERSECTOR];
else if (sectnum == SECT_BOOT) return &bootsec;
else if (sectnum == SECT_MBR) return &mbr;
else if (sectnum == SECT_BOOT+1) return fsinfosec;
else if (sectnum == SECT_BOOT+2) return fsinfosec; // additional boot loader code (anything is ok for us but needs 0x55AA footer signature)
else if (sectnum == SECT_BOOT+6) return &bootsec; // boot sector copy
else if (sectnum == SECT_BOOT+7) return fsinfosec; // boot sector copy
else if (sectnum == SECT_BOOT+8) return fsinfosec; // boot sector copy
return NULL;
}
uint8_t ReadSector(uint32_t sectnum, void* data)
{
uint32_t sectorHash = sectnum % CACHECOUNT;
void *cachedata = cacheSectorData[sectorHash];
if (cacheSectorNumber[sectorHash] == sectnum)
{
memcpy(data, cachedata, BYTESPERSECTOR);
return 0;
}
cacheSectorNumber[sectorHash] = sectnum;
void *src;
uint32_t cursor = (sectnum >= diffSectors.size() ? NULL_CURSOR : diffSectors[sectnum].cursor);
if (cursor != NULL_CURSOR)
{
if (saveFile)
{
fseeko64(saveFile, cursor + sizeof(sectnum), SEEK_SET);
src = (fread(cachedata, BYTESPERSECTOR, 1, saveFile) ? cachedata : NULL);
}
else src = diffSectorBufs[cursor].data;
}
else src = GetUnmodifiedSector(sectnum, cachedata);
if (src) memcpy(data, src, BYTESPERSECTOR);
else memset(data, 0, BYTESPERSECTOR);
if (src != cachedata) memcpy(cachedata, data, BYTESPERSECTOR);
return 0;
}
};
diskGeo DiskGeometryList[] = {
{ 160, 8, 1, 40, 0, 512, 64, 1, 0xFE}, // IBM PC double density 5.25" single-sided 160KB
{ 180, 9, 1, 40, 0, 512, 64, 2, 0xFC}, // IBM PC double density 5.25" single-sided 180KB
@ -91,7 +932,7 @@ void FreeBIOSDiskList() {
for (int i=0;i < MAX_DISK_IMAGES;i++) {
if (imageDiskList[i] != NULL) {
if (i >= 2) IDE_Hard_Disk_Detach(i);
imageDiskList[i]->Release();
if (!imageDiskList[i]->ffdd) imageDiskList[i]->Release();
imageDiskList[i] = NULL;
}
}
@ -269,6 +1110,8 @@ uint8_t imageDisk::Read_Sector(uint32_t head,uint32_t cylinder,uint32_t sector,v
}
uint8_t imageDisk::Read_AbsoluteSector(uint32_t sectnum, void * data) {
if (ffdd) return ffdd->ReadSector(sectnum, data);
uint64_t bytenum,res;
int got;
@ -314,6 +1157,8 @@ uint8_t imageDisk::Write_Sector(uint32_t head,uint32_t cylinder,uint32_t sector,
uint8_t imageDisk::Write_AbsoluteSector(uint32_t sectnum, const void *data) {
if (ffdd) return ffdd->WriteSector(sectnum, data);
uint64_t bytenum;
bytenum = (uint64_t)sectnum * sector_size;
@ -346,7 +1191,8 @@ uint32_t imageDisk::Get_Reserved_Cylinders() {
imageDisk::imageDisk(IMAGE_TYPE class_id) : class_id(class_id) {
}
imageDisk::imageDisk(FILE* diskimg, const char* diskName, uint32_t cylinders, uint32_t heads, uint32_t sectors, uint32_t sector_size, bool hardDrive) {
imageDisk::imageDisk(FILE* diskimg, const char* diskName, uint32_t cylinders, uint32_t heads, uint32_t sectors, uint32_t sector_size, bool hardDrive) : ffdd(NULL)
{
if (diskName) this->diskname = diskName;
this->cylinders = cylinders;
this->heads = heads;
@ -642,6 +1488,50 @@ imageDisk::imageDisk(FILE* imgFile, const char* imgName, uint32_t imgSizeK, bool
}
}
imageDisk::imageDisk(class DOS_Drive *useDrive)
{
ffdd = new fatFromDOSDrive(useDrive);
diskimg = NULL;
diskname[0] = '\0';
hardDrive = true;
Set_GeometryForHardDisk();
}
imageDisk::~imageDisk()
{
if(diskimg != NULL) {
fclose(diskimg);
diskimg=NULL;
}
if (ffdd)
delete ffdd;
}
void imageDisk::Set_GeometryForHardDisk()
{
sector_size = 512;
partTable mbrData;
for (int m = (Read_AbsoluteSector(0, &mbrData) ? 0 : 4); m--;)
{
if(!mbrData.pentry[m].partSize) continue;
bootstrap bootbuffer;
if (Read_AbsoluteSector(mbrData.pentry[m].absSectStart, &bootbuffer)) continue;
bootbuffer.sectorspertrack = var_read(&bootbuffer.sectorspertrack);
bootbuffer.headcount = var_read(&bootbuffer.headcount);
uint32_t setSect = bootbuffer.sectorspertrack;
uint32_t setHeads = bootbuffer.headcount;
uint32_t setCyl = (mbrData.pentry[m].absSectStart + mbrData.pentry[m].partSize) / (setSect * setHeads);
Set_Geometry(setHeads, setCyl, setSect, 512);
return;
}
if (!diskimg) return;
uint32_t diskimgsize;
fseek(diskimg,0,SEEK_END);
diskimgsize = (uint32_t)ftell(diskimg);
fseek(diskimg,current_fpos,SEEK_SET);
Set_Geometry(16, (uint32_t)(diskimgsize / (512 * 63 * 16)), 63, 512);
}
void imageDisk::Set_Geometry(uint32_t setHeads, uint32_t setCyl, uint32_t setSect, uint32_t setSectSize) {
Bitu bigdisk_shift = 0;

View File

@ -57,7 +57,7 @@ extern const char *modifier;
extern unsigned int sendkeymap;
extern std::string langname, configfile, dosbox_title;
extern int autofixwarn, enablelfn, fat32setver, paste_speed, wheel_key, freesizecap, wpType, wpVersion, wpBG, wpFG, lastset, blinkCursor;
extern bool dos_kernel_disabled, force_nocachedir, wpcolon, lockmount, enable_config_as_shell_commands, lesssize, load, winrun, winautorun, startcmd, startwait, startquiet, starttranspath, mountwarning, wheel_guest, clipboard_dosapi, noremark_save_state, force_load_state, sync_time, manualtime, ttfswitch, loadlang, showbold, showital, showline, showsout, char512, printfont, rtl, gbk, chinasea, uao, showdbcs, dbcs_sbcs, autoboxdraw, halfwidthkana, ticksLocked, outcon, enable_dbcs_tables, show_recorded_filename;
extern bool dos_kernel_disabled, force_nocachedir, wpcolon, convertimg, lockmount, enable_config_as_shell_commands, lesssize, load, winrun, winautorun, startcmd, startwait, startquiet, starttranspath, mountwarning, wheel_guest, clipboard_dosapi, noremark_save_state, force_load_state, sync_time, manualtime, ttfswitch, loadlang, showbold, showital, showline, showsout, char512, printfont, rtl, gbk, chinasea, uao, showdbcs, dbcs_sbcs, autoboxdraw, halfwidthkana, ticksLocked, outcon, enable_dbcs_tables, show_recorded_filename, internal_program;
/* This registers a file on the virtual drive and creates the correct structure for it*/
@ -136,7 +136,9 @@ void PROGRAMS_MakeFile(char const * const name,PROGRAMS_Main * main,const char *
ipe->comsize = size;
ipe->comdata = comdata;
internal_progs.push_back(ipe);
internal_program = true;
VFILE_Register(name,ipe->comdata,ipe->comsize,dir);
internal_program = false;
}
static Bitu PROGRAMS_Handler(void) {
@ -641,6 +643,7 @@ void ApplySetting(std::string pvar, std::string inputline, bool quiet) {
if (freesizestr == "fixed" || freesizestr == "false" || freesizestr == "0") freesizecap = 0;
else if (freesizestr == "relative" || freesizestr == "2") freesizecap = 2;
else freesizecap = 1;
convertimg = section->Get_bool("convertdrivefat");
wpcolon = section->Get_bool("leading colon write protect image");
lockmount = section->Get_bool("locking disk image mount");
if (!strcasecmp(inputline.substr(0, 9).c_str(), "saveslot=")) SetGameState_Run(section->Get_int("saveslot")-1);

View File

@ -50,9 +50,9 @@
#endif
#include "build_timestamp.h"
extern bool startcmd, startwait, startquiet, winautorun;
extern bool dos_shell_running_program, mountwarning, winautorun;
extern bool startcmd, startwait, startquiet, internal_program;
extern bool halfwidthkana, force_conversion, showdbcs;
extern bool dos_shell_running_program, mountwarning;
extern bool addovl, addipx, addne2k, enableime, gbk;
extern const char* RunningProgram;
extern int enablelfn, msgcodepage;
@ -212,7 +212,11 @@ void AutoexecObject::CreateAutoexec(void) {
}
sprintf((autoexec_data + auto_len),"%s\r\n",linecopy.c_str());
}
if (first_shell) VFILE_Register("AUTOEXEC.BAT",(uint8_t *)autoexec_data,(uint32_t)strlen(autoexec_data));
if (first_shell) {
internal_program = true;
VFILE_Register("AUTOEXEC.BAT",(uint8_t *)autoexec_data,(uint32_t)strlen(autoexec_data));
internal_program = false;
}
}
void AutoexecObject::Uninstall() {
@ -854,7 +858,9 @@ void DOS_Shell::Prepare(void) {
strcat(config_data, section->Get_string("rem"));
strcat(config_data, "\r\n");
}
internal_program = true;
VFILE_Register("CONFIG.SYS",(uint8_t *)config_data,(uint32_t)strlen(config_data));
internal_program = false;
#if defined(WIN32)
if (!control->opt_securemode&&!control->SecureMode())
{

View File

@ -1534,8 +1534,8 @@ char *FormatTime(Bitu hour, Bitu min, Bitu sec, Bitu msec) {
return retBuf;
}
uint32_t byte_count,file_count,dir_count;
uint64_t byte_count;
uint32_t file_count,dir_count;
Bitu p_count;
std::vector<std::string> dirs, adirs;
static bool dirPaused(DOS_Shell * shell, Bitu w_size, bool optP, bool optW, bool show=true) {
@ -1581,7 +1581,8 @@ static bool doDir(DOS_Shell * shell, char * args, DOS_DTA dta, char * numformat,
}
if (*(sargs+strlen(sargs)-1) != '\\') strcat(sargs,"\\");
uint32_t cbyte_count=0,cfile_count=0,w_count=0;
uint64_t cbyte_count=0;
uint32_t cfile_count=0,w_count=0;
int fbak=lfn_filefind_handle;
lfn_filefind_handle=uselfn&&!optZ?LFN_FILEFIND_INTERNAL:LFN_FILEFIND_NONE;
bool ret=DOS_FindFirst(args,0xffff & ~DOS_ATTR_VOLUME), found=true, first=true;
@ -2064,7 +2065,7 @@ void DOS_Shell::CMD_DIR(char * args) {
if ((dos.version.major > 7 || (dos.version.major == 7 && dos.version.minor >= 10)) &&
Drives[drive]->AllocationInfo32(&bytes_sector32,&sectors_cluster32,&total_clusters32,&free_clusters32)) { /* FAT32 aware extended API */
freec=0;
free_space=(Bitu)bytes_sector32 * (Bitu)sectors_cluster32 * (Bitu)(freec?freec:free_clusters32);
free_space=(Bitu)bytes_sector32 * (Bitu)sectors_cluster32 * (Bitu)free_clusters32;
} else {
uint16_t bytes_sector;uint8_t sectors_cluster;uint16_t total_clusters;uint16_t free_clusters;
rsize=true;