mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
670 lines
20 KiB
670 lines
20 KiB
/* #includes */ /*{{{C}}}*//*{{{*/
|
|
#include "config.h"
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
|
|
#include "cpmdir.h"
|
|
#include "cpmfs.h"
|
|
|
|
#ifdef USE_DMALLOC
|
|
#include <dmalloc.h>
|
|
#endif
|
|
/*}}}*/
|
|
/* types */ /*{{{*/
|
|
#define PHYSICAL_SECTOR_1 1 /* First physical sector */
|
|
|
|
/* Use the INT13 interface rather than INT25/INT26. This appears to
|
|
* improve performance, but is less well tested. */
|
|
#define USE_INT13
|
|
|
|
/* Windows 95 disk I/O functions - based on Stan Mitchell's DISKDUMP.C */
|
|
#define VWIN32_DIOC_DOS_IOCTL 1 /* DOS ioctl calls 4400h-4411h */
|
|
#define VWIN32_DIOC_DOS_INT25 2 /* absolute disk read, DOS int 25h */
|
|
#define VWIN32_DIOC_DOS_INT26 3 /* absolute disk write, DOS int 26h */
|
|
#define VWIN32_DIOC_DOS_INT13 4 /* BIOS INT13 functions */
|
|
|
|
typedef struct _DIOC_REGISTERS {
|
|
DWORD reg_EBX;
|
|
DWORD reg_EDX;
|
|
DWORD reg_ECX;
|
|
DWORD reg_EAX;
|
|
DWORD reg_EDI;
|
|
DWORD reg_ESI;
|
|
DWORD reg_Flags;
|
|
}
|
|
DIOC_REGISTERS, *PDIOC_REGISTERS;
|
|
|
|
#define LEVEL0_LOCK 0
|
|
#define LEVEL1_LOCK 1
|
|
#define LEVEL2_LOCK 2
|
|
#define LEVEL3_LOCK 3
|
|
#define LEVEL1_LOCK_MAX_PERMISSION 0x0001
|
|
|
|
#define DRIVE_IS_REMOTE 0x1000
|
|
#define DRIVE_IS_SUBST 0x8000
|
|
|
|
/*********************************************************
|
|
**** Note: all MS-DOS data structures must be packed ****
|
|
**** on a one-byte boundary. ****
|
|
*********************************************************/
|
|
#pragma pack(1)
|
|
|
|
typedef struct _DISKIO {
|
|
DWORD diStartSector; /* sector number to start at */
|
|
WORD diSectors; /* number of sectors */
|
|
DWORD diBuffer; /* address of buffer */
|
|
}
|
|
DISKIO, *PDISKIO;
|
|
|
|
typedef struct MID {
|
|
WORD midInfoLevel; /* information level, must be 0 */
|
|
DWORD midSerialNum; /* serial number for the medium */
|
|
char midVolLabel[11]; /* volume label for the medium */
|
|
char midFileSysType[8]; /* type of file system as 8-byte ASCII */
|
|
}
|
|
MID, *PMID;
|
|
|
|
typedef struct driveparams { /* Disk geometry */
|
|
BYTE special;
|
|
BYTE devicetype;
|
|
WORD deviceattrs;
|
|
WORD cylinders;
|
|
BYTE mediatype;
|
|
/* BPB starts here */
|
|
WORD bytespersector;
|
|
BYTE sectorspercluster;
|
|
WORD reservedsectors;
|
|
BYTE numberofFATs;
|
|
WORD rootdirsize;
|
|
WORD totalsectors;
|
|
BYTE mediaid;
|
|
WORD sectorsperfat;
|
|
WORD sectorspertrack;
|
|
WORD heads;
|
|
DWORD hiddensectors;
|
|
DWORD bigtotalsectors;
|
|
BYTE reserved[6];
|
|
/* BPB ends here */
|
|
WORD sectorcount;
|
|
WORD sectortable[80];
|
|
} DRIVEPARAMS, *PDRIVEPARAMS;
|
|
/*}}}*/
|
|
|
|
static char *strwin32error(void) /*{{{*/
|
|
{
|
|
static char buffer[1024];
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
GetLastError(),
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
|
(LPTSTR)buffer,
|
|
1023, NULL);
|
|
return buffer;
|
|
}
|
|
/*}}}*/
|
|
static BOOL LockVolume( HANDLE hDisk ) /*{{{*/
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
|
|
return DeviceIoControl( hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL,
|
|
0, &ReturnedByteCount, NULL );
|
|
}
|
|
/*}}}*/
|
|
static BOOL UnlockVolume( HANDLE hDisk ) /*{{{*/
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
|
|
return DeviceIoControl( hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL,
|
|
0, &ReturnedByteCount, NULL );
|
|
}
|
|
/*}}}*/
|
|
static BOOL DismountVolume( HANDLE hDisk ) /*{{{*/
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
|
|
return DeviceIoControl( hDisk, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL,
|
|
0, &ReturnedByteCount, NULL );
|
|
}
|
|
/*}}}*/
|
|
static int GetDriveParams( HANDLE hVWin32Device, int volume, DRIVEPARAMS* pParam ) /*{{{*/
|
|
{
|
|
DIOC_REGISTERS reg;
|
|
BOOL bResult;
|
|
DWORD cb;
|
|
|
|
reg.reg_EAX = 0x440d; /* IOCTL for block device */
|
|
reg.reg_EBX = volume; /* one-based drive number */
|
|
reg.reg_ECX = 0x0860; /* Get Device params */
|
|
reg.reg_EDX = (DWORD)pParam;
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
|
|
bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_IOCTL,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
|
|
if ( !bResult || (reg.reg_Flags & 1) )
|
|
return (reg.reg_EAX & 0xffff);
|
|
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
static int SetDriveParams( HANDLE hVWin32Device, int volume, DRIVEPARAMS* pParam ) /*{{{*/
|
|
{
|
|
DIOC_REGISTERS reg;
|
|
BOOL bResult;
|
|
DWORD cb;
|
|
|
|
reg.reg_EAX = 0x440d; /* IOCTL for block device */
|
|
reg.reg_EBX = volume; /* one-based drive number */
|
|
reg.reg_ECX = 0x0840; /* Set Device params */
|
|
reg.reg_EDX = (DWORD)pParam;
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
|
|
bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_IOCTL,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
|
|
if ( !bResult || (reg.reg_Flags & 1) )
|
|
return (reg.reg_EAX & 0xffff);
|
|
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
static int GetMediaID( HANDLE hVWin32Device, int volume, MID* pMid ) /*{{{*/
|
|
{
|
|
DIOC_REGISTERS reg;
|
|
BOOL bResult;
|
|
DWORD cb;
|
|
|
|
reg.reg_EAX = 0x440d; /* IOCTL for block device */
|
|
reg.reg_EBX = volume; /* one-based drive number */
|
|
reg.reg_ECX = 0x0866; /* Get Media ID */
|
|
reg.reg_EDX = (DWORD)pMid;
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
|
|
bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_IOCTL,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
|
|
if ( !bResult || (reg.reg_Flags & 1) )
|
|
return (reg.reg_EAX & 0xffff);
|
|
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
static int VolumeCheck(HANDLE hVWin32Device, int volume, WORD* flags ) /*{{{*/
|
|
{
|
|
DIOC_REGISTERS reg;
|
|
BOOL bResult;
|
|
DWORD cb;
|
|
|
|
reg.reg_EAX = 0x4409; /* Is Drive Remote */
|
|
reg.reg_EBX = volume; /* one-based drive number */
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
|
|
bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_IOCTL,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
|
|
if ( !bResult || (reg.reg_Flags & 1) )
|
|
return (reg.reg_EAX & 0xffff);
|
|
|
|
*flags = (WORD)(reg.reg_EDX & 0xffff);
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
static int LockLogicalVolume(HANDLE hVWin32Device, int volume, int lock_level, int permissions) /*{{{*/
|
|
{
|
|
DIOC_REGISTERS reg;
|
|
BOOL bResult;
|
|
DWORD cb;
|
|
|
|
reg.reg_EAX = 0x440d; /* generic IOCTL */
|
|
reg.reg_ECX = 0x084a; /* lock logical volume */
|
|
reg.reg_EBX = volume | (lock_level << 8);
|
|
reg.reg_EDX = permissions;
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
|
|
bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_IOCTL,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
|
|
if ( !bResult || (reg.reg_Flags & 1) )
|
|
return (reg.reg_EAX & 0xffff);
|
|
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
static int UnlockLogicalVolume( HANDLE hVWin32Device, int volume ) /*{{{*/
|
|
{
|
|
DIOC_REGISTERS reg;
|
|
BOOL bResult;
|
|
DWORD cb;
|
|
|
|
reg.reg_EAX = 0x440d;
|
|
reg.reg_ECX = 0x086a; /* lock logical volume */
|
|
reg.reg_EBX = volume;
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
|
|
bResult = DeviceIoControl( hVWin32Device, VWIN32_DIOC_DOS_IOCTL,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
|
|
if ( !bResult || (reg.reg_Flags & 1) ) return -1;
|
|
return 0;
|
|
}
|
|
/*}}}*/
|
|
static int w32mode(int mode) /*{{{*/
|
|
{
|
|
switch(mode)
|
|
{
|
|
case O_RDONLY: return GENERIC_READ;
|
|
case O_WRONLY: return GENERIC_WRITE;
|
|
}
|
|
return GENERIC_READ | GENERIC_WRITE;
|
|
}
|
|
/*}}}*/
|
|
|
|
/* Device_open -- Open an image file */ /*{{{*/
|
|
const char *Device_open(struct Device *sb, const char *filename, int mode, const char *deviceOpts)
|
|
{
|
|
/* Windows 95/NT: floppy drives using handles */
|
|
if (strlen(filename) == 2 && filename[1] == ':') /* Drive name */
|
|
{
|
|
char vname[20];
|
|
DWORD dwVers;
|
|
|
|
sb->fd = -1;
|
|
dwVers = GetVersion();
|
|
|
|
if (dwVers & 0x80000000L) /* Win32s (3.1) or Win32c (Win95) */
|
|
{
|
|
int lock, driveno, res, permissions;
|
|
unsigned short drive_flags;
|
|
MID media;
|
|
|
|
vname[0] = toupper(filename[0]);
|
|
driveno = vname[0] - 'A' + 1; /* 1=A: 2=B: */
|
|
sb->drvtype = CPMDRV_WIN95;
|
|
sb->hdisk = CreateFile( "\\\\.\\vwin32",
|
|
0,
|
|
0,
|
|
NULL,
|
|
0,
|
|
FILE_FLAG_DELETE_ON_CLOSE,
|
|
NULL );
|
|
if (!sb->hdisk)
|
|
{
|
|
return "Failed to open VWIN32 driver.";
|
|
}
|
|
if (VolumeCheck(sb->hdisk, driveno, &drive_flags))
|
|
{
|
|
CloseHandle(sb->hdisk);
|
|
return "Invalid drive";
|
|
}
|
|
res = GetMediaID( sb->hdisk, driveno, &media );
|
|
if ( res )
|
|
{
|
|
const char *lboo = NULL;
|
|
|
|
if ( res == ERROR_INVALID_FUNCTION &&
|
|
(drive_flags & DRIVE_IS_REMOTE ))
|
|
lboo = "Network drive";
|
|
else if (res == ERROR_ACCESS_DENIED) lboo = "Access denied";
|
|
/* nb: It's perfectly legitimate for GetMediaID() to fail; most CP/M */
|
|
/* CP/M disks won't have a media ID. */
|
|
|
|
if (lboo != NULL)
|
|
{
|
|
CloseHandle(sb->hdisk);
|
|
return lboo;
|
|
}
|
|
}
|
|
if (!res &&
|
|
(!memcmp( media.midFileSysType, "CDROM", 5 ) ||
|
|
!memcmp( media.midFileSysType, "CD001", 5 ) ||
|
|
!memcmp( media.midFileSysType, "CDAUDIO", 5 )))
|
|
{
|
|
CloseHandle(sb->hdisk);
|
|
return "CD-ROM drive";
|
|
}
|
|
if (w32mode(mode) & GENERIC_WRITE)
|
|
{
|
|
lock = LEVEL0_LOCK; /* Exclusive access */
|
|
permissions = 0;
|
|
}
|
|
else
|
|
{
|
|
lock = LEVEL1_LOCK; /* Allow other processes access */
|
|
permissions = LEVEL1_LOCK_MAX_PERMISSION;
|
|
}
|
|
if (LockLogicalVolume( sb->hdisk, driveno, lock, permissions))
|
|
{
|
|
CloseHandle(sb->hdisk);
|
|
return "Could not acquire a lock on the drive.";
|
|
}
|
|
|
|
sb->fd = driveno; /* 1=A: 2=B: etc - we will need this later */
|
|
|
|
}
|
|
else
|
|
{
|
|
sprintf(vname, "\\\\.\\%s", filename);
|
|
sb->drvtype = CPMDRV_WINNT;
|
|
sb->hdisk = CreateFile(vname, /* Name */
|
|
w32mode(mode), /* Access mode */
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE, /*Sharing*/
|
|
NULL, /* Security attributes */
|
|
OPEN_EXISTING, /* See MSDN */
|
|
0, /* Flags & attributes */
|
|
NULL); /* Template file */
|
|
|
|
if (sb->hdisk != INVALID_HANDLE_VALUE)
|
|
{
|
|
sb->fd = 1; /* Arbitrary value >0 */
|
|
if (LockVolume(sb->hdisk) == FALSE) /* Lock drive */
|
|
{
|
|
char *lboo = strwin32error();
|
|
CloseHandle(sb->hdisk);
|
|
sb->fd = -1;
|
|
return lboo;
|
|
}
|
|
}
|
|
else return strwin32error();
|
|
}
|
|
sb->opened = 1;
|
|
return NULL;
|
|
}
|
|
|
|
/* Not a floppy. Treat it as a normal file */
|
|
|
|
mode |= O_BINARY;
|
|
sb->fd = open(filename, mode);
|
|
if (sb->fd == -1) return strerror(errno);
|
|
sb->drvtype = CPMDRV_FILE;
|
|
sb->opened = 1;
|
|
return NULL;
|
|
}
|
|
/*}}}*/
|
|
/* Device_setGeometry -- Set disk geometry */ /*{{{*/
|
|
const char * Device_setGeometry(struct Device *this, int secLength, int sectrk, int tracks, off_t offset, const char *libdskGeometry)
|
|
{
|
|
int n;
|
|
|
|
this->secLength=secLength;
|
|
this->sectrk=sectrk;
|
|
this->tracks=tracks;
|
|
// Bill Buckels - add this->offset
|
|
this->offset=offset;
|
|
|
|
|
|
// Bill Buckels - not sure what to do here
|
|
if (this->drvtype == CPMDRV_WIN95)
|
|
{
|
|
DRIVEPARAMS drvp;
|
|
memset(&drvp, 0, sizeof(drvp));
|
|
if (GetDriveParams( this->hdisk, this->fd, &drvp )) return "GetDriveParams failed";
|
|
|
|
drvp.bytespersector = secLength;
|
|
drvp.sectorspertrack = sectrk;
|
|
drvp.totalsectors = sectrk * tracks;
|
|
|
|
/* Guess the cylinder/head configuration from the track count. This will
|
|
* get single-sided 80-track discs wrong, but it's that or double-sided
|
|
* 40-track (or add cylinder/head counts to diskdefs)
|
|
*/
|
|
if (tracks < 44)
|
|
{
|
|
drvp.cylinders = tracks;
|
|
drvp.heads = 1;
|
|
}
|
|
else
|
|
{
|
|
drvp.cylinders = tracks / 2;
|
|
drvp.heads = 2;
|
|
}
|
|
|
|
/* Set up "reasonable" values for the other members */
|
|
|
|
drvp.sectorspercluster = 1024 / secLength;
|
|
drvp.reservedsectors = 1;
|
|
drvp.numberofFATs = 2;
|
|
drvp.sectorcount = sectrk;
|
|
drvp.rootdirsize = 64;
|
|
drvp.mediaid = 0xF0;
|
|
drvp.hiddensectors = 0;
|
|
drvp.sectorsperfat = 3;
|
|
for (n = 0; n < sectrk; n++)
|
|
{
|
|
drvp.sectortable[n*2] = n + PHYSICAL_SECTOR_1; /* Physical sector numbers */
|
|
drvp.sectortable[n*2+1] = secLength;
|
|
}
|
|
drvp.special = 6;
|
|
/* We have not set:
|
|
|
|
drvp.mediatype
|
|
drvp.devicetype
|
|
drvp.deviceattrs
|
|
|
|
which should have been read correctly by GetDriveParams().
|
|
*/
|
|
SetDriveParams( this->hdisk, this->fd, &drvp );
|
|
}
|
|
return NULL;
|
|
}
|
|
/*}}}*/
|
|
/* Device_close -- Close an image file */ /*{{{*/
|
|
const char *Device_close(struct Device *sb)
|
|
{
|
|
sb->opened = 0;
|
|
switch(sb->drvtype)
|
|
{
|
|
case CPMDRV_WIN95:
|
|
UnlockLogicalVolume(sb->hdisk, sb->fd );
|
|
if (!CloseHandle( sb->hdisk )) return strwin32error();
|
|
return NULL;
|
|
|
|
case CPMDRV_WINNT:
|
|
DismountVolume(sb->hdisk);
|
|
UnlockVolume(sb->hdisk);
|
|
if (!CloseHandle(sb->hdisk)) return strwin32error();
|
|
return NULL;
|
|
}
|
|
if (close(sb->fd)) return strerror(errno);
|
|
return NULL;
|
|
}
|
|
/*}}}*/
|
|
/* Device_readSector -- read a physical sector */ /*{{{*/
|
|
const char *Device_readSector(const struct Device *drive, int track, int sector, char *buf)
|
|
{
|
|
int res;
|
|
off_t offset;
|
|
|
|
assert(sector>=0);
|
|
assert(sector<drive->sectrk);
|
|
assert(track>=0);
|
|
assert(track<drive->tracks);
|
|
|
|
offset = ((sector+track*drive->sectrk)*drive->secLength);
|
|
|
|
if (drive->drvtype == CPMDRV_WINNT)
|
|
{
|
|
LPVOID iobuffer;
|
|
DWORD bytesread;
|
|
|
|
// Bill Buckels - add drive->offset
|
|
if (SetFilePointer(drive->hdisk, offset+drive->offset, NULL, FILE_BEGIN) == INVALID_FILE_SIZE)
|
|
{
|
|
return strwin32error();
|
|
}
|
|
iobuffer = VirtualAlloc(NULL, drive->secLength, MEM_COMMIT, PAGE_READWRITE);
|
|
if (!iobuffer)
|
|
{
|
|
return strwin32error();
|
|
}
|
|
res = ReadFile(drive->hdisk, iobuffer, drive->secLength, &bytesread, NULL);
|
|
if (!res)
|
|
{
|
|
char *lboo = strwin32error();
|
|
VirtualFree(iobuffer, drive->secLength, MEM_RELEASE);
|
|
return lboo;
|
|
}
|
|
|
|
memcpy(buf, iobuffer, drive->secLength);
|
|
VirtualFree(iobuffer, drive->secLength, MEM_RELEASE);
|
|
|
|
if (bytesread < (unsigned)drive->secLength)
|
|
{
|
|
memset(buf + bytesread, 0, drive->secLength - bytesread);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Bill Buckels - not sure what to do here
|
|
if (drive->drvtype == CPMDRV_WIN95)
|
|
{
|
|
DIOC_REGISTERS reg;
|
|
BOOL bResult;
|
|
DWORD cb;
|
|
|
|
#ifdef USE_INT13
|
|
int cyl, head;
|
|
|
|
if (drive->tracks < 44) { cyl = track; head = 0; }
|
|
else { cyl = track/2; head = track & 1; }
|
|
|
|
reg.reg_EAX = 0x0201; /* Read 1 sector */
|
|
reg.reg_EBX = (DWORD)buf;
|
|
reg.reg_ECX = (cyl << 8) | (sector + PHYSICAL_SECTOR_1);
|
|
reg.reg_EDX = (head << 8) | (drive->fd - 1);
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
bResult = DeviceIoControl( drive->hdisk, VWIN32_DIOC_DOS_INT13,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
#else
|
|
DISKIO di;
|
|
|
|
reg.reg_EAX = drive->fd - 1; /* zero-based volume number */
|
|
reg.reg_EBX = (DWORD)&di;
|
|
reg.reg_ECX = 0xffff; /* use DISKIO structure */
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
di.diStartSector = sector+track*drive->sectrk;
|
|
di.diSectors = 1;
|
|
di.diBuffer = (DWORD)buf;
|
|
bResult = DeviceIoControl( drive->hdisk, VWIN32_DIOC_DOS_INT25,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
|
|
#endif
|
|
if ( !bResult || (reg.reg_Flags & 1) )
|
|
{
|
|
if (GetLastError()) return strwin32error();
|
|
return "Unknown read error.";
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Bill Buckels - add drive->offset
|
|
if (lseek(drive->fd,offset+drive->offset,SEEK_SET)==-1)
|
|
{
|
|
return strerror(errno);
|
|
}
|
|
if ((res=read(drive->fd, buf, drive->secLength)) != drive->secLength)
|
|
{
|
|
if (res==-1)
|
|
{
|
|
return strerror(errno);
|
|
}
|
|
else memset(buf+res,0,drive->secLength-res); /* hit end of disk image */
|
|
}
|
|
return NULL;
|
|
}
|
|
/*}}}*/
|
|
/* Device_writeSector -- write physical sector */ /*{{{*/
|
|
const char *Device_writeSector(const struct Device *drive, int track, int sector, const char *buf)
|
|
{
|
|
off_t offset;
|
|
int res;
|
|
|
|
assert(sector>=0);
|
|
assert(sector<drive->sectrk);
|
|
assert(track>=0);
|
|
assert(track<drive->tracks);
|
|
|
|
offset = ((sector+track*drive->sectrk)*drive->secLength);
|
|
|
|
if (drive->drvtype == CPMDRV_WINNT)
|
|
{
|
|
LPVOID iobuffer;
|
|
DWORD byteswritten;
|
|
|
|
// Bill Buckels - add drive->offset
|
|
if (SetFilePointer(drive->hdisk, offset+drive->offset, NULL, FILE_BEGIN) == INVALID_FILE_SIZE)
|
|
{
|
|
return strwin32error();
|
|
}
|
|
iobuffer = VirtualAlloc(NULL, drive->secLength, MEM_COMMIT, PAGE_READWRITE);
|
|
if (!iobuffer)
|
|
{
|
|
return strwin32error();
|
|
}
|
|
memcpy(iobuffer, buf, drive->secLength);
|
|
res = WriteFile(drive->hdisk, iobuffer, drive->secLength, &byteswritten, NULL);
|
|
if (!res || (byteswritten < (unsigned)drive->secLength))
|
|
{
|
|
char *lboo = strwin32error();
|
|
VirtualFree(iobuffer, drive->secLength, MEM_RELEASE);
|
|
return lboo;
|
|
}
|
|
|
|
VirtualFree(iobuffer, drive->secLength, MEM_RELEASE);
|
|
return NULL;
|
|
}
|
|
|
|
// Bill Buckels - not sure what to do here
|
|
if (drive->drvtype == CPMDRV_WIN95)
|
|
{
|
|
DIOC_REGISTERS reg;
|
|
BOOL bResult;
|
|
DWORD cb;
|
|
|
|
#ifdef USE_INT13
|
|
int cyl, head;
|
|
|
|
if (drive->tracks < 44) { cyl = track; head = 0; }
|
|
else { cyl = track/2; head = track & 1; }
|
|
|
|
reg.reg_EAX = 0x0301; /* Write 1 sector */
|
|
reg.reg_EBX = (DWORD)buf;
|
|
reg.reg_ECX = (cyl << 8) | (sector + PHYSICAL_SECTOR_1);
|
|
reg.reg_EDX = (head << 8) | (drive->fd - 1);
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
bResult = DeviceIoControl( drive->hdisk, VWIN32_DIOC_DOS_INT13,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
#else
|
|
DISKIO di;
|
|
|
|
reg.reg_EAX = drive->fd - 1; /* zero-based volume number */
|
|
reg.reg_EBX = (DWORD)&di;
|
|
reg.reg_ECX = 0xffff; /* use DISKIO structure */
|
|
reg.reg_Flags = 1; /* preset the carry flag */
|
|
di.diStartSector = sector+track*drive->sectrk;
|
|
di.diSectors = 1;
|
|
di.diBuffer = (DWORD)buf;
|
|
bResult = DeviceIoControl( drive->hdisk, VWIN32_DIOC_DOS_INT26,
|
|
®, sizeof( reg ), ®, sizeof( reg ), &cb, 0 );
|
|
#endif
|
|
|
|
if ( !bResult || (reg.reg_Flags & 1) )
|
|
{
|
|
if (GetLastError()) return strwin32error();
|
|
return "Unknown write error.";
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Bill Buckels - add drive->offset
|
|
if (lseek(drive->fd,offset+drive->offset, SEEK_SET)==-1)
|
|
{
|
|
return strerror(errno);
|
|
}
|
|
if (write(drive->fd, buf, drive->secLength) == drive->secLength) return NULL;
|
|
return strerror(errno);
|
|
}
|
|
/*}}}*/
|
|
|