#include "compiler.h"
#if defined(SUPPORT_HOSTDRV)
/*
ゲストOS(DOS)からホストOS(Win)にアクセスするの〜
完全にDOS(3.1以上)依存だお(汗
ネットワークインタフェイス搭載前の繋ぎだけど
更に、手抜き版だし(マテ
*/
#include "dosio.h"
#include "cpucore.h"
#include "pccore.h"
#include "iocore.h"
#include "hostdrv.h"
#include "hostdrvs.h"
#include "hostdrv.tbl"
#define IS_PERMITWRITE (np2cfg.hdrvacc & HDFMODE_WRITE)
#define IS_PERMITDELETE (np2cfg.hdrvacc & HDFMODE_DELETE)
#define ROOTPATH_NAME "\\\\HOSTDRV\\"
#define ROOTPATH_SIZE (sizeof(ROOTPATH_NAME) - 1)
static const char ROOTPATH[ROOTPATH_SIZE + 1] = ROOTPATH_NAME;
static const HDRVDIR hdd_volume = {"_HOSTDRIVE_", 0, 0, 0, 0x08, {0}, {0}};
static const HDRVDIR hdd_owner = {". ", 0, 0, 0, 0x10, {0}, {0}};
static const HDRVDIR hdd_parent = {".. ", 0, 0, 0, 0x10, {0}, {0}};
// see int2159-BX0000
enum {
ERR_NOERROR = 0x00,
ERR_FILENOTFOUND = 0x02,
ERR_PATHNOTFOUND = 0x03,
ERR_ACCESSDENIED = 0x05,
ERR_ATTEMPTEDCURRDIR = 0x10,
ERR_NOMOREFILES = 0x12,
ERR_DISKWRITEPROTECTED = 0x13,
ERR_WRITEFAULT = 0x1d,
ERR_READFAULT = 0x1e
};
HOSTDRV hostdrv;
// ---- i/f
static void succeed(INTRST intrst) {
intrst->r.b.flag_l &= ~C_FLAG;
STOREINTELWORD(intrst->r.w.ax, ERR_NOERROR);
}
static void fail(INTRST intrst, UINT16 err_code) {
intrst->r.b.flag_l |= C_FLAG;
STOREINTELWORD(intrst->r.w.ax, err_code);
}
static void fetch_if4dos(void) {
REG16 off;
REG16 seg;
IF4DOS if4dos;
off = MEMR_READ16(IF4DOSPTR_SEG, IF4DOSPTR_OFF + 0);
seg = MEMR_READ16(IF4DOSPTR_SEG, IF4DOSPTR_OFF + 2);
MEMR_READS(seg, off, &if4dos, sizeof(if4dos));
hostdrv.stat.drive_no = if4dos.drive_no;
hostdrv.stat.dosver_major = if4dos.dosver_major;
hostdrv.stat.dosver_minor = if4dos.dosver_minor;
hostdrv.stat.sda_off = LOADINTELWORD(if4dos.sda_off);
hostdrv.stat.sda_seg = LOADINTELWORD(if4dos.sda_seg);
TRACEOUT(("hostdrv:drive_no = %d", if4dos.drive_no));
TRACEOUT(("hostdrv:dosver = %d.%.2d", if4dos.dosver_major, if4dos.dosver_minor));
TRACEOUT(("hostdrv.sda = %.4x:%.4x", hostdrv.stat.sda_seg, hostdrv.stat.sda_off));
}
static void fetch_intr_regs(INTRST is) {
MEMR_READS(CPU_SS, CPU_BP, &is->r, sizeof(is->r));
}
static void store_intr_regs(INTRST is) {
MEMR_WRITES(CPU_SS, CPU_BP, &is->r, sizeof(is->r));
}
static void fetch_sda_currcds(SDACDS sc) {
REG16 off;
REG16 seg;
if (hostdrv.stat.dosver_major == 3) {
MEMR_READS(hostdrv.stat.sda_seg, hostdrv.stat.sda_off,
&sc->ver3.sda, sizeof(sc->ver3.sda));
off = LOADINTELWORD(sc->ver3.sda.cdsptr.off);
seg = LOADINTELWORD(sc->ver3.sda.cdsptr.seg);
MEMR_READS(seg, off, &sc->ver3.cds, sizeof(sc->ver3.cds));
}
else {
MEMR_READS(hostdrv.stat.sda_seg, hostdrv.stat.sda_off,
&sc->ver4.sda, sizeof(sc->ver4.sda));
off = LOADINTELWORD(sc->ver4.sda.cdsptr.off);
seg = LOADINTELWORD(sc->ver4.sda.cdsptr.seg);
MEMR_READS(seg, off, &sc->ver4.cds, sizeof(sc->ver4.cds));
}
}
static void store_sda_currcds(SDACDS sc) {
REG16 off;
REG16 seg;
if (hostdrv.stat.dosver_major == 3) {
MEMR_WRITES(hostdrv.stat.sda_seg, hostdrv.stat.sda_off,
&sc->ver3.sda, sizeof(sc->ver3.sda));
off = LOADINTELWORD(sc->ver3.sda.cdsptr.off);
seg = LOADINTELWORD(sc->ver3.sda.cdsptr.seg);
MEMR_WRITES(seg, off, &sc->ver3.cds, sizeof(sc->ver3.cds));
}
else {
MEMR_WRITES(hostdrv.stat.sda_seg, hostdrv.stat.sda_off,
&sc->ver4.sda, sizeof(sc->ver4.sda));
off = LOADINTELWORD(sc->ver4.sda.cdsptr.off);
seg = LOADINTELWORD(sc->ver4.sda.cdsptr.seg);
MEMR_WRITES(seg, off, &sc->ver4.cds, sizeof(sc->ver4.cds));
}
}
static void fetch_sft(INTRST is, SFTREC sft) {
REG16 off;
REG16 seg;
off = LOADINTELWORD(is->r.w.di);
seg = LOADINTELWORD(is->r.w.es);
MEMR_READS(seg, off, sft, sizeof(_SFTREC));
}
static void store_sft(INTRST is, SFTREC sft) {
REG16 off;
REG16 seg;
off = LOADINTELWORD(is->r.w.di);
seg = LOADINTELWORD(is->r.w.es);
MEMR_WRITES(seg, off, sft, sizeof(_SFTREC));
}
static void store_srch(INTRST is) {
SRCHREC srchrec;
// SDA内のSRCHRECにセット
srchrec = is->srchrec_ptr;
srchrec->drive_no = 0xc0 | hostdrv.stat.drive_no;
CopyMemory(srchrec->srch_mask, is->fcbname_ptr, 11);
srchrec->attr_mask = *is->srch_attr_ptr;
STOREINTELWORD(srchrec->dir_entry_no, ((UINT16)-1));
STOREINTELWORD(srchrec->dir_sector, ((UINT16)-1));
}
static void store_dir(INTRST is, const HDRVDIR *di) {
DIRREC dirrec;
UINT8 attr;
UINT16 reg;
// SDA内のDIRRECにセット
dirrec = is->dirrec_ptr;
CopyMemory(dirrec->file_name, di->fcbname, 11);
attr = (UINT8)(di->attr & 0x3f);
if (!IS_PERMITWRITE) {
attr |= 0x01;
}
dirrec->file_attr = attr;
reg = 0;
if (di->caps & FLICAPS_TIME) {
reg |= (di->time.hour & 0x1f) << 11;
reg |= (di->time.minute & 0x3f) << 5;
reg |= (di->time.second & 0x3e) >> 1;
}
STOREINTELWORD(dirrec->file_time, reg);
reg = 0;
if (di->caps & FLICAPS_DATE) {
reg |= ((di->date.year - 1980) & 0x7f) << 9;
reg |= (di->date.month & 0x0f) << 5;
reg |= di->date.day & 0x1f;
}
STOREINTELWORD(dirrec->file_date, reg);
STOREINTELWORD(dirrec->start_sector, ((UINT16)-1));
STOREINTELDWORD(dirrec->file_size, di->size);
}
static void fill_sft(INTRST is, SFTREC sft, UINT num, HDRVDIR *di) {
UINT8 attr;
UINT16 reg;
attr = di->attr;
if (!IS_PERMITWRITE) {
attr |= 0x01;
}
sft->file_attr = attr;
STOREINTELWORD(sft->start_sector, (UINT16)num);
reg = 0;
if (di->caps & FLICAPS_TIME) {
reg |= (di->time.hour & 0x1f) << 11;
reg |= (di->time.minute & 0x3f) << 5;
reg |= (di->time.second & 0x3e) >> 1;
}
STOREINTELWORD(sft->file_time, reg);
reg = 0;
if (di->caps & FLICAPS_DATE) {
reg |= ((di->date.year - 1980) & 0x7f) << 9;
reg |= (di->date.month & 0x0f) << 5;
reg |= di->date.day & 0x1f;
}
STOREINTELWORD(sft->file_date, reg);
STOREINTELDWORD(sft->file_size, di->size);
STOREINTELWORD(sft->dir_sector, (UINT16)-1);
sft->dir_entry_no = (UINT8)-1;
CopyMemory(sft->file_name, is->fcbname_ptr, 11);
TRACEOUT(("open -> size %d", di->size));
}
static void init_sft(SFTREC sft) {
if (sft->open_mode[1] & 0x80) { // fcb mode
sft->open_mode[0] |= 0xf0;
}
else {
sft->open_mode[0] &= 0x0f;
}
sft->dev_info_word[0] = (UINT8)(0x40 | hostdrv.stat.drive_no);
sft->dev_info_word[1] = 0x80;
STOREINTELDWORD(sft->dev_drvr_ptr, 0);
STOREINTELDWORD(sft->file_pos, 0);
STOREINTELWORD(sft->rel_sector, (UINT16)-1);
STOREINTELWORD(sft->abs_sector, (UINT16)-1);
if (sft->open_mode[1] & 0x80) { // fcb mode
CPU_FLAG |= C_FLAG;
}
}
static BOOL is_wildcards(const char *path) {
int i;
for (i=0; i<11; i++) {
if (path[i] == '?') {
return(TRUE);
}
}
return(FALSE);
}
static BOOL match2mask(const char *mask, const char *path) {
int i;
for (i=0; i<11; i++) {
if ((mask[i] != path[i]) && (mask[i] != '?')) {
return(FALSE);
}
}
return(TRUE);
}
// ぽいんた初期化
static void setup_ptrs(INTRST is, SDACDS sc) {
char *rootpath;
int off;
if (hostdrv.stat.dosver_major == 3) {
is->fcbname_ptr = sc->ver3.sda.fcb_name;
is->filename_ptr = sc->ver3.sda.file_name + ROOTPATH_SIZE - 1;
is->fcbname_ptr_2 = sc->ver3.sda.fcb_name_2;
is->filename_ptr_2 = sc->ver3.sda.file_name_2 + ROOTPATH_SIZE - 1;
is->srchrec_ptr = &sc->ver3.sda.srchrec;
is->dirrec_ptr = &sc->ver3.sda.dirrec;
is->srchrec_ptr_2 = &sc->ver3.sda.rename_srchrec;
is->dirrec_ptr_2 = &sc->ver3.sda.rename_dirrec;
is->srch_attr_ptr = &sc->ver3.sda.srch_attr;
rootpath = sc->ver3.cds.current_path;
off = LOADINTELWORD(sc->ver3.cds.root_ofs);
is->root_path = rootpath;
is->current_path = rootpath + off;
}
else {
is->fcbname_ptr = sc->ver4.sda.fcb_name;
is->filename_ptr = sc->ver4.sda.file_name + ROOTPATH_SIZE - 1;
is->fcbname_ptr_2 = sc->ver4.sda.fcb_name_2;
is->filename_ptr_2 = sc->ver4.sda.file_name_2 + ROOTPATH_SIZE - 1;
is->srchrec_ptr = &sc->ver4.sda.srchrec;
is->dirrec_ptr = &sc->ver4.sda.dirrec;
is->srchrec_ptr_2 = &sc->ver4.sda.rename_srchrec;
is->dirrec_ptr_2 = &sc->ver4.sda.rename_dirrec;
is->srch_attr_ptr = &sc->ver4.sda.srch_attr;
rootpath = sc->ver4.cds.current_path;
off = LOADINTELWORD(sc->ver4.cds.root_ofs);
is->root_path = rootpath;
is->current_path = rootpath + off;
}
}
static BOOL pathishostdrv(INTRST is, SDACDS sc) {
fetch_sda_currcds(sc);
setup_ptrs(is, sc);
if (memcmp(is->root_path, ROOTPATH, ROOTPATH_SIZE)) {
CPU_FLAG &= ~Z_FLAG; // chain
return(FAILURE);
}
if (is->is_chardev) {
fail(is, ERR_ACCESSDENIED);
return(FAILURE);
}
return(SUCCESS);
}
static BOOL read_data(UINT num, UINT32 pos, UINT size, UINT seg, UINT off) {
HDRVFILE hdf;
FILEH fh;
UINT8 work[1024];
UINT r;
hdf = (HDRVFILE)listarray_getitem(hostdrv.fhdl, num);
if (hdf == NULL) {
return(FAILURE);
}
fh = (FILEH)hdf->hdl;
if (file_seek(fh, (long)pos, FSEEK_SET) != (long)pos) {
return(FAILURE);
}
while(size) {
r = min(size, sizeof(work));
if (file_read(fh, work, r) != r) {
return(FAILURE);
}
MEMR_WRITES(seg, off, work, r);
off += r;
size -= r;
}
return(SUCCESS);
}
static BOOL write_data(UINT num, UINT32 pos, UINT size, UINT seg, UINT off) {
HDRVFILE hdf;
FILEH fh;
UINT8 work[1024];
UINT r;
hdf = (HDRVFILE)listarray_getitem(hostdrv.fhdl, num);
if (hdf == NULL) {
return(FAILURE);
}
fh = (FILEH)hdf->hdl;
if (file_seek(fh, (long)pos, FSEEK_SET) != (long)pos) {
return(FAILURE);
}
if (!size) {
file_write(fh, work, 0);
}
else {
do {
r = min(size, sizeof(work));
MEMR_READS(seg, off, work, r);
if (file_write(fh, work, r) != r) {
return(FAILURE);
}
off += r;
size -= r;
} while(size);
}
return(SUCCESS);
}
static BOOL find_file1(INTRST is, const HDRVDIR *di) {
UINT8 attrmask;
UINT attr;
attrmask = *is->srch_attr_ptr;
attr = (di->attr) & (~(attrmask));
if (attr & 0x16) {
return(FAILURE);
}
if (!match2mask(is->srchrec_ptr->srch_mask, di->fcbname)) {
return(FAILURE);
}
store_dir(is, di);
return(SUCCESS);
}
static BOOL find_file(INTRST is) {
BOOL ret;
UINT pos;
HDRVLST hdl;
const HDRVDIR *di;
store_srch(is);
ret = FAILURE;
pos = hostdrv.stat.flistpos;
do {
if (pos == 0) {
di = &hdd_owner;
}
else if (pos == 1) {
di = &hdd_parent;
}
else {
hdl = listarray_getitem(hostdrv.flist, pos - 2);
if (hdl == NULL) {
listarray_destroy(hostdrv.flist);
hostdrv.flist = NULL;
break;
}
di = &hdl->di;
}
pos++;
ret = find_file1(is, di);
} while(ret != SUCCESS);
hostdrv.stat.flistpos = pos;
return(ret);
}
// ----
/* cmd in int2f11 */
/* 00 */
static void inst_check(INTRST intrst) {
intrst->r.b.flag_l &= ~C_FLAG;
intrst->r.b.al = 0xff; // インストール済み。追加OKだお
}
/* 05 */
static void change_currdir(INTRST intrst) {
_SDACDS sc;
char *ptr;
HDRVPATH hdp;
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
ptr = intrst->filename_ptr;
TRACEOUT(("change_currdir %s", intrst->filename_ptr));
if (ptr[0] == '\0') { // るーと
strcpy(intrst->filename_ptr, "\\");
strcpy(intrst->current_path, intrst->filename_ptr);
store_sda_currcds(&sc);
succeed(intrst);
return;
}
if ((strlen(intrst->filename_ptr) >= (67 - ROOTPATH_SIZE)) ||
(is_wildcards(intrst->fcbname_ptr) != FALSE) ||
(hostdrvs_getrealpath(&hdp, ptr) != SUCCESS) ||
(hdp.di.fcbname[0] == ' ') || (!(hdp.di.attr & 0x10))) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
strcpy(intrst->current_path, intrst->filename_ptr);
store_sda_currcds(&sc);
succeed(intrst);
}
/* 06 */
static void close_file(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
UINT16 handle_count;
UINT16 start_sector;
HDRVFILE hdf;
fetch_sda_currcds(&sc);
fetch_sft(intrst, &sft);
setup_ptrs(intrst, &sc);
if ((sft.dev_info_word[0] & 0x3f) != hostdrv.stat.drive_no) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
handle_count = LOADINTELWORD(sft.handle_count);
if (handle_count) {
handle_count--;
}
if (handle_count == 0) {
start_sector = LOADINTELWORD(sft.start_sector);
hdf = listarray_getitem(hostdrv.fhdl, start_sector);
if (hdf) {
file_close((FILEH)hdf->hdl);
hdf->hdl = (long)FILEH_INVALID;
hdf->path[0] = '\0';
}
}
STOREINTELWORD(sft.handle_count, handle_count);
store_sft(intrst, &sft);
succeed(intrst);
}
/* 07 */
static void commit_file(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
fetch_sda_currcds(&sc);
fetch_sft(intrst, &sft);
if ((sft.dev_info_word[0] & 0x3f) != hostdrv.stat.drive_no) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
// なんもしないよー
succeed(intrst);
}
/* 08 */
static void read_file(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
UINT16 cx;
UINT file_size;
UINT32 file_pos;
fetch_sda_currcds(&sc);
fetch_sft(intrst, &sft);
setup_ptrs(intrst, &sc);
if ((sft.dev_info_word[0] & 0x3f) != hostdrv.stat.drive_no) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
if (sft.open_mode[0] & 1) {
fail(intrst, ERR_ACCESSDENIED);
return;
}
cx = LOADINTELWORD(intrst->r.w.cx);
file_size = LOADINTELDWORD(sft.file_size);
file_pos = LOADINTELDWORD(sft.file_pos);
if (cx > (file_size - file_pos)) {
cx = (UINT16)(file_size - file_pos);
STOREINTELWORD(intrst->r.w.cx, cx);
}
if (cx == 0) {
succeed(intrst);
return;
}
if (read_data(LOADINTELWORD(sft.start_sector), file_pos, cx,
LOADINTELWORD(sc.ver3.sda.current_dta.seg),
LOADINTELWORD(sc.ver3.sda.current_dta.off)) != SUCCESS) {
fail(intrst, ERR_READFAULT);
return;
}
file_pos += cx;
STOREINTELDWORD(sft.file_pos, file_pos);
store_sft(intrst, &sft);
// store_sda_currcds(&sc); // ver0.74 Yui / sdaは変更無し
succeed(intrst);
}
/* 09 */
static void write_file(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
UINT16 cx;
UINT file_size;
UINT32 file_pos;
fetch_sda_currcds(&sc);
fetch_sft(intrst, &sft);
setup_ptrs(intrst, &sc);
if ((sft.dev_info_word[0] & 0x3f) != hostdrv.stat.drive_no) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
if ((!IS_PERMITWRITE) ||
(!(sft.open_mode[0] & 3))) { // read only
fail(intrst, ERR_ACCESSDENIED);
return;
}
cx = LOADINTELWORD(intrst->r.w.cx);
file_size = LOADINTELDWORD(sft.file_size);
file_pos = LOADINTELDWORD(sft.file_pos);
if (write_data(LOADINTELWORD(sft.start_sector), file_pos, cx,
LOADINTELWORD(sc.ver3.sda.current_dta.seg),
LOADINTELWORD(sc.ver3.sda.current_dta.off)) != SUCCESS) {
fail(intrst, ERR_WRITEFAULT);
return;
}
if (cx) {
file_pos += cx;
if (file_size < file_pos) {
file_size = file_pos;
}
}
else {
file_size = file_pos;
}
STOREINTELDWORD(sft.file_size, file_size);
STOREINTELDWORD(sft.file_pos, file_pos);
store_sft(intrst, &sft);
succeed(intrst);
}
/* 0A */
static void lock_file(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
fetch_sda_currcds(&sc);
fetch_sft(intrst, &sft);
if ((sft.dev_info_word[0] & 0x3f) != hostdrv.stat.drive_no) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
// 未実装
TRACEOUT(("hostdrv: lock_file"));
}
/* 0B */
static void unlock_file(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
fetch_sda_currcds(&sc);
fetch_sft(intrst, &sft);
if ((sft.dev_info_word[0] & 0x3f) != hostdrv.stat.drive_no) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
// 未実装
TRACEOUT(("hostdrv: unlock_file"));
}
/* 0E */
static void set_fileattr(INTRST intrst) {
_SDACDS sc;
HDRVPATH hdp;
REG16 attr;
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
if ((is_wildcards(intrst->fcbname_ptr)) ||
(hostdrvs_getrealpath(&hdp, intrst->filename_ptr) != SUCCESS)) {
fail(intrst, ERR_FILENOTFOUND);
return;
}
if (!IS_PERMITWRITE) {
fail(intrst, ERR_ACCESSDENIED);
return;
}
attr = MEMR_READ16(CPU_SS, CPU_BP + sizeof(IF4INTR)) & 0x37;
// 成功したことにする...
succeed(intrst);
}
/* 0F */
static void get_fileattr(INTRST intrst) {
_SDACDS sc;
HDRVPATH hdp;
UINT16 ax;
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
TRACEOUT(("get_fileattr: ->%s", intrst->fcbname_ptr));
if ((is_wildcards(intrst->fcbname_ptr)) ||
(hostdrvs_getrealpath(&hdp, intrst->filename_ptr) != SUCCESS)) {
fail(intrst, ERR_FILENOTFOUND);
return;
}
TRACEOUT(("get_fileattr: %s - %x", hdp.path, hdp.di.attr));
ax = hdp.di.attr & 0x37;
if (!IS_PERMITWRITE) {
ax |= 0x01;
}
intrst->r.b.flag_l &= ~C_FLAG;
STOREINTELWORD(intrst->r.w.ax, ax);
}
/* 11 */
static void rename_file(INTRST intrst) {
_SDACDS sc;
HDRVPATH hdp1;
HDRVPATH hdp2;
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
// ワイルドカードくるんで要修正…
if ((hostdrvs_getrealpath(&hdp1, intrst->filename_ptr) != SUCCESS) ||
(hostdrvs_getrealpath(&hdp2, intrst->filename_ptr_2) != SUCCESS)) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
TRACEOUT(("rename_file %s to %s - failed", hdp1.path, hdp2.path));
fail(intrst, ERR_ACCESSDENIED);
}
/* 13 */
static void delete_file(INTRST intrst) {
_SDACDS sc;
HDRVPATH hdp;
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
// ワイルドカードくるんで要修正…
if ((hostdrvs_getrealpath(&hdp, intrst->filename_ptr) != SUCCESS) ||
(hdp.di.attr & 0x10)) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
TRACEOUT(("delete_file %s - failed", hdp.path));
fail(intrst, ERR_ACCESSDENIED);
}
/* 16 */
static void open_file(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
HDRVPATH hdp;
UINT mode;
FILEH fh;
HDRVFILE hdf;
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
// fetch_sft(intrst, &sft);
ZeroMemory(&sft, sizeof(sft));
if ((is_wildcards(intrst->fcbname_ptr)) ||
(hostdrvs_getrealpath(&hdp, intrst->filename_ptr) != SUCCESS) ||
(hdp.di.attr & 0x10)) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
TRACEOUT(("open_file: %s -> %s %d", intrst->filename_ptr,
hdp.path, sft.open_mode[0] & 7));
switch(sft.open_mode[0] & 7) {
case 1: // write only
mode = HDFMODE_WRITE;
break;
case 2: // read/write
mode = HDFMODE_READ | HDFMODE_WRITE;
break;
default:
mode = HDFMODE_READ;
break;
}
if (mode & HDFMODE_WRITE) {
if (!IS_PERMITWRITE) {
fail(intrst, ERR_ACCESSDENIED);
return;
}
fh = file_open(hdp.path);
}
else {
fh = file_open_rb(hdp.path);
}
if (fh == FILEH_INVALID) {
TRACEOUT(("file open error!"));
fail(intrst, ERR_PATHNOTFOUND);
return;
}
hdf = hostdrvs_fhdlsea(hostdrv.fhdl);
if (hdf == NULL) {
file_close(fh);
fail(intrst, ERR_PATHNOTFOUND);
return;
}
hdf->hdl = (long)fh;
hdf->mode = mode;
file_cpyname(hdf->path, hdp.path, sizeof(hdf->path));
fill_sft(intrst, &sft, listarray_getpos(hostdrv.fhdl, hdf), &hdp.di);
init_sft(&sft);
store_sft(intrst, &sft);
store_sda_currcds(&sc);
succeed(intrst);
}
/* 17 */
static void create_file(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
HDRVPATH hdp;
HDRVFILE hdf;
FILEH fh;
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
fetch_sft(intrst, &sft);
if ((is_wildcards(intrst->fcbname_ptr)) ||
(hostdrvs_newrealpath(&hdp, intrst->filename_ptr) != SUCCESS) ||
(hdp.di.attr & 0x10)) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
TRACEOUT(("create_file: %s -> %s %d", intrst->filename_ptr,
hdp.path, sft.open_mode[0] & 7));
if (!IS_PERMITWRITE) {
fail(intrst, ERR_ACCESSDENIED);
return;
}
hdf = hostdrvs_fhdlsea(hostdrv.fhdl);
if (hdf == NULL) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
fh = file_create(hdp.path);
if (fh == FILEH_INVALID) {
TRACEOUT(("file create error!"));
fail(intrst, ERR_ACCESSDENIED);
return;
}
hdf->hdl = (long)fh;
hdf->mode = HDFMODE_READ | HDFMODE_WRITE;
file_cpyname(hdf->path, hdp.path, sizeof(hdf->path));
fill_sft(intrst, &sft, listarray_getpos(hostdrv.fhdl, hdf), &hdp.di);
init_sft(&sft);
store_sft(intrst, &sft);
store_sda_currcds(&sc);
succeed(intrst);
}
/* 1B */
static void find_first(INTRST intrst) {
_SDACDS sc;
HDRVPATH hdp;
LISTARRAY flist;
flist = hostdrv.flist;
if (flist) {
hostdrv.flist = NULL;
hostdrv.stat.flistpos = 0;
listarray_destroy(flist);
}
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
if (*intrst->srch_attr_ptr == 0x08) { // ボリュームラベル
store_srch(intrst);
store_dir(intrst, &hdd_volume);
}
else {
if ((hostdrvs_getrealpath(&hdp, intrst->current_path) != SUCCESS) ||
(!(hdp.di.attr & 0x10))) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
TRACEOUT(("find_first %s -> %s", intrst->current_path, hdp.path));
hostdrv.flist = hostdrvs_getpathlist(hdp.path);
hostdrv.stat.flistpos = 0;
if (find_file(intrst) != SUCCESS) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
}
store_sda_currcds(&sc);
succeed(intrst);
}
/* 1C */
static void find_next(INTRST intrst) {
_SDACDS sc;
SRCHREC srchrec;
fetch_sda_currcds(&sc);
setup_ptrs(intrst, &sc);
srchrec = intrst->srchrec_ptr;
if ((!(srchrec->drive_no & 0x40)) ||
((srchrec->drive_no & 0x1f) != hostdrv.stat.drive_no)) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
if (find_file(intrst) != SUCCESS) {
fail(intrst, ERR_NOMOREFILES);
return;
}
store_sda_currcds(&sc);
succeed(intrst);
}
#if 1
/* 1E */
static void do_redir(INTRST intrst) {
_SDACDS sc;
REG16 mode;
REG16 bx;
char tmp[4];
TRACEOUT(("do_redir"));
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
mode = MEMR_READ16(CPU_SS, CPU_BP + sizeof(IF4INTR));
TRACEOUT(("do_redir: %.4x", mode));
switch(mode) {
case 0x5f02:
bx = LOADINTELWORD(intrst->r.w.bx);
if (bx) {
fail(intrst, 0x12);
return;
}
MEMR_WRITE16(CPU_DS, CPU_BX + 2, 4);
MEMR_WRITE16(CPU_DS, CPU_BX + 4, 1);
tmp[0] = (char)('A' + hostdrv.stat.drive_no);
tmp[1] = ':';
tmp[2] = '\0';
MEMR_WRITES(LOADINTELWORD(intrst->r.w.ds),
LOADINTELWORD(intrst->r.w.si), tmp, 3);
MEMR_WRITES(LOADINTELWORD(intrst->r.w.es),
LOADINTELWORD(intrst->r.w.di),
ROOTPATH, ROOTPATH_SIZE + 1);
break;
default:
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
succeed(intrst);
}
#endif
/* 21 */
// dos4以降呼ばれることはあんまない・・・
static void seek_fromend(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
UINT16 reg;
UINT32 pos;
UINT file_size;
fetch_sda_currcds(&sc);
fetch_sft(intrst, &sft);
if ((sft.dev_info_word[0] & 0x3f) != hostdrv.stat.drive_no) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
reg = LOADINTELWORD(intrst->r.w.cx);
pos = reg << 16;
reg = LOADINTELWORD(intrst->r.w.dx);
pos += reg;
file_size = LOADINTELDWORD(sft.file_size);
if (pos > file_size) {
pos = file_size;
}
reg = (UINT16)(pos >> 16);
STOREINTELWORD(intrst->r.w.dx, reg);
reg = (UINT16)pos;
STOREINTELWORD(intrst->r.w.ax, reg);
pos = file_size - pos;
STOREINTELDWORD(sft.file_pos, pos);
store_sft(intrst, &sft);
intrst->r.b.flag_l &= ~C_FLAG;
}
/* 2D */
static void unknownfunc_2d(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
fetch_sda_currcds(&sc);
fetch_sft(intrst, &sft);
if ((sft.dev_info_word[0] & 0x3f) != hostdrv.stat.drive_no) {
CPU_FLAG &= ~Z_FLAG; // chain
return;
}
#if 1
TRACEOUT(("unknownfunc_2d"));
#else
intr_regs.flags &= ~C_FLAG;
intr_regs.ax = 2;
#endif
}
/* 2E */
// for dos4+
static void ext_openfile(INTRST intrst) {
_SDACDS sc;
_SFTREC sft;
HDRVPATH hdp;
UINT mode;
BOOL create;
REG16 act;
REG16 cx;
FILEH fh;
HDRVFILE hdf;
if (pathishostdrv(intrst, &sc) != SUCCESS) {
return;
}
fetch_sft(intrst, &sft);
// ファイルを探しに〜
if ((is_wildcards(intrst->fcbname_ptr)) ||
(hostdrvs_newrealpath(&hdp, intrst->filename_ptr) != SUCCESS) ||
(hdp.di.attr & 0x10)) {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
sft.open_mode[0] = sc.ver4.sda.mode_2E[0] & 0x7f;
sft.open_mode[1] = sc.ver4.sda.mode_2E[1] & 0x00;
act = LOADINTELWORD(sc.ver4.sda.action_2E);
switch(sft.open_mode[0] & 7) {
case 1: // write only
mode = HDFMODE_WRITE;
break;
case 2: // read/write
mode = HDFMODE_READ | HDFMODE_WRITE;
break;
default:
mode = HDFMODE_READ;
break;
}
create = FALSE;
if (hdp.di.exist) { // ファイルが存在
switch(act & 3) {
case 1:
cx = 1;
break;
case 2:
create = TRUE;
cx = 3;
break;
default:
fail(intrst, ERR_ACCESSDENIED);
return;
}
}
else { // 新規ファイル
if (act & 0x10) {
create = TRUE;
cx = 2;
}
else {
fail(intrst, ERR_PATHNOTFOUND);
return;
}
}
if (create) {
if (!IS_PERMITWRITE) {
fail(intrst, ERR_ACCESSDENIED);
return;
}
fh = file_create(hdp.path);
}
else if (mode & HDFMODE_WRITE) {
if (!IS_PERMITWRITE) {
fail(intrst, ERR_ACCESSDENIED);
return;
}
fh = file_open(hdp.path);
}
else {
fh = file_open_rb(hdp.path);
}
if (fh == FILEH_INVALID) {
TRACEOUT(("file open error!"));
fail(intrst, ERR_PATHNOTFOUND);
return;
}
hdf = hostdrvs_fhdlsea(hostdrv.fhdl);
if (hdf == NULL) {
file_close(fh);
fail(intrst, ERR_PATHNOTFOUND);
return;
}
hdf->hdl = (long)fh;
hdf->mode = mode;
file_cpyname(hdf->path, hdp.path, sizeof(hdf->path));
STOREINTELWORD(intrst->r.w.cx, cx);
fill_sft(intrst, &sft, listarray_getpos(hostdrv.fhdl, hdf), &hdp.di);
init_sft(&sft);
store_sft(intrst, &sft);
store_sda_currcds(&sc);
succeed(intrst);
}
// ----
typedef void (*HDINTRFN)(INTRST intrst);
static const HDINTRFN intr_func[] = {
inst_check, /* 00 */
NULL, // remove_dir, /* 01 */
NULL,
NULL, // make_dir, /* 03 */
NULL,
change_currdir, /* 05 */
close_file, /* 06 */
commit_file, /* 07 */
read_file, /* 08 */
write_file, /* 09 */
lock_file, /* 0A */
unlock_file, /* 0B */
NULL, // get_diskspace, /* 0C */
NULL,
set_fileattr, /* 0E */
get_fileattr, /* 0F */
NULL,
rename_file, /* 11 */
NULL,
delete_file, /* 13 */
NULL,
NULL,
open_file, /* 16 */
create_file, /* 17 */
NULL,
NULL,
NULL,
find_first, /* 1B */
find_next, /* 1C */
NULL,
do_redir,
NULL,
NULL,
seek_fromend, /* 21 */
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
unknownfunc_2d, /* 2D */
ext_openfile /* 2E */
};
// ----
// 始めに一回だけ呼んでね(はーと
void hostdrv_initialize(void) {
ZeroMemory(&hostdrv, sizeof(hostdrv));
hostdrv.fhdl = listarray_new(sizeof(_HDRVFILE), 16);
TRACEOUT(("hostdrv_initialize"));
}
// 終わりに一回だけ呼んでね(はーと
void hostdrv_deinitialize(void) {
listarray_destroy(hostdrv.flist);
hostdrvs_fhdlallclose(hostdrv.fhdl);
listarray_destroy(hostdrv.fhdl);
TRACEOUT(("hostdrv_deinitialize"));
}
// リセットルーチンで呼ぶべしべし
void hostdrv_reset(void) {
hostdrv_deinitialize();
hostdrv_initialize();
}
// ---- for np2sysp
void hostdrv_mount(const void *arg1, long arg2) {
if ((np2cfg.hdrvroot[0] == '\0') || (hostdrv.stat.is_mount)) {
np2sysp_outstr(OEMTEXT("ng"), 0);
return;
}
hostdrv.stat.is_mount = TRUE;
fetch_if4dos();
np2sysp_outstr(OEMTEXT("ok"), 0);
(void)arg1;
(void)arg2;
}
void hostdrv_unmount(const void *arg1, long arg2) {
if (hostdrv.stat.is_mount) {
hostdrv_reset();
}
(void)arg1;
(void)arg2;
}
void hostdrv_intr(const void *arg1, long arg2) {
_INTRST intrst;
ZeroMemory(&intrst, sizeof(intrst));
intrst.is_chardev = (CPU_FLAG & C_FLAG) == 0;
CPU_FLAG &= ~(C_FLAG | Z_FLAG); // not fcb / chain
if (!hostdrv.stat.is_mount) {
return;
}
fetch_intr_regs(&intrst);
TRACEOUT(("hostdrv: AL=%.2x", intrst.r.b.al));
if ((intrst.r.b.al >= NELEMENTS(intr_func)) ||
(intr_func[intrst.r.b.al] == NULL)) {
return;
}
CPU_FLAG |= Z_FLAG; // not chain
(*intr_func[intrst.r.b.al])(&intrst);
store_intr_regs(&intrst);
(void)arg1;
(void)arg2;
}
// ---- for statsave
typedef struct {
UINT stat;
UINT files;
UINT flists;
} SFHDRV;
static BOOL fhdl_wr(void *vpItem, void *vpArg) {
OEMCHAR *p;
UINT len;
p = ((HDRVFILE)vpItem)->path;
len = OEMSTRLEN(p);
statflag_write((STFLAGH)vpArg, &len, sizeof(len));
if (len) {
if (len < MAX_PATH) {
ZeroMemory(p + len, (MAX_PATH - len) * sizeof(OEMCHAR));
}
statflag_write((STFLAGH)vpArg, vpItem, sizeof(_HDRVFILE));
}
return(FALSE);
}
static BOOL flist_wr(void *vpItem, void *vpArg) {
OEMCHAR *p;
int len;
p = ((HDRVLST)vpItem)->realname;
len = OEMSTRLEN(p);
if (len < MAX_PATH) {
ZeroMemory(p + len, (MAX_PATH - len) * sizeof(OEMCHAR));
}
statflag_write((STFLAGH)vpArg, vpItem, sizeof(_HDRVLST));
return(FALSE);
}
int hostdrv_sfsave(STFLAGH sfh, const SFENTRY *tbl) {
SFHDRV sfhdrv;
int ret;
if (!hostdrv.stat.is_mount) {
return(STATFLAG_SUCCESS);
}
sfhdrv.stat = sizeof(hostdrv.stat);
sfhdrv.files = listarray_getitems(hostdrv.fhdl);
sfhdrv.flists = listarray_getitems(hostdrv.flist);
ret = statflag_write(sfh, &sfhdrv, sizeof(sfhdrv));
ret |= statflag_write(sfh, &hostdrv.stat, sizeof(hostdrv.stat));
listarray_enum(hostdrv.fhdl, fhdl_wr, sfh);
listarray_enum(hostdrv.flist, flist_wr, sfh);
(void)tbl;
return(ret);
}
int hostdrv_sfload(STFLAGH sfh, const SFENTRY *tbl) {
SFHDRV sfhdrv;
int ret;
UINT i;
UINT len;
HDRVFILE hdf;
FILEH fh;
HDRVLST hdl;
listarray_clr(hostdrv.fhdl);
listarray_clr(hostdrv.flist);
ret = statflag_read(sfh, &sfhdrv, sizeof(sfhdrv));
if (sfhdrv.stat != sizeof(hostdrv.stat)) {
return(STATFLAG_FAILURE);
}
ret |= statflag_read(sfh, &hostdrv.stat, sizeof(hostdrv.stat));
for (i=0; i<sfhdrv.files; i++) {
hdf = (HDRVFILE)listarray_append(hostdrv.fhdl, NULL);
if (hdf == NULL) {
return(STATFLAG_FAILURE);
}
ret |= statflag_read(sfh, &len, sizeof(len));
if (len) {
ret |= statflag_read(sfh, hdf, sizeof(_HDRVFILE));
if (hdf->mode & HDFMODE_WRITE) {
fh = file_open(hdf->path);
}
else {
fh = file_open_rb(hdf->path);
}
hdf->hdl = (long)fh;
}
}
for (i=0; i<sfhdrv.flists; i++) {
hdl = (HDRVLST)listarray_append(hostdrv.flist, NULL);
if (hdl == NULL) {
return(STATFLAG_FAILURE);
}
ret |= statflag_read(sfh, hdl, sizeof(_HDRVLST));
}
(void)tbl;
return(ret);
}
#endif
RetroPC.NET-CVS <cvs@retropc.net>