Files
david 9f107b5f80 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
2026-06-15 22:33:53 -07:00

866 lines
21 KiB
C
Executable File

/*
* 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 */