Initial commit: akai-fetch - AKAI sampler ISO downloader & extractor
- fetch: Go CLI tool for searching, downloading, and extracting AKAI sampler ISOs from archive.org - scripts/extract_wavs.sh: Shell script driving akaiutil to convert samples to WAV - Dockerfile: Multi-stage build packaging akaiutil + fetch - third_party/akaiutil: Vendored akaiutil v4.6.7 source (GPLv2) - docs/akaiutil.md: Full akaiutil reference
This commit is contained in:
+865
@@ -0,0 +1,865 @@
|
||||
/*
|
||||
* Copyright (C) 2008,2019,2020,2021 Klaus Michael Indlekofer. All rights reserved.
|
||||
*
|
||||
* m.indlekofer@gmx.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "commoninclude.h"
|
||||
#include "akaiutil_io.h"
|
||||
|
||||
|
||||
|
||||
#ifdef _VISUALCPP
|
||||
/* for low-level floppy I/O, using fdrawcmd.sys */
|
||||
#include "fdrawcmd.h" /* from http://simonowen.com/fdrawcmd/fdrawcmd.h */
|
||||
|
||||
HANDLE fldr_h[FLDRNUM]; /* handle for floppy drive */
|
||||
u_int fldr_type[FLDRNUM]; /* floppy drive type */
|
||||
PBYTE fldr_secbuf; /* DMA buffer for sector */
|
||||
|
||||
int
|
||||
fldr_init(void)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i=0;i<FLDRNUM;i++){
|
||||
fldr_h[i]=INVALID_HANDLE_VALUE;
|
||||
fldr_type[i]=FLDR_TYPE_FLL; /* XXX */
|
||||
}
|
||||
|
||||
/* allocate DMA buffer for sector */
|
||||
fldr_secbuf=(PBYTE)VirtualAlloc(NULL,AKAI_FL_SECSIZE,MEM_COMMIT,PAGE_READWRITE);
|
||||
if (fldr_secbuf==NULL){
|
||||
PRINTF_ERR("fldr_init: cannot allocate DMA buffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
fldr_end(void)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i=0;i<FLDRNUM;i++){
|
||||
if (fldr_h[i]!=INVALID_HANDLE_VALUE){
|
||||
CloseHandle(fldr_h[i]);
|
||||
fldr_h[i]=INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
if (fldr_secbuf!=NULL){
|
||||
VirtualFree(fldr_secbuf,0,MEM_RELEASE);
|
||||
fldr_secbuf=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
fldr_open(int fldrn,u_int fldrtype)
|
||||
{
|
||||
static char devname[32]; /* XXX */
|
||||
HANDLE h;
|
||||
DWORD version;
|
||||
BYTE datarate;
|
||||
DWORD ret;
|
||||
|
||||
if ((fldrn<0)||(fldrn>=FLDRNUM)){
|
||||
PRINTF_ERR("fldr_open: invalid floppy drive number\n");
|
||||
return -1;
|
||||
}
|
||||
if (fldr_h[fldrn]!=INVALID_HANDLE_VALUE){
|
||||
PRINTF_ERR("fldr_open: floppy drive already opened\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check driver */
|
||||
version=0; /* invalid */
|
||||
/* Note: must use GENERIC_READ|GENERIC_WRITE for DeviceIoControl() */
|
||||
h=CreateFileA("\\\\.\\fdrawcmd",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
|
||||
if (h!=INVALID_HANDLE_VALUE){
|
||||
if (!DeviceIoControl(h,IOCTL_FDRAWCMD_GET_VERSION,NULL,0,&version,sizeof(version),&ret,NULL)){
|
||||
version=0; /* invalid */
|
||||
}
|
||||
CloseHandle(h);
|
||||
}
|
||||
if (version==0){
|
||||
PRINTF_ERR("fldr_open: fdrawcmd.sys is not installed, see: http://simonowen.com/fdrawcmd/\n");
|
||||
return -1;
|
||||
}
|
||||
if (HIWORD(version)!=HIWORD(FDRAWCMD_VERSION)){
|
||||
PRINTF_ERR("fldr_open: the installed fdrawcmd.sys is not compatible with this program\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open and init device */
|
||||
sprintf(devname,"\\\\.\\fdraw%u",(u_int)fldrn);
|
||||
/* Note: must use GENERIC_READ|GENERIC_WRITE for DeviceIoControl() */
|
||||
h=CreateFileA(devname,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
|
||||
if (h==INVALID_HANDLE_VALUE){
|
||||
PRINTF_ERR("fldr_open: cannot open floppy drive\n");
|
||||
return -1;
|
||||
}
|
||||
if (fldrtype==FLDR_TYPE_FLH){
|
||||
datarate=AKAI_FLH_DISK_DATARATE;
|
||||
}else{
|
||||
datarate=AKAI_FLL_DISK_DATARATE;
|
||||
}
|
||||
if (!DeviceIoControl(h,IOCTL_FD_SET_DATA_RATE,&datarate,sizeof(datarate),NULL,0,&ret,NULL)){
|
||||
PRINTF_ERR("fldr_open: cannot set floppy data rate\n");
|
||||
CloseHandle(h);
|
||||
return -1;
|
||||
}
|
||||
if (!DeviceIoControl(h,IOCTL_FD_RESET,NULL,0,NULL,0,&ret,NULL)){
|
||||
PRINTF_ERR("fldr_open: cannot reset floppy controller\n");
|
||||
CloseHandle(h);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save handle and type */
|
||||
fldr_h[fldrn]=h;
|
||||
fldr_type[fldrn]=fldrtype;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fldr_checkfloppyinserted(int fldrn)
|
||||
{
|
||||
DWORD ret;
|
||||
|
||||
if ((fldrn<0)||(fldrn>=FLDRNUM)||(fldr_h[fldrn]==INVALID_HANDLE_VALUE)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check if no floppy inserted */
|
||||
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FD_CHECK_DISK,NULL,0,NULL,0,&ret,NULL)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0; /* floppy is inserted */
|
||||
}
|
||||
|
||||
int
|
||||
fldr_io_direct(int fldrn,u_int blk,u_char *buf,int mode)
|
||||
{
|
||||
BYTE cyl;
|
||||
BYTE head;
|
||||
BYTE sec;
|
||||
DWORD ret;
|
||||
FD_READ_WRITE_PARAMS rwp;
|
||||
u_int retry;
|
||||
int retval;
|
||||
|
||||
if ((fldrn<0)||(fldrn>=FLDRNUM)||(fldr_h[fldrn]==INVALID_HANDLE_VALUE)||(buf==NULL)){
|
||||
return -1;
|
||||
}
|
||||
if ((mode!=IO_BLKS_READ)&&(mode!=IO_BLKS_WRITE)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fldr_type[fldrn]==FLDR_TYPE_FLH){
|
||||
cyl=blk/(AKAI_FL_DISK_SIDES*AKAI_FLH_DISK_SECTORS);
|
||||
head=1&(blk/AKAI_FLH_DISK_SECTORS);
|
||||
sec=AKAI_FL_SECTOR_BASE+(blk%AKAI_FLH_DISK_SECTORS);
|
||||
}else{
|
||||
cyl=blk/(AKAI_FL_DISK_SIDES*AKAI_FLL_DISK_SECTORS);
|
||||
head=1&(blk/AKAI_FLL_DISK_SECTORS);
|
||||
sec=AKAI_FL_SECTOR_BASE+(blk%AKAI_FLL_DISK_SECTORS);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
PRINTF_OUT("fldr_io_direct: cyl=%u head=%u sec=%u\n",(u_int)cyl,(u_int)head,(u_int)sec);
|
||||
#endif
|
||||
|
||||
/* check if no floppy inserted */
|
||||
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FD_CHECK_DISK,NULL,0,NULL,0,&ret,NULL)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* goto track */
|
||||
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_SEEK,&cyl,sizeof(cyl),NULL,0,&ret,NULL)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set parameters */
|
||||
rwp.flags=FD_OPTION_MFM;
|
||||
rwp.phead=head;
|
||||
rwp.cyl=cyl;
|
||||
rwp.head=head;
|
||||
rwp.sector=sec;
|
||||
rwp.size=AKAI_FL_SECTOR_SIZE_CODE;
|
||||
rwp.eot=sec+1; /* for IOCTL_FDCMD_READ_DATA,IOCTL_FDCMD_WRITE_DATA: last sector number+1 !!! */
|
||||
rwp.gap=0x0a;
|
||||
rwp.datalen=0xff;
|
||||
|
||||
retval=0; /* no error so far */
|
||||
if (mode==IO_BLKS_WRITE){
|
||||
/* copy sector from buf to DMA buffer */
|
||||
bcopy(buf,(u_char *)fldr_secbuf,AKAI_FL_SECSIZE);
|
||||
|
||||
for (retry=0;retry<FLDR_RETRYMAX;retry++){
|
||||
/* write sector */
|
||||
if (DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_WRITE_DATA,&rwp,sizeof(rwp),(PVOID)fldr_secbuf,AKAI_FL_SECSIZE,&ret,NULL)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retry>=FLDR_RETRYMAX){
|
||||
retval=-1; /* error */
|
||||
}
|
||||
}else{
|
||||
for (retry=0;retry<FLDR_RETRYMAX;retry++){
|
||||
/* read sector */
|
||||
if (DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_READ_DATA,&rwp,sizeof(rwp),(PVOID)fldr_secbuf,AKAI_FL_SECSIZE,&ret,NULL)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retry>=FLDR_RETRYMAX){
|
||||
retval=-1; /* error */
|
||||
}
|
||||
|
||||
/* copy sector from DMA buffer to buf */
|
||||
/* Note: even if DeviceIoControl() above returned an error */
|
||||
/* in this case, DMA buffer could contain leftover from last call */
|
||||
/* or could contain correct complete or partial sector */
|
||||
/* -> let caller decide what to do with buf in case of an error */
|
||||
bcopy((u_char *)fldr_secbuf,buf,AKAI_FL_SECSIZE);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
fldr_format(int fldrn)
|
||||
{
|
||||
BYTE cyl;
|
||||
BYTE head;
|
||||
BYTE sec;
|
||||
BYTE secnum;
|
||||
BYTE secgap3;
|
||||
BYTE secoffset;
|
||||
BYTE trackskew;
|
||||
DWORD ret;
|
||||
static BYTE fpbuf[sizeof(FD_FORMAT_PARAMS)+sizeof(FD_ID_HEADER)*AKAI_FLH_DISK_SECTORS]; /* space for max. track size */
|
||||
PFD_FORMAT_PARAMS fpp;
|
||||
DWORD fpsize;
|
||||
#ifndef FLDR_FORMAT_NOVERIFY
|
||||
FD_READ_WRITE_PARAMS rwp;
|
||||
#endif
|
||||
u_int retry;
|
||||
int retval;
|
||||
|
||||
if ((fldrn<0)||(fldrn>=FLDRNUM)||(fldr_h[fldrn]==INVALID_HANDLE_VALUE)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fldr_type[fldrn]==FLDR_TYPE_FLH){
|
||||
secnum=AKAI_FLH_DISK_SECTORS;
|
||||
secgap3=AKAI_FLH_SECTOR_GAP3;
|
||||
secoffset=AKAI_FLH_SECTOR_OFFSET;
|
||||
trackskew=AKAI_FLH_TRACK_SKEW;
|
||||
}else{
|
||||
secnum=AKAI_FLL_DISK_SECTORS;
|
||||
secgap3=AKAI_FLL_SECTOR_GAP3;
|
||||
secoffset=AKAI_FLL_SECTOR_OFFSET;
|
||||
trackskew=AKAI_FLL_TRACK_SKEW;
|
||||
}
|
||||
|
||||
retval=0; /* no error so far */
|
||||
fpp=(PFD_FORMAT_PARAMS)fpbuf;
|
||||
fpsize=sizeof(FD_FORMAT_PARAMS)+secnum*sizeof(FD_ID_HEADER);
|
||||
for (cyl=0;cyl<AKAI_FL_DISK_TRACKS;cyl++){
|
||||
/* check if no floppy inserted */
|
||||
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FD_CHECK_DISK,NULL,0,NULL,0,&ret,NULL)){
|
||||
PRINTF_OUT("\rno floppy inserted \n",((u_int)cyl)+1);
|
||||
FLUSH_ALL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* goto track */
|
||||
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_SEEK,&cyl,sizeof(cyl),NULL,0,&ret,NULL)){
|
||||
PRINTF_OUT("\rtrack %u - cannot seek track\n",((u_int)cyl)+1);
|
||||
FLUSH_ALL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (head=0;head<AKAI_FL_DISK_SIDES;head++){
|
||||
PRINTF_OUT("\rtrack %u side %u",((u_int)cyl)+1,((u_int)head)+1);
|
||||
FLUSH_ALL;
|
||||
|
||||
/* set parameters */
|
||||
fpp->flags=FD_OPTION_MFM;
|
||||
fpp->phead=head;
|
||||
fpp->size=AKAI_FL_SECTOR_SIZE_CODE;
|
||||
fpp->sectors=secnum;
|
||||
fpp->gap=secgap3;
|
||||
fpp->fill=AKAI_FL_SECTOR_FILL;
|
||||
for (sec=0;sec<secnum;sec++){
|
||||
fpp->Header[sec].cyl=cyl;
|
||||
fpp->Header[sec].head=head;
|
||||
fpp->Header[sec].sector=AKAI_FL_SECTOR_BASE+((secoffset+sec+cyl*(secnum-trackskew))%secnum);
|
||||
fpp->Header[sec].size=AKAI_FL_SECTOR_SIZE_CODE;
|
||||
}
|
||||
#ifndef FLDR_FORMAT_NOVERIFY
|
||||
rwp.flags=FD_OPTION_MFM;
|
||||
rwp.phead=head;
|
||||
rwp.cyl=cyl;
|
||||
rwp.head=head;
|
||||
rwp.sector=AKAI_FL_SECTOR_BASE;
|
||||
rwp.size=AKAI_FL_SECTOR_SIZE_CODE;
|
||||
rwp.eot=AKAI_FL_SECTOR_BASE+secnum-1; /* for IOCTL_FDCMD_VERIFY: last sector number !!! */
|
||||
rwp.gap=0x0a;
|
||||
rwp.datalen=0xff;
|
||||
#endif
|
||||
|
||||
for (retry=0;retry<FLDR_RETRYMAX;retry++){
|
||||
/* format track */
|
||||
if (DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_FORMAT_TRACK,fpp,fpsize,NULL,0,&ret,NULL)){
|
||||
#ifndef FLDR_FORMAT_NOVERIFY
|
||||
/* verify track */
|
||||
if (DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_VERIFY,&rwp,sizeof(rwp),NULL,0,&ret,NULL))
|
||||
#endif
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (retry>=FLDR_RETRYMAX){
|
||||
PRINTF_OUT(" - cannot format track\n");
|
||||
FLUSH_ALL;
|
||||
#if 1
|
||||
/* XXX ignore error, continue */
|
||||
retval=-1;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
PRINTF_OUT("\rdone \n");
|
||||
FLUSH_ALL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif /* _VISUALCPP */
|
||||
|
||||
|
||||
|
||||
/* cache */
|
||||
|
||||
struct blk_cache_s blk_cache[BLK_CACHE_NUM];
|
||||
int blk_cache_enable;
|
||||
|
||||
|
||||
|
||||
void
|
||||
init_blk_cache(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<BLK_CACHE_NUM;i++){
|
||||
blk_cache[i].valid=0; /* free entry */
|
||||
blk_cache[i].buf=NULL; /* not allocated yet */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
free_blk_cache(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<BLK_CACHE_NUM;i++){
|
||||
if (blk_cache[i].buf!=NULL){ /* buffer allocated? */
|
||||
/* free buffer */
|
||||
free(blk_cache[i].buf);
|
||||
blk_cache[i].valid=0; /* free entry */
|
||||
blk_cache[i].buf=NULL; /* not allocated yet */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
print_blk_cache(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef _VISUALCPP
|
||||
PRINTF_OUT("nr fd fldrn start/B blksize blk age mod\n");
|
||||
PRINTF_OUT("--------------------------------------------------------------\n");
|
||||
#else /* !_VISUALCPP */
|
||||
PRINTF_OUT("nr fd start/B blksize blk age mod\n");
|
||||
PRINTF_OUT("--------------------------------------------------------\n");
|
||||
#endif /* !_VISUALCPP */
|
||||
for (i=0;i<BLK_CACHE_NUM;i++){
|
||||
if (!blk_cache[i].valid){ /* free entry? */
|
||||
continue; /* next */
|
||||
}
|
||||
#ifdef _VISUALCPP
|
||||
PRINTF_OUT("%4i %3i %3i 0x%02x%08x 0x%04x 0x%04x 0x%08x %i\n",
|
||||
i,
|
||||
blk_cache[i].fd,
|
||||
blk_cache[i].fldrn,
|
||||
(u_int)(blk_cache[i].startoff>>32),
|
||||
(u_int)(0xffffffff&blk_cache[i].startoff),
|
||||
blk_cache[i].blksize,
|
||||
blk_cache[i].blk,
|
||||
blk_cache[i].age,
|
||||
blk_cache[i].modified);
|
||||
#else /* !_VISUALCPP */
|
||||
PRINTF_OUT("%4i %3i 0x%02x%08x 0x%04x 0x%04x 0x%08x %i\n",
|
||||
i,
|
||||
blk_cache[i].fd,
|
||||
(u_int)(blk_cache[i].startoff>>32),
|
||||
(u_int)(0xffffffff&blk_cache[i].startoff),
|
||||
blk_cache[i].blksize,
|
||||
blk_cache[i].blk,
|
||||
blk_cache[i].age,
|
||||
blk_cache[i].modified);
|
||||
#endif /* !_VISUALCPP */
|
||||
}
|
||||
#ifdef _VISUALCPP
|
||||
PRINTF_OUT("--------------------------------------------------------------\n");
|
||||
#else /* !_VISUALCPP */
|
||||
PRINTF_OUT("--------------------------------------------------------\n");
|
||||
#endif /* !_VISUALCPP */
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
find_blk_cache(int fd,
|
||||
#ifdef _VISUALCPP
|
||||
int fldrn,
|
||||
#endif /* _VISUALCPP */
|
||||
OFF64_T startoff,u_int blk,u_int blksize)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* scan cache */
|
||||
for (i=0;i<BLK_CACHE_NUM;i++){
|
||||
if (blk_cache[i].buf==NULL){
|
||||
continue; /* next */
|
||||
}
|
||||
if (!blk_cache[i].valid){ /* free? */
|
||||
continue; /* next */
|
||||
}
|
||||
/* check if contained within cache */
|
||||
/* Note: must check for blksize as well!!! */
|
||||
if ((fd==blk_cache[i].fd)
|
||||
#ifdef _VISUALCPP
|
||||
&&(fldrn==blk_cache[i].fldrn)
|
||||
#endif /* _VISUALCPP */
|
||||
&&(startoff==blk_cache[i].startoff)
|
||||
&&(blk==blk_cache[i].blk)
|
||||
&&(blksize==blk_cache[i].blksize)){
|
||||
break; /* found it */
|
||||
}
|
||||
}
|
||||
|
||||
if (i==BLK_CACHE_NUM){ /* none found? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
blk_cache_aging(int i)
|
||||
{
|
||||
int j;
|
||||
u_int agemin;
|
||||
|
||||
if ((i<0)||(i>=BLK_CACHE_NUM)||(!blk_cache[i].valid)){
|
||||
return;
|
||||
}
|
||||
|
||||
blk_cache[i].age=0; /* reset age */
|
||||
|
||||
/* find the youngest of the others */
|
||||
agemin=BLK_CACHE_AGE_MAX;
|
||||
for (j=0;j<BLK_CACHE_NUM;j++){
|
||||
if (!blk_cache[j].valid){ /* free? */
|
||||
continue; /* next */
|
||||
}
|
||||
if (j==i){
|
||||
continue; /* next */
|
||||
}
|
||||
if (blk_cache[j].age<agemin){
|
||||
agemin=blk_cache[j].age;
|
||||
}
|
||||
}
|
||||
if (agemin==0){ /* somebody else too young? */
|
||||
/* increment age of the others */
|
||||
for (j=0;j<BLK_CACHE_NUM;j++){
|
||||
if (j==i){
|
||||
continue; /* next */
|
||||
}
|
||||
if (blk_cache[j].age<BLK_CACHE_AGE_MAX){
|
||||
blk_cache[j].age++; /* increase age */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
io_blks_direct(int fd,
|
||||
#ifdef _VISUALCPP
|
||||
int fldrn,
|
||||
#endif /* _VISUALCPP */
|
||||
OFF64_T startoff,u_char *buf,u_int bstart,u_int bsize,u_int blksize,int cachealloc,int mode)
|
||||
{
|
||||
int err;
|
||||
int j,jmax;
|
||||
u_int agemax;
|
||||
u_int blk,blkmin,blkmax,blkchunk;
|
||||
|
||||
if (buf==NULL){
|
||||
return -1;
|
||||
}
|
||||
#ifdef _VISUALCPP
|
||||
if ((fd<0)&&(fldrn<0)){
|
||||
return -1;
|
||||
}
|
||||
#else /* !_VISUALCPP */
|
||||
if (fd<0){
|
||||
return -1;
|
||||
}
|
||||
#endif /* !_VISUALCPP */
|
||||
|
||||
if ((mode!=IO_BLKS_READ)&&(mode!=IO_BLKS_WRITE)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Note: OFF64_T against overflow */
|
||||
if ((((OFF64_T)bstart)+((OFF64_T)bsize))>(OFF64_T)0xffffffff){ /* XXX */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bsize==0){
|
||||
return 0; /* done */
|
||||
}
|
||||
|
||||
if (!blk_cache_enable){ /* cache disabled? */
|
||||
cachealloc=0; /* don't allocate cache */
|
||||
}
|
||||
|
||||
if (cachealloc /* must allocate cache? */
|
||||
#ifdef _VISUALCPP
|
||||
||(fldrn>=0) /* or is floppy drive? */
|
||||
#endif /* _VISUALCPP */
|
||||
){
|
||||
/* single blocks */
|
||||
blkmin=bstart;
|
||||
blkmax=bstart+bsize;
|
||||
blkchunk=1;
|
||||
}else{
|
||||
/* all blocks at once */
|
||||
blkmin=bstart;
|
||||
blkmax=bstart+1; /* fake value: only once */
|
||||
blkchunk=bsize;
|
||||
}
|
||||
|
||||
for (blk=blkmin;blk<blkmax;blk++){
|
||||
#ifdef _VISUALCPP
|
||||
if (fldrn>=0){ /* is floppy drive? */
|
||||
/* Note: ignore startoff if floppy drive */
|
||||
if (fldr_io_direct(fldrn,blk,buf+(blk-blkmin)*blksize,mode)<0){
|
||||
return -1;
|
||||
}
|
||||
}else /* no floppy drive */
|
||||
#endif /* _VISUALCPP */
|
||||
{
|
||||
/* goto blk */
|
||||
if (LSEEK64(fd,startoff+(OFF64_T)(blk*blksize),SEEK_SET)<0){
|
||||
#ifdef DEBUG
|
||||
PERROR("lseek");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
if (mode==IO_BLKS_WRITE){
|
||||
/* write block(s) */
|
||||
err=WRITE(fd,(void *)(buf+(blk-blkmin)*blksize),blkchunk*blksize);
|
||||
if (err<0){
|
||||
#ifdef DEBUG
|
||||
PERROR("write");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
if (err!=(int)(blkchunk*blksize)){
|
||||
#ifdef DEBUG
|
||||
PRINTF_ERR("write: incomplete\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
/* read block(s) */
|
||||
err=READ(fd,(void *)(buf+(blk-blkmin)*blksize),blkchunk*blksize);
|
||||
if (err<0){
|
||||
#ifdef DEBUG
|
||||
PERROR("read");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
if (err!=(int)(blkchunk*blksize)){
|
||||
#ifdef DEBUG
|
||||
PRINTF_ERR("read: incomplete\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cachealloc){ /* must allocate cache? */
|
||||
/* find free entry or the oldest one */
|
||||
agemax=0;
|
||||
jmax=0; /* first guess */
|
||||
for (j=0;j<BLK_CACHE_NUM;j++){
|
||||
if (!blk_cache[j].valid){ /* free? */
|
||||
jmax=j;
|
||||
break; /* found one */
|
||||
}
|
||||
if (blk_cache[j].age>=agemax){ /* older or equal? */
|
||||
agemax=blk_cache[j].age;
|
||||
jmax=j;
|
||||
}
|
||||
}
|
||||
/* old cache entry not free and modified? */
|
||||
err=0;
|
||||
if ((blk_cache[jmax].valid)&&(blk_cache[jmax].modified)&&(blk_cache[jmax].buf!=NULL)){
|
||||
/* must flush this block */
|
||||
if (io_blks_direct(blk_cache[jmax].fd,
|
||||
#ifdef _VISUALCPP
|
||||
blk_cache[jmax].fldrn,
|
||||
#endif /* _VISUALCPP */
|
||||
blk_cache[jmax].startoff,
|
||||
(u_char *)blk_cache[jmax].buf,
|
||||
blk_cache[jmax].blk,
|
||||
1,
|
||||
blk_cache[jmax].blksize,
|
||||
0, /* don't alloc cache */
|
||||
IO_BLKS_WRITE)<0){
|
||||
PRINTF_ERR("cannot flush cache block 0x%08x of fd %i\n",blk_cache[jmax].blk,blk_cache[jmax].fd);
|
||||
err=1; /* cannot allocate below */
|
||||
}
|
||||
}
|
||||
if (!err){
|
||||
if ((blk_cache[jmax].buf!=NULL)&&(blk_cache[jmax].blksize!=blksize)){ /* not compatible? */
|
||||
/* free buffer */
|
||||
free(blk_cache[jmax].buf);
|
||||
blk_cache[jmax].buf=NULL;
|
||||
}
|
||||
if (blk_cache[jmax].buf==NULL){ /* buffer not allocated yet/anymore? */
|
||||
/* need to allocate buffer */
|
||||
if ((blk_cache[jmax].buf=(u_char *)malloc(blksize))==NULL){
|
||||
PERROR("malloc");
|
||||
err=1; /* cannot allocate below */
|
||||
}
|
||||
blk_cache[jmax].valid=0; /* free */
|
||||
blk_cache[jmax].blksize=blksize;
|
||||
}
|
||||
}
|
||||
if (!err){
|
||||
/* allocate cache entry */
|
||||
blk_cache[jmax].valid=1;
|
||||
blk_cache[jmax].modified=0;
|
||||
blk_cache[jmax].fd=fd;
|
||||
#ifdef _VISUALCPP
|
||||
blk_cache[jmax].fldrn=fldrn;
|
||||
#endif /* _VISUALCPP */
|
||||
blk_cache[jmax].startoff=startoff;
|
||||
blk_cache[jmax].blk=blk;
|
||||
blk_cache_aging(jmax); /* adjust ages */
|
||||
/* copy data */
|
||||
bcopy(buf+(blk-blkmin)*blksize,blk_cache[jmax].buf,blksize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Note: prior to changing blksize of any device/file, must flush cache first !!! */
|
||||
int
|
||||
flush_blk_cache(void)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/* scan cache */
|
||||
ret=0; /* no error so far */
|
||||
for (i=0;i<BLK_CACHE_NUM;i++){
|
||||
if (blk_cache[i].buf==NULL){
|
||||
continue; /* next */
|
||||
}
|
||||
if (!blk_cache[i].valid){ /* free? */
|
||||
continue; /* next */
|
||||
}
|
||||
if (!blk_cache[i].modified){ /* not modified? */
|
||||
continue; /* next */
|
||||
}
|
||||
/* must write */
|
||||
if (io_blks_direct(blk_cache[i].fd,
|
||||
#ifdef _VISUALCPP
|
||||
blk_cache[i].fldrn,
|
||||
#endif /* _VISUALCPP */
|
||||
blk_cache[i].startoff,
|
||||
(u_char *)blk_cache[i].buf,
|
||||
blk_cache[i].blk,
|
||||
1,
|
||||
blk_cache[i].blksize,
|
||||
0, /* don't alloc cache */
|
||||
IO_BLKS_WRITE)<0){
|
||||
PRINTF_ERR("cannot flush cache block 0x%08x of fd %i\n",blk_cache[i].blk,blk_cache[i].fd);
|
||||
/* XXX cannot do more now, maybe more luck next time */
|
||||
ret=-1;
|
||||
}else{
|
||||
blk_cache[i].modified=0; /* done */
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
io_blks(int fd,
|
||||
#ifdef _VISUALCPP
|
||||
int fldrn,
|
||||
#endif /* _VISUALCPP */
|
||||
OFF64_T startoff,u_char *buf,u_int bstart,u_int bsize,u_int blksize,int cachealloc,int mode)
|
||||
{
|
||||
int i;
|
||||
u_int blk;
|
||||
u_int chunkstart,chunksize;
|
||||
|
||||
if (buf==NULL){
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((mode!=IO_BLKS_READ)&&(mode!=IO_BLKS_WRITE)){
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Note: OFF64_T against overflow */
|
||||
if ((((OFF64_T)bstart)+((OFF64_T)bsize))>(OFF64_T)0xffffffff){ /* XXX */
|
||||
return -1;
|
||||
}
|
||||
#ifdef _VISUALCPP
|
||||
if ((fd<0)&&(fldrn<0)){
|
||||
return -1;
|
||||
}
|
||||
#else /* !_VISUALCPP */
|
||||
if (fd<0){
|
||||
return -1;
|
||||
}
|
||||
#endif /* !_VISUALCPP */
|
||||
|
||||
if (!blk_cache_enable){ /* cache disabled? */
|
||||
cachealloc=0; /* don't allocate cache */
|
||||
}
|
||||
|
||||
/* check every block */
|
||||
chunkstart=bstart;
|
||||
chunksize=0; /* no chunk of missing blocks so far */
|
||||
for (blk=bstart;blk<(bstart+bsize);blk++){
|
||||
if (blk_cache_enable){ /* cache enabled? */
|
||||
/* look in cache */
|
||||
i=find_blk_cache(fd,
|
||||
#ifdef _VISUALCPP
|
||||
fldrn,
|
||||
#endif /* _VISUALCPP */
|
||||
startoff,blk,blksize);
|
||||
/* Note: no match for blk if blksize has changed!!! */
|
||||
/* however, these cache entries can be reused if needed */
|
||||
}else{
|
||||
i=-1; /* not found in cache */
|
||||
}
|
||||
if (i<0){ /* not found in cache? */
|
||||
if (chunksize==0){ /* new chunk of missing blocks? */
|
||||
chunkstart=blk; /* start of chunk */
|
||||
}
|
||||
chunksize++; /* one more missing block */
|
||||
}else{
|
||||
/* found in cache */
|
||||
/* Note: now, blk_cache[i].buf!=NULL */
|
||||
|
||||
/* Note: must do cache-I/O first, since io_blks_direct could steal i from cache */
|
||||
if (mode==IO_BLKS_WRITE){
|
||||
/* copy to cache */
|
||||
bcopy(buf+(blk-bstart)*blksize,blk_cache[i].buf,blksize);
|
||||
blk_cache[i].modified=1; /* modified */
|
||||
}else{
|
||||
/* copy from cache */
|
||||
bcopy(blk_cache[i].buf,buf+(blk-bstart)*blksize,blksize);
|
||||
}
|
||||
blk_cache_aging(i); /* adjust ages */
|
||||
|
||||
/* chunk of missing blocks pending? */
|
||||
if (chunksize>0){
|
||||
/* must read or write */
|
||||
if (io_blks_direct(fd,
|
||||
#ifdef _VISUALCPP
|
||||
fldrn,
|
||||
#endif /* _VISUALCPP */
|
||||
startoff,
|
||||
(u_char *)(buf+(chunkstart-bstart)*blksize),
|
||||
chunkstart,
|
||||
chunksize,
|
||||
blksize,
|
||||
cachealloc,
|
||||
mode)<0){
|
||||
return -1;
|
||||
}
|
||||
chunksize=0; /* no chunk of missing blocks anymore */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* one last time: chunk of missing blocks pending? */
|
||||
if (chunksize>0){
|
||||
/* must read or write */
|
||||
if (io_blks_direct(fd,
|
||||
#ifdef _VISUALCPP
|
||||
fldrn,
|
||||
#endif /* _VISUALCPP */
|
||||
startoff,
|
||||
(u_char *)(buf+(chunkstart-bstart)*blksize),
|
||||
chunkstart,
|
||||
chunksize,
|
||||
blksize,
|
||||
cachealloc,
|
||||
mode)<0){
|
||||
return -1;
|
||||
}
|
||||
chunksize=0; /* no chunk of missing blocks anymore */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* EOF */
|
||||
Reference in New Issue
Block a user