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

7255 lines
183 KiB
C
Executable File

/*
* Copyright (C) 2008,2010,2012,2018,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"
#include "akaiutil.h"
#include "akaiutil_file.h"
#include "akaiutil_take.h"
/* disks */
struct disk_s disk[DISK_NUM_MAX]; /* disks, Note: one for each disk, system-wide */
u_int disk_num; /* number of disks */
/* partitions */
struct part_s part[PART_NUM_MAX]; /* partitions, Note: one for each partition, system-wide */
u_int part_num; /* number of partitions */
/* current directory */
struct disk_s *curdiskp; /* current disk pointer into disk[], NULL if system-level */
/* Note: unique, fixed mapping to each file */
struct part_s *curpartp; /* current partition pointer into part[], NULL if disk-level */
/* Note: unique, fixed mapping to each partition */
struct vol_s *curvolp; /* current volume pointer into curvol_buf, NULL if disk- or partition-level */
/* Note: neither fixed nor unique mapping to each volume!!! */
struct vol_s curvol_buf; /* current volume buffer, Note: only one buffer, might change volume identity!!! */
/* for operations with current directory, Note: one instance only, not recursive!!! */
struct disk_s *savecurdiskp;
struct part_s *savecurpartp;
struct vol_s *savecurvolp;
struct vol_s savecurvol_buf;
int savecurvolmodflag; /* modifier flag */
char savecurvolname[AKAI_NAME_LEN+1]; /* +1 for '\0' */
u_int savecurvolindex;
char dirnamebuf[DIRNAMEBUF_LEN+1]; /* +1 for '\0' */
/* filter tags */
u_char curfiltertag[AKAI_FILE_TAGNUM];
int
open_disk(char *name,int readonly,OFF64_T startoff,u_int pseudodisksize,u_int pseudodisknum)
{
int fd;
#ifdef _VISUALCPP
int fldrn;
int fldrtype;
#endif /* _VISUALCPP */
u_int disksize;
u_int i;
if (name==NULL){
return -1;
}
if (disk_num>=DISK_NUM_MAX){
return -1;
}
/* Note: pseudodisksize>AKAI_DISKSIZE_MAX is allowed */
/* Note: pseudodisksize==0 is allowed and means: pseudo-disk size is not specified */
if (pseudodisknum>PSEUDODISK_NUM_MAX){
pseudodisknum=PSEUDODISK_NUM_MAX; /* limit */
}
/* Note: pseudodisknum==0 is allowed and means: max. number of pseudo-disks is not specified */
fd=-1;
#ifdef _VISUALCPP
fldrn=-1;
fldrtype=FLDR_TYPE_FLH; /* XXX */
/* check if name corresponds to floppy drive */
if (strcasecmp(name,"floppyla:")==0){
fldrn=0;
fldrtype=FLDR_TYPE_FLL;
}else if (strcasecmp(name,"floppylb:")==0){
fldrn=1;
fldrtype=FLDR_TYPE_FLL;
}else if (strcasecmp(name,"floppyha:")==0){
fldrn=0;
fldrtype=FLDR_TYPE_FLH;
}else if (strcasecmp(name,"floppyhb:")==0){
fldrn=1;
fldrtype=FLDR_TYPE_FLH;
}
if (fldrn>=0){ /* is floppy drive? */
/* Note: ignore startoff,pseudodisksize,pseudodisknum if floppy drive */
/* Note: fldr_open() does not consider readonly flag */
if (fldr_open(fldrn,fldrtype)<0){
PRINTF_ERR("disk%u: cannot open \"%s\"\n",disk_num,name);
/* discard disk, keep old disk_num */
return -1;
}
PRINTF_OUT("disk%u: \"%s\"\n",disk_num,name);
disk[disk_num].index=disk_num; /* index */
disk[disk_num].fd=-1; /* no file descriptor */
disk[disk_num].fldrn=fldrn; /* floppy drive number */
disk[disk_num].readonly=readonly;
disk[disk_num].startoff=0; /* no start offset (Note: startoff is ignored by io_blks_direct() if floppy drive) */
if (fldrtype==FLDR_TYPE_FLH){
disk[disk_num].totsize=AKAI_FLH_SIZE*AKAI_FL_BLOCKSIZE; /* disk size in bytes */
disk[disk_num].type=DISK_TYPE_FLH;
}else{
disk[disk_num].totsize=AKAI_FLL_SIZE*AKAI_FL_BLOCKSIZE; /* disk size in bytes */
disk[disk_num].type=DISK_TYPE_FLL;
}
disk[disk_num].blksize=AKAI_FL_BLOCKSIZE; /* blocksize */
/* disk size in blocks */
disk[disk_num].bsize=disk[disk_num].totsize/disk[disk_num].blksize;
disk_num++; /* found one */
return 0;
}else{
fldrn=-1; /* no floppy drive */
}
#endif /* _VISUALCPP */
if (readonly){
fd=OPEN(name,O_RDONLY|O_BINARY,0);
}else{
fd=OPEN(name,O_RDWR|O_BINARY,0666);
}
if (fd<0){
PERROR("open");
PRINTF_ERR("disk%u: cannot open \"%s\"\n",disk_num,name);
/* discard disk, keep old disk_num */
return -1;
}
for (i=0;(disk_num<DISK_NUM_MAX)&&(i<PSEUDODISK_NUM_MAX);){
if ((pseudodisksize>0)&&(pseudodisknum>0)){ /* pseudo-disk size and max. number of pseudo-disks given? */
/* take given pseudodisksize as usable disk size */
/* Note: don't determine usable disk size of current pseudo-disk */
/* Note: in particular useful for disk with bad blocks */
disksize=pseudodisksize;
}else{
/* determine usable disk size of current pseudo-disk, use pseudodisksize as upper limit (if >0) */
/* Note: possibly not useful for disk with bad blocks */
disksize=akai_disksize(fd,startoff,pseudodisksize);
if ((i>0)&&(disksize==0)){ /* not first pseudo-disk and empty? */
break; /* done */
}
}
if ((pseudodisksize>0)||(pseudodisknum>0)||(startoff>0)){
PRINTF_OUT("disk%u: \"%s\" (start: byte 0x%02x%08x)\n",
disk_num,
name,
(u_int)(startoff>>32),
(u_int)(0xffffffff&startoff));
}else{
PRINTF_OUT("disk%u: \"%s\"\n",disk_num,name);
}
if (disksize>AKAI_DISKSIZE_MAX){
disksize=AKAI_DISKSIZE_MAX; /* limit for usable disk size */
}
if ((pseudodisksize>0)&&(disksize<pseudodisksize)){
PRINTF_OUT("disk%u: usable disk size is limited to %u KB\n",disk_num,disksize/1024);
}
disk[disk_num].index=disk_num; /* index */
disk[disk_num].fd=fd;
#ifdef _VISUALCPP
disk[disk_num].fldrn=-1; /* no floppy drive */
#endif /* _VISUALCPP */
disk[disk_num].readonly=readonly;
disk[disk_num].startoff=startoff; /* start offset in bytes */
disk[disk_num].totsize=disksize; /* disk size in bytes */
disk[disk_num].type=DISK_TYPE_HD; /* XXX first guess for type */
disk[disk_num].blksize=AKAI_HD_BLOCKSIZE; /* XXX first guess for blocksize */
/* disk size in blocks */
disk[disk_num].bsize=disk[disk_num].totsize/disk[disk_num].blksize;
disk_num++; /* found one */
if ((pseudodisksize==0) /* pseudo-disk size not given? */
&&((pseudodisknum==0)||(disksize==0))){ /* and: max. number of pseudo-disks not given or usable disk size==0? */
break; /* done */
}
/* next pseudo-disk */
i++;
if ((pseudodisknum>0)&&(i>=pseudodisknum)){ /* max. number of pseudo-disks given and done? */
break; /* done */
}
if (pseudodisksize>0){ /* pseudo-disk size given? */
/* increment pseudo-disk start offset by pseudodisksize (which can be larger than the usable disk size) */
startoff+=(OFF64_T)pseudodisksize;
}else{
/* pseudo-disk size is not given */
/* increment pseudo-disk start offset by disksize (usable disk size, determined above) */
/* Note: now, disksize>0 (see check above) */
startoff+=disksize;
}
}
return 0;
}
void
close_alldisks(void)
{
int fd;
#ifdef _VISUALCPP
int fldrn;
#endif /* _VISUALCPP */
u_int i;
while (disk_num>0){
disk_num--;
fd=disk[disk_num].fd;
if (fd>=0){ /* opened? */
/* close */
CLOSE(disk[disk_num].fd);
/* mark all disks with same fd as closed */
for (i=0;i<=disk_num;i++){
if (disk[i].fd==fd){
disk[i].fd=-1; /* closed */
}
}
}
#ifdef _VISUALCPP
fldrn=disk[disk_num].fldrn;
if ((fldrn>=0)&&(fldrn<FLDRNUM)&&(fldr_h[fldrn]!=INVALID_HANDLE_VALUE)){ /* floppy drive opened? */
/* close */
CloseHandle(fldr_h[fldrn]);
fldr_h[fldrn]=INVALID_HANDLE_VALUE; /* closed */
}
disk[disk_num].fldrn=-1; /* no floppy drive */
#endif /* _VISUALCPP */
}
}
/* determine usable disk size in bytes */
/* Note: possibly not useful for disk with bad blocks */
u_int
akai_disksize(int fd,OFF64_T startoff,u_int disksizemax)
{
u_int off,siz;
static u_char bbuf[AKAI_DISKSIZE_GRAN];
if (fd<0){
return 0;
}
/* Note: disksizemax==0 is allowed and means: max. usable disk size is not specified */
if ((disksizemax==0)||(disksizemax>AKAI_DISKSIZE_MAX)){
disksizemax=AKAI_DISKSIZE_MAX; /* limit for usable disk size */
}
/* XXX 32bit overflow protection for off<<=1 below */
if (disksizemax>0x80000000){
disksizemax=0x80000000;
}
/* determine start offset >= disksizemax, must be power of 2 */
for (off=1;off<disksizemax;off<<=1)
;
siz=off;
for (;;){
siz>>=1;
/* can read 1 block at off ? */
if ((off>=disksizemax) /* beyond max. disk limit? */
||(LSEEK64(fd,startoff+((OFF64_T)off),SEEK_SET)<0)
||(READ(fd,bbuf,AKAI_DISKSIZE_GRAN)!=(int)AKAI_DISKSIZE_GRAN)){
/* block at off is not readable -> off is too high */
#ifdef DEBUG
PRINTF_ERR("akai_disksize: off=%08x siz=%08x high\n",off,siz);
#endif
if (siz<AKAI_DISKSIZE_GRAN){
if (off==0){ /* even block at 0 is not readable? */
/* no blocks are readable */
return 0; /* exit */
}
off-=AKAI_DISKSIZE_GRAN; /* block at off is not readable */
/* Note: must check if block at new off is readable */
}else{
off-=siz;
}
}else{
/* block at off is readable -> off is OK or too low */
#ifdef DEBUG
PRINTF_ERR("akai_disksize: off=%08x siz=%08x low\n",off,siz);
#endif
if (siz<AKAI_DISKSIZE_GRAN){
break; /* end of iteration */
}
off+=siz;
}
}
/* now, off is at last readable disk block */
/* return value in bytes */
if (off<AKAI_DISKSIZE_MAX){
off+=AKAI_DISKSIZE_GRAN; /* !!! */
}else{
off=AKAI_DISKSIZE_MAX;
}
if (off>disksizemax){
off=disksizemax;
}
#ifdef DEBUG
PRINTF_ERR("akai_disksize done: size=%08x (%u)\n",off,off);
#endif
return off;
}
int
akai_io_blks(struct part_s *pp,u_char *buf,u_int bstart,u_int bsize,int cachealloc,int mode)
{
if ((pp==NULL)||(pp->diskp==NULL)){
return -1;
}
if ((pp->diskp->readonly)&&(mode==IO_BLKS_WRITE)){
PRINTF_ERR("disk%u: read-only, cannot write\n",pp->diskp->index);
return -1;
}
if (((bstart+bsize)>pp->bsize)
||((pp->bstart+bstart+bsize)>pp->diskp->bsize)){
PRINTF_ERR("disk%u: cannot %s outside partition/disk\n",
pp->diskp->index,
(mode==IO_BLKS_WRITE)?"write":"read");
return -1;
}
return io_blks(pp->diskp->fd,
#ifdef _VISUALCPP
pp->diskp->fldrn,
#endif /* _VISUALCPP */
pp->diskp->startoff,
buf,
pp->bstart+bstart,
bsize,
pp->blksize,
cachealloc,mode);
}
/* open external file read-only */
int
akai_openreadonly_extfile(char *name)
{
int fd;
u_int nlen;
char *nbuf;
u_int k;
if (name==NULL){
return -1;
}
/* try given name */
fd=OPEN(name,O_RDONLY|O_BINARY,0);
if (fd>=0){ /* success? */
return fd;
}
/* no success with name */
/* try again with modified name: ' ' instead of '_' for keyboard entry */
nlen=(u_int)strlen(name);
if (nlen==0){
return -1;
}
/* Note: use own file name buffer for (possible) modification, don't modify string in name */
nbuf=(char *)malloc(nlen+1); /* +1 for '\0' */
if (nbuf==NULL){
PERROR("malloc");
return -1;
}
for (k=0;k<nlen;k++){
if (name[k]=='_'){
nbuf[k]=' ';
}else{
nbuf[k]=name[k];
}
}
nbuf[k]='\0';
fd=OPEN(nbuf,O_RDONLY|O_BINARY,0);
free(nbuf);
return fd;
}
/* check external WAV file name (and modify given file name if required) */
/* Note: assumes that wavname may be modified */
int
akai_check_extwavname(char *wavname)
{
u_int nlen;
int fd;
u_int k;
if (wavname==NULL){
return -1;
}
/* check if correct suffix in WAV file name */
nlen=(u_int)strlen(wavname);
if ((nlen<4)||(strncasecmp(wavname+nlen-4,".wav",4)!=0)){
PRINTF_ERR("invalid WAV file name\n");
return -1;
}
#if 1
/* wildcard characters are not allowed */
for (k=0;k<nlen-4;k++){
if ((wavname[k]=='*')||(wavname[k]=='?')){
PRINTF_ERR("invalid WAV file name\n");
return -1;
}
}
#endif
/* check if external file with given file name can be opened */
fd=OPEN(wavname,O_RDONLY|O_BINARY,0);
if (fd<0){ /* no success? */
/* modify name: ' ' instead of '_' for keyboard entry */
/* Note: assume that string in wavname may be modified */
for (k=0;k<nlen-4;k++){
if (wavname[k]=='_'){
wavname[k]=' ';
}
}
/* check if external file with (possibly) modified file name can be opened */
fd=OPEN(wavname,O_RDONLY|O_BINARY,0);
if (fd<0){ /* no success? */
PRINTF_ERR("cannot access WAV file\n");
return -1;
}
}
CLOSE(fd);
return 0; /* OK */
}
/* count free and bad blocks in partition */
void
akai_countfree_part(struct part_s *pp)
{
u_int i;
u_int n;
if (pp==NULL){
return;
}
pp->bfree=0;
pp->bbad=0;
if ((!pp->valid)||(pp->fat==NULL)){
return;
}
if (pp->type==PART_TYPE_DD){
/* S1100/S3000 harddisk DD partition */
/* Note: start at cluster 1 in order to skip reserved system cluster 0 which contains partition header */
for (i=1;i<pp->csize;i++){
n=(pp->fat[i][1]<<8)+pp->fat[i][0];
if (n==AKAI_DDFAT_CODE_FREE){
pp->bfree+=AKAI_DDPART_CBLKS; /* +1 cluster */
}else if (n==AKAI_DDFAT_CODE_BAD){
pp->bbad+=AKAI_DDPART_CBLKS; /* +1 cluster */
#if 1
}else if (((n>=pp->bsize)||(n<pp->bsyssize))
/* Note: here, n!=AKAI_DDFAT_CODE_FREE, see check above */
&&(n!=AKAI_DDFAT_CODE_SYS)
&&(n!=AKAI_DDFAT_CODE_END)){ /* invalid? */
pp->bbad+=AKAI_DDPART_CBLKS; /* +1 cluster */
#endif
}
}
return;
}
/* Note: start at block pp->bsyssize in order to skip reserved system blocks */
/* => also avoids problem due to AKAI_FAT_CODE_SYS900FL==AKAI_FAT_CODE_FREE */
for (i=pp->bsyssize;i<pp->bsize;i++){
n=(pp->fat[i][1]<<8)+pp->fat[i][0];
if (n==AKAI_FAT_CODE_FREE){
pp->bfree++;
}else if (n==AKAI_FAT_CODE_BAD){
pp->bbad++;
#if 1
}else if (((n>=pp->bsize)||(n<pp->bsyssize))
/* Note: here, n!=AKAI_FAT_CODE_FREE, see check above */
/* Note: here, n!=AKAI_FAT_CODE_BAD, see check above */
&&(n!=AKAI_FAT_CODE_SYS900FL) /* XXX same as AKAI_FAT_CODE_FREE */
&&(n!=AKAI_FAT_CODE_SYS900HD)
&&(n!=AKAI_FAT_CODE_SYS)
&&(n!=AKAI_FAT_CODE_DIREND900HD)
&&(n!=AKAI_FAT_CODE_DIREND1000HD)
&&(n!=AKAI_FAT_CODE_DIREND3000)
&&(n!=AKAI_FAT_CODE_FILEEND900)
&&(n!=AKAI_FAT_CODE_FILEEND)){ /* invalid? */
pp->bbad++;
#endif
}
}
}
int
akai_check_fatblk(u_int blk,u_int bsize,u_int bsyssize)
{
if ( (blk==AKAI_FAT_CODE_FREE)
||(blk==AKAI_FAT_CODE_BAD)
||(blk==AKAI_FAT_CODE_SYS900FL) /* XXX same as AKAI_FAT_CODE_FREE */
||(blk==AKAI_FAT_CODE_SYS900HD)
||(blk==AKAI_FAT_CODE_SYS)
||(blk==AKAI_FAT_CODE_DIREND900HD)
||(blk==AKAI_FAT_CODE_DIREND1000HD)
||(blk==AKAI_FAT_CODE_DIREND3000)
||(blk==AKAI_FAT_CODE_FILEEND900)
||(blk==AKAI_FAT_CODE_FILEEND)
||(blk>=bsize)
||(blk<bsyssize)){
return -1; /* special code or invalid */
}
return 0; /* OK */
}
int
print_fatchain(struct part_s *pp,u_int blk)
{
u_int i;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type==PART_TYPE_DD){
return -1;
}
PRINTF_OUT("lblk pblk\n");
PRINTF_OUT("--------------\n");
for (i=0;i<pp->bsize;i++){ /* XXX to avoid loop */
if (akai_check_fatblk(blk,pp->bsize,pp->bsyssize)<0){
break; /* end of chain */
}
PRINTF_OUT("0x%04x 0x%04x\n",i,blk);
/* next block */
blk=(pp->fat[blk][1]<<8)+pp->fat[blk][0];
}
PRINTF_OUT("--------------\n");
#if 0
PRINTF_OUT("END= 0x%04x\n",blk);
#endif
if (i==pp->bsize){ /* XXX stuck in loop? */
return 1;
}
return 0;
}
/* Note: if writeflag==0, free block counter of partition is not updated!!! */
int
akai_free_fatchain(struct part_s *pp,u_int bstart,int writeflag)
{
int ret;
u_int fblk,nblk;
u_int bc;
u_int i;
u_int hdsiz;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)||(bstart>pp->bsize)){
return -1;
}
if (pp->type==PART_TYPE_DD){
return -1;
}
ret=0; /* OK so far */
/* free FAT chain */
fblk=bstart;
bc=0; /* block counter */
for (i=0;i<pp->bsize;i++){ /* XXX to avoid loop */
/* check fblk */
if ( /* Note: don't check for AKAI_FAT_CODE_SYS900FL here since it is ==AKAI_FAT_CODE_FREE !!! */
(fblk==AKAI_FAT_CODE_SYS900HD)
||(fblk==AKAI_FAT_CODE_SYS)
||(fblk==AKAI_FAT_CODE_DIREND900HD)
||(fblk==AKAI_FAT_CODE_DIREND1000HD)
||(fblk==AKAI_FAT_CODE_DIREND3000)
||(fblk==AKAI_FAT_CODE_FILEEND900)
||(fblk==AKAI_FAT_CODE_FILEEND)){ /* valid end of chain? */
break; /* done */
}
if ( (fblk==AKAI_FAT_CODE_FREE)
||(fblk==AKAI_FAT_CODE_BAD)
||(fblk>=pp->bsize)){ /* invalid? */
PRINTF_ERR("invalid block in chain\n");
ret=-1;
break;
}
/* next block */
nblk=(pp->fat[fblk][1]<<8)+pp->fat[fblk][0];
/* free block in FAT */
pp->fat[fblk][1]=0xff&(AKAI_FAT_CODE_FREE>>8);
pp->fat[fblk][0]=0xff&AKAI_FAT_CODE_FREE;
bc++;
/* advance */
fblk=nblk;
}
if (writeflag){
/* update free block counter */
pp->bfree+=bc;
/* write new FAT to partition */
if ((pp->type==PART_TYPE_FLL)||(pp->type==PART_TYPE_FLH)){
/* write floppy header */
if (pp->type==PART_TYPE_FLL){
hdsiz=AKAI_FLLHEAD_BLKS; /* floppy header */
}else{
hdsiz=AKAI_FLHHEAD_BLKS; /* floppy header */
}
if (akai_io_blks(pp,(u_char *)&pp->head.flh,
0,
hdsiz,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}else if (pp->type==PART_TYPE_HD9){
/* copy first FAT entries */
bcopy((u_char *)&pp->head.hd9.fatblk,(u_char *)&pp->head.hd9.fatblk0,AKAI_HD9FAT0_ENTRIES*2);
/* write S900 harddisk header */
if (akai_io_blks(pp,(u_char *)&pp->head.hd9,
0,
AKAI_HD9HEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}else if (pp->type==PART_TYPE_HD){
/* write S1000/S3000 partition header */
if (akai_io_blks(pp,(u_char *)&pp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
}
return ret;
}
/* returns first block in *bstartp */
int
akai_allocate_fatchain(struct part_s *pp,u_int bsize,u_int *bstartp,u_int bcont0,u_int endcode)
{
int ret;
u_int fblk,pblk;
u_int bc;
u_int hdsiz;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type==PART_TYPE_DD){
return -1;
}
if (bstartp==NULL){
return -1;
}
if (bcont0>bsize){ /* want more contiguous blocks than total? */
return -1;
}
/* check if enough space left */
if (bsize>pp->bfree){
PRINTF_ERR("not enough space left\n");
return -1;
}
/* now there should be enough free blocks if there was no bcont0 constraint */
/* check code for end of chain */
if ( /* Note: don't check for AKAI_FAT_CODE_SYS900FL here since it is ==AKAI_FAT_CODE_FREE !!! */
(endcode!=AKAI_FAT_CODE_SYS900HD)
&&(endcode!=AKAI_FAT_CODE_SYS)
&&(endcode!=AKAI_FAT_CODE_DIREND900HD)
&&(endcode!=AKAI_FAT_CODE_DIREND1000HD)
&&(endcode!=AKAI_FAT_CODE_DIREND3000)
&&(endcode!=AKAI_FAT_CODE_FILEEND900)
&&(endcode!=AKAI_FAT_CODE_FILEEND)){
return -1;
}
if (bsize==0){
return 0; /* done */
}
/* scan FAT */
ret=0; /* no error so far */
bc=0; /* block counter */
*bstartp=pp->bsize; /* invalid */
pblk=0;
/* Note: start at block pp->bsyssize in order to skip reserved system blocks */
/* => also avoids problem due to AKAI_FAT_CODE_SYS900FL==AKAI_FAT_CODE_FREE */
for (fblk=pp->bsyssize;fblk<pp->bsize;fblk++){ /* block */
/* check if fblk is free */
if (((pp->fat[fblk][1]<<8)+pp->fat[fblk][0])!=AKAI_FAT_CODE_FREE){
continue; /* not free, next */
}
/* is free */
/* allocate */
if (bc==0){ /* is first free block? */
/* start of chain */
*bstartp=fblk;
}else{
if ((bcont0<=1)||(fblk==(pblk+1))){ /* don't care or contiguous to previous block? */
/* link chain in previous free block */
pp->fat[pblk][1]=0xff&(fblk>>8);
pp->fat[pblk][0]=0xff&fblk;
}else{
/* we care and this is a non-contiguous block */
if (bc<bcont0){ /* not enough so far? */
/* must discard chain allocated so far */
/* free chain */
if (akai_free_fatchain(pp,*bstartp,0)<0){ /* 0: don't write FAT yet */
ret=-1;
goto akai_allocate_fatchain_done;
}
/* nothing anymore, new start */
*bstartp=fblk;
bc=0;
}else{
/* enough contiguous blocks, non-contiguous blocks may follow now */
bcont0=0; /* don't care anymore */
}
}
}
bc++; /* found one */
/* temporarily mark end of chain */
pp->fat[fblk][1]=0xff&(endcode>>8);
pp->fat[fblk][0]=0xff&endcode;
if (bc==bsize){ /* enough? */
/* keep end mark */
break; /* done */
}
pblk=fblk; /* save for next element */
}
if (bc!=bsize){ /* not enough? */
if (*bstartp<pp->bsize){ /* valid chain? */
/* free chain */
if (akai_free_fatchain(pp,*bstartp,0)<0){ /* 0: don't write FAT yet */
ret=-1;
goto akai_allocate_fatchain_done;
}
}
}else{
/* enough */
/* update free block counter */
pp->bfree-=bc;
}
akai_allocate_fatchain_done:
if (ret<0){
/* XXX in case something went wrong */
/* count free and bad blocks */
akai_countfree_part(pp);
}
/* write new FAT to partition */
if ((pp->type==PART_TYPE_FLL)||(pp->type==PART_TYPE_FLH)){
/* write floppy header */
if (pp->type==PART_TYPE_FLL){
hdsiz=AKAI_FLLHEAD_BLKS; /* floppy header */
}else{
hdsiz=AKAI_FLHHEAD_BLKS; /* floppy header */
}
if (akai_io_blks(pp,(u_char *)&pp->head.flh,
0,
hdsiz,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
ret=-1;
}
}else if (pp->type==PART_TYPE_HD9){
/* copy first FAT entries */
bcopy((u_char *)&pp->head.hd9.fatblk,(u_char *)&pp->head.hd9.fatblk0,AKAI_HD9FAT0_ENTRIES*2);
/* write S900 harddisk header */
if (akai_io_blks(pp,(u_char *)&pp->head.hd9,
0,
AKAI_HD9HEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
ret=-1;
}
}else if (pp->type==PART_TYPE_HD){
/* write S1000/S3000 partition header */
if (akai_io_blks(pp,(u_char *)&pp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
ret=-1;
}
}
return ret;
}
int
akai_scanbad(struct part_s *pp,int markflag)
{
static u_char buf[AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE]; /* XXX enough for all partition types */
u_int hdsiz;
u_int i,n;
int modifflag;
if ((pp==NULL)||(!pp->valid)){
return -1;
}
if (pp->type==PART_TYPE_DD){
/* S1100/S3000 harddisk DD partition */
/* scan for bad clusters */
modifflag=0;
for (i=0;i<pp->csize;i++){
PRINTF_OUT("\rcluster 0x%04x",i);
FLUSH_ALL;
/* try to read cluster */
if (akai_io_blks(pp,(u_char *)buf,
i*AKAI_DDPART_CBLKS, /* block offset */
AKAI_DDPART_CBLKS, /* 1 cluster */
0,IO_BLKS_READ)<0){ /* 0: don't alloc cache */
/* cannot read cluster */
if (i==0){ /* reserved cluster for system? */
PRINTF_OUT(" bad (system)\n");
/* XXX don't mark system cluster as bad */
}else{
n=(pp->fat[i][1]<<8)+pp->fat[i][0];
if ((n==AKAI_DDFAT_CODE_FREE)||(n==AKAI_DDFAT_CODE_BAD)){
PRINTF_OUT(" bad\n");
if (markflag&&(n!=AKAI_DDFAT_CODE_BAD)){
/* mark as bad cluster */
pp->fat[i][1]=0xff&(AKAI_DDFAT_CODE_BAD>>8);
pp->fat[i][0]=0xff&AKAI_DDFAT_CODE_BAD;
modifflag=1;
}
}else{
PRINTF_OUT(" bad (used)\n");
/* XXX don't mark used cluster as bad */
}
}
FLUSH_ALL;
if (markflag&&modifflag){
/* count free and bad blocks */
akai_countfree_part(pp);
/* write partition header */
if (akai_io_blks(pp,(u_char *)&pp->head.dd,
0,
AKAI_DDPARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
}
}
return 0;
}
/* scan for bad blocks */
modifflag=0;
for (i=0;i<pp->bsize;i++){
PRINTF_OUT("\rblock 0x%04x",i);
FLUSH_ALL;
#ifdef _VISUALCPP
if (pp->diskp->fldrn>=0){ /* is floppy drive? */
/* check if no floppy inserted */
if (fldr_checkfloppyinserted(pp->diskp->fldrn)!=0){
PRINTF_OUT("\nerror: no floppy inserted\n");
FLUSH_ALL;
return -1;
}
}
#endif /* _VISUALCPP */
/* try to read block */
if (akai_io_blks(pp,(u_char *)buf,
i,
1,
0,IO_BLKS_READ)<0){ /* 0: don't alloc cache */
/* cannot read block */
if (i<pp->bsyssize){ /* reserved block for system? */
PRINTF_OUT(" bad (system)\n");
/* XXX don't mark system block as bad */
}else{
n=(pp->fat[i][1]<<8)+pp->fat[i][0];
if ((n==AKAI_FAT_CODE_FREE)||(n==AKAI_FAT_CODE_BAD)){
PRINTF_OUT(" bad\n");
if (markflag&&(n!=AKAI_FAT_CODE_BAD)){
/* mark as bad block */
pp->fat[i][1]=0xff&(AKAI_FAT_CODE_BAD>>8);
pp->fat[i][0]=0xff&AKAI_FAT_CODE_BAD;
modifflag=1;
}
}else{
PRINTF_OUT(" bad (used)\n");
/* XXX don't mark used block as bad */
}
}
FLUSH_ALL;
}
}
if (markflag&&modifflag){
/* count free and bad blocks */
akai_countfree_part(pp);
/* write new FAT to partition */
if ((pp->type==PART_TYPE_FLL)||(pp->type==PART_TYPE_FLH)){
/* write floppy header */
if (pp->type==PART_TYPE_FLL){
hdsiz=AKAI_FLLHEAD_BLKS; /* floppy header */
}else{
hdsiz=AKAI_FLHHEAD_BLKS; /* floppy header */
}
if (akai_io_blks(pp,(u_char *)&pp->head.flh,
0,
hdsiz,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}else if (pp->type==PART_TYPE_HD9){
/* copy first FAT entries */
bcopy((u_char *)&pp->head.hd9.fatblk,(u_char *)&pp->head.hd9.fatblk0,AKAI_HD9FAT0_ENTRIES*2);
/* write S900 harddisk header */
if (akai_io_blks(pp,(u_char *)&pp->head.hd9,
0,
AKAI_HD9HEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}else if (pp->type==PART_TYPE_HD){
/* write S1000/S3000 partition header */
if (akai_io_blks(pp,(u_char *)&pp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
}
return 0;
}
int
akai_read_file(int outfd,u_char *outbuf,struct file_s *fp,u_int begin,u_int end)
{
u_char fbuf[AKAI_HD_BLOCKSIZE];
u_int fblk,fchunk,fremain,skipbyte;
u_char (*fatp)[2];
int err;
if ((outfd<0)&&(outbuf==NULL)){
return -1;
}
if (fp==NULL){
return -1;
}
if ((fp->volp==NULL)||(fp->volp->type==AKAI_VOL_TYPE_INACT)){
return -1;
}
if ((fp->volp->partp==NULL)||(!fp->volp->partp->valid)){
return -1;
}
fatp=fp->volp->partp->fat;
if (fatp==NULL){
return -1;
}
if ((fp->volp->partp->blksize==0)||(fp->volp->partp->blksize>AKAI_HD_BLOCKSIZE)){
return -1;
}
if (fp->type==AKAI_FTYPE_FREE){
return -1;
}
if ((end<begin)||(end>fp->size)){
PRINTF_ERR("invalid limits\n");
return -1;
}
fblk=fp->bstart; /* start block */
fremain=end; /* remaining bytes */
skipbyte=begin; /* bytes to skip */
for (;fremain>0;){ /* byte counter */
if (fremain>=fp->volp->partp->blksize){
fchunk=fp->volp->partp->blksize;
}else{
fchunk=fremain;
}
/* check fblk */
if (akai_check_fatblk(fblk,fp->volp->partp->bsize,fp->volp->partp->bsyssize)<0){
PRINTF_ERR("invalid block in file\n");
return -1;
}
if (skipbyte<fchunk){
/* read block */
if (akai_io_blks(fp->volp->partp,(u_char *)fbuf,
fblk,
1,
0,IO_BLKS_READ)<0){ /* 0: don't alloc cache */
return -1;
}
if (outbuf!=NULL){
/* to buffer */
bcopy(fbuf+skipbyte,outbuf,fchunk-skipbyte);
outbuf+=fchunk-skipbyte;
}else{
/* write to file */
err=WRITE(outfd,(void *)(fbuf+skipbyte),fchunk-skipbyte);
if (err<0){
PERROR("write");
return -1;
}
if (err!=(int)(fchunk-skipbyte)){
PRINTF_ERR("write: incomplete\n");
return -1;
}
}
skipbyte=0; /* done */
}else{
skipbyte-=fchunk;
}
/* next block */
fblk=(fatp[fblk][1]<<8)+fatp[fblk][0];
/* chunk done */
fremain-=fchunk;
}
return 0;
}
int
akai_write_file(int inpfd,u_char *inpbuf,struct file_s *fp,u_int begin,u_int end)
{
u_char fbuf[AKAI_HD_BLOCKSIZE];
u_int fblk,fchunk,fremain,skipbyte;
u_char (*fatp)[2];
int err;
if ((inpfd<0)&&(inpbuf==NULL)){
return -1;
}
if (fp==NULL){
return -1;
}
if ((fp->volp==NULL)||(fp->volp->type==AKAI_VOL_TYPE_INACT)){
return -1;
}
if ((fp->volp->partp==NULL)||(!fp->volp->partp->valid)){
return -1;
}
fatp=fp->volp->partp->fat;
if (fatp==NULL){
return -1;
}
if ((fp->volp->partp->blksize==0)||(fp->volp->partp->blksize>AKAI_HD_BLOCKSIZE)){
return -1;
}
if (fp->type==AKAI_FTYPE_FREE){
return -1;
}
if ((end<begin)||(end>fp->size)){
PRINTF_ERR("invalid limits\n");
return -1;
}
fblk=fp->bstart; /* start block */
fremain=end; /* remaining bytes */
skipbyte=begin; /* bytes to skip */
for (;fremain>0;){ /* byte counter */
if (fremain>=fp->volp->partp->blksize){
fchunk=fp->volp->partp->blksize;
}else{
fchunk=fremain;
}
/* check fblk */
if (akai_check_fatblk(fblk,fp->volp->partp->bsize,fp->volp->partp->bsyssize)<0){
PRINTF_ERR("invalid block in file\n");
return -1;
}
if (skipbyte<fchunk){
if ((skipbyte>0)||(fchunk<fp->volp->partp->blksize)){ /* need to read? */
/* read block */
if (akai_io_blks(fp->volp->partp,(u_char *)fbuf,
fblk,
1,
0,IO_BLKS_READ)<0){ /* 0: don't alloc cache */
return -1;
}
}
if (inpbuf!=NULL){
/* from buffer */
bcopy(inpbuf,fbuf+skipbyte,fchunk-skipbyte);
inpbuf+=fchunk-skipbyte;
}else{
/* read file */
err=READ(inpfd,(void *)(fbuf+skipbyte),fchunk-skipbyte);
if (err<0){
PERROR("read");
return -1;
}
if (err!=(int)(fchunk-skipbyte)){
PRINTF_ERR("read: incomplete\n");
return -1;
}
}
/* write block */
if (akai_io_blks(fp->volp->partp,(u_char *)fbuf,
fblk,
1,
0,IO_BLKS_WRITE)<0){ /* 0: don't alloc cache */
return -1;
}
skipbyte=0; /* done */
}else{
skipbyte-=fchunk;
}
/* next block */
fblk=(fatp[fblk][1]<<8)+fatp[fblk][0];
/* chunk done */
fremain-=fchunk;
}
return 0;
}
int
print_ddfatchain(struct part_s *pp,u_int cstart)
{
u_int i;
u_int cl,nextcl;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type!=PART_TYPE_DD){
return -1;
}
if (cstart>=pp->csize){
return -1;
}
PRINTF_OUT("lcl pcl\n");
PRINTF_OUT("--------------\n");
cl=cstart;
for (i=0;i<pp->csize;i++){ /* XXX to avoid loop */
/* check cl */
if ((cl==AKAI_DDFAT_CODE_FREE)
||(cl==AKAI_DDFAT_CODE_BAD)
||(cl==AKAI_DDFAT_CODE_SYS)
||(cl==AKAI_DDFAT_CODE_END)
||(cl>=pp->csize)){ /* invalid? */
break; /* exit */
}
/* next cluster */
nextcl=(pp->fat[cl][1]<<8)+pp->fat[cl][0];
/* print */
PRINTF_OUT("0x%04x 0x%04x\n",i,cl);
/* advance */
if (nextcl==AKAI_DDFAT_CODE_END){
break; /* end of chain */
}
cl=nextcl;
}
PRINTF_OUT("--------------\n");
#if 0
PRINTF_OUT("END= 0x%04x\n",cl);
#endif
if (i==pp->csize){ /* XXX stuck in loop? */
return 1;
}
return 0;
}
u_int
akai_count_ddfatchain(struct part_s *pp,u_int cstart)
{
u_int cc;
u_int i;
u_int cl,nextcl;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return 0;
}
if (pp->type!=PART_TYPE_DD){
return 0;
}
if (cstart>=pp->csize){
return 0;
}
cc=0;
cl=cstart;
for (i=0;i<pp->csize;i++){ /* XXX to avoid loop */
/* check cl */
if ((cl==AKAI_DDFAT_CODE_FREE)
||(cl==AKAI_DDFAT_CODE_BAD)
||(cl==AKAI_DDFAT_CODE_SYS)
||(cl==AKAI_DDFAT_CODE_END)
||(cl>=pp->csize)){ /* invalid? */
break; /* exit */
}
/* next cluster */
nextcl=(pp->fat[cl][1]<<8)+pp->fat[cl][0];
cc++; /* +1 cluster */
/* advance */
if (nextcl==AKAI_DDFAT_CODE_END){
break; /* end of chain, done */
}
cl=nextcl;
}
return cc;
}
/* Note: if writeflag==0, free block counter of partition is not updated!!! */
int
akai_free_ddfatchain(struct part_s *pp,u_int cstart,int writeflag)
{
int ret;
u_int cl,nextcl;
u_int cc;
u_int i;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)||(cstart>pp->csize)){
return -1;
}
if (pp->type!=PART_TYPE_DD){
return -1;
}
ret=0; /* OK so far */
/* free DD FAT chain */
cl=cstart;
cc=0; /* cluster counter */
for (i=0;i<pp->csize;i++){ /* XXX to avoid loop */
/* check cl */
if ((cl==AKAI_DDFAT_CODE_FREE)
||(cl==AKAI_DDFAT_CODE_BAD)
||(cl==AKAI_DDFAT_CODE_SYS)
||(cl==AKAI_DDFAT_CODE_END)
||(cl>=pp->csize)){ /* invalid? */
PRINTF_ERR("invalid cluster in chain\n");
ret=-1;
break;
}
/* next cluster */
nextcl=(pp->fat[cl][1]<<8)+pp->fat[cl][0];
/* free cluster in FAT */
pp->fat[cl][1]=0xff&(AKAI_DDFAT_CODE_FREE>>8);
pp->fat[cl][0]=0xff&AKAI_DDFAT_CODE_FREE;
cc++;
/* advance */
if (nextcl==AKAI_DDFAT_CODE_END){
break; /* end of chain, done */
}
cl=nextcl;
}
if (writeflag){
/* update free block counter */
pp->bfree+=cc*AKAI_DDPART_CBLKS;
/* write partition header */
if (akai_io_blks(pp,(u_char *)&pp->head.dd,
0,
AKAI_DDPARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
return ret;
}
/* returns first cluster in *cstartp */
int
akai_allocate_ddfatchain(struct part_s *pp,u_int csize,u_int *cstartp,u_int ccont0)
{
int ret;
u_int fcl,pcl;
u_int cc;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type!=PART_TYPE_DD){
return -1;
}
if (cstartp==NULL){
return -1;
}
if (ccont0>csize){ /* want more contiguous clusters than total? */
return -1;
}
/* check if enough space left */
if (csize*AKAI_DDPART_CBLKS>pp->bfree){
PRINTF_ERR("not enough space left\n");
return -1;
}
/* now there should be enough free clusters if there was no ccont0 constraint */
if (csize==0){
return 0; /* done */
}
/* scan FAT */
ret=0; /* no error so far */
cc=0; /* cluster counter */
*cstartp=pp->csize; /* invalid */
pcl=0;
/* Note: start at cluster 1 in order to skip reserved system cluster 0 which contains partition header */
for (fcl=1;fcl<pp->csize;fcl++){ /* cluster */
/* check if fcl is free */
if (((pp->fat[fcl][1]<<8)+pp->fat[fcl][0])!=AKAI_DDFAT_CODE_FREE){
continue; /* not free, next */
}
/* is free */
/* allocate */
if (cc==0){ /* is first free cluster? */
/* start of chain */
*cstartp=fcl;
}else{
if ((ccont0<=1)||(fcl==(pcl+1))){ /* don't care or contiguous to previous cluster? */
/* link chain in previous free cluster */
pp->fat[pcl][1]=0xff&(fcl>>8);
pp->fat[pcl][0]=0xff&fcl;
}else{
/* we care and this is a non-contiguous cluster */
if (cc<ccont0){ /* not enough so far? */
/* must discard chain allocated so far */
/* free chain */
if (akai_free_ddfatchain(pp,*cstartp,0)<0){ /* 0: don't write FAT yet */
ret=-1;
goto akai_allocate_ddfatchain_done;
}
/* nothing anymore, new start */
*cstartp=fcl;
cc=0;
}else{
/* enough contiguous clusters, non-contiguous clusters may follow now */
ccont0=0; /* don't care anymore */
}
}
}
cc++; /* found one */
/* temporarily mark end of chain */
pp->fat[fcl][1]=0xff&(AKAI_DDFAT_CODE_END>>8);
pp->fat[fcl][0]=0xff&AKAI_DDFAT_CODE_END;
if (cc==csize){ /* enough? */
/* keep end mark */
break; /* done */
}
pcl=fcl; /* save for next element */
}
if (cc!=csize){ /* not enough? */
if (*cstartp<pp->csize){ /* valid chain? */
/* free chain */
if (akai_free_ddfatchain(pp,*cstartp,0)<0){ /* 0: don't write FAT yet */
ret=-1;
goto akai_allocate_ddfatchain_done;
}
}
}else{
/* enough */
/* update free block counter */
pp->bfree-=cc*AKAI_DDPART_CBLKS;
}
akai_allocate_ddfatchain_done:
if (ret<0){
/* XXX in case something went wrong */
/* count free and bad blocks */
akai_countfree_part(pp);
}
/* write partition header */
if (akai_io_blks(pp,(u_char *)&pp->head.dd,
0,
AKAI_DDPARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
ret=-1;
}
return ret;
}
int
akai_export_ddfatchain(struct part_s *pp,u_int cstart,u_int bstart,u_int bsize,int outfd,u_char *outbuf)
{
static u_char buf[AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE];
u_int bufsiz;
u_int i,i0,i1;
u_int cl,nextcl;
u_int chunkoff,chunksiz;
int err;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type!=PART_TYPE_DD){
return -1;
}
if (cstart>=pp->csize){
return -1;
}
if ((outfd<0)&&(outbuf==NULL)){
return -1;
}
if (bsize==0){
return 0;
}
bufsiz=AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE; /* 1 cluster in bytes */
i0=bstart/bufsiz; /* first cluster for export */
i1=(bstart+bsize-1)/bufsiz; /* last cluster for export */
if (i1>=pp->csize){
return -1;
}
cl=cstart;
for (i=0;i<=i1;i++){
/* check cl */
if ((cl==AKAI_DDFAT_CODE_FREE)
||(cl==AKAI_DDFAT_CODE_BAD)
||(cl==AKAI_DDFAT_CODE_SYS)
||(cl==AKAI_DDFAT_CODE_END)
||(cl>=pp->csize)){ /* invalid? */
return -1;
}
/* next cluster */
nextcl=(pp->fat[cl][1]<<8)+pp->fat[cl][0];
if (i>=i0){ /* far enough? */
/* read cluster */
if (akai_io_blks(pp,buf,
cl*AKAI_DDPART_CBLKS, /* block offset */
AKAI_DDPART_CBLKS, /* 1 cluster */
1,IO_BLKS_READ)<0){ /* 1: alloc cache if possible */
return -1;
}
if (i==i0){ /* first cluster? */
chunkoff=bstart-i0*bufsiz;
chunksiz=bufsiz-chunkoff;
/* Note: chunkoff and chunksiz <= bufsiz by definition of i0 */
if (chunksiz>bsize){
chunksiz=bsize;
}
}else if (i==i1){ /* last cluster? */
chunkoff=0;
chunksiz=bstart+bsize-i1*bufsiz;
/* Note: chunksiz <= bufsiz by definition of i1 */
}else{
chunkoff=0;
chunksiz=bufsiz; /* 1 cluster */
}
if (outbuf!=NULL){
/* to buffer */
bcopy(buf+chunkoff,outbuf,chunksiz);
outbuf+=chunksiz;
}else{
/* write to file */
err=WRITE(outfd,buf+chunkoff,chunksiz);
if (err<0){
PERROR("write");
return -1;
}
if (err!=(int)chunksiz){
PRINTF_ERR("write: incomplete\n");
return -1;
}
}
}
/* advance */
if (nextcl==AKAI_DDFAT_CODE_END){
break; /* end of chain, done */
}
cl=nextcl;
}
return 0;
}
int
akai_import_ddfatchain(struct part_s *pp,u_int cstart,u_int bstart,u_int bsize,int inpfd,u_char *inpbuf)
{
static u_char buf[AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE];
u_int bufsiz;
u_int i,i0,i1;
u_int cl,nextcl;
u_int chunkoff,chunksiz;
int readflag;
int err;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type!=PART_TYPE_DD){
return -1;
}
if (cstart>=pp->csize){
return -1;
}
if ((inpfd<0)&&(inpbuf==NULL)){
return -1;
}
if (bsize==0){
return 0;
}
bufsiz=AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE; /* 1 cluster in bytes */
i0=bstart/bufsiz; /* first cluster for export */
i1=(bstart+bsize-1)/bufsiz; /* last cluster for export */
if (i1>=pp->csize){
return -1;
}
cl=cstart;
for (i=0;i<=i1;i++){
/* check cl */
if ((cl==AKAI_DDFAT_CODE_FREE)
||(cl==AKAI_DDFAT_CODE_BAD)
||(cl==AKAI_DDFAT_CODE_SYS)
||(cl==AKAI_DDFAT_CODE_END)
||(cl>=pp->csize)){ /* invalid? */
return -1;
}
/* next cluster */
nextcl=(pp->fat[cl][1]<<8)+pp->fat[cl][0];
if (i>=i0){ /* far enough? */
if (i==i0){ /* first cluster? */
chunkoff=bstart-i0*bufsiz;
chunksiz=bufsiz-chunkoff;
/* Note: chunkoff and chunksiz <= bufsiz by definition of i0 */
if (chunksiz>bsize){
chunksiz=bsize;
}
readflag=1;
}else if (i==i1){ /* last cluster? */
chunkoff=0;
chunksiz=bstart+bsize-i1*bufsiz;
/* Note: chunksiz <= bufsiz by definition of i1 */
readflag=1;
}else{
chunkoff=0;
chunksiz=bufsiz; /* 1 cluster */
readflag=0;
}
if (readflag){
/* read cluster */
if (akai_io_blks(pp,buf,
cl*AKAI_DDPART_CBLKS, /* block offset */
AKAI_DDPART_CBLKS, /* 1 cluster */
1,IO_BLKS_READ)<0){ /* 1: alloc cache if possible */
return -1;
}
}
if (inpbuf!=NULL){
/* from buffer */
bcopy(inpbuf,buf+chunkoff,chunksiz);
inpbuf+=chunksiz;
}else{
/* read from file */
err=READ(inpfd,buf+chunkoff,chunksiz);
if (err<0){
PERROR("read");
return -1;
}
if (err!=(int)chunksiz){
PRINTF_ERR("read: incomplete\n");
return -1;
}
}
/* write cluster */
if (akai_io_blks(pp,buf,
cl*AKAI_DDPART_CBLKS, /* block offset */
AKAI_DDPART_CBLKS, /* 1 cluster */
1,IO_BLKS_WRITE)<0){ /* 1: alloc cache if possible */
return -1;
}
}
/* advance */
if (nextcl==AKAI_DDFAT_CODE_END){
break; /* end of chain, done */
}
cl=nextcl;
}
return 0;
}
/* convert char for S1000/S3000 */
char
akai2ascii(u_char c)
{
char a;
if (c<=9){
a='0'+c-0;
}else if (c==10){
a=' ';
}else if ((c>=11)&&(c<=36)){
a='A'+c-11;
}else if (c==37){
a='#';
}else if (c==38){
a='+';
}else if (c==39){
a='-';
}else if (c==40){
a='.';
}else{
a='.'; /* XXX */
}
return a;
}
/* convert char for S900 */
char
akai2ascii900(u_char c)
{
char a;
if (((c>='0')&&(c<='9'))
||(c==' ')
||((c>='A')&&(c<='Z'))
||((c>='a')&&(c<='z'))
||(c=='#')
||(c=='+')
||(c=='-')
||(c=='.')){
a=c;
}else if (c=='\0'){
a=' '; /* XXX */
}else{
a='.'; /* XXX */
}
return a;
}
void
akai2ascii_name(u_char *aname,char *name,int s900flag)
{
int i;
int len;
if (name==NULL){
return;
}
if (aname==NULL){
name[0]='\0';
return;
}
if (s900flag){
len=AKAI_NAME_LEN_S900;
}else{
len=AKAI_NAME_LEN;
}
for (i=0;i<len;i++){
if (s900flag){
#if 1
if (aname[i]=='\0'){ /* end? */
len=i;
break; /* done */
}
#endif
name[i]=akai2ascii900(aname[i]);
}else{
name[i]=akai2ascii(aname[i]);
}
}
name[len]='\0';
/* remove trailing ' ' */
for (i=0;i<len;i++){
if (name[len-i-1]==' '){
name[len-i-1]='\0';
}else{
break;
}
}
}
void
akai2ascii_filename(u_char *aname,u_char ft,u_int osver,char *name,int s900flag)
{
int l;
if (name==NULL){
return;
}
/* Note: aname==NULL is also OK */
if (aname==NULL){
name[0]='\0';
}else{
akai2ascii_name(aname,name,s900flag);
}
/* type */
l=(int)strlen(name);
if (ft==AKAI_SAMPLE900_FTYPE){
/* S900 sample file */
if (osver!=0){
/* S900 compressed sample format */
sprintf(name+l,".S9C");
}else{
/* S900 non-compressed sample format */
sprintf(name+l,".S9");
}
}else if (ft==AKAI_CDSETUP3000_FTYPE){
/* CD3000 CD-ROM setup file */
/* Note: not ".T9" */
sprintf(name+l,".CD");
}else if (ft==AKAI_CDSAMPLE3000_FTYPE){
/* CD3000 CD-ROM sample parameters file */
/* Note: not ".H3" */
sprintf(name+l,".s+");
}else if ((ft>=AKAI_S900_FTYPE_MIN)&&(ft<=AKAI_S900_FTYPE_MAX)){
/* S900 */
/* Note: 'T'==AKAI_CDSETUP3000_FTYPE was handled above */
sprintf(name+l,".%c9",(char)('A'+ft-AKAI_S900_FTYPE_MIN));
}else if ((ft>=AKAI_S1000_FTYPE_MIN)&&(ft<=AKAI_S1000_FTYPE_MAX)){
/* S1000 */
#if 1
if ((ft=='p')||(ft=='s')){
sprintf(name+l,".%c1",(char)('A'+ft-AKAI_S1000_FTYPE_MIN));
}else
#endif
{
sprintf(name+l,".%c",(char)('A'+ft-AKAI_S1000_FTYPE_MIN));
}
}else if ((ft>=(u_char)AKAI_S3000_FTYPE_MIN)&&(ft<=(u_char)AKAI_S3000_FTYPE_MAX)){
/* S3000 */
/* Note: 'h'+0x80==AKAI_CDSAMPLE3000_FTYPE was handled above */
sprintf(name+l,".%c3",(char)('A'+ft-AKAI_S3000_FTYPE_MIN));
}else{
/* unknown */
sprintf(name+l,".x%02x",(u_int)ft);
}
}
/* convert char for S1000/S3000 */
u_char
ascii2akai(char a)
{
char c;
if (a=='_'){ /* for keyboard entry */
a=' ';
}
if ((a>='0')&&(a<='9')){
c=a-'0';
}else if (a==' '){
c=10;
}else if ((a>='A')&&(a<='Z')){
c=11+a-'A';
}else if ((a>='a')&&(a<='z')){
c=11+a-'a';
}else if (a=='#'){
c=37;
}else if (a=='+'){
c=38;
}else if (a=='-'){
c=39;
}else if (a=='.'){
c=40;
}else{
c=40; /* XXX */
}
return c;
}
/* convert char for S900 */
u_char
ascii2akai900(char a)
{
char c;
if (a=='_'){ /* for keyboard entry */
a=' ';
}
if (((a>='0')&&(a<='9'))
||(a==' ')
||((a>='A')&&(a<='Z'))
||((a>='a')&&(a<='z'))
||(a=='#')
||(a=='+')
||(a=='-')
||(a=='.')){
c=a;
}else{
c='.'; /* XXX */
}
return c;
}
void
ascii2akai_name(char *name,u_char *aname,int s900flag)
{
int i;
u_char blank;
int len;
if (aname==NULL){
return;
}
/* fill with default ' ' */
if (s900flag){
blank=ascii2akai900(' ');
len=AKAI_NAME_LEN_S900;
}else{
blank=ascii2akai(' ');
len=AKAI_NAME_LEN;
}
for (i=0;i<len;i++){
if ((name==NULL)||(name[i]=='\0')){ /* nothing or end? */
aname[i]=blank; /* default */
name=NULL; /* don't want to go beyond end */
}else{
if (s900flag){
aname[i]=ascii2akai900(name[i]);
}else{
aname[i]=ascii2akai(name[i]);
}
}
}
}
u_char
ascii2akai_filename(char *name,u_char *aname,u_int *osverp,int s900flag)
{
char *tn;
u_int tl;
u_int i,l;
u_int u;
u_char ft;
char namebuf[AKAI_NAME_LEN+4+1]; /* +4 for ".<type>", +1 for '\0' */
if ((aname==NULL)||(osverp==NULL)){
return 0; /* XXX */
}
l=(u_int)strlen(name);
/* check prior to strcpy */
if (l>AKAI_NAME_LEN+4){ /* too long for namebuf? */
/* invalid length */
return AKAI_FTYPE_FREE;
}
/* copy name for possible manipulation below */
strcpy(namebuf,name);
/* check length and suffix */
if ((l>=2)&&(l<=AKAI_NAME_LEN+2)&&(namebuf[l-2]=='.')){
namebuf[l-2]='\0'; /* separate */
tn=&namebuf[l-1]; /* type field */
tl=1; /* type length */
}else if ((l>=3)&&(l<=AKAI_NAME_LEN+3)&&(namebuf[l-3]=='.')){
namebuf[l-3]='\0'; /* separate */
tn=&namebuf[l-2]; /* type field */
tl=2; /* type length */
}else if ((l>=4)&&(l<=AKAI_NAME_LEN+4)&&(namebuf[l-4]=='.')){
namebuf[l-4]='\0'; /* separate */
tn=&namebuf[l-3]; /* type field */
tl=3; /* type length */
}else{
/* no valid suffix */
return AKAI_FTYPE_FREE;
}
l=(u_int)strlen(namebuf);
/* remove trailing ' ' or '_' (XXX don't care how many) */
for (i=0;i<l;i++){
if ((namebuf[l-i-1]==' ')||(namebuf[l-i-1]=='_')){
namebuf[l-i-1]='\0';
}else{
break;
}
}
/* check name length */
l=(u_int)strlen(namebuf);
if (l>(u_int)(s900flag?AKAI_NAME_LEN_S900:AKAI_NAME_LEN)){
/* invalid length */
return AKAI_FTYPE_FREE;
}
/* type */
if ((tl==2)&&(strcasecmp(tn,"S9")==0)){
/* S900 sample file, non-compressed sample format */
ft=AKAI_SAMPLE900_FTYPE;
/* Note: set osver, even if not S900 volume */
*osverp=0; /* non-compressed */
}else if ((tl==3)&&(strcasecmp(tn,"S9C")==0)){
/* S900 sample file, compressed sample format */
ft=AKAI_SAMPLE900_FTYPE;
/* Note: check/set osver, even if not S900 volume */
if (*osverp==0){ /* unsuitable osver? */
*osverp=1; /* XXX non zero */
}
}else if ((tl==2)&&(strcasecmp(tn,"CD")==0)){
/* CD3000 CD-ROM setup file */
/* Note: AKAI_CDSETUP3000_FTYPE=='T' => ".T9" will also lead to this type */
ft=AKAI_CDSETUP3000_FTYPE;
if (s900flag){
*osverp=0; /* non-compressed */
}
}else if ((tl==2)&&(strcasecmp(tn,"s+")==0)){
/* CD3000 CD-ROM sample parameters file */
/* Note: AKAI_CDSAMPLE3000_FTYPE=='h'+0x80 => ".H3" will also lead to this type */
ft=AKAI_CDSAMPLE3000_FTYPE;
if (s900flag){
*osverp=0; /* non-compressed */
}
}else if ((tl==1)||(tl==2)){
ft=(u_char)tn[0];
if ((ft>='A')&&(ft<='Z')){
ft+='a'-'A'; /* to lower case */
}
if ((ft<'a')||(ft>'z')){
/* invalid suffix */
ft=AKAI_FTYPE_FREE;
}
if ((tl==1)||(tn[1]=='1')){
/* S1000 */
ft=AKAI_S1000_FTYPE_MIN+ft-'a';
}else if (tn[1]=='9'){
/* S900 */
ft=AKAI_S900_FTYPE_MIN+ft-'a';
*osverp=0; /* non-compressed */
}else if (tn[1]=='3'){
/* S3000 */
ft=AKAI_S3000_FTYPE_MIN+ft-'a';
}else{
/* invalid suffix */
ft=AKAI_FTYPE_FREE;
}
if (s900flag){
*osverp=0; /* non-compressed */
}
}else{ /* must be tl==3 now */
if (((tn[0]!='X')&&(tn[0]!='x'))
||
(((tn[1]<'0')||(tn[1]>'9'))
&&((tn[1]<'A')||(tn[1]>'F'))
&&((tn[1]<'a')||(tn[1]>'f')))
||
(((tn[2]<'0')||(tn[2]>'9'))
&&((tn[2]<'A')||(tn[2]>'F'))
&&((tn[2]<'a')||(tn[2]>'f')))){
/* invalid suffix */
ft=AKAI_FTYPE_FREE;
}else{
u=AKAI_FTYPE_FREE; /* default: invalid */
sscanf(tn+1,"%x",&u);
/* Note: if sscanf finds nothing, u remains! */
ft=(u_char)u;
/* Note: might still be invalid */
}
if (s900flag){
*osverp=0; /* non-compressed */
}
}
/* name */
ascii2akai_name(namebuf,aname,s900flag);
#if 1
if (ft==AKAI_VOLDIR3000FL_FTYPE){ /* S3000 floppy flag? */
ft=AKAI_FTYPE_FREE; /* invalid */
}
#endif
/* Note: caller must check for AKAI_FTYPE_FREE as invalid code */
return ft;
}
void
akai_vol_info(struct vol_s *vp,u_int ai,int verbose)
{
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)
||(vp->partp==NULL)||(!vp->partp->valid)){
return;
}
if (verbose){
#if 1
if ((vp->partp->type==PART_TYPE_FLL)||(vp->partp->type==PART_TYPE_FLH)){ /* floppy? */
/* for floppy, print also some info about partition: */
/* Note: floppy has only one volume within one partition which covers the whole disk */
PRINTF_OUT("parttype: ");
if (vp->partp->type==PART_TYPE_FLL){
PRINTF_OUT("low-density floppy");
}else{
PRINTF_OUT("high-density floppy");
}
PRINTF_OUT("\nblksize: 0x%04x bytes\n",vp->partp->blksize);
PRINTF_OUT("size: 0x%04x blocks (%6u KB)\n",
vp->partp->bsize,
(vp->partp->bsize*vp->partp->blksize)/1024); /* in KB */
PRINTF_OUT("free: 0x%04x blocks (%6u KB) = %5.1lf%%\n",
vp->partp->bfree,
(vp->partp->bfree*vp->partp->blksize)/1024, /* in KB */
(vp->partp->bsize>0)?(100.0*((double)vp->partp->bfree)/((double)vp->partp->bsize)):0.0);
PRINTF_OUT("bad: 0x%04x blocks (%6u KB) = %5.1lf%%\n",
vp->partp->bbad,
(vp->partp->bbad*vp->partp->blksize)/1024, /* in KB */
(vp->partp->bsize>0)?(100.0*((double)vp->partp->bbad)/((double)vp->partp->bsize)):0.0);
}
#endif
PRINTF_OUT("vnr: %u\n",vp->index+1);
PRINTF_OUT("vname: \"%s\"\n",vp->name);
if (vp->partp->type==PART_TYPE_HD9){
if (ai>0){
PRINTF_OUT("alias: V%u\n",ai);
}
}else if (vp->type!=AKAI_VOL_TYPE_S900){
PRINTF_OUT("load number: ");
akai_print_lnum(vp->lnum);
PRINTF_OUT("\n");
}
PRINTF_OUT("voltype: ");
}else{
PRINTF_OUT("%3u %-12s ",vp->index+1,vp->name);
if (vp->partp->type==PART_TYPE_HD9){
PRINTF_OUT("V%-3u",ai);
}else{
akai_print_lnum(vp->lnum);
}
PRINTF_OUT(" 0x%04x ",vp->dirblk[0]);
if (vp->type!=AKAI_VOL_TYPE_S900){
PRINTF_OUT("%2u.%02u ",0xff&(vp->osver>>8),0xff&vp->osver);
}else{
PRINTF_OUT(" - ");
}
}
switch (vp->type){
case AKAI_VOL_TYPE_INACT:
PRINTF_OUT("INACT");
break;
case AKAI_VOL_TYPE_S1000:
PRINTF_OUT("S1000");
break;
case AKAI_VOL_TYPE_S3000:
PRINTF_OUT("S3000");
break;
case AKAI_VOL_TYPE_CD3000:
PRINTF_OUT("CD3000");
break;
case AKAI_VOL_TYPE_S900:
PRINTF_OUT("S900");
break;
default:
PRINTF_OUT("(%02x)",vp->type);
break;
}
PRINTF_OUT("\n");
if (verbose){
if (vp->type!=AKAI_VOL_TYPE_S900){
PRINTF_OUT("osver: %u.%02u\n",0xff&(vp->osver>>8),0xff&vp->osver);
}
PRINTF_OUT("start: block 0x%04x\n",vp->dirblk[0]);
PRINTF_OUT("max. files: %u\n",vp->fimax);
}
}
void
akai_list_vol(struct vol_s *vp,u_char *filtertagp)
{
u_int fi;
struct file_s tmpfile; /* current file */
u_int totf,totb;
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)
||(vp->partp==NULL)||(!vp->partp->valid)
||(vp->partp->diskp==NULL)){
return;
}
PRINTF_OUT("/disk%u/%c/%s\n",vp->partp->diskp->index,vp->partp->letter,vp->name);
if (vp->type==AKAI_VOL_TYPE_S900){
PRINTF_OUT("fnr fname size/B startblk uncompr\n");
PRINTF_OUT("--------------------------------------------------\n");
}else{
PRINTF_OUT("fnr fname size/B startblk osver tags\n");
PRINTF_OUT("--------------------------------------------------------------\n");
}
/* files in volume directory */
totf=0;
totb=0;
for (fi=0;fi<vp->fimax;fi++){
/* get file */
if (akai_get_file(vp,&tmpfile,fi)<0){
continue; /* next file */
}
/* test if tag-filter matches */
if (akai_match_filetags(filtertagp,tmpfile.tag)<0){ /* no match? */
continue; /* next file */
}
totf++;
totb+=tmpfile.size;
/* print file info */
akai_file_info(&tmpfile,0);
}
if (vp->type==AKAI_VOL_TYPE_S900){
PRINTF_OUT("--------------------------------------------------\n");
}else{
PRINTF_OUT("--------------------------------------------------------------\n");
}
PRINTF_OUT("total: %3u file(s) (max. %3u), %9u bytes\n\n",totf,vp->fimax,totb);
}
int
akai_read_voldir(struct vol_s *vp)
{
u_int i,imax;
u_int blk;
u_char *addr;
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)||(vp->file==NULL)){
return -1;
}
if ((vp->partp==NULL)||(!vp->partp->valid)||(vp->partp->blksize==0)){
return -1;
}
/* number of blocks */
imax=vp->fimax*sizeof(struct akai_voldir_entry_s);
imax=(imax+vp->partp->blksize-1)/vp->partp->blksize; /* round up */
if (imax>VOL_DIRBLKS){
return -1;
}
/* Note: first file starts at byte 0 in first block */
addr=(u_char *)vp->file;
for (i=0;i<imax;i++){
blk=vp->dirblk[i];
#ifdef DEBUG
PRINTF_OUT("read dir block %2u: 0x%04x\n",i,blk);
#endif
/* read volume directory block */
if (akai_io_blks(vp->partp,addr,
blk,
1,
1,IO_BLKS_READ)<0){ /* 1: alloc cache if possible */
return -1;
}
addr+=vp->partp->blksize; /* next */
}
return 0;
}
int
akai_write_voldir(struct vol_s *vp,u_int fi)
{
u_int blk0,blk1;
u_int blk;
u_char *addr;
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)||(vp->file==NULL)){
return -1;
}
if ((vp->partp==NULL)||(!vp->partp->valid)||(vp->partp->blksize==0)){
return -1;
}
if (fi>=vp->fimax){
return -1;
}
/* Note: file entry might overlap two adjacent blocks !!! */
/* block(s) for file fi */
blk0=fi*sizeof(struct akai_voldir_entry_s);
blk1=blk0+sizeof(struct akai_voldir_entry_s)-1;
blk0/=vp->partp->blksize;
blk1/=vp->partp->blksize;
if ((blk0>=VOL_DIRBLKS)||(blk1>=VOL_DIRBLKS)){
return -1;
}
/* write volume directory block 0 to partition */
blk=vp->dirblk[blk0];
/* Note: first file starts at byte 0 in first block */
addr=((u_char *)vp->file)+blk0*vp->partp->blksize;
#ifdef DEBUG
PRINTF_OUT("write dir block %2u: 0x%04x\n",blk0,blk);
#endif
if (akai_io_blks(vp->partp,addr,
blk,
1,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
if (blk1!=blk0){
/* write volume directory block 1 to partition */
blk=vp->dirblk[blk1];
addr+=vp->partp->blksize; /* next */
#ifdef DEBUG
PRINTF_OUT("write dir block %2u: 0x%04x\n",blk1,blk);
#endif
if (akai_io_blks(vp->partp,addr,
blk,
1,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
return 0;
}
/* Note: see comment in akaiutil.h for struct vol_s about copying vol_s!!! */
void
akai_copy_structvol(struct vol_s *srcvp,struct vol_s *dstvp)
{
if ((srcvp==NULL)||(srcvp->partp==NULL)||(!srcvp->partp->valid)){
return;
}
if (dstvp==NULL){
return;
}
/* copy */
*dstvp=*srcvp;
/* fix pointers for copy to be self-contained */
if ((srcvp->partp->type==PART_TYPE_FLL)||(srcvp->partp->type==PART_TYPE_FLH)){
/* floppy */
if ((srcvp->type==AKAI_VOL_TYPE_S3000)||(srcvp->type==AKAI_VOL_TYPE_CD3000)){
/* S3000 */
/* start of files */
dstvp->file=&dstvp->dir.s3000fl.file[0];
}
/* Note: pointers into floppy header (in partition) remain the same!!! */
}else if ((srcvp->partp->type==PART_TYPE_HD9)||(srcvp->partp->type==PART_TYPE_HD)){
/* harddisk */
if (srcvp->type==AKAI_VOL_TYPE_S900){
/* S900 */
/* start of files */
dstvp->file=&dstvp->dir.s900hd.file[0];
/* volume parameters */
dstvp->param=NULL; /* S900 has no volume parameters */
}else if (srcvp->type==AKAI_VOL_TYPE_S1000){
/* S1000 */
/* start of files */
dstvp->file=&dstvp->dir.s1000hd.file[0];
/* volume parameters */
dstvp->param=&dstvp->dir.s1000hd.param;
}else{
/* S3000 */
/* start of files */
dstvp->file=&dstvp->dir.s3000hd.file[0];
/* volume parameters */
dstvp->param=&dstvp->dir.s3000hd.param;
}
}
}
/* get volume with index vi */
/* saves result in *vp */
int
akai_get_vol(struct part_s *pp,struct vol_s *vp,u_int vi)
{
u_int i,j;
struct akai_flvol_label_s *lp;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type==PART_TYPE_DD){
return -1;
}
if (vp==NULL){
return -1;
}
/* in partition */
vp->partp=pp;
if ((pp->type==PART_TYPE_FLL)||(pp->type==PART_TYPE_FLH)){
/* S900/S1000/S3000 floppy */
/* fake index */
if (vi!=0){
return -1;
}
vp->index=vi;
/* Note: low- and high-density floppy headers are identical */
/* up to first AKAI_FAT_ENTRIES_FLL FAT-entries */
/* floppy volume label */
if (pp->type==PART_TYPE_FLL){
lp=&pp->head.fll.label;
}else{
lp=&pp->head.flh.label;
}
/* load number */
vp->lnum=AKAI_VOL_LNUM_OFF;
/* OS version in floppy header */
vp->osver=(lp->osver[1]<<8)+lp->osver[0];
/* determine floppy volume type */
if (pp->head.flh.file[0].type==AKAI_VOLDIR3000FL_FTYPE){ /* S3000 flag? */
/* S3000 */
/* volume type */
vp->type=AKAI_VOL_TYPE_S3000;
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S3000FL;
/* start of files */
vp->file=&vp->dir.s3000fl.file[0];
/* set volume directory blocks */
if (pp->type==PART_TYPE_FLL){
j=AKAI_VOLDIR3000FLL_BSTART;
}else{
j=AKAI_VOLDIR3000FLH_BSTART;
}
for (i=0;i<AKAI_VOLDIR3000FL_BLKS;i++){
vp->dirblk[i]=j+i;
}
}else{
/* S900 or S1000 */
/* determine volume type */
if (vp->osver==AKAI_OSVER_S900VOL){
/* S900 */
vp->type=AKAI_VOL_TYPE_S900;
}else{
/* S1000 */
vp->type=AKAI_VOL_TYPE_S1000;
}
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S1000FL;
/* start of files */
/* Note: see comment above: start of files is the same for low- and high density */
/* Note: S900 and S1000 floppy volume directory is within floppy header */
vp->file=&pp->head.flh.file[0]; /* Note: in floppy header */
/* set volume directory blocks */
if (pp->type==PART_TYPE_FLL){
j=AKAI_FLLHEAD_BLKS;
}else{
j=AKAI_FLHHEAD_BLKS;
}
for (i=0;i<j;i++){
vp->dirblk[i]=i; /* start at offset 0 */
}
}
/* name in floppy header */
akai2ascii_name(lp->name,vp->name,vp->type==AKAI_VOL_TYPE_S900);
if (vp->name[0]=='\0'){ /* empty volume name? */
/* use default volume name as fake volume name */
sprintf(vp->name,"VOLUME %03u",vp->index+1);
}
/* volume parameters */
if (vp->type==AKAI_VOL_TYPE_S900){
/* S900 */
vp->param=NULL; /* S900 has no volume parameters */
}else{
/* S1000 or S3000 */
vp->param=&lp->param; /* Note: in floppy header */
}
if (vp->type==AKAI_VOL_TYPE_S3000){
/* S3000 */
/* read volume directory */
if (akai_read_voldir(vp)<0){
PRINTF_ERR("volume %u: cannot read volume directory\n",vp->index+1);
vp->type=AKAI_VOL_TYPE_INACT; /* XXX mark invalid */
return -1;
}
} /* else: S900 and S1000 floppy volume directory is within floppy header */
return 0;
}
if (pp->type==PART_TYPE_HD9){
/* S900 harddisk */
/* index */
if (vi>=pp->volnummax){
return -1;
}
vp->index=vi;
/* get volume infos from root directory entry for volume */
/* volume type */
vp->type=AKAI_VOL_TYPE_S900;
/* load number */
vp->lnum=AKAI_VOL_LNUM_OFF;
/* OS version */
/* Note: no floppy volume labels for volumes on harddisk => cannot get OS version */
vp->osver=AKAI_OSVER_S900VOL;
/* name */
/* Note: volume names in root directory use S1000/S3000 char conversion */
akai2ascii_name(vp->partp->head.hd9.vol[vp->index].name,vp->name,1); /* 1: S900 */
if (vp->name[0]=='\0'){ /* empty volume name? */
/* use default volume name as fake volume name */
sprintf(vp->name,"VOLUME %03u",vp->index+1);
}
/* volume directory block */
vp->dirblk[0]=(vp->partp->head.hd9.vol[vp->index].start[1]<<8)
+vp->partp->head.hd9.vol[vp->index].start[0];
if (vp->dirblk[0]==AKAI_VOL_START_INACT){ /* volume inactive? */
vp->type=AKAI_VOL_TYPE_INACT;
return -1;
}
/* check vp->dirblk[0] */
if (akai_check_fatblk(vp->dirblk[0],vp->partp->bsize,vp->partp->bsyssize)<0){
PRINTF_ERR("volume %u: invalid dir block 0: 0x%04x\n",vp->index+1,vp->dirblk[0]);
vp->type=AKAI_VOL_TYPE_INACT; /* XXX mark invalid */
return -1;
}
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S900HD;
/* start of files */
vp->file=&vp->dir.s900hd.file[0];
/* volume parameters */
vp->param=NULL; /* S900 has no volume parameters */
/* read volume directory */
if (akai_read_voldir(vp)<0){
PRINTF_ERR("volume %u: cannot read volume directory\n",vp->index+1);
vp->type=AKAI_VOL_TYPE_INACT; /* XXX mark invalid */
return -1;
}
return 0;
}
if (pp->type==PART_TYPE_HD){
/* S1000/S3000 harddisk sampler partition */
/* index */
if (vi>=pp->volnummax){
return -1;
}
vp->index=vi;
/* get volume infos from root directory entry for volume */
/* volume type */
vp->type=vp->partp->head.hd.vol[vp->index].type;
/* load number */
vp->lnum=vp->partp->head.hd.vol[vp->index].lnum;
/* OS version */
/* Note: no floppy volume labels for volumes on harddisk => cannot get OS version */
/* derive OS version from volume type in root directory entry */
if ((vp->type==AKAI_VOL_TYPE_S3000)||(vp->type==AKAI_VOL_TYPE_CD3000)){
vp->osver=AKAI_OSVER_S3000MAX; /* XXX */
}else{
/* XXX assume S1000 */
vp->osver=AKAI_OSVER_S1000MAX; /* XXX */
}
/* name */
/* Note: volume names in root directory entries use S1000/S3000 char conversion */
akai2ascii_name(vp->partp->head.hd.vol[vp->index].name,vp->name,0); /* 0: not S900 */
if (vp->name[0]=='\0'){ /* empty volume name? */
/* use default volume name as fake volume name */
sprintf(vp->name,"VOLUME %03u",vp->index+1);
}
switch (vp->type){
case AKAI_VOL_TYPE_INACT:
return -1; /* invalid */
case AKAI_VOL_TYPE_S1000:
case AKAI_VOL_TYPE_S3000:
case AKAI_VOL_TYPE_CD3000:
break;
default:
#if 0
/* XXX assume S1000 */
vp->type=AKAI_VOL_TYPE_S1000;
break;
#else
PRINTF_ERR("volume %u: unknown volume type (0x%04x)\n",vp->index+1,vp->type);
vp->type=AKAI_VOL_TYPE_INACT; /* XXX mark inactive */
return -1;
#endif
}
/* volume directory block(s) */
vp->dirblk[0]=(vp->partp->head.hd.vol[vp->index].start[1]<<8)
+vp->partp->head.hd.vol[vp->index].start[0];
/* check vp->dirblk[0] */
if (akai_check_fatblk(vp->dirblk[0],vp->partp->bsize,vp->partp->bsyssize)<0){
PRINTF_ERR("volume %u: invalid dir block 0: 0x%04x\n",vp->index+1,vp->dirblk[0]);
vp->type=AKAI_VOL_TYPE_INACT; /* XXX mark invalid */
return -1;
}
/* volume directory entries */
if (vp->type==AKAI_VOL_TYPE_S1000){
/* S1000 */
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S1000HD;
/* start of files */
vp->file=&vp->dir.s1000hd.file[0];
}else{
/* should be S3000 */
vp->dirblk[1]=(vp->partp->fat[vp->dirblk[0]][1]<<8)
+vp->partp->fat[vp->dirblk[0]][0];
/* check vp->dirblk[1] */
if (akai_check_fatblk(vp->dirblk[1],vp->partp->bsize,vp->partp->bsyssize)<0){ /* block 1 not found? */
/* Note: S3000 format should always have block 1 */
#if 1
PRINTF_ERR("volume %u: S3000 volume directory block 1 missing, assuming S1000 volume\n",vp->index+1);
/* XXX assume S1000 */
vp->type=AKAI_VOL_TYPE_S1000;
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S1000HD;
/* start of files */
vp->file=&vp->dir.s1000hd.file[0];
#else
PRINTF_ERR("volume %u: S3000 volume directory block 1 missing\n",vp->index+1);
vp->type=AKAI_VOL_TYPE_INACT; /* XXX mark invalid */
return -1;
#endif
}else{
/* S3000 */
/* vp->dirblk[1] should be volume directory block 1 now */
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S3000HD; /* block 0 and 1 */
/* start of files */
vp->file=&vp->dir.s3000hd.file[0];
}
}
/* volume parameters */
if (vp->type==AKAI_VOL_TYPE_S1000){
/* S1000 harddisk */
vp->param=&vp->dir.s1000hd.param;
}else{
/* S3000 harddisk */
vp->param=&vp->dir.s3000hd.param;
}
/* read volume directory */
if (akai_read_voldir(vp)<0){
PRINTF_ERR("volume %u: cannot read volume directory\n",vp->index+1);
vp->type=AKAI_VOL_TYPE_INACT; /* XXX mark invalid */
return -1;
}
return 0;
}
return -1;
}
/* find first volume with given name */
/* saves result in *vp */
int
akai_find_vol(struct part_s *pp,struct vol_s *vp,char *name)
{
u_int osver;
u_int vi;
u_int ai,aivifound;
char namebuf[AKAI_NAME_LEN+1]; /* +1 for '\0' */
char vnamebuf[AKAI_NAME_LEN+1]; /* +1 for '\0' */
u_int i,j,l;
if ((pp==NULL)||(!pp->valid)){
return -1;
}
if (pp->type==PART_TYPE_DD){
return -1;
}
if (vp==NULL){
return -1;
}
if (name==NULL){
return -1;
}
/* fix name */
l=(u_int)strlen(name);
if (l>AKAI_NAME_LEN){ /* too long for namebuf? */
return -1;
}
for (i=0;i<l;i++){
if (name[i]=='_'){ /* for keyboard entry */
namebuf[i]=' ';
}else{
namebuf[i]=name[i];
}
}
namebuf[i]='\0';
/* remove trailing ' ' (XXX don't care how many) */
for (i=0;i<l;i++){
if (namebuf[l-i-1]==' '){
namebuf[l-i-1]='\0';
}else{
break;
}
}
/* volumes in partition */
aivifound=pp->volnummax; /* invalid */
ai=0;
for (vi=0;vi<pp->volnummax;vi++){
if (pp->type==PART_TYPE_FLL){
/* OS version in floppy header */
osver=(pp->head.fll.label.osver[1]<<8)+pp->head.fll.label.osver[0];
/* volume name in floppy header */
akai2ascii_name(pp->head.fll.label.name,vnamebuf,osver==AKAI_OSVER_S900VOL);
}else if (pp->type==PART_TYPE_FLH){
/* OS version in floppy header */
osver=(pp->head.flh.label.osver[1]<<8)+pp->head.flh.label.osver[0];
/* volume name in floppy header */
akai2ascii_name(pp->head.flh.label.name,vnamebuf,osver==AKAI_OSVER_S900VOL);
}else if (pp->type==PART_TYPE_HD9){
/* S900 harddisk */
j=vp->dirblk[0]=(pp->head.hd9.vol[vi].start[1]<<8)
+pp->head.hd9.vol[vi].start[0];
if (j==AKAI_VOL_START_INACT){ /* inactive? */
continue; /* next */
}
/* volume name in root directory entry */
akai2ascii_name(pp->head.hd9.vol[vi].name,vnamebuf,1); /* 1: S900 */
}else if (pp->type==PART_TYPE_HD){
/* S1000/S3000 harddisk sampler partition */
if (pp->head.hd.vol[vi].type==AKAI_VOL_TYPE_INACT){ /* inactive? */
continue; /* next */
}
/* volume name in root directory */
akai2ascii_name(pp->head.hd.vol[vi].name,vnamebuf,0); /* 0: not S900 */
}else{
continue; /* next */
}
ai++;
if (vnamebuf[0]=='\0'){ /* empty volume name? */
/* use default volume name as fake volume name */
sprintf(vnamebuf,"VOLUME %03u",vi+1);
}
/* compare name (case-insensitive) */
if (strcasecmp(vnamebuf,namebuf)==0){ /* match? */
break; /* found */
}
if ((pp->type==PART_TYPE_HD9)&&(aivifound>=pp->volnummax)){ /* S900 harddisk and no alias name match yet? */
/* alias name for volume on S900 harddisk */
sprintf(vnamebuf,"V%u",ai);
/* compare name (case-insensitive) */
if (strcasecmp(vnamebuf,namebuf)==0){ /* match? */
/* Note: name match takes precendence over alias name match */
aivifound=vi; /* save for later */
}
}
}
if (vi==pp->volnummax){ /* no name match? */
if ((pp->type==PART_TYPE_HD9)&&(aivifound<pp->volnummax)){ /* S900 harddisk and alias name match? */
vi=aivifound;
}else{
return -1;
}
}
/* get volume */
return akai_get_vol(pp,vp,vi);
}
int
akai_rename_vol(struct vol_s *vp,char *name,u_int lnum,u_int osver,struct akai_volparam_s *parp)
{
int modflag;
u_int blk;
u_char *addr;
struct akai_flvol_label_s *lp;
u_int hdsiz;
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)){
return -1;
}
if ((vp->partp==NULL)||(!vp->partp->valid)){
return -1;
}
if ((vp->partp->type==PART_TYPE_FLL)||(vp->partp->type==PART_TYPE_FLH)){
/* floppy */
modflag=0; /* floppy header not modified yet */
/* floppy volume label */
if (vp->partp->type==PART_TYPE_FLL){
lp=&vp->partp->head.fll.label;
hdsiz=AKAI_FLLHEAD_BLKS;
}else{
lp=&vp->partp->head.flh.label;
hdsiz=AKAI_FLHHEAD_BLKS;
}
/* Note: no load number on floppy */
/* Note: cannot switch volume type S900/S1000/S3000 */
if (vp->type==AKAI_VOL_TYPE_S900){
/* S900 floppy */
/* correct OS version if necessary */
osver=AKAI_OSVER_S900VOL;
if (osver!=vp->osver){ /* need to modify? */
vp->osver=osver;
/* Note: S900 has no floppy volume label, all zero */
bzero(lp,sizeof(struct akai_flvol_label_s));
modflag=1;
}
}else{
/* S1000/S300 floppy */
/* correct OS version if necessary */
if (vp->type==AKAI_VOL_TYPE_S1000){
/* S1000 floppy */
if ((osver==AKAI_OSVER_S900VOL)||(osver>AKAI_OSVER_S1100MAX)){
osver=AKAI_OSVER_S1000MAX; /* XXX */
}
}else{
/* S3000 floppy */
if ((osver==AKAI_OSVER_S900VOL)||(osver>AKAI_OSVER_S3000MAX)){
osver=AKAI_OSVER_S3000MAX; /* XXX */
}
}
/* OS version */
if (osver!=vp->osver){ /* new OS version? */
vp->osver=osver;
lp->osver[1]=0xff&(osver>>8);
lp->osver[0]=0xff&osver;
modflag=1;
}
/* name */
if (name!=NULL){ /* new name? */
if (strlen(name)>(u_int)AKAI_NAME_LEN){
PRINTF_ERR("invalid name length\n");
return -1;
}
if (name!=vp->name){ /* not already in vp->name? */
/* copy */
strcpy(vp->name,name); /* Note: name has been checked above */
}
ascii2akai_name(name,lp->name,0); /* 0: not S900 */
modflag=1;
}
/* volume parameters */
if ((parp!=NULL)&&(vp->param!=NULL)){ /* new volume parameters? */
if (parp!=vp->param){ /* not already vp->param? */
/* copy */
bcopy(parp,vp->param,sizeof(struct akai_volparam_s));
} /* else: vp->param[] possibly modified */
modflag=1;
}
}
if (modflag){
/* write floppy header */
if (akai_io_blks(vp->partp,(u_char *)&vp->partp->head.flh,
0,
hdsiz,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
return 0;
}
if (vp->partp->type==PART_TYPE_HD9){
/* S900 harddisk */
/* set vol_s */
modflag=0; /* root directory not modified yet */
/* Note: no load number on S900 harddisk */
/* correct type and OS version */
vp->type=AKAI_VOL_TYPE_S900;
vp->osver=AKAI_OSVER_S900VOL;
/* Note: no floppy volume labels for volumes on harddisk => cannot save OS version */
/* name */
if (name!=NULL){
if (strlen(name)>AKAI_NAME_LEN_S900){
PRINTF_ERR("invalid name length\n");
return -1;
}
if (name!=vp->name){ /* not already in vp->name? */
/* copy */
strcpy(vp->name,name); /* Note: name has been checked above */
}
/* change root directory entry in partition */
ascii2akai_name(name,vp->partp->head.hd9.vol[vp->index].name,1); /* 1: S900 */
modflag=1;
}
if (modflag){
/* write new root directory to partition */
/* copy first FAT entries */
bcopy((u_char *)&vp->partp->head.hd9.fatblk,(u_char *)&vp->partp->head.hd9.fatblk0,AKAI_HD9FAT0_ENTRIES*2);
/* write harddisk header */
if (akai_io_blks(vp->partp,(u_char *)&vp->partp->head.hd9,
0,
AKAI_HD9HEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
/* Note: no volume parameters on S900 harddisk */
return 0;
}
if (vp->partp->type==PART_TYPE_HD){
/* S1000/S3000 harddisk sampler partition */
/* set vol_s */
modflag=0; /* root directory not modified yet */
/* load number */
if (lnum!=vp->lnum){ /* need to modify? */
if ((lnum!=AKAI_VOL_LNUM_OFF)
&&((lnum<AKAI_VOL_LNUM_MIN)||(lnum>AKAI_VOL_LNUM_MAX))){
return -1;
}
vp->lnum=lnum;
/* change root directory entry in partition */
vp->partp->head.hd.vol[vp->index].lnum=lnum;
modflag=1;
}
/* correct type and OS version */
if ((vp->type==AKAI_VOL_TYPE_S900)||(vp->osver==AKAI_OSVER_S900VOL)){ /* incorrect for partition type? */
vp->type=AKAI_VOL_TYPE_S1000; /* XXX */
vp->osver=AKAI_OSVER_S1000MAX; /* XXX */
}
/* Note: no floppy volume labels for volumes on harddisk => cannot save OS version */
/* name */
if (name!=NULL){
if (strlen(name)>AKAI_NAME_LEN){
PRINTF_ERR("invalid name length\n");
return -1;
}
if (name!=vp->name){ /* not already in vp->name? */
/* copy */
strcpy(vp->name,name); /* Note: name has been checked above */
}
/* change root directory entry in partition */
ascii2akai_name(name,vp->partp->head.hd.vol[vp->index].name,0); /* 0: not S900 */
modflag=1;
}
if (modflag){
/* write new root directory to partition */
/* write partition header */
if (akai_io_blks(vp->partp,(u_char *)&vp->partp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
/* volume parameters */
if ((parp!=NULL)&&(vp->param!=NULL)){
if (parp!=vp->param){ /* not already vp->param? */
/* copy */
bcopy(parp,vp->param,sizeof(struct akai_volparam_s));
} /* else: vp->param[] possibly modified */
/* get volume directory block of volume parameters */
if ((vp->type==AKAI_VOL_TYPE_S3000)||(vp->type==AKAI_VOL_TYPE_CD3000)){
blk=vp->dirblk[1];
addr=((u_char *)&vp->dir)+AKAI_HD_BLOCKSIZE;
}else{
blk=vp->dirblk[0];
addr=(u_char *)&vp->dir;
}
/* write new volume directory block to partition */
if (akai_io_blks(vp->partp,addr,
blk,
1,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
return 0;
}
return -1;
}
/* uses *vp as output */
int
akai_create_vol(struct part_s *pp,struct vol_s *vp,u_int type,u_int index,char *name,u_int lnum,struct akai_volparam_s *parp)
{
u_char *addr;
u_int i,j;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (vp==NULL){
return -1;
}
if ((pp->type!=PART_TYPE_HD9)&&(pp->type!=PART_TYPE_HD)){
PRINTF_ERR("cannot create additional volume for this partition type\n");
return -1;
}
/* now, harddisk */
/* partition */
vp->partp=pp;
/* type */
if (pp->type==PART_TYPE_HD9){
/* S900 */
if (type!=AKAI_VOL_TYPE_S900){
PRINTF_ERR("cannot create this volume type for this partition type\n");
return -1;
}
}else if (pp->type==PART_TYPE_HD){
/* S1000/S3000 */
if ((type!=AKAI_VOL_TYPE_S1000)&&(type!=AKAI_VOL_TYPE_S3000)&&(type!=AKAI_VOL_TYPE_CD3000)){
PRINTF_ERR("cannot create this volume type for this partition type\n");
return -1;
}
}
vp->type=type;
/* load number */
if (pp->type==PART_TYPE_HD9){
/* S900 */
vp->lnum=AKAI_VOL_LNUM_OFF;
}else{
/* S1000/S3000 */
if ((lnum!=AKAI_VOL_LNUM_OFF)
&&((lnum<AKAI_VOL_LNUM_MIN)||(lnum>AKAI_VOL_LNUM_MAX))){
return -1;
}
vp->lnum=lnum;
}
/* OS version */
if (vp->type==AKAI_VOL_TYPE_S900){
/* S900 */
vp->osver=AKAI_OSVER_S900VOL;
}else if (vp->type==AKAI_VOL_TYPE_S1000){
/* S1000 */
vp->osver=AKAI_OSVER_S1000MAX; /* XXX */
}else{
/* S3000 */
vp->osver=AKAI_OSVER_S3000MAX; /* XXX */
}
/* name */
if ((name!=NULL)&&(name[0]!='\0')){ /* volume name given? */
if (strlen(name)>(u_int)((vp->type==AKAI_VOL_TYPE_S900)?AKAI_NAME_LEN_S900:AKAI_NAME_LEN)){
PRINTF_ERR("invalid name length\n");
return -1;
}
strcpy(vp->name,name);
}
/* index */
if (index==AKAI_CREATE_VOL_NOINDEX){ /* no user-supplied volume index? */
/* find inactive entry in root directory in partition */
for (i=0;i<pp->volnummax;i++){
if (pp->type==PART_TYPE_HD9){
/* S900 */
j=vp->dirblk[0]=(vp->partp->head.hd9.vol[i].start[1]<<8)
+vp->partp->head.hd9.vol[i].start[0];
if (j==AKAI_VOL_START_INACT){ /* inactive? */
/* index */
vp->index=i;
break; /* found one */
}
}else{
/* S1000/S3000 */
if (vp->partp->head.hd.vol[i].type==AKAI_VOL_TYPE_INACT){ /* inactive? */
/* index */
vp->index=i;
break; /* found one */
}
}
}
if (i==pp->volnummax){ /* none found? */
PRINTF_OUT("no inactive volume found");
return -1;
}
}else{
/* user-supplied index */
if (index>=pp->volnummax){
return -1;
}
if (pp->type==PART_TYPE_HD9){
/* S900 */
j=vp->dirblk[0]=(vp->partp->head.hd9.vol[index].start[1]<<8)
+vp->partp->head.hd9.vol[index].start[0];
if (j!=AKAI_VOL_START_INACT){ /* not inactive? */
PRINTF_OUT("volume not inactive\n");
return -1;
}
}else{
/* S1000/S3000 */
if (vp->partp->head.hd.vol[index].type!=AKAI_VOL_TYPE_INACT){ /* not inactive? */
PRINTF_OUT("volume not inactive\n");
return -1;
}
}
/* index */
vp->index=index;
}
if ((name==NULL)||(name[0]=='\0')){ /* no volume name given? */
/* default volume name */
sprintf(vp->name,"VOLUME %03u",vp->index+1);
}
/* allocate volume directory */
if (vp->type==AKAI_VOL_TYPE_S900){
/* S900 */
if (akai_allocate_fatchain(vp->partp,
AKAI_VOLDIR900HD_BLKS,
&vp->dirblk[0],
AKAI_VOLDIR900HD_BLKS,
AKAI_FAT_CODE_DIREND900HD)<0){ /* end code */
return -1;
}
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S900HD;
/* start of files */
vp->file=&vp->dir.s900hd.file[0];
}else if (vp->type==AKAI_VOL_TYPE_S1000){
/* S1000 */
if (akai_allocate_fatchain(vp->partp,
AKAI_VOLDIR1000HD_BLKS,
&vp->dirblk[0],
AKAI_VOLDIR1000HD_BLKS,
AKAI_FAT_CODE_DIREND1000HD)<0){ /* end code */
return -1;
}
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S1000HD;
/* start of files */
vp->file=&vp->dir.s1000hd.file[0];
}else{
/* S3000 */
if (akai_allocate_fatchain(vp->partp,
AKAI_VOLDIR3000HD_BLKS,
&vp->dirblk[0],
AKAI_VOLDIR3000HD_BLKS, /* XXX want contiguous blocks */
AKAI_FAT_CODE_DIREND3000)<0){ /* end code */
return -1;
}
/* number of volume directory entries */
vp->fimax=AKAI_VOLDIR_ENTRIES_S3000HD;
/* start of files */
vp->file=&vp->dir.s3000hd.file[0];
}
/* initialize volume directory */
bzero(&vp->dir,sizeof(union akai_voldir_u));
for (i=0;i<vp->fimax;i++){
vp->file[i].type=AKAI_FTYPE_FREE;
}
/* volume parameters */
if (vp->type==AKAI_VOL_TYPE_S900){
/* S900 */
vp->param=NULL; /* S900 has no volume paramaters */
}else if (vp->type==AKAI_VOL_TYPE_S1000){
/* S1000 */
vp->param=&vp->dir.s1000hd.param;
}else{
/* S3000 */
vp->param=&vp->dir.s3000hd.param;
}
if (vp->param!=NULL){
if (parp!=NULL){
/* copy volume parameters */
bcopy(parp,vp->param,sizeof(struct akai_volparam_s));
}else{
/* default volume parameters */
akai_init_volparam(vp->param,(vp->type==AKAI_VOL_TYPE_S3000)||(vp->type==AKAI_VOL_TYPE_CD3000));
}
}
/* write new volume directory block 0 to partition */
addr=(u_char *)&vp->dir;
if (akai_io_blks(vp->partp,addr,
vp->dirblk[0],
1,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
if (vp->fimax>AKAI_VOLDIR_ENTRIES_1BLKHD){ /* second volume directory block? */
/* block 1 from FAT */
vp->dirblk[1]=(vp->partp->fat[vp->dirblk[0]][1]<<8)
+vp->partp->fat[vp->dirblk[0]][0];
/* write new volume directory block 1 to partition */
addr+=AKAI_HD_BLOCKSIZE;
if (akai_io_blks(vp->partp,addr,
vp->dirblk[1],
1,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
/* update root directory entry in partition */
if (pp->type==PART_TYPE_HD9){
/* S900 */
/* Note: no OS version nor load number on S900 harddisk */
ascii2akai_name(vp->name,vp->partp->head.hd9.vol[vp->index].name,1); /* 1: S900 */
/* start */
vp->partp->head.hd9.vol[vp->index].start[1]=0xff&(vp->dirblk[0]>>8);
vp->partp->head.hd9.vol[vp->index].start[0]=0xff&vp->dirblk[0];
/* write new root directory to harddisk */
/* copy first FAT entries */
bcopy((u_char *)&vp->partp->head.hd9.fatblk,(u_char *)&vp->partp->head.hd9.fatblk0,AKAI_HD9FAT0_ENTRIES*2);
/* write harddisk header */
if (akai_io_blks(vp->partp,(u_char *)&vp->partp->head.hd9,
0,
AKAI_HD9HEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}else{
/* S1000/S3000 */
vp->partp->head.hd.vol[vp->index].type=(u_char)vp->type;
/* Note: no floppy volume labels for volumes on harddisk => cannot write OS version */
/* akai_get_vol() will derive OS version from volume type in root directory entry */
vp->partp->head.hd.vol[vp->index].lnum=(u_char)vp->lnum;
ascii2akai_name(vp->name,vp->partp->head.hd.vol[vp->index].name,0); /* 0: not S900 */
/* start */
vp->partp->head.hd.vol[vp->index].start[1]=0xff&(vp->dirblk[0]>>8);
vp->partp->head.hd.vol[vp->index].start[0]=0xff&vp->dirblk[0];
/* write new root directory to partition */
/* write partition header */
if (akai_io_blks(vp->partp,(u_char *)&vp->partp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
return 0;
}
int
akai_wipe_vol(struct vol_s *vp,int delflag)
{
u_int fi;
struct file_s tmpfile;
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)){
return -1;
}
if ((vp->partp==NULL)||(!vp->partp->valid)||(vp->partp->fat==NULL)){
return -1;
}
if (delflag&&(vp->partp->type!=PART_TYPE_HD9)&&(vp->partp->type!=PART_TYPE_HD)){
PRINTF_ERR("cannot remove floppy volume\n");
return -1;
}
/* delete all files in volume */
for (fi=0;fi<vp->fimax;fi++){
if (akai_get_file(vp,&tmpfile,fi)<0){
continue; /* next file */
}
if (akai_delete_file(&tmpfile)<0){
return -1;
}
}
if (delflag){
/* now, harddisk */
/* free FAT block(s) of volume */
vp->partp->fat[vp->dirblk[0]][1]=0xff&(AKAI_FAT_CODE_FREE>>8);
vp->partp->fat[vp->dirblk[0]][0]=0xff&AKAI_FAT_CODE_FREE;
if ((vp->fimax>AKAI_VOLDIR_ENTRIES_1BLKHD)
&&(akai_check_fatblk(vp->dirblk[1],vp->partp->bsize,vp->partp->bsyssize)==0)){ /* also block 1? */
vp->partp->fat[vp->dirblk[1]][1]=0xff&(AKAI_FAT_CODE_FREE>>8);
vp->partp->fat[vp->dirblk[1]][0]=0xff&AKAI_FAT_CODE_FREE;
}
/* Note: free and bad block counter will be updated below */
/* free root directory entry in partition */
if (vp->partp->type==PART_TYPE_HD9){
/* S900 */
vp->partp->head.hd9.vol[vp->index].start[1]=0xff&(AKAI_VOL_START_INACT>>8);
vp->partp->head.hd9.vol[vp->index].start[0]=0xff&AKAI_VOL_START_INACT;
/* XXX keep name */
/* write new FAT and root directory to partition */
/* copy first FAT entries */
bcopy((u_char *)&vp->partp->head.hd9.fatblk,(u_char *)&vp->partp->head.hd9.fatblk0,AKAI_HD9FAT0_ENTRIES*2);
/* write harddisk header */
if (akai_io_blks(vp->partp,(u_char *)&vp->partp->head.hd9,
0,
AKAI_HD9HEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}else{
/* S1000/S3000 */
vp->partp->head.hd.vol[vp->index].type=AKAI_VOL_TYPE_INACT;
/* XXX keep name etc. */
/* write new FAT and root directory to partition */
/* write partition header */
if (akai_io_blks(vp->partp,(u_char *)&vp->partp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
}
/* count free and bad blocks */
akai_countfree_part(vp->partp);
/* Note: no need to exit or restart now */
return 0;
}
void
akai_list_volparam(struct akai_volparam_s *parp,int listflag)
{
u_int i;
if (parp==NULL){
return;
}
if (listflag){
PRINTF_OUT("volume parameters:\nidx val\n---------\n");
for (i=0;i<sizeof(struct akai_volparam_s);i++){
/* XXX */
PRINTF_OUT("%3u 0x%02x",i,(u_int)((u_char *)parp)[i]);
switch (i){
case 0:
PRINTF_OUT(" (program select MIDI channel-1)\n");
break;
case 1:
PRINTF_OUT(" (MIDI OMNI for program select)\n");
break;
case 2:
PRINTF_OUT(" (program select enable)\n");
break;
case 3:
PRINTF_OUT(" (selected program number-1)\n");
break;
case 4:
PRINTF_OUT(" (MIDI OMNI override for play input)\n");
break;
case 5:
PRINTF_OUT(" (MIDI system exclusive channel-1)\n");
break;
default:
PRINTF_OUT("\n");
break;
}
}
PRINTF_OUT("---------\n\n");
}
PRINTF_OUT("volume parameters:\n");
PRINTF_OUT("program select MIDI channel: %u\n",((u_int)parp->progselmidich1)+1);
PRINTF_OUT("MIDI OMNI for program select: %s\n",parp->progselomni?"ON":"OFF");
PRINTF_OUT("program select enable: %s\n",parp->progselenab?"ON":"OFF");
PRINTF_OUT("selected program number: %u\n",((u_int)parp->prognr1)+1);
PRINTF_OUT("MIDI OMNI override for play input: %s\n",parp->playinominovrr?"ON":"OFF");
PRINTF_OUT("MIDI system exclusive channel: %u\n",((u_int)parp->sysexch1)+1);
}
void
akai_init_volparam(struct akai_volparam_s *parp,int s3000flag)
{
if (parp==NULL){
return;
}
/* default volume parameters */
bzero(parp,sizeof(struct akai_volparam_s));
if (s3000flag){
/* S3000 */
parp->progselomni=0x01; /* XXX */
parp->progselenab=0x01; /* XXX */
parp->dummy1[0]=0x32; /* XXX */
parp->dummy1[1]=0x09; /* XXX */
parp->dummy1[2]=0x0c; /* XXX */
parp->dummy1[3]=0xff; /* XXX */
}else{
/* S1000 */
parp->progselomni=0x01; /* XXX */
parp->progselenab=0x01; /* XXX */
}
}
void
akai_print_lnum(u_int lnum)
{
if (lnum==AKAI_VOL_LNUM_OFF){
PRINTF_OUT("- ");
}else{
PRINTF_OUT("%03u",lnum);
}
}
u_int
akai_get_lnum(char *name)
{
u_int lnum;
if (name==NULL){
return AKAI_VOL_LNUM_OFF;
}
if (strcasecmp(name,"OFF")==0){
return AKAI_VOL_LNUM_OFF;
}
lnum=(u_int)atoi(name);
if ((lnum<AKAI_VOL_LNUM_MIN)||(lnum>AKAI_VOL_LNUM_MAX)){
PRINTF_ERR("invalid load number, setting OFF\n");
return AKAI_VOL_LNUM_OFF;
}
return lnum;
}
void
akai_list_tags(struct part_s *pp)
{
u_int i;
char namebuf[AKAI_NAME_LEN+1]; /* +1 for '\0' */
if ((pp==NULL)||(!pp->valid)){
return;
}
if (pp->type!=PART_TYPE_HD){
PRINTF_OUT("no tags in this partition type\n");
return;
}
/* now, S1000/S3000 harddisk sampler partition */
/* check magic */
if (strncmp(AKAI_PARTHEAD_TAGSMAGIC,(char *)pp->head.hd.tagsmagic,4)!=0){
PRINTF_OUT("no tags present\n");
return;
}
PRINTF_OUT("tag name\n");
PRINTF_OUT("-----------------\n");
for (i=0;i<AKAI_PARTHEAD_TAGNUM;i++){
/* Note: tag names use S1000/S3000 char conversion */
akai2ascii_name(pp->head.hd.tag[i],namebuf,0); /* 0: not S900 */
PRINTF_OUT(" %02u %s\n",i+1,namebuf); /* XXX default tag name */
}
PRINTF_OUT("-----------------\n");
}
int
akai_rename_tag(struct part_s *pp,char *name,u_int ti,int wipeflag)
{
u_int i;
char namebuf[AKAI_NAME_LEN+1]; /* +1 for '\0' */
if ((pp==NULL)||(!pp->valid)){
return -1;
}
if (pp->type!=PART_TYPE_HD){
PRINTF_OUT("no tags in this partition type\n");
return -1;
}
/* now, S1000/S3000 harddisk sampler partition */
if (name!=NULL){
if ((strlen(name)>AKAI_NAME_LEN)||(ti>=AKAI_PARTHEAD_TAGNUM)){
return -1;
}
}
if (wipeflag){
bcopy(AKAI_PARTHEAD_TAGSMAGIC,pp->head.hd.tagsmagic,4); /* magic */
for (i=0;i<AKAI_PARTHEAD_TAGNUM;i++){
sprintf(namebuf,"TAG %c ",(char)('A'+i)); /* XXX default tag name */
/* Note: tag names use S1000/S3000 char conversion */
ascii2akai_name(namebuf,pp->head.hd.tag[i],0); /* 0: not S900 */
}
}
if (name!=NULL){
/* check magic */
if (strncmp(AKAI_PARTHEAD_TAGSMAGIC,(char *)pp->head.hd.tagsmagic,4)!=0){
PRINTF_OUT("no tags present\n");
return -1;
}
/* set tag */
/* Note: tag names use S1000/S3000 char conversion */
ascii2akai_name(name,pp->head.hd.tag[ti],0); /* 0: not S900 */
}
/* write new tag(s) to partition */
/* write partition header */
return akai_io_blks(pp,(u_char *)&pp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE); /* 1: allocate cache if possible */
}
int
copy_tags(struct part_s *srcpp,struct part_s *dstpp)
{
if ((srcpp==NULL)||(!srcpp->valid)){
return -1;
}
if ((dstpp==NULL)||(!dstpp->valid)){
return -1;
}
if ((srcpp->type!=PART_TYPE_HD)||(dstpp->type!=PART_TYPE_HD)){
PRINTF_OUT("no tags in this partition type\n");
return -1;
}
/* now, S1000/S3000 harddisk sampler partition */
/* copy tags */
bcopy(srcpp->head.hd.tagsmagic,dstpp->head.hd.tagsmagic,4); /* magic */
bcopy(srcpp->head.hd.tag[0],dstpp->head.hd.tag[0],
AKAI_PARTHEAD_TAGNUM*AKAI_NAME_LEN); /* tag names */
/* write new tag(s) to partition */
/* write partition header */
return akai_io_blks(dstpp,(u_char *)&dstpp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE);/* 1: allocate cache if possible */
}
void
akai_print_cdinfo(struct part_s *pp,int verbose)
{
u_int c;
u_int i;
u_int fnum;
u_int bn;
char namebuf[AKAI_NAME_LEN+1]; /* +1 for '\0' */
char fnamebuf[AKAI_NAME_LEN+4+1]; /* name (ASCII), +4 for ".<type>", +1 for '\0' */
u_char buf[AKAI_HD_BLOCKSIZE];
struct akai_cdinfohead_s *hp;
struct akai_voldir_entry_s *dep;
u_char *buf2;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return;
}
if (pp->type!=PART_TYPE_HD){
PRINTF_OUT("no CD-ROM info in this partition type\n");
return;
}
/* now, S1000/S3000 harddisk sampler partition */
/* check if S3000 with CD-ROM info: */
/* check if tags magic */
if (strncmp(AKAI_PARTHEAD_TAGSMAGIC,(char *)pp->head.hd.tagsmagic,4)!=0){
PRINTF_OUT("no CD-ROM info in this partition\n");
return;
}
/* check if at least minimum number of blocks for CD-ROM info have FAT code SYS */
/* Note: S1000 volume also uses SYS for volume directory */
for (i=AKAI_CDINFO_BLK;i<AKAI_CDINFO_BLK+AKAI_CDINFO_MINSIZB;i++){
c=(pp->fat[i][1]<<8)+pp->fat[i][0];
if (c!=AKAI_FAT_CODE_SYS){
PRINTF_OUT("no CD-ROM info in this partition\n");
return;
}
}
/* read CD-ROM info header */
if (akai_io_blks(pp,buf,
AKAI_CDINFO_BLK,
1,
0,IO_BLKS_READ)<0){ /* 0: don't allocate new cache */
PRINTF_ERR("cannot read CD-ROM info\n");
return;
}
/* CD-ROM info header */
hp=(struct akai_cdinfohead_s *)buf;
/* CD-ROM label */
/* Note: CD-ROM label uses S1000/S3000 char conversion */
akai2ascii_name(hp->cdlabel,namebuf,0); /* 0: not S900 */
PRINTF_OUT("CD-ROM label: \"%s\"\n",namebuf);
/* number of files */
fnum=(hp->fnum[1]<<8)+hp->fnum[0];
PRINTF_OUT("\nnumber of files in partition %c: %u\n",pp->letter,fnum);
/* required number of blocks */
bn=sizeof(struct akai_cdinfohead_s)+fnum*sizeof(struct akai_voldir_entry_s);
bn=(bn+AKAI_HD_BLOCKSIZE-1)/AKAI_HD_BLOCKSIZE; /* round up */
if (AKAI_CDINFO_BLK+bn>pp->bsize){
PRINTF_ERR("invalid number of files for partition size\n");
return;
}
/* check if all required blocks for CD-ROM info have FAT code SYS */
/* Note: S1000 volume also uses SYS for volume directory */
for (i=1;i<bn;i++){
c=(pp->fat[AKAI_CDINFO_BLK+i][1]<<8)
+pp->fat[AKAI_CDINFO_BLK+i][0];
if (c!=AKAI_FAT_CODE_SYS){
/* truncate number of blocks */
bn=i;
/* truncate number of files */
fnum=((bn*AKAI_HD_BLOCKSIZE)-sizeof(struct akai_cdinfohead_s))/sizeof(struct akai_voldir_entry_s);
PRINTF_OUT("CD-ROM info is incomplete, truncated to %u files\n",fnum);
break;
}
}
if (verbose){
/* print volume sizes */
PRINTF_OUT("\nvolume files\n------------\n");
for (i=0;i<pp->volnummax;i++){
c=(hp->volesiz[i][1]<<8)+hp->volesiz[i][0]; /* size of volume directory entries for files in bytes */
if (c!=0){ /* used? */
c/=sizeof(struct akai_voldir_entry_s); /* number of file entries */
PRINTF_OUT("%03u %3u\n",i+1,c);
}
}
PRINTF_OUT("------------\n");
if ((buf2=(u_char *)malloc(bn*AKAI_HD_BLOCKSIZE))==NULL){
PERROR("malloc");
return;
}
/* read directory of files from CD-ROM info */
if (akai_io_blks(pp,buf2,
AKAI_CDINFO_BLK,
bn,
0,IO_BLKS_READ)<0){ /* 0: don't allocate new cache */
PRINTF_ERR("cannot read CD-ROM directory of files\n");
free(buf2);
return;
}
/* print directory of files */
PRINTF_OUT("\ndirectory of files:\n---------------------------------------------------------------------\n");
for (i=0;i<fnum;i++){
dep=(struct akai_voldir_entry_s *)(buf2+sizeof(struct akai_cdinfohead_s));
/* name */
/* Note: file names in CD-ROM info use S1000/S3000 char conversion */
akai2ascii_filename(dep[i].name,dep[i].type,AKAI_OSVER_S3000MAX,fnamebuf,0); /* 0: not S900 */
PRINTF_OUT("%-16s ",fnamebuf);
if (i%4==3){
PRINTF_OUT("\n");
}
}
if (i%4!=0){
PRINTF_OUT("\n");
}
PRINTF_OUT("---------------------------------------------------------------------\n");
free(buf2);
}
}
int
akai_set_cdinfo(struct part_s *pp,char *cdlabel)
{
u_int c;
u_int i,j;
u_int fnum,fnummax;
u_int vsiz;
static u_char buf[AKAI_CDINFO_MINSIZB*AKAI_HD_BLOCKSIZE]; /* XXX minimum size */
u_char *bp;
struct akai_cdinfohead_s *hp;
struct vol_s vol;
struct file_s file;
u_char oldcdlabel[AKAI_NAME_LEN];
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type!=PART_TYPE_HD){
PRINTF_OUT("no CD-ROM info in this partition type\n");
return -1;
}
/* now, S1000/S3000 harddisk sampler partition */
/* check if S3000 with CD-ROM info: */
/* check if tags magic */
if (strncmp(AKAI_PARTHEAD_TAGSMAGIC,(char *)pp->head.hd.tagsmagic,4)!=0){
PRINTF_OUT("no CD-ROM info in this partition\n");
return -1;
}
/* check if at least minimum number of blocks for CD-ROM info have FAT code SYS */
/* Note: S1000 volume also uses SYS for volume directory */
for (i=AKAI_CDINFO_BLK;i<AKAI_CDINFO_BLK+AKAI_CDINFO_MINSIZB;i++){
c=(pp->fat[i][1]<<8)+pp->fat[i][0];
if (c!=AKAI_FAT_CODE_SYS){
PRINTF_OUT("no CD-ROM info in this partition\n");
return -1;
}
}
/* CD-ROM info header */
hp=(struct akai_cdinfohead_s *)buf;
if (cdlabel==NULL){
/* read old CD-ROM info */
if (akai_io_blks(pp,buf,
AKAI_CDINFO_BLK,
1, /* XXX 1 block is enough for header */
0,IO_BLKS_READ)<0){ /* 0: don't allocate new cache */
PRINTF_ERR("cannot read CD-ROM info\n");
return -1;
}
/* save old label */
bcopy(hp->cdlabel,oldcdlabel,AKAI_NAME_LEN);
}
/* wipe CD-ROM info */
bzero(buf,AKAI_CDINFO_MINSIZB*AKAI_HD_BLOCKSIZE);
/* max. number of files in CD-ROM info */
/* XXX minimum size */
fnummax=((AKAI_CDINFO_MINSIZB*AKAI_HD_BLOCKSIZE)-sizeof(struct akai_cdinfohead_s))/sizeof(struct akai_voldir_entry_s);
/* read all volumes in partition */
fnum=0;
bp=buf+sizeof(struct akai_cdinfohead_s); /* behind header */
for (i=0;i<pp->volnummax;i++){
vsiz=0;
if (akai_get_vol(pp,&vol,i)<0){
continue; /* ignore error, next */
}
/* check all files in volume */
for (j=0;j<vol.fimax;j++){
if (akai_get_file(&vol,&file,j)<0){
continue; /* ignore error, next */
}
/* copy volume entry */
bcopy(&vol.file[j],bp,sizeof(struct akai_voldir_entry_s));
bp+=sizeof(struct akai_voldir_entry_s);
vsiz+=sizeof(struct akai_voldir_entry_s);
fnum++;
if (fnum>=fnummax){
break; /* exit, ignore rest */
}
}
/* size of volume directory entries for files in bytes */
hp->volesiz[i][1]=0xff&(vsiz>>8);
hp->volesiz[i][0]=0xff&vsiz;
if (fnum>=fnummax){
break; /* exit, ignore rest */
}
}
/* total number of files */
hp->fnum[1]=0xff&(fnum>>8);
hp->fnum[0]=0xff&fnum;
/* CD-ROM label */
if (cdlabel!=NULL){
/* Note: CD-ROM label uses S1000/S3000 char conversion */
ascii2akai_name(cdlabel,hp->cdlabel,0); /* 0: not S900 */
}else{
/* restore old label */
bcopy(oldcdlabel,hp->cdlabel,AKAI_NAME_LEN);
}
/* write CD-ROM info */
if (akai_io_blks(pp,buf,
AKAI_CDINFO_BLK,
AKAI_CDINFO_MINSIZB,
0,IO_BLKS_WRITE)<0){ /* 0: don't allocate new cache */
PRINTF_ERR("cannot write CD-ROM info\n");
return -1;
}
return 0;
}
void
akai_part_info(struct part_s *pp,int verbose)
{
if (pp==NULL){
return;
}
if (verbose){
PRINTF_OUT("part: ");
if (pp->type==PART_TYPE_DD){
/* harddisk DD partition */
if (pp->letter==0){
PRINTF_OUT("DD\n");
}else{
PRINTF_OUT("DD%u\n",(u_int)pp->letter);
}
}else{
/* floppy or harddisk sampler partition */
PRINTF_OUT("%c\n",pp->letter);
}
if (!pp->valid){
PRINTF_OUT("*** marked invalid ***\n");
}
PRINTF_OUT("parttype: ");
switch (pp->type){
case PART_TYPE_FLL:
PRINTF_OUT("low-density floppy");
break;
case PART_TYPE_FLH:
PRINTF_OUT("high-density floppy");
break;
case PART_TYPE_HD9:
PRINTF_OUT("S900 harddisk");
break;
case PART_TYPE_HD:
PRINTF_OUT("S1000/S3000 harddisk sampler partition");
break;
case PART_TYPE_DD:
PRINTF_OUT("S1100/S3000 harddisk DD parttion");
break;
default:
PRINTF_OUT("\?\?\?");
break;
}
PRINTF_OUT("\nblksize: 0x%04x bytes\n",pp->blksize);
PRINTF_OUT("start: block 0x%04x\n",
pp->bstart);
PRINTF_OUT("size: 0x%04x blocks (%6u KB)\n",
pp->bsize,
(pp->bsize*pp->blksize)/1024); /* in KB */
PRINTF_OUT("free: 0x%04x blocks (%6u KB) = %5.1lf%%\n",
pp->bfree,
(pp->bfree*pp->blksize)/1024, /* in KB */
(pp->bsize>0)?(100.0*((double)pp->bfree)/((double)pp->bsize)):0.0);
PRINTF_OUT("bad: 0x%04x blocks (%6u KB) = %5.1lf%%\n",
pp->bbad,
(pp->bbad*pp->blksize)/1024, /* in KB */
(pp->bsize>0)?(100.0*((double)pp->bbad)/((double)pp->bsize)):0.0);
if (pp->type!=PART_TYPE_DD){
PRINTF_OUT("max. vols: %u\n",pp->volnummax);
}
}else{
if (pp->type==PART_TYPE_DD){
/* harddisk DD partition */
if (pp->letter==0){
PRINTF_OUT(" DD");
}else if (pp->letter<=9){
PRINTF_OUT(" DD%u",(u_int)pp->letter);
}else{
PRINTF_OUT("DD%u",(u_int)pp->letter);
}
}else{
/* floppy or harddisk sampler partition */
PRINTF_OUT(" %c",pp->letter);
}
PRINTF_OUT("%c ",pp->valid?' ':'*');
switch (pp->type){
case PART_TYPE_FLL:
PRINTF_OUT("FLL");
break;
case PART_TYPE_FLH:
PRINTF_OUT("FLH");
break;
case PART_TYPE_HD9:
PRINTF_OUT("HD9");
break;
case PART_TYPE_HD:
PRINTF_OUT(" HD");
break;
case PART_TYPE_DD:
PRINTF_OUT(" DD");
break;
default:
PRINTF_OUT("\?\?\?");
break;
}
PRINTF_OUT(" 0x%04x 0x%04x %5.1lf 0x%04x %5.1lf %5.1lf\n",
pp->bstart,
pp->bsize,
((double)pp->bsize*pp->blksize)/((double)1024*1024),
pp->bfree,
((double)pp->bfree*pp->blksize)/((double)1024*1024),
(pp->bsize>0)?(100.0*((double)pp->bfree)/((double)pp->bsize)):0.0);
}
}
void
akai_list_part(struct part_s *pp,int recflag,u_char *filtertagp)
{
u_int vi;
u_int ai;
struct vol_s tmpvol;
if ((pp==NULL)||(!pp->valid)||(pp->diskp==NULL)){
return;
}
if (pp->type==PART_TYPE_DD){
/* harddisk DD partition */
u_int tott;
u_int i;
PRINTF_OUT("/disk%u/DD",pp->diskp->index);
if (pp->letter!=0){
PRINTF_OUT("%u",(u_int)pp->letter);
}
PRINTF_OUT("\ntnr tname cstarts cstarte csizes csizee scount srate stype\n");
PRINTF_OUT("---------------------------------------------------------------------------\n");
/* DD takes in partition */
tott=0;
for (i=0;i<AKAI_DDTAKE_MAXNUM;i++){
if (pp->head.dd.take[i].stat==AKAI_DDTAKESTAT_FREE){ /* free? */
continue; /* next */
}
tott++;
/* print DD take info */
akai_ddtake_info(pp,i,0);
}
PRINTF_OUT("---------------------------------------------------------------------------\n");
PRINTF_OUT("total: %3u take(s)\n\n",tott);
return;
}
/* now, floppy or harddisk sampler partition */
PRINTF_OUT("/disk%u/%c\n",pp->diskp->index,pp->letter);
PRINTF_OUT("vnr vname %s startblk osver type\n",
(pp->type==PART_TYPE_HD9)?"alias":"lnum");
PRINTF_OUT("---------------------------------------------------\n");
/* volumes in partition */
ai=0;
for (vi=0;vi<pp->volnummax;vi++){
/* get volume */
if (akai_get_vol(pp,&tmpvol,vi)<0){
continue; /* next volume */
}
ai++;
/* print volume info */
akai_vol_info(&tmpvol,ai,0);
}
PRINTF_OUT("---------------------------------------------------\n");
PRINTF_OUT("total: %3u volume(s) (max. %3u)\n\n",ai,pp->volnummax);
if (recflag){
/* volumes in partition */
ai=0;
for (vi=0;vi<pp->volnummax;vi++){
/* get volume */
if (akai_get_vol(pp,&tmpvol,vi)<0){
continue; /* next volume */
}
if (tmpvol.type!=AKAI_VOL_TYPE_INACT){
/* list volume directory */
akai_list_vol(&tmpvol,filtertagp);
}
}
}
}
/* find partition with given name (letter) */
struct part_s *
akai_find_part(struct disk_s *dp,char *name)
{
u_int p;
char namebuf[16]; /* XXX */
if ((dp==NULL)||(name==NULL)){
return NULL;
}
for (p=0;p<part_num;p++){
/* Note: allow even invalid partition to be found!!! */
if (part[p].diskp!=dp){ /* not on this disk? */
continue; /* next */
}
/* name */
if (part[p].type==PART_TYPE_DD){
if (part[p].letter==0){
sprintf(namebuf,"DD");
}else{
sprintf(namebuf,"DD%u",(u_int)part[p].letter);
}
}else{
sprintf(namebuf,"%c",part[p].letter);
}
/* compare name (case-insensitive) */
if (strcasecmp(namebuf,name)==0){ /* match? */
return &part[p]; /* found */
}
}
return NULL; /* not found */
}
void
print_fat(struct part_s *pp)
{
u_int i,ilim;
u_int j;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return;
}
PRINTF_OUT("%s +0 +1 +2 +3 +4 +5 +6 +7\n----------------------------------------------\n",
(pp->type==PART_TYPE_DD)?"clu":"blk");
ilim=(pp->type==PART_TYPE_DD)?pp->csize:pp->bsize;
for (i=0;i<ilim;i++){
if ((i%8)==0){
PRINTF_OUT("%04x: ",i);
}
j=(pp->fat[i][1]<<8)+pp->fat[i][0];
if (pp->type==PART_TYPE_DD){ /* harddisk DD partition? */
switch (j){
case AKAI_DDFAT_CODE_FREE:
PRINTF_OUT(" - ");
break;
case AKAI_DDFAT_CODE_BAD:
PRINTF_OUT(" BAD ");
break;
case AKAI_DDFAT_CODE_SYS:
PRINTF_OUT(" SYS ");
break;
case AKAI_DDFAT_CODE_END:
PRINTF_OUT(" END ");
break;
default:
PRINTF_OUT(" %04x",j);
break;
}
}else{
if (i<pp->bsyssize){ /* reserved block for system? */
PRINTF_OUT(" SYS ");
}else{
switch (j){
case AKAI_FAT_CODE_FREE: /* XXX same as AKAI_FAT_CODE_SYS900FL */
PRINTF_OUT(" - ");
break;
case AKAI_FAT_CODE_BAD:
PRINTF_OUT(" BAD ");
break;
case AKAI_FAT_CODE_SYS900HD:
case AKAI_FAT_CODE_SYS: /* XXX same as AKAI_FAT_CODE_DIREND1000HD */
PRINTF_OUT(" SYS ");
break;
case AKAI_FAT_CODE_FILEEND900: /* XXX same as AKAI_FAT_CODE_DIREND900HD, AKAI_FAT_CODE_DIREND3000 */
case AKAI_FAT_CODE_FILEEND:
PRINTF_OUT(" END ");
break;
default:
PRINTF_OUT(" %04x",j);
break;
}
}
}
if (((i%8)==7)||(i+1==ilim)){
PRINTF_OUT("\n");
}
}
PRINTF_OUT("----------------------------------------------\n");
}
void
akai_disk_info(struct disk_s *dp,int verbose)
{
u_int totp;
u_int totf;
u_int totb;
u_int pi;
if (dp==NULL){
return;
}
/* scan all partitions in system */
totp=0;
totf=0;
totb=0;
for (pi=0;pi<part_num;pi++){
if (part[pi].diskp!=dp){ /* not this disk? */
continue;
}
totp++;
if (part[pi].valid){ /* valid? */
totf+=part[pi].bfree;
totb+=part[pi].bbad;
}
}
if (verbose){
PRINTF_OUT("disk: %u\n",dp->index);
PRINTF_OUT("fd: %i\n",dp->fd);
#ifdef _VISUALCPP
PRINTF_OUT("fldrn: %i\n",dp->fldrn);
#endif /* _VISUALCPP */
PRINTF_OUT("start: byte 0x%02x%08x\n",
(u_int)(dp->startoff>>32),
(u_int)(0xffffffff&dp->startoff));
PRINTF_OUT("parts: %u\n",totp);
PRINTF_OUT("disktype: ");
switch (dp->type){
case DISK_TYPE_FLL:
PRINTF_OUT("low-density floppy");
break;
case DISK_TYPE_FLH:
PRINTF_OUT("high-density floppy");
break;
case DISK_TYPE_HD9:
PRINTF_OUT("S900 harddisk");
break;
case DISK_TYPE_HD:
PRINTF_OUT("S1000/S3000 harddisk");
break;
default:
PRINTF_OUT("\?\?\?");
break;
}
PRINTF_OUT("\nblksize: 0x%04x bytes\n",dp->blksize);
PRINTF_OUT("total: 0x%04x blocks (%6u KB)\n",
dp->bsize,
dp->totsize/1024); /* in KB */
PRINTF_OUT("free: 0x%04x blocks (%6u KB) = %5.1lf%%\n",
totf,
(totf*dp->blksize)/1024, /* in KB */
(dp->bsize>0)?(100.0*((double)totf)/((double)dp->bsize)):0.0);
PRINTF_OUT("bad: 0x%04x blocks (%6u KB) = %5.1lf%%\n",
totb,
(totb*dp->blksize)/1024, /* in KB */
(dp->bsize>0)?(100.0*((double)totb)/((double)dp->bsize)):0.0);
}else{
PRINTF_OUT(" %3u ",dp->index);
switch (dp->type){
case DISK_TYPE_FLL:
PRINTF_OUT("FLL");
break;
case DISK_TYPE_FLH:
PRINTF_OUT("FLH");
break;
case DISK_TYPE_HD9:
PRINTF_OUT("HD9");
break;
case DISK_TYPE_HD:
PRINTF_OUT(" HD");
break;
default:
PRINTF_OUT("\?\?\?");
break;
}
PRINTF_OUT(" %3u 0x%04x 0x%04x %5.1lf 0x%04x %5.1lf %5.1lf\n",
totp,
dp->blksize,
dp->bsize,
((double)dp->bsize*dp->blksize)/((double)1024*1024),
totf,
((double)totf*dp->blksize)/((double)1024*1024),
(dp->bsize>0)?(100.0*((double)totf)/((double)dp->bsize)):0.0);
}
}
void
akai_list_disk(struct disk_s *dp,int recflag,u_char *filtertagp)
{
u_int p;
u_int totp;
if (dp==NULL){
return;
}
PRINTF_OUT("/disk%u\n",dp->index);
PRINTF_OUT("part type startblk size/blks size/MB free/blks free/MB free/%%\n");
PRINTF_OUT("----------------------------------------------------------------\n");
/* partitions on disk */
totp=0;
for (p=0;p<part_num;p++){
if (part[p].diskp==dp){ /* on this disk? */
/* print partition info */
akai_part_info(&part[p],0);
totp++;
}
}
PRINTF_OUT("----------------------------------------------------------------\n");
PRINTF_OUT("total: %3u partition(s)\n\n",totp);
if (recflag){
/* partitions on disk */
for (p=0;p<part_num;p++){
if ((part[p].diskp==dp) /* on this disk? */
&&(part[p].valid)){
/* list root directory in partition */
akai_list_part(&part[p],recflag,filtertagp);
}
}
}
}
void
akai_list_alldisks(int recflag,u_char *filtertagp)
{
u_int di;
PRINTF_OUT("/\n");
PRINTF_OUT("disk type parts blksize tot/blks tot/MB free/blks free/MB free/%%\n");
PRINTF_OUT("--------------------------------------------------------------------\n");
/* disks */
for (di=0;di<disk_num;di++){
/* print disk info */
akai_disk_info(&disk[di],0);
}
PRINTF_OUT("--------------------------------------------------------------------\n");
PRINTF_OUT("total: %3u disk(s)\n\n",disk_num);
if (recflag){
/* disks */
for (di=0;di<disk_num;di++){
/* list disk */
akai_list_disk(&disk[di],recflag,filtertagp);
}
}
}
void
akai_sort_filetags(u_char *tagp)
{
u_int i,j;
u_char b;
if (tagp==NULL){
return;
}
for (i=0;i<(AKAI_FILE_TAGNUM-1);i++){
for (j=i+1;j<AKAI_FILE_TAGNUM;j++){
if (tagp[i]>tagp[j]){
/* swap */
b=tagp[i];
tagp[i]=tagp[j];
tagp[j]=b;
}
}
}
}
int
akai_match_filetags(u_char *filtertagp,u_char *testtagp)
{
u_int i,j;
if (filtertagp==NULL){
return 0; /* no filter, matches always */
}
if (testtagp==NULL){
return -1; /* no match */
}
if (testtagp[0]==AKAI_FILE_TAGS1000){ /* XXX check if testtagp[] stems from S1000 */
/* now, match only if all entries in filtertagp[] are free */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
if ((filtertagp[i]!=AKAI_FILE_TAGFREE)&&(filtertagp[i]!=AKAI_FILE_TAGS1000)){ /* not free? */
return -1; /* no match */
}
}
return 0; /* match */
}
for (i=0;i<AKAI_FILE_TAGNUM;i++){
if ((filtertagp[i]==AKAI_FILE_TAGFREE)||(filtertagp[i]==AKAI_FILE_TAGS1000)){ /* free? */
continue; /* next */
}
for (j=0;j<AKAI_FILE_TAGNUM;j++){
if ((testtagp[i]==AKAI_FILE_TAGFREE)||(testtagp[i]==AKAI_FILE_TAGS1000)){ /* free? */
continue; /* next */
}
if (testtagp[j]==filtertagp[i]){ /* found? */
break; /* found entry i */
}
}
if (j==AKAI_FILE_TAGNUM){ /* not found? */
return -1; /* no match */
}
}
/* now, all non-free entries of filtertagp[] are found in testtagp[] => match */
return 0; /* match */
}
int
akai_set_filetag(u_char *tagp,u_int ti)
{
u_int i;
if (tagp==NULL){
return -1;
}
if ((ti<1)||(ti>AKAI_PARTHEAD_TAGNUM)){
PRINTF_ERR("invalid tag index\n");
return -1;
}
/* check if already present */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
if (tagp[i]==ti){
return 0; /* nothing to do */
}
}
/* find free entry */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
if ((tagp[i]==AKAI_FILE_TAGFREE)||(tagp[i]==AKAI_FILE_TAGS1000)){ /* free? */
break; /* found */
}
}
if (i==AKAI_FILE_TAGNUM){ /* none found? */
PRINTF_OUT("no free tag entry\n");
return -1;
}
/* set tag */
tagp[i]=ti;
akai_sort_filetags(tagp);
return 0;
}
int
akai_clear_filetag(u_char *tagp,u_int ti)
{
u_int i;
if (tagp==NULL){
return -1;
}
/* XXX allow to clear invalid tag index */
if (ti==AKAI_FILE_TAGFREE){
/* clear all */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
tagp[i]=AKAI_FILE_TAGFREE;
}
}else if (ti==AKAI_FILE_TAGS1000){
/* clear all */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
tagp[i]=AKAI_FILE_TAGS1000;
}
}else{
/* find entry */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
if (tagp[i]==ti){
/* clear */
tagp[i]=AKAI_FILE_TAGFREE;
/* Note: must not break, must find (although invalid) repitions as well */
}
}
}
akai_sort_filetags(tagp);
return 0;
}
/* get file with index fi */
/* saves result in *fp */
int
akai_get_file(struct vol_s *vp,struct file_s *fp,u_int fi)
{
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)||(vp->file==NULL)){
return -1;
}
if ((vp->partp==NULL)||(!vp->partp->valid)){
return -1;
}
if (fp==NULL){
return -1;
}
if (fi>=vp->fimax){
return -1;
}
/* in volume */
fp->volp=vp;
/* index */
fp->index=fi;
/* type */
fp->type=vp->file[fi].type;
if (fp->type==AKAI_FTYPE_FREE){ /* free entry? */
return -1;
}
/* tags */
bcopy(vp->file[fi].tag,fp->tag,AKAI_FILE_TAGNUM);
/* osver: */
/* if S1000/S3000: OS version */
/* if S900 compressed file: number of un-compressed floppy blocks */
/* else: zero */
fp->osver=(vp->file[fi].osver[1]<<8)
+vp->file[fi].osver[0];
/* name */
akai2ascii_filename(vp->file[fi].name,(u_char)fp->type,fp->osver,fp->name,vp->type==AKAI_VOL_TYPE_S900);
/* size */
fp->size=(vp->file[fi].size[2]<<16)
+(vp->file[fi].size[1]<<8)
+vp->file[fi].size[0];
/* start */
fp->bstart=(vp->file[fi].start[1]<<8)
+vp->file[fi].start[0];
return 0;
}
/* find file with given name */
/* saves result in *fp */
int
akai_find_file(struct vol_s *vp,struct file_s *fp,char *name)
{
u_int fi;
char namebuf[AKAI_NAME_LEN+4+1]; /* +4 for ".<type>", +1 for '\0' */
u_int i,j,k,l;
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)){
return -1;
}
if ((vp->partp==NULL)||(!vp->partp->valid)){
return -1;
}
if (fp==NULL){
return -1;
}
if (name==NULL){
return -1;
}
/* fix name */
l=(u_int)strlen(name);
if (l>AKAI_NAME_LEN+4){ /* too long for namebuf? */
return -1;
}
j=l; /* end */
for (i=0;i<l;i++){
if (name[i]=='_'){ /* for keyboard entry */
namebuf[i]=' ';
}else{
namebuf[i]=name[i];
if (name[i]=='.'){
j=i; /* last '.' so far */
}
}
}
namebuf[i]='\0';
/* remove trailing ' ' (XXX don't care how many) before last '.' (or end if no '.') */
k=j;
for (i=0;i<j;i++){
if (namebuf[j-i-1]==' '){
namebuf[j-i-1]='\0';
k--;
}else{
break;
}
}
if ((k<j)&&(j<l)){
/* move ".<type>" */
for (i=0;(k+i<l)&&(j+i<l);i++){
namebuf[k+i]=namebuf[j+i];
}
namebuf[k+i]='\0';
}
/* files in volume directory */
for (fi=0;fi<vp->fimax;fi++){
/* get file */
if (akai_get_file(vp,fp,fi)<0){
continue; /* next file */
}
/* compare name (case-insensitive) */
if (strcasecmp(fp->name,namebuf)==0){ /* match? */
return 0; /* found */
}
}
return -1; /* not found */
}
int
akai_rename_file(struct file_s *fp,char *name,struct vol_s *vp,u_int dstindex,u_char *tagp,u_int osver)
{
u_int i;
u_int diffvolflag;
u_int fisrc,fidst;
struct vol_s *volsrcp,*voldstp;
u_char ft;
u_char anamebuf[AKAI_NAME_LEN];
if ((fp==NULL)||(fp->type==AKAI_FTYPE_FREE)){
return -1;
}
if ((fp->volp==NULL)||(fp->volp->type==AKAI_VOL_TYPE_INACT)||(fp->volp->file==NULL)){
return -1;
}
if ((fp->volp->partp==NULL)||(!fp->volp->partp->valid)){
return -1;
}
if ((vp!=NULL)&&((vp->type==AKAI_VOL_TYPE_INACT)||(vp->file==NULL))){
return -1;
}
if ((vp!=NULL)&&(vp->partp!=fp->volp->partp)){ /* if vp specified: not on same partition? */
PRINTF_OUT("must be in same partition\n");
return -1;
}
/* Note: must not compare pointers (vp and fp->volp) if the buffer behind volume pointer is not unique for each volume!!! */
/* use dirblk[0] instead, which is unique if same partition (see check above) */
if ((vp!=NULL)&&(vp->dirblk[0]!=fp->volp->dirblk[0])){ /* different volume specified? */
diffvolflag=1;
}else{
diffvolflag=0;
}
if ((name==NULL)&&((osver!=fp->osver)||diffvolflag)){ /* no new name but different OS version or different volume? */
/* possibly different char conversion or possibly need to correct osver -> handle as new name below */
name=fp->name;
}
if ((diffvolflag==0)&&(name==NULL)&&(tagp==NULL)){ /* nothing to do? */
return 0; /* done */
}
/* source file */
fisrc=fp->index;
volsrcp=fp->volp;
if (diffvolflag){ /* different volume specified? */
voldstp=vp;
if (dstindex==AKAI_CREATE_FILE_NOINDEX){ /* no user-supplied index? */
/* find free destination volume directory entry */
for (fidst=0;fidst<voldstp->fimax;fidst++){
if (voldstp->file[fidst].type==AKAI_FTYPE_FREE){ /* free? */
break; /* found one */
}
}
if (fidst==voldstp->fimax){ /* none found? */
PRINTF_OUT("no free file entry found\n");
return -1;
}
}else{
if (voldstp->file[dstindex].type!=AKAI_FTYPE_FREE){ /* not free? */
PRINTF_OUT("destination index not free\n");
return -1;
}
fidst=dstindex;
}
}else{
/* same volume */
voldstp=volsrcp;
if ((dstindex==AKAI_CREATE_FILE_NOINDEX) /* no user-supplied index? */
||(dstindex==fisrc)){ /* or same as before? */
fidst=fisrc; /* keep index */
}else{
if (voldstp->file[dstindex].type!=AKAI_FTYPE_FREE){ /* not free? */
PRINTF_OUT("destination index not free\n");
return -1;
}
fidst=dstindex; /* new index */
}
}
/* name and type */
ft=0;
if (name!=NULL){ /* new name? */
/* new name and type and possibly correct osver */
ft=ascii2akai_filename(name,anamebuf,&osver,voldstp->type==AKAI_VOL_TYPE_S900);
if (ft==AKAI_FTYPE_FREE){
PRINTF_ERR("invalid name\n");
return -1;
}
}
/* update volume entries (after having checked the name!!!) */
if (diffvolflag||(fidst!=fisrc)){ /* different volume specified, or different index within same volume? */
/* create destination volume directory entry */
bcopy(&volsrcp->file[fisrc],&voldstp->file[fidst],sizeof(struct akai_voldir_entry_s));
/* new volume */
fp->volp=voldstp;
/* new index */
fp->index=fidst;
/* free old volume directory entry */
bzero(&volsrcp->file[fisrc],sizeof(struct akai_voldir_entry_s));
volsrcp->file[fisrc].type=AKAI_FTYPE_FREE;
/* write source volume directory */
if (akai_write_voldir(volsrcp,fisrc)<0){
return -1;
}
}
/* set destination volume directory entry */
if (osver!=fp->osver){ /* different OS version? */
/* new OS version */
fp->osver=osver;
voldstp->file[fidst].osver[1]=0xff&(fp->osver>>8);
voldstp->file[fidst].osver[0]=0xff&fp->osver;
}
/* name and type */
if (name!=NULL){ /* new name/type? */
/* new name */
if (vp->type==AKAI_VOL_TYPE_S900){
bcopy(anamebuf,voldstp->file[fidst].name,AKAI_NAME_LEN_S900);
bzero(voldstp->file[fidst].name+AKAI_NAME_LEN_S900,AKAI_NAME_LEN-AKAI_NAME_LEN_S900);
}else{
bcopy(anamebuf,voldstp->file[fidst].name,AKAI_NAME_LEN);
}
if (name!=fp->name){ /* not already in fp->name? */
/* copy */
strcpy(fp->name,name); /* Note: name has been checked above */
}
/* new type */
voldstp->file[fidst].type=ft;
fp->type=ft;
}
/* else: keep old name and type */
/* No need to copy since whole dir entry has been copied above if necessary */
/* tags */
if (vp->type==AKAI_VOL_TYPE_S900){
/* S900 */
/* no tags */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
fp->tag[i]=AKAI_FILE_TAGFREE;
}
bzero(voldstp->file[fidst].tag,AKAI_FILE_TAGNUM);
}else{
/* S1000/S3000 */
if (tagp!=NULL){ /* new tags? */
/* copy tags */
bcopy(tagp,voldstp->file[fidst].tag,AKAI_FILE_TAGNUM);
akai_sort_filetags(voldstp->file[fidst].tag);
if (tagp!=fp->tag){ /* not already in fp->tag? */
/* copy */
bcopy(voldstp->file[fidst].tag,fp->tag,AKAI_FILE_TAGNUM);
/* XXX no check for validity of tag indices */
}
}
/* else: keep old tags */
/* No need to copy since whole dir entry has been copied above if necessary */
}
/* write destination volume directory */
/* Note: the same partition for source and destination */
if (akai_write_voldir(voldstp,fidst)<0){
return -1;
}
return 0;
}
/* uses *fp as output */
/* size in bytes */
int
akai_create_file(struct vol_s *vp,struct file_s *fp,u_int size,u_int index,char *name,u_int osver,u_char *tagp)
{
u_char ft;
u_int bsize;
u_int fi;
u_int i;
u_char anamebuf[AKAI_NAME_LEN];
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)||(vp->file==NULL)){
return -1;
}
if ((vp->partp==NULL)||(!vp->partp->valid)||(vp->partp->blksize==0)){
return -1;
}
if (fp==NULL){
return -1;
}
if (name==NULL){
return -1;
}
if (size>AKAI_FILE_SIZEMAX){
PRINTF_ERR("file size is too large\n");
return -1;
}
/* volume */
fp->volp=vp;
/* name and type and possibly correct osver */
ft=ascii2akai_filename(name,anamebuf,&osver,vp->type==AKAI_VOL_TYPE_S900);
if (ft==AKAI_FTYPE_FREE){
PRINTF_ERR("invalid name\n");
return -1;
}
/* now, lengths also OK */
strcpy(fp->name,name);
fp->type=ft;
/* osver */
fp->osver=osver;
/* index */
if (index==AKAI_CREATE_FILE_NOINDEX){ /* no user-supplied volume index? */
/* find free volume directory entry */
for (fi=0;fi<vp->fimax;fi++){
if (vp->file[fi].type==AKAI_FTYPE_FREE){ /* free? */
break; /* found one */
}
}
if (fi==vp->fimax){ /* none found? */
PRINTF_OUT("no free file entry found\n");
return -1;
}
}else{
/* user-supplied index */
fi=index;
if (fi>vp->fimax){
return -1;
}
if (vp->file[fi].type!=AKAI_FTYPE_FREE){ /* not free? */
PRINTF_OUT("file entry not free\n");
return -1;
}
}
fp->index=fi;
/* size */
fp->size=size;
/* tags */
if (vp->type==AKAI_VOL_TYPE_S900){
/* S900 */
/* no tags */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
fp->tag[i]=AKAI_FILE_TAGFREE;
}
}else{
/* S1000/S3000 */
if (tagp!=NULL){
/* correct and copy */
/* Note: even if tagp==fp->tag */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
if ((tagp[i]>=1)&&(tagp[i]<=AKAI_PARTHEAD_TAGNUM)){
fp->tag[i]=tagp[i];
}else{
/* set free */
if (fp->osver<=AKAI_OSVER_S1100MAX){
fp->tag[i]=AKAI_FILE_TAGS1000;
}else{
fp->tag[i]=AKAI_FILE_TAGFREE;
}
}
}
akai_sort_filetags(fp->tag);
}else{
/* all free */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
if (fp->osver<=AKAI_OSVER_S1100MAX){
fp->tag[i]=AKAI_FILE_TAGS1000;
}else{
fp->tag[i]=AKAI_FILE_TAGFREE;
}
}
}
}
/* allocate space */
bsize=(fp->size+fp->volp->partp->blksize-1)/fp->volp->partp->blksize; /* round up */
if (akai_allocate_fatchain(vp->partp,bsize,
&fp->bstart,
1,
(vp->type==AKAI_VOL_TYPE_S900)?AKAI_FAT_CODE_FILEEND900:AKAI_FAT_CODE_FILEEND)<0){ /* end code */
return -1;
}
/* create volume directory entry */
bzero(&vp->file[fi],sizeof(struct akai_voldir_entry_s));
if (vp->type==AKAI_VOL_TYPE_S900){
/* S900 */
/* name */
bcopy(anamebuf,vp->file[fi].name,AKAI_NAME_LEN_S900);
bzero(vp->file[fi].name+AKAI_NAME_LEN_S900,AKAI_NAME_LEN-AKAI_NAME_LEN_S900);
/* no tags */
bzero(vp->file[fi].tag,AKAI_FILE_TAGNUM);
}else{
/* S1000/S3000 */
/* name */
bcopy(anamebuf,vp->file[fi].name,AKAI_NAME_LEN);
/* tags */
bcopy(fp->tag,vp->file[fi].tag,AKAI_FILE_TAGNUM);
}
/* type */
vp->file[fi].type=fp->type;
/* size */
vp->file[fi].size[2]=0xff&(fp->size>>16);
vp->file[fi].size[1]=0xff&(fp->size>>8);
vp->file[fi].size[0]=0xff&fp->size;
/* start */
vp->file[fi].start[1]=0xff&(fp->bstart>>8);
vp->file[fi].start[0]=0xff&fp->bstart;
/* OS version */
vp->file[fi].osver[1]=0xff&(fp->osver>>8);
vp->file[fi].osver[0]=0xff&fp->osver;
/* write volume directory */
if (akai_write_voldir(vp,fi)<0){
return -1;
}
return 0;
}
void
akai_fvol1000_initfile(struct akai_voldir_entry_s *ep,u_int osver,u_int tag)
{
u_int i;
if (ep==NULL){
return;
}
/* OS version */
ep->osver[1]=0xff&(osver>>8);
ep->osver[0]=0xff&osver;
if (osver==AKAI_OSVER_S900VOL){
/* S900 */
/* zero name and tags */
bzero(ep->name,AKAI_NAME_LEN);
bzero(ep->tag,AKAI_FILE_TAGNUM);
}else{
/* S1000/S3000 */
/* default name */
ascii2akai_name(AKAI_EMPTY1000_FNAME,ep->name,0); /* 0: not S900 */
/* default tags */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
ep->tag[i]=tag;
}
}
/* type: free entry */
ep->type=AKAI_FTYPE_FREE;
}
int
akai_delete_file(struct file_s *fp)
{
u_int fi;
if ((fp==NULL)||(fp->type==AKAI_FTYPE_FREE)){
return -1;
}
if ((fp->volp==NULL)||(fp->volp->type==AKAI_VOL_TYPE_INACT)||(fp->volp->file==NULL)){
return -1;
}
if ((fp->volp->partp==NULL)||(!fp->volp->partp->valid)){
return -1;
}
/* file index */
fi=fp->index;
/* free volume directory entry */
bzero(&fp->volp->file[fi],sizeof(struct akai_voldir_entry_s));
if ((fp->volp->partp->type==PART_TYPE_HD9)
||(fp->volp->partp->type==PART_TYPE_HD)
||(fp->volp->type==AKAI_VOL_TYPE_S3000)||(fp->volp->type==AKAI_VOL_TYPE_CD3000)){
/* harddisk and/or S3000 volume */
fp->volp->file[fi].type=AKAI_FTYPE_FREE;
}else{
/* S900/S1000 floppy */
akai_fvol1000_initfile(&fp->volp->file[fi],fp->volp->osver,AKAI_FILE_TAGS1000);
}
/* write volume directory */
if (akai_write_voldir(fp->volp,fi)<0){
return -1;
}
/* free FAT chain */
if (akai_free_fatchain(fp->volp->partp,fp->bstart,1)<0){ /* 1: write FAT */
PRINTF_ERR("failed to free blocks of file, however, volume directory entry deleted\n");
return -1;
}
return 0;
}
int
akai_rename_ddtake(struct part_s *pp,u_int ti,char *name)
{
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type!=PART_TYPE_DD){
return -1;
}
if (ti>=AKAI_DDTAKE_MAXNUM){
return -1;
}
if (name==NULL){
return -1;
}
if (pp->head.dd.take[ti].stat==AKAI_DDTAKESTAT_FREE){ /* free? */
return -1;
}
/* rename */
ascii2akai_name(name,pp->head.dd.take[ti].name,0); /* 0: not S900 */
/* write partition header */
if (akai_io_blks(pp,(u_char *)&pp->head.dd,
0,
AKAI_DDPARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
return 0;
}
int
akai_delete_ddtake(struct part_s *pp,u_int ti)
{
u_int cstarts,cstarte;
if ((pp==NULL)||(!pp->valid)||(pp->fat==NULL)){
return -1;
}
if (pp->type!=PART_TYPE_DD){
return -1;
}
if (ti>=AKAI_DDTAKE_MAXNUM){
return -1;
}
if (pp->head.dd.take[ti].stat==AKAI_DDTAKESTAT_FREE){ /* free? */
return -1;
}
/* free DD FAT chains */
cstarts=(pp->head.dd.take[ti].cstarts[1]<<8)
+pp->head.dd.take[ti].cstarts[0];
if (cstarts!=0){ /* sample not empty? */
if (akai_free_ddfatchain(pp,cstarts,0)<0){ /* 0: don't write header yet */
return -1;
}
}
cstarte=(pp->head.dd.take[ti].cstarte[1]<<8)
+pp->head.dd.take[ti].cstarte[0];
if (cstarte!=0){ /* envelope not empty? */
if (akai_free_ddfatchain(pp,cstarte,0)<0){ /* 0: don't write header yet */
return -1;
}
}
/* wipe directory entry for take */
bzero(&pp->head.dd.take[ti],sizeof(struct akai_ddtake_s));
pp->head.dd.take[ti].stat=AKAI_DDTAKESTAT_FREE; /* free */
/* count free and bad blocks */
akai_countfree_part(pp);
/* write partition header */
if (akai_io_blks(pp,(u_char *)&pp->head.dd,
0,
AKAI_DDPARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
return 0;
}
void
akai_fix_partheadmagic(struct part_s *pp)
{
u_int i;
u_int m,cs;
/* Note: allow invalid partitions to be fixed!!! */
if (pp==NULL){
return;
}
if (pp->type!=PART_TYPE_HD){
return;
}
/* now, S1000/S3000 harddisk sampler partition */
cs=pp->bsize;
/* set magic */
for (i=0;i<AKAI_PARTHEAD_MAGICNUM;i++){
m=0xffff&(i*AKAI_PARTHEAD_MAGICVAL);
pp->head.hd.magic[i][1]=0xff&(m>>8);
pp->head.hd.magic[i][0]=0xff&m;
cs+=m;
}
/* set checksum */
pp->head.hd.chksum[3]=0xff&(cs>>24);
pp->head.hd.chksum[2]=0xff&(cs>>16);
pp->head.hd.chksum[1]=0xff&(cs>>8);
pp->head.hd.chksum[0]=0xff&cs;
}
int
akai_check_partheadmagic(struct part_s *pp)
{
u_int i;
u_int m,cs,c;
/* Note: allow invalid partitions to be checked!!! */
if (pp==NULL){
return -1;
}
if (pp->type==PART_TYPE_DD){
return -1;
}
cs=pp->bsize;
/* magic */
for (i=0;i<AKAI_PARTHEAD_MAGICNUM;i++){
m=(pp->head.hd.magic[i][1]<<8)
+pp->head.hd.magic[i][0];
if (m!=(0xffff&(i*AKAI_PARTHEAD_MAGICVAL))){
return -1; /* magic error */
}
cs+=m;
}
/* checksum */
c=(pp->head.hd.chksum[3]<<24)
+(pp->head.hd.chksum[2]<<16)
+(pp->head.hd.chksum[1]<<8)
+pp->head.hd.chksum[0];
if (c!=cs){
return -2; /* only checksum error */
}
return 0; /* OK */
}
void
akai_fix_parttabmagic(struct akai_parttab_s *ptp)
{
u_int i;
u_int m;
if (ptp==NULL){
return;
}
/* set magic */
for (i=0;i<AKAI_PARTTAB_MAGICNUM;i++){
m=0xffff&(i*AKAI_PARTTAB_MAGICVAL);
ptp->magic[i][1]=0xff&(m>>8);
ptp->magic[i][0]=0xff&m;
}
}
int
akai_check_parttabmagic(struct akai_parttab_s *ptp)
{
u_int i;
u_int m;
if (ptp==NULL){
return -1;
}
/* magic */
for (i=0;i<AKAI_PARTTAB_MAGICNUM;i++){
m=(ptp->magic[i][1]<<8)+ptp->magic[i][0];
if (m!=(0xffff&(i*AKAI_PARTTAB_MAGICVAL))){
return -1; /* magic error */
}
}
return 0; /* OK */
}
int
akai_scan_floppy(struct disk_s *dp)
{
u_int i,n;
if (dp==NULL){
return -1;
}
/* disk blocksize and total size */
if (dp->blksize!=AKAI_FL_BLOCKSIZE){ /* wrong blocksize? */
/* set new blksize */
dp->blksize=AKAI_FL_BLOCKSIZE;
/* disk size in blocks */
dp->bsize=dp->totsize/dp->blksize;
} /* else: assume that dp->bsize is valid */
#ifdef _VISUALCPP
if (dp->fldrn>=0){ /* is floppy drive? */
/* Note: open_disk() has set disk type */
/* check if no floppy inserted */
if (fldr_checkfloppyinserted(dp->fldrn)!=0){
PRINTF_OUT("disk%u: no floppy inserted\n",dp->index);
/* discard this partition, keep old part_num */
return -1;
}
}else /* no floppy drive */
#endif /* _VISUALCPP */
{
/* set disk type */
/* Note: requires valid dp->bsize (see above) */
if (dp->bsize>=AKAI_FLH_SIZE){
dp->type=DISK_TYPE_FLH;
}else{
dp->type=DISK_TYPE_FLL;
}
}
/* disk pointer */
part[part_num].diskp=dp;
part[part_num].valid=1; /* OK so far */
/* set partition type = disk type (first guess) */
part[part_num].type=dp->type;
/* fake index on disk */
part[part_num].index=0;
/* block size */
part[part_num].blksize=dp->blksize;
/* start block */
part[part_num].bstart=0;
/* size (Note: also needed to read floppy header below) */
/* first guess: disk size (Note: part[part_num].bstart==0) */
part[part_num].bsize=dp->bsize;
/* try to read floppy header at block 0 relative to start */
/* Note: low- and high-density floppy headers are identical */
/* up to first AKAI_FAT_ENTRIES_FLL FAT-entries!!! */
/* => try to read the largest header (AKAI_FLHHEAD_BLKS blocks) */
/* XXX bad luck for low-density floppy which has bad block(s) */
/* at AKAI_FLLHEAD_BLKS <= block < AKAI_FLHHEAD_BLKS */
if ((part[part_num].bsize<AKAI_FLHHEAD_BLKS)
||(akai_io_blks(&part[part_num],(u_char *)&part[part_num].head.flh,
0,
AKAI_FLHHEAD_BLKS,
1,IO_BLKS_READ)<0)){ /* 1: alloc cache if possible */
PRINTF_OUT("disk%u: cannot read floppy header\n",dp->index);
/* discard this partition, keep old part_num */
/* assume end of disk, done */
return -1;
}
/* start of FAT */
/* Note: see comment above: FAT-start same for low- and high density */
part[part_num].fat=&part[part_num].head.flh.fatblk[0];
part[part_num].bsize=AKAI_FLH_SIZE;
/* count S1000/S3000 system blocks in FAT */
for (i=0;i<(AKAI_FLHHEAD_BLKS+AKAI_VOLDIR3000FL_BLKS);i++){
n=(part[part_num].fat[i][1]<<8)+part[part_num].fat[i][0];
if (n!=AKAI_FAT_CODE_SYS){ /* not reserved for system anymore? */
break; /* end of system blocks */
}
}
if (i>0){
/* assume S1000/S3000 */
/* reserved blocks for system */
part[part_num].bsyssize=i;
/* check floppy type */
if ((dp->bsize>=AKAI_FLL_SIZE)&&(dp->bsize<AKAI_FLH_SIZE)
&&((i==AKAI_FLLHEAD_BLKS)||(i==(AKAI_FLLHEAD_BLKS+AKAI_VOLDIR3000FL_BLKS)))){ /* S1000 or S3000 low-density? */
/* if correct, must be low-density floppy now */
part[part_num].type=PART_TYPE_FLL;
part[part_num].bsize=AKAI_FLL_SIZE;
/* Note: see comment above: no need to read low-density header again */
}else if ((dp->bsize>=AKAI_FLH_SIZE)
&&((i==AKAI_FLHHEAD_BLKS)||(i==(AKAI_FLHHEAD_BLKS+AKAI_VOLDIR3000FL_BLKS)))){ /* S1000 or S3000 high-density? */
/* if correct, must be high-density floppy now */
part[part_num].type=PART_TYPE_FLH;
part[part_num].bsize=AKAI_FLH_SIZE;
}else{
return -1;
}
}else{
/* count S900 system blocks in FAT */
for (i=0;i<AKAI_FLHHEAD_BLKS;i++){
n=(part[part_num].fat[i][1]<<8)+part[part_num].fat[i][0];
if (n!=AKAI_FAT_CODE_SYS900FL){ /* not reserved for system anymore? */
break; /* end of system blocks */
}
}
/* reserved blocks for system */
part[part_num].bsyssize=i;
/* check floppy type */
/* Note: since AKAI_FAT_CODE_SYS900FL==AKAI_FAT_CODE_FREE, */
/* a low-density floppy may have i>=AKAI_FLLHEAD_BLKS here */
if ((dp->bsize>=AKAI_FLL_SIZE)&&(dp->bsize<AKAI_FLH_SIZE)&&(i>=AKAI_FLLHEAD_BLKS)){ /* low-density? */
/* if correct, must be low-density floppy now */
part[part_num].type=PART_TYPE_FLL;
part[part_num].bsize=AKAI_FLL_SIZE;
/* Note: AKAI_FLLHEAD_BLKS system blocks, i may differ */
part[part_num].bsyssize=AKAI_FLLHEAD_BLKS;
/* Note: see comment above: no need to read low-density header again */
}else if ((dp->bsize>=AKAI_FLH_SIZE)&&(i==AKAI_FLHHEAD_BLKS)){ /* high-density? */
/* if correct, must be high-density floppy now */
part[part_num].type=PART_TYPE_FLH;
part[part_num].bsize=AKAI_FLH_SIZE;
}else{
return -1;
}
}
/* Note: now, part[part_num].bsize <= dp->bsize */
/* Note: if floppy drive -> open_disk() has set disk type, may differ from partition type */
/* count free and bad blocks */
akai_countfree_part(&part[part_num]);
/* number of volumes */
part[part_num].volnummax=1;
/* fake partition letter */
part[part_num].letter='A';
part_num++; /* found one */
return 0;
}
int
akai_scan_harddisk9(struct disk_s *dp)
{
u_int i,n;
if (dp==NULL){
return -1;
}
/* set disk type */
dp->type=DISK_TYPE_HD9;
/* disk blocksize and total size */
if (dp->blksize!=AKAI_HD_BLOCKSIZE){ /* wrong blocksize? */
/* set new blksize */
dp->blksize=AKAI_HD_BLOCKSIZE;
/* disk size in blocks */
dp->bsize=dp->totsize/dp->blksize;
} /* else: assume that dp->bsize is valid */
/* disk pointer */
part[part_num].diskp=dp;
part[part_num].valid=1; /* OK so far */
/* set partition type = disk type */
part[part_num].type=dp->type;
/* fake index on disk */
part[part_num].index=0;
/* block size */
part[part_num].blksize=dp->blksize;
/* start block */
part[part_num].bstart=0;
/* size (Note: also needed to read harddisk header below) */
/* first guess: disk size (Note: part[part_num].bstart==0) */
part[part_num].bsize=dp->bsize;
/* try to read S900 harddisk header at block 0 relative to start */
if ((part[part_num].bsize<AKAI_HD9HEAD_BLKS)
||(akai_io_blks(&part[part_num],(u_char *)&part[part_num].head.hd9,
0,
AKAI_HD9HEAD_BLKS,
1,IO_BLKS_READ)<0)){ /* 1: alloc cache if possible */
/* discard this partition, keep old part_num */
PRINTF_OUT("disk%u: cannot read S900 harddisk header\n",dp->index);
/* assume end of disk, done */
return -1;
}
/* start of FAT */
part[part_num].fat=&part[part_num].head.hd9.fatblk[0];
/* count system blocks in FAT */
for (i=0;i<AKAI_HD9HEAD_BLKS;i++){
n=(part[part_num].fat[i][1]<<8)+part[part_num].fat[i][0];
if (n!=AKAI_FAT_CODE_SYS900HD){ /* not reserved for system anymore? */
/* discard this partition, keep old part_num */
return -1;
}
}
/* size */
if (part[part_num].head.hd9.flag1==AKAI_HD9FLAG1_SIZEVALID){
/* get size from header */
part[part_num].bsize=(((u_int)part[part_num].head.hd9.size[1])<<8)
+((u_int)part[part_num].head.hd9.size[0]);
if (part[part_num].bsize>AKAI_HD9_MAXSIZE){
PRINTF_OUT("disk%u: invalid size (0x%04x) of harddisk",
dp->index,part[part_num].bsize);
part[part_num].bsize=AKAI_HD9_MAXSIZE;
PRINTF_OUT(", truncated (0x%04x)\n",part[part_num].bsize);
/* XXX keep valid */
}
}else{
/* default size */
part[part_num].bsize=AKAI_HD9_DEFSIZE;
}
/* Note: part[part_num].bstart==0 */
if (part[part_num].bsize>dp->bsize){
PRINTF_OUT("disk%u: expected size (0x%04x) of harddisk is too large",
dp->index,part[part_num].bsize);
/* truncate */
part[part_num].bsize=dp->bsize;
PRINTF_OUT(", truncated (0x%04x)\n",part[part_num].bsize);
/* XXX keep valid */
}
/* reserved blocks for system */
part[part_num].bsyssize=AKAI_HD9HEAD_BLKS;
/* count free and bad blocks */
akai_countfree_part(&part[part_num]);
/* number of volumes */
part[part_num].volnummax=AKAI_HD9ROOTDIR_ENTRIES;
/* fake partition letter */
part[part_num].letter='A';
part_num++; /* found one */
return 0;
}
int
akai_scan_ddpart(struct disk_s *dp,struct akai_parttab_s *ptp,u_int bstart,u_int pi)
{
u_int ptcsize;
u_int ptbsize;
u_int totsize;
u_int di,dimax;
if ((dp==NULL)||(ptp==NULL)){
return -1;
}
if (bstart>dp->bsize){
return -1;
}
/* get number of DD partitions */
dimax=ptp->ddpartnum;
if (dimax==0){
return 0;
}
if (dimax>AKAI_DDPART_NUM){
PRINTF_OUT("disk%u: invalid DD partition number (%u), truncated (%u)\n",
dp->index,dimax,AKAI_DDPART_NUM);
dimax=AKAI_PART_NUM; /* XXX truncate */
}
totsize=0;
for (di=0;(di<dimax)&&(part_num<PART_NUM_MAX);){
/* disk pointer */
part[part_num].diskp=dp;
part[part_num].valid=1; /* OK so far */
/* type */
part[part_num].type=PART_TYPE_DD;
/* index on disk */
part[part_num].index=pi;
/* block size */
part[part_num].blksize=dp->blksize;
/* start block */
part[part_num].bstart=bstart;
/* partition size according to partition table */
ptcsize=(ptp->ddpart[di][1]<<8)+ptp->ddpart[di][0]; /* in clusters */
ptbsize=ptcsize*AKAI_DDPART_CBLKS; /* in blocks */
/* check size */
if (ptbsize==0){
PRINTF_OUT("disk%u: premature end of DD partitions\n",dp->index);
/* end of partitions, done */
/* no further partition, keep old part_num */
break; /* done */
}
if (ptbsize>AKAI_HD_MAXSIZE){
PRINTF_OUT("disk%u: invalid size (0x%04x) of DD partition %u",
dp->index,ptbsize,di);
/* truncate */
ptbsize=AKAI_HD_MAXSIZE;
ptcsize=ptbsize/AKAI_DDPART_CBLKS; /* in clusters */
ptbsize=ptcsize*AKAI_DDPART_CBLKS; /* in blocks */
PRINTF_OUT(", truncated (0x%04x)\n",ptbsize);
/* XXX keep valid */
}
if ((part[part_num].bstart+ptbsize)>dp->bsize){
PRINTF_OUT("disk%u: expected size (0x%04x) of DD partition %u is too large",
dp->index,ptbsize,di);
/* truncate */
if (part[part_num].bstart<dp->bsize){
ptbsize=dp->bsize-part[part_num].bstart;
}else{
ptbsize=0;
}
ptcsize=ptbsize/AKAI_DDPART_CBLKS; /* in clusters */
ptbsize=ptcsize*AKAI_DDPART_CBLKS; /* in blocks */
PRINTF_OUT(", truncated (0x%04x)\n",ptbsize);
/* XXX keep valid */
/* Note: this will be the last DD partition */
}
part[part_num].bsize=ptbsize;
part[part_num].csize=ptcsize;
/* try to read S1100/S3000 harddisk DD partition header at block 0 relative to start */
if ((part[part_num].bsize<AKAI_DDPARTHEAD_BLKS)
||(akai_io_blks(&part[part_num],(u_char *)&part[part_num].head.dd,
0,
AKAI_DDPARTHEAD_BLKS,
1,IO_BLKS_READ)<0)){ /* 1: alloc cache if possible */
/* discard this partition, keep old part_num */
PRINTF_OUT("disk%u: cannot read header of DD partition %u, discarded\n",
dp->index,di);
break; /* assume end of disk, done */
}
/* start of FAT */
part[part_num].fat=&part[part_num].head.dd.fatcl[0];
/* count free and bad blocks */
akai_countfree_part(&part[part_num]);
/* no volumes */
part[part_num].volnummax=0;
/* fake partition letter */
part[part_num].letter=di; /* XXX */
/* bstart of next DD partition */
bstart+=ptbsize;
/* update total size of DD partitions */
totsize+=ptbsize;
di++;
pi++;
part_num++; /* found one */
if (bstart>=dp->bsize){
break; /* done */
}
}
/* check total number of DD partitions */
if (di!=dimax){
PRINTF_OUT("disk%u: inconsistent DD partition number (%u instead of %u), ignored\n",
dp->index,di,dimax);
/* XXX ignore */
}
/* check total size of DD partitions */
/* total size according to partition table */
ptcsize=(ptp->ddpart[di][1]<<8)+ptp->ddpart[di][0]; /* in clusters */
ptbsize=ptcsize*AKAI_DDPART_CBLKS; /* in blocks */
if (ptbsize!=totsize){
PRINTF_OUT("disk%u: inconsistent total size of DD partitions (0x%04x instead of 0x%04x), ignored\n",
dp->index,totsize,ptbsize);
/* XXX ignore */
}
return 0;
}
int
akai_scan_disk(struct disk_s *dp,int floppyenable)
{
u_int bstart;
u_int pi,pimax;
u_int ptbsize;
struct akai_parttab_s *ptp;
int retval;
if (dp==NULL){
return -1;
}
if (dp->totsize==0){
PRINTF_OUT("disk%u: zero size\n",dp->index);
return -1;
}
/* set disk type */
/* first guess: S1000/S3000 harddisk */
dp->type=DISK_TYPE_HD;
/* set disk blocksize */
/* first guess: harddisk */
/* Note: blksize may change now!!! */
dp->blksize=AKAI_HD_BLOCKSIZE;
/* disk size in blocks */
/* Note: uses harddisk blocksize (AKAI_HD_BLOCKSIZE) here */
dp->bsize=dp->totsize/dp->blksize;
/* Note: dp->bsize can be 0 here */
/* scan for S1000/S3000 harddisk sampler partitions or S900 harddisk or S900/S1000/S3000 floppy */
bstart=0; /* first partition */
pimax=AKAI_PART_NUM; /* first guess for number of partitions */
ptp=NULL; /* no partition table found so far */
for (pi=0;(pi<pimax)&&(part_num<PART_NUM_MAX);){
/* Note: possibly scan for S900 harddisk or S900/S1000/S3000 floppy format below => must allow bstart >= dp->bsize here */
/* Note: members of current part[part_num] may be overwritten in akai_scan_harddisk9() or akai_scan_floppy() below */
/* disk pointer */
part[part_num].diskp=dp;
part[part_num].valid=1; /* OK so far */
/* set partition type = disk type (first guess) */
/* Note: DISK_TYPE_HD (==PART_TYPE_HD) here */
part[part_num].type=dp->type;
/* index on disk */
part[part_num].index=pi;
/* block size */
/* Note: AKAI_HD_BLOCKSIZE here */
part[part_num].blksize=dp->blksize;
/* start block */
part[part_num].bstart=bstart;
/* partition size (Note: also needed to read sampler partition header below) */
/* first guess: max. available size */
/* Note: uses harddisk blocksize (AKAI_HD_BLOCKSIZE) here */
if (part[part_num].bstart<dp->bsize){
part[part_num].bsize=dp->bsize-part[part_num].bstart;
}else{
part[part_num].bsize=0;
}
/* partition letter */
part[part_num].letter='A'+pi;
/* try to read S1000/S3000 harddisk sampler partition header at block 0 relative to start */
if ((part[part_num].bsize<AKAI_PARTHEAD_BLKS)
||(akai_io_blks(&part[part_num],(u_char *)&part[part_num].head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_READ)<0)){ /* 1: alloc cache if possible */
/* not a valid S1000/S3000 harddisk sampler partition */
if (pi==0){ /* first partition? */
/* scan for S900 harddisk or S900/S1000/S3000 floppy format */
goto scan_hd9_floppy;
}
/* discard this partition, keep old part_num */
PRINTF_OUT("disk%u: cannot read header of partition %c, discarded\n",
dp->index,part[part_num].letter);
break; /* assume end of disk, done */
}
/* sampler partition size (Note: also needed for checksum in magic check below) */
/* expected value, will be checked below */
part[part_num].bsize=(part[part_num].head.hd.size[1]<<8)+part[part_num].head.hd.size[0];
/* reserved blocks for system */
/* first guess */
part[part_num].bsyssize=AKAI_PARTHEAD_BLKS;
/* number of volumes */
/* first guess */
part[part_num].volnummax=AKAI_ROOTDIR_ENTRIES;
/* check magic: indicates S1000/S3000 harddisk sampler partition */
if (akai_check_partheadmagic(&part[part_num])<0){
/* not a valid S1000/S3000 harddisk sampler partition */
if (pi==0){ /* first partition? */
/* scan for S900 harddisk or S900/S1000/S3000 floppy format */
goto scan_hd9_floppy;
}else{
PRINTF_OUT("disk%u: invalid format in partition %c, ignored\n",dp->index,'A'+pi);
/* XXX invalid, but keep it */
part[part_num].valid=0; /* invalid partition so far */
/* Note: if non-empty, part_num++ via for-loop */
}
}
/* Note: now, S1000/S3000 harddisk sampler partition */
/* end of sampler partitions? */
if (part[part_num].bsize==0){ /* empty partition? */
/* Note: if partition table present, this is a premature end, since pimax should be correct */
if (ptp!=NULL){ /* partition table present? */
PRINTF_OUT("disk%u: premature end of sampler partitions\n",dp->index);
/* XXX ignore */
}
/* end of sampler partitions, done */
/* no further sampler partition, keep old part_num */
break; /* done */
}
if (pi==0){ /* first partition? */
/* Note: now, first partition header was read and checked */
/* check magic in parttab: indicates S1000/S3000 harddisk partition table */
ptp=&(part[part_num].head.hd.parttab); /* try */
if (akai_check_parttabmagic(ptp)==0){
/* get number of sampler partitions: first entry in partition table */
pimax=ptp->partnum;
if (pimax==0){
PRINTF_OUT("disk%u: empty partition table, ignored\n",dp->index);
pimax=AKAI_PART_NUM; /* XXX try all */
}
if (pimax>AKAI_PART_NUM){
PRINTF_OUT("disk%u: invalid partition number (%u), truncated (%u)\n",
dp->index,pimax,AKAI_PART_NUM);
pimax=AKAI_PART_NUM; /* XXX truncate */
}
}else{
/* if correct, no partition table present, e.g. for old harddisk format */
ptp=NULL;
/* XXX nevertheless, try without partition table to find valid partitions */
/* XXX no need to mark invalid */
PRINTF_OUT("disk%u: no partition table present, ignored\n",dp->index);
}
}
if (ptp!=NULL){ /* partition table present? */
/* partition size according to partition table */
ptbsize=(ptp->part[pi][1]<<8)+ptp->part[pi][0];
/* compare */
if (part[part_num].bsize!=ptbsize){
PRINTF_OUT("disk%u: inconsistent size of partition %c (0x%04x instead of 0x%04x), ignored\n",
dp->index,part[part_num].letter,part[part_num].bsize,ptbsize);
/* XXX keep valid */
}
}else{
ptbsize=part[part_num].bsize; /* XXX */
}
/* check size */
if (part[part_num].bsize>AKAI_PART_MAXSIZE){
PRINTF_OUT("disk%u: invalid size (0x%04x) of partition %c",
dp->index,part[part_num].bsize,part[part_num].letter);
part[part_num].bsize=AKAI_PART_MAXSIZE;
PRINTF_OUT(", truncated (0x%04x)\n",part[part_num].bsize);
/* XXX keep valid */
}
if ((part[part_num].bstart+part[part_num].bsize)>dp->bsize){
PRINTF_OUT("disk%u: expected size (0x%04x) of partition %c is too large",
dp->index,part[part_num].bsize,part[part_num].letter);
/* truncate */
if (part[part_num].bstart<dp->bsize){
part[part_num].bsize=dp->bsize-part[part_num].bstart;
}else{
part[part_num].bsize=0;
}
PRINTF_OUT(", truncated (0x%04x)\n",part[part_num].bsize);
/* XXX keep valid */
/* Note: this will be the last sampler partition */
}
/* start of FAT */
part[part_num].fat=&part[part_num].head.hd.fatblk[0];
/* count free and bad blocks */
akai_countfree_part(&part[part_num]);
/* bstart of next sampler partition */
/* XXX trust part[part_num].bsize instead of ptbsize */
bstart+=part[part_num].bsize;
pi++;
part_num++; /* found one */
if (bstart>=dp->bsize){
break; /* done */
}
}
/* Note: now, bstart is total size of S1000/S3000 harddisk sampler partitions in blocks */
if (ptp!=NULL){ /* partition table present? */
/* check total number of non-empty sampler partitions */
if (pi!=pimax){
PRINTF_OUT("disk%u: inconsistent sampler partition number (%u instead of %u), ignored\n",
dp->index,pi,pimax);
/* XXX ignore */
}
/* check total size of sampler partitions */
/* total size according to partition table */
ptbsize=(ptp->part[pimax][1]<<8)+ptp->part[pimax][0];
if (ptbsize!=bstart){
PRINTF_OUT("disk%u: inconsistent total size of sampler partitions (0x%04x instead of 0x%04x), ignored\n",
dp->index,bstart,ptbsize);
/* XXX ignore */
}
/* scan for S1100/S3000 harddisk DD partitions */
akai_scan_ddpart(dp,ptp,bstart,pi); /* Note: ignore possible error */
}
/* Note: valid S1000/S3000 harddisk should have at least one non-empty sampler partition */
if (pi==0){
PRINTF_OUT("disk%u: invalid format\n",dp->index);
return -1;
}
return 0;
scan_hd9_floppy:
/* scan for S900 harddisk or S900/S1000/S3000 floppy format */
if ((!floppyenable)||(dp->bsize*dp->blksize>AKAI_FLH_SIZE*AKAI_FL_BLOCKSIZE)){
/* scan for S900 harddisk format */
/* Note: akai_scan_harddisk9() may overwrite members of current disk and/or part[part_num] if necessary */
retval=akai_scan_harddisk9(dp);
}else{
/* scan for floppy format */
/* Note: akai_scan_floppy() may overwrite members of current disk and/or part[part_num] if necessary */
/* XXX first blocks with wrong blocksize cached, no problem, will be re-used */
retval=akai_scan_floppy(dp);
}
if (retval<0){
PRINTF_OUT("disk%u: invalid format\n",dp->index);
/* discard this partition, keep old part_num */
/* Note: keep current disk type */
}
/* assume end of disk, done */
return retval;
}
int
akai_wipe_part(struct part_s *pp,int wipeflag,struct part_s *plistp,u_int pimax,int cdromflag)
{
int i;
char namebuf[AKAI_NAME_LEN+1]; /* +1 for '\0' */
u_int pi,siz;
u_int pnum,totb;
u_int dnum,totdb;
/* Note: allow invalid partitions to be wiped!!! */
if ((pp==NULL)||(pp->blksize==0)||(pp->diskp==NULL)){
return -1;
}
if (pp->type==PART_TYPE_DD){
/* S1100/S3000 harddisk DD partition */
if (wipeflag){
static u_char buf[AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE];
struct akai_ddparthead_s *hp;
/* wipe cluster 0: contains partition header */
bzero(buf,AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE);
hp=(struct akai_ddparthead_s *)buf;
/* mark cluster 0 as reserved for system: contains partition header */
hp->fatcl[0][1]=0xff&(AKAI_DDFAT_CODE_SYS>>8);
hp->fatcl[0][0]=0xff&(AKAI_DDFAT_CODE_SYS);
/* update partition header in memory */
bcopy(hp,&pp->head.dd,sizeof(struct akai_ddparthead_s));
/* write cluster 0 */
if (akai_io_blks(pp,buf,
0,
AKAI_DDPART_CBLKS, /* 1 cluster */
0,IO_BLKS_WRITE)<0){ /* 0: don't allocate new cache */
return -1;
}
}
/* count free and bad blocks */
akai_countfree_part(pp);
pp->volnummax=0;
pp->valid=1; /* fixed */
/* Note: no need to exit or restart now */
return 0;
}
if ((pp->type==PART_TYPE_HD9)&&(pp->fat!=NULL)){
/* S900 harddisk */
/* number of volumes */
pp->volnummax=AKAI_HD9ROOTDIR_ENTRIES;
if (wipeflag){
/* wipe whole header */
bzero(&pp->head.hd9,sizeof(struct akai_hd9head_s));
/* allocate blocks for harddisk header */
for (i=0;i<AKAI_HD9HEAD_BLKS;i++){
pp->fat[i][1]=0xff&(AKAI_FAT_CODE_SYS900HD>>8);
pp->fat[i][0]=0xff&AKAI_FAT_CODE_SYS900HD;
}
}
/* set harddisk size */
if (pp->bsize>AKAI_HD9_MAXSIZE){
pp->bsize=AKAI_HD9_MAXSIZE;
}
pp->head.hd9.size[1]=0xff&(pp->bsize>>8);
pp->head.hd9.size[0]=0xff&pp->bsize;
pp->head.hd9.flag1=AKAI_HD9FLAG1_SIZEVALID;
/* reserved blocks for system */
pp->bsyssize=AKAI_HD9HEAD_BLKS;
/* count free and bad blocks */
akai_countfree_part(pp);
if (wipeflag){
/* wipe root directory */
bzero(&pp->head.hd9.vol[0],pp->volnummax*sizeof(struct akai_hd9rootdir_entry_s));
for (i=0;i<(int)pp->volnummax;i++){
/* default volume name */
sprintf(namebuf,"VOLUME %03i",i+1);
ascii2akai_name(namebuf,pp->head.hd9.vol[i].name,1); /* 1: S900 */
pp->head.hd9.vol[i].start[1]=0xff&(AKAI_VOL_START_INACT>>8);
pp->head.hd9.vol[i].start[0]=0xff&AKAI_VOL_START_INACT;
}
/* XXX must erase all vol_s which link to this partition */
}
/* copy first FAT entries */
bcopy((u_char *)&pp->head.hd9.fatblk,(u_char *)&pp->head.hd9.fatblk0,AKAI_HD9FAT0_ENTRIES*2);
/* write new harddisk header to harddisk */
if (akai_io_blks(pp,(u_char *)&pp->head.hd9,
0,
AKAI_HD9HEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
pp->valid=1; /* fixed */
/* Note: no need to exit or restart now */
return 0;
}
if ((pp->type!=PART_TYPE_HD)||(pp->fat==NULL)){
return -1;
}
/* now, S1000/S3000 harddisk sampler partition */
/* number of volumes */
pp->volnummax=AKAI_ROOTDIR_ENTRIES;
if (wipeflag){
/* wipe whole header */
bzero(&pp->head.hd,sizeof(struct akai_parthead_s));
/* Note: tagsmagic is cleared as well */
/* allocate blocks for partition header */
for (i=0;i<AKAI_PARTHEAD_BLKS;i++){
pp->fat[i][1]=0xff&(AKAI_FAT_CODE_SYS>>8);
pp->fat[i][0]=0xff&AKAI_FAT_CODE_SYS;
}
if (cdromflag){
/* allocate blocks for CD-ROM info */
/* XXX minimum size */
for (i=AKAI_CDINFO_BLK;i<AKAI_CDINFO_BLK+AKAI_CDINFO_MINSIZB;i++){
pp->fat[i][1]=0xff&(AKAI_FAT_CODE_SYS>>8);
pp->fat[i][0]=0xff&AKAI_FAT_CODE_SYS;
}
}
}
/* set partition size */
if (pp->bsize>AKAI_PART_MAXSIZE){
pp->bsize=AKAI_PART_MAXSIZE;
}
pp->head.hd.size[1]=0xff&(pp->bsize>>8);
pp->head.hd.size[0]=0xff&pp->bsize;
/* reserved blocks for system */
pp->bsyssize=AKAI_PARTHEAD_BLKS;
/* count free and bad blocks */
akai_countfree_part(pp);
/* fix magic: indicates harddisk */
akai_fix_partheadmagic(pp);
if (wipeflag){
/* wipe root directory */
bzero(&pp->head.hd.vol[0],pp->volnummax*sizeof(struct akai_rootdir_entry_s));
for (i=0;i<(int)pp->volnummax;i++){
/* default volume name */
sprintf(namebuf,"VOLUME %03i",i+1);
ascii2akai_name(namebuf,pp->head.hd.vol[i].name,0); /* 0: not S900 */
pp->head.hd.vol[i].type=AKAI_VOL_TYPE_INACT;
}
/* XXX must erase all vol_s which link to this partition */
}
/* first partition on disk and want to fix partition table? */
if ((pp->index==0)&&(plistp!=NULL)){
/* initialize partition table */
bzero(&(pp->head.hd.parttab),sizeof(struct akai_parttab_s));
/* fix parttab magic: indicates partition table */
akai_fix_parttabmagic(&(pp->head.hd.parttab));
/* count number of partitions on same disk */
pnum=0;
totb=0;
dnum=0;
totdb=0;
for (pi=0;pi<pimax;pi++){
if ((plistp[pi].diskp!=NULL)&&(plistp[pi].diskp->fd==pp->diskp->fd)){ /* same disk? */
if (plistp[pi].type==PART_TYPE_DD){
/* S1100/S3000 harddisk DD partition */
if (dnum>=AKAI_DDPART_NUM){ /* already enough and another one? */
PRINTF_OUT("too many DD partitions on disk, truncated\n");
continue; /* next */
}
siz=plistp[pi].bsize/AKAI_DDPART_CBLKS; /* XXX round down */
/* set partition size in partition table */
pp->head.hd.parttab.ddpart[dnum][1]=0xff&(siz>>8);
pp->head.hd.parttab.ddpart[dnum][0]=0xff&siz;
/* accumulate total size */
totdb+=siz;
dnum++; /* found one */
}else{
if (pnum>=AKAI_PART_NUM){ /* already enough and another one? */
PRINTF_OUT("too many partitions on disk, truncated\n");
continue; /* next */
}
siz=plistp[pi].bsize;
/* set partition size in partition table */
pp->head.hd.parttab.part[pnum][1]=0xff&(siz>>8);
pp->head.hd.parttab.part[pnum][0]=0xff&siz;
/* accumulate total size */
totb+=siz;
pnum++; /* found one */
}
}
}
/* set partition number */
pp->head.hd.parttab.partnum=0xff&pnum;
/* append total size at end of table */
/* Note: pnum has been checked above */
pp->head.hd.parttab.part[pnum][1]=0xff&(totb>>8);
pp->head.hd.parttab.part[pnum][0]=0xff&totb;
/* set DD partition number */
pp->head.hd.parttab.ddpartnum=0xff&dnum;
/* append total size at end of DD table */
/* Note: dnum has been checked above */
pp->head.hd.parttab.ddpart[dnum][1]=0xff&(totdb>>8);
pp->head.hd.parttab.ddpart[dnum][0]=0xff&totdb;
}
/* write new partition header to partition */
if (akai_io_blks(pp,(u_char *)&pp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
if (cdromflag){
static u_char buf[AKAI_CDINFO_MINSIZB*AKAI_HD_BLOCKSIZE]; /* XXX minimum size */
struct akai_cdinfohead_s *p;
/* wipe CD-ROM info */
/* XXX minimum size */
bzero(buf,AKAI_CDINFO_MINSIZB*AKAI_HD_BLOCKSIZE);
p=(struct akai_cdinfohead_s *)buf;
/* default label */
/* Note: CD-ROM label uses S1000/S3000 char conversion */
ascii2akai_name(AKAI_CDINFO_DEFLABEL,p->cdlabel,0); /* 0: not S900 */
if (akai_io_blks(pp,buf,
AKAI_CDINFO_BLK,
AKAI_CDINFO_MINSIZB,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return -1;
}
}
pp->valid=1; /* fixed */
/* Note: no need to exit or restart now */
return 0;
}
/* Note: blksize might change, must flush prior to formatting!!! */
/* Note: overwrites part[] */
/* Note: must flush cache and exit (or restart) if return value >=0 !!! */
int
akai_wipe_harddisk(struct disk_s *dp,u_int bsize,u_int totb,int s3000flag,int cdromflag)
{
u_int pi,pimax;
u_int bc,bremain,bchunk,bmin;
if (dp==NULL){
return -1;
}
/* S1000/S3000 harddisk */
if (totb*AKAI_HD_BLOCKSIZE>dp->bsize*dp->blksize){
totb=(dp->bsize*dp->blksize)/AKAI_HD_BLOCKSIZE; /* truncate */
}
if (totb>AKAI_HD_MAXSIZE){
totb=AKAI_HD_MAXSIZE; /* truncate */
}
if (bsize>totb){
bsize=totb; /* truncate */
}
if (bsize>AKAI_PART_MAXSIZE){
bsize=AKAI_PART_MAXSIZE; /* truncate */
}
if (bsize<AKAI_PARTHEAD_BLKS){
PRINTF_ERR("invalid partition size\n");
return -1;
}
/* set disk blocksize */
dp->blksize=AKAI_HD_BLOCKSIZE;
/* disk size in blocks */
dp->bsize=dp->totsize/dp->blksize;
/* minimum harddisk sampler partition size */
if (cdromflag){
/* with min. CD-ROM info behind header */
bmin=AKAI_PARTHEAD_BLKS+AKAI_CDINFO_MINSIZB;
}else{
bmin=AKAI_PARTHEAD_BLKS;
}
/* Note: overwrite part[] */
bremain=totb;
bc=0; /* block counter */
for (pi=0;(pi<AKAI_PART_NUM)&&(pi<PART_NUM_MAX);){
if (bremain>bsize){
bchunk=bsize;
}else{
bchunk=bremain;
}
if (bchunk<bmin){
/* not enough for harddisk sampler partition */
break; /* done */
}
/* initialize partition */
part[pi].diskp=dp;
part[pi].valid=1;
part[pi].type=PART_TYPE_HD;
part[pi].index=pi;
part[pi].blksize=dp->blksize;
part[pi].bstart=bc;
part[pi].bsize=bchunk;
part[pi].bsyssize=AKAI_PARTHEAD_BLKS;
part[pi].fat=&part[pi].head.hd.fatblk[0];
part[pi].volnummax=AKAI_ROOTDIR_ENTRIES;
part[pi].letter='A'+pi;
pi++; /* created one */
bremain-=bchunk;
bc+=bchunk;
if (bremain==0){
break; /* done */
}
}
if (pi==0){
PRINTF_OUT("no partitions created\n");
return 0;
}
/* space for DD */
/* XXX check totb alignment to AKAI_DDPART_BLKS granularity */
bremain=dp->bsize-totb;
/* fix size */
bremain/=AKAI_DDPART_CBLKS; /* round down */
if (bremain>0){
bremain--; /* XXX */
}
bremain*=AKAI_DDPART_CBLKS;
if ((pi<PART_NUM_MAX)&&(bremain>0)){ /* space for DD left at end of disk? */
PRINTF_OUT("0x%04x blocks for DD at end of disk\n",bremain);
/* initialize one DD partition at end of disk */
part[pi].diskp=dp;
part[pi].valid=1;
part[pi].type=PART_TYPE_DD;
part[pi].index=pi;
part[pi].blksize=dp->blksize;
part[pi].bstart=totb;
part[pi].bsize=bremain;
part[pi].csize=bremain/AKAI_DDPART_CBLKS;
part[pi].fat=NULL;
part[pi].volnummax=0;
part[pi].letter=0;
pi++; /* created one */
}
/* now, all partitions known for partition table */
pimax=pi;
for (pi=0;pi<pimax;pi++){
/* wipe partition */
if (akai_wipe_part(&part[pi],1,&part[0],pimax,cdromflag)<0){ /* 1: wipe */
if (part[pi].type==PART_TYPE_DD){
if (part[pi].letter==0){
PRINTF_ERR("cannot wipe partition DD\n");
}else{
PRINTF_ERR("cannot wipe partition DD%u\n",(u_int)part[pi].letter);
}
}else{
PRINTF_ERR("cannot wipe partition %c\n",part[pi].letter);
}
return 1; /* fatal */
}
if ((part[pi].type==PART_TYPE_HD)&&s3000flag){
if (akai_rename_tag(&part[pi],NULL,0,1)<0){ /* 1: wipe */
PRINTF_ERR("cannot initialize tags in partition %c\n",part[pi].letter);
/* XXX ignore error */
}
}
#if 0 /* Note: must exit (or restart) anyway, no need to count free and bad blocks here */
akai_countfree_part(&part[pi]);
#endif
}
PRINTF_OUT("created %u partition(s)\n",pimax);
return 0;
}
/* Note: blksize might change, must flush prior to formatting!!! */
/* Note: overwrites part[] */
/* Note: must flush cache and exit (or restart) if return value >=0 !!! */
int
akai_wipe_harddisk9(struct disk_s *dp,u_int totb)
{
if (dp==NULL){
return -1;
}
/* S900 harddisk */
/* Note: overwrite part[] */
if (PART_NUM_MAX<1){
PRINTF_ERR("not enough partition space allocated\n");
return -1;
}
if (totb*AKAI_HD_BLOCKSIZE>dp->bsize*dp->blksize){
totb=(dp->bsize*dp->blksize)/AKAI_HD_BLOCKSIZE; /* truncate */
}
if (totb>AKAI_HD9_MAXSIZE){
totb=AKAI_HD9_MAXSIZE; /* truncate */
}
if (totb<AKAI_HD9HEAD_BLKS){
PRINTF_ERR("invalid size\n");
return -1;
}
/* set disk blocksize */
dp->blksize=AKAI_HD_BLOCKSIZE;
/* disk size in blocks */
dp->bsize=dp->totsize/dp->blksize;
/* Note: overwrite part[] */
/* initialize partition */
part[0].diskp=dp;
part[0].valid=1;
part[0].type=PART_TYPE_HD9;
part[0].index=0;
part[0].blksize=dp->blksize;
part[0].bstart=0;
part[0].bsize=totb;
part[0].bsyssize=AKAI_HD9HEAD_BLKS;
part[0].fat=&part[0].head.hd9.fatblk[0];
part[0].volnummax=AKAI_HD9ROOTDIR_ENTRIES;
part[0].letter='A'; /* fake partition letter */
/* wipe partition */
if (akai_wipe_part(&part[0],1,NULL,0,0)<0){ /* 1: wipe */
return 1; /* fatal */
}
#if 0 /* Note: must exit (or restart) anyway, no need to count free and bad blocks here */
akai_countfree_part(&part[0]);
#endif
return 0;
}
/* Note: blksize might change, must flush prior to formatting!!! */
/* Note: overwrites part[] */
/* Note: must flush cache and exit (or restart) if return value >=0 !!! */
int
akai_wipe_floppy(struct disk_s *dp,int lodensflag,int s3000flag,int s900flag)
{
struct akai_voldir3000fl_s tmpdir3000;
struct akai_flvol_label_s *lp;
u_int hdsiz;
u_int voldir3000bstart;
u_int i,imax;
u_int osver;
u_int fatcodesys;
if (dp==NULL){
return -1;
}
/* floppy */
/* Note: overwrite part[] */
if (PART_NUM_MAX<1){
PRINTF_ERR("not enough partition space allocated\n");
return -1;
}
if (((!lodensflag)&&(dp->bsize*dp->blksize<AKAI_FLH_SIZE*AKAI_FL_BLOCKSIZE))
||((lodensflag)&&(dp->bsize*dp->blksize<AKAI_FLL_SIZE*AKAI_FL_BLOCKSIZE))){
PRINTF_ERR("invalid disk size\n");
return -1;
}
/* set disk blocksize */
dp->blksize=AKAI_FL_BLOCKSIZE;
/* disk size in blocks */
dp->bsize=dp->totsize/dp->blksize;
/* floppy header */
if (lodensflag){
lp=&part[0].head.fll.label;
hdsiz=AKAI_FLLHEAD_BLKS;
voldir3000bstart=AKAI_VOLDIR3000FLL_BSTART; /* for S3000 */
}else{
lp=&part[0].head.flh.label;
hdsiz=AKAI_FLHHEAD_BLKS;
voldir3000bstart=AKAI_VOLDIR3000FLH_BSTART; /* for S3000 */
}
/* Note: low- and high-density floppy headers are identical */
/* up to first AKAI_FAT_ENTRIES_FLL FAT-entries */
/* => set files and system blocks in FAT in high-density header */
/* initialize partition */
part[0].diskp=dp;
part[0].valid=1;
if (lodensflag){
part[0].type=PART_TYPE_FLL;
}else{
part[0].type=PART_TYPE_FLH;
}
part[0].index=0;
part[0].blksize=dp->blksize;
part[0].bstart=0;
if (lodensflag){
part[0].bsize=AKAI_FLL_SIZE;
}else{
part[0].bsize=AKAI_FLH_SIZE;
}
/* Note: see comment above: FAT-start same for low- and high density */
part[0].fat=&part[0].head.flh.fatblk[0];
/* number of volumes */
part[0].volnummax=1;
/* fake partition letter */
part[0].letter='A';
/* wipe floppy header */
/* Note: high-density floppy header enough, also for low-density floppy case */
bzero(&part[0].head.flh,sizeof(struct akai_flhhead_s));
/* OS version */
if (s3000flag){
/* S3000 */
osver=AKAI_OSVER_S3000MAX; /* XXX */
}else if (s900flag){
/* S900 */
osver=AKAI_OSVER_S900VOL;
}else{
/* S1000 */
osver=AKAI_OSVER_S1000MAX; /* XXX */
}
lp->osver[1]=0xff&(osver>>8);
lp->osver[0]=0xff&osver;
/* wipe S900/S1000 volume directory */
for (i=0;i<AKAI_VOLDIR_ENTRIES_S1000FL;i++){
akai_fvol1000_initfile(&part[0].head.flh.file[i],osver,
s3000flag?AKAI_FILE_TAGFREE:AKAI_FILE_TAGS1000);
}
if (s3000flag){
/* mark S3000 floppy */
part[0].head.flh.file[0].type=AKAI_VOLDIR3000FL_FTYPE;
}
if (!s900flag){
/* S1000/S3000 */
/* default volume name */
ascii2akai_name("NOT NAMED ",lp->name,0); /* 0: not S900 */
/* default volume parameters */
akai_init_volparam(&lp->param,s3000flag);
}
/* allocate blocks in FAT */
if (s900flag){
/* S900 */
fatcodesys=AKAI_FAT_CODE_SYS900FL;
}else{
/* S1000/S3000 */
fatcodesys=AKAI_FAT_CODE_SYS;
}
imax=hdsiz; /* floppy header */
if (s3000flag){
/* S3000 volume directory is directly behind floppy header */
imax+=AKAI_VOLDIR3000FL_BLKS;
}
for (i=0;i<imax;i++){
part[0].fat[i][1]=0xff&(fatcodesys>>8);
part[0].fat[i][0]=0xff&fatcodesys;
}
/* reserved blocks for system */
part[0].bsyssize=imax;
/* write floppy header */
if (akai_io_blks(&part[0],(u_char *)&part[0].head.flh,
0,
hdsiz,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return 1; /* fatal */
}
if (s3000flag){
/* wipe S3000 volume directory */
bzero(&tmpdir3000,sizeof(struct akai_voldir3000fl_s));
for (i=0;i<AKAI_VOLDIR_ENTRIES_S3000FL;i++){
tmpdir3000.file[i].type=AKAI_FTYPE_FREE;
}
/* write S3000 volume directory */
if (akai_io_blks(&part[0],(u_char *)&tmpdir3000,
voldir3000bstart,
AKAI_VOLDIR3000FL_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
return 1; /* fatal */
}
}
#if 0 /* Note: must exit (or restart) anyway, no need to count free and bad blocks here */
akai_countfree_part(&part[0]);
#endif
return 0;
}
/* XXX no check for recursion overflow */
int
change_curdir(char *name,u_int vi,char *lastname,int checklast)
{
/* Note: variables below must be auto, for recursion!!! */
char namebuf[DIRNAMEBUF_LEN+1]; /* +1 for '\0' */
u_int l;
u_int i;
int j;
char *np0,*np1;
struct disk_s *tmpcurdiskp;
struct part_s *tmpcurpartp;
struct vol_s *tmpcurvolp;
struct vol_s tmpcurvol_buf; /* change_curdir does not modify directories => OK to save and restore buffer */
int ret;
/* save state, needed in case of error */
tmpcurdiskp=curdiskp;
tmpcurpartp=curpartp;
tmpcurvolp=curvolp;
if (curvolp!=NULL){ /* need to save? */
tmpcurvol_buf=*curvolp; /* !!! */
/* Note: save original, to be restored later on, copy not to be used!!! */
}
ret=0; /* no error so far */
np0=namebuf; /* first token */
np1=NULL; /* no recursion so far */
if (name==NULL){
/* must be in partition */
if ((curpartp==NULL)||(curvolp!=NULL)){
ret=-1;
goto change_curdir_done;
}
/* user-supplied volume index */
if (vi>=curpartp->volnummax){
ret=-1;
goto change_curdir_done;
}
if (akai_get_vol(curpartp,&curvol_buf,vi)<0){ /* not found? */
ret=-1;
goto change_curdir_done;
}
curvolp=&curvol_buf;
goto change_curdir_done;
}
/* copy name for possible manupulation */
strncpy(namebuf,name,DIRNAMEBUF_LEN);
namebuf[DIRNAMEBUF_LEN]='\0'; /* just in case */
/* check if absolute path */
if (np0[0]=='/'){
/* goto system level */
curdiskp=NULL;
curpartp=NULL;
curvolp=NULL;
np0++; /* '\0' in worst case */
}
l=(u_int)strlen(np0);
/* search first delimiter */
for (i=0;i<l;i++){
if (np0[i]=='/'){
break;
}
}
if (i<l){ /* found one? */
/* separate strings */
np0[i]='\0';
np1=&np0[i+1]; /* '\0' in worst case, since i<l */
/* Note: np1 must not be absolute path again!!! */
if (np1[0]=='/'){ /* first char again delimiter? */
ret=-1;
goto change_curdir_done;
}
/* take care of np1 below */
}
/* now, np0 contains only one hirarchy level, but not the last one if np1!=NULL */
if ((np1==NULL)&&(lastname!=NULL)){ /* is last hirarchy level and want to extract it? */
/* Note: in particular if l==0, we end up here (for lastname!=NULL) */
/* XXX no overflow check in strcpy */
strcpy(lastname,np0);
goto change_curdir_done;
}
/* Note: checklast irrelevant if lastname!=NULL */
/* now, change current directory */
if (l==0){
/* Note: we do not search for disk, partition, or volume with empty name */
/* nothing to do */
goto change_curdir_done; /* done */
}
if (strcmp(np0,".")==0){
/* nothing to do */
goto change_curdir_done;
}
if (strcmp(np0,"..")==0){
/* one level up */
if (curdiskp==NULL){
/* nothing to do */
goto change_curdir_done;
}
if (curpartp==NULL){
curdiskp=NULL;
goto change_curdir_done;
}
if (curvolp==NULL){
curpartp=NULL;
goto change_curdir_done;
}
curvolp=NULL;
goto change_curdir_done;
}
if (curdiskp==NULL){
#if 1
if (strncasecmp(np0,"floppy",6)==0){
np0+=6;
/* find floppy */
if (strlen(np0)==0){ /* empty? */
/* "/floppy" -> "/disk0/A/<volume1>" */
j=0; /* disk0 */
}else{
/* "/floppyN" -> "/diskN/A/<volume1>" */
j=atoi(np0);
}
/* find disk */
if ((j<0)||(j>=(int)disk_num)){
PRINTF_ERR("invalid disk\n");
ret=-1;
goto change_curdir_done;
}
curdiskp=&disk[j];
/* find partition */
curpartp=akai_find_part(curdiskp,"A");
if (curpartp==NULL){ /* not found? */
ret=-1;
goto change_curdir_done;
}
if ((np1!=NULL)||checklast){ /* not last or need to check last? */
if (!curpartp->valid){
PRINTF_ERR("invalid partition\n");
ret=-1;
goto change_curdir_done;
}
if ((curpartp->type!=PART_TYPE_FLL)&&(curpartp->type!=PART_TYPE_FLH)){
PRINTF_OUT("disk%i is not a floppy\n",j);
ret=-1;
goto change_curdir_done;
}
}
/* get volume1 (volume index 0) */
if (akai_get_vol(curpartp,&curvol_buf,0)<0){ /* not found? */
PRINTF_ERR("invalid volume\n");
ret=-1;
goto change_curdir_done;
}
curvolp=&curvol_buf; /* only this one!!! */
goto change_curdir_done;
}
#endif
/* find disk */
if (strncasecmp(np0,"disk",4)==0){
np0+=4;
}
if (strlen(np0)==0){ /* empty? */
ret=-1;
goto change_curdir_done;
}
j=atoi(np0);
if ((j<0)||(j>=(int)disk_num)){
PRINTF_ERR("invalid disk\n");
ret=-1;
goto change_curdir_done;
}
curdiskp=&disk[j];
goto change_curdir_done;
}
if (curpartp==NULL){
/* find partition */
curpartp=akai_find_part(curdiskp,np0);
if (curpartp==NULL){ /* not found? */
ret=-1;
goto change_curdir_done;
}
if ((np1!=NULL)||checklast){ /* not last or need to check last? */
if (!curpartp->valid){
PRINTF_ERR("invalid partition\n");
ret=-1;
goto change_curdir_done;
}
}
goto change_curdir_done;
}
if (curvolp==NULL){
if (curpartp->type==PART_TYPE_DD){
PRINTF_OUT("no volumes in DD partition\n");
ret=-1;
goto change_curdir_done;
}
/* find volume */
if (akai_find_vol(curpartp,&curvol_buf,np0)<0){ /* not found? */
ret=-1;
goto change_curdir_done;
}
/* Note: akai_find_volume has checked for AKAI_VOL_TYPE_INACT */
curvolp=&curvol_buf; /* only this one!!! */
goto change_curdir_done;
}
/* no further directories */
ret=-1;
goto change_curdir_done;
change_curdir_done:
if ((ret==0)&&(np1!=NULL)){ /* recursion requested? */
ret=change_curdir(np1,vi,lastname,checklast); /* recursion */
}
if (ret<0){
/* error, must restore state */
curdiskp=tmpcurdiskp;
curpartp=tmpcurpartp;
curvolp=tmpcurvolp;
if (curvolp!=NULL){ /* was saved? */
*curvolp=tmpcurvol_buf; /* !!! */
/* Note: restore orginal from copy!!! */
}
}
return ret;
}
int
change_curdir_home(void)
{
/* goto system level */
curdiskp=NULL;
curpartp=NULL;
curvolp=NULL;
if (disk_num==1){
/* goto first disk */
curdiskp=&disk[0];
if ((part_num==1)&&part[0].valid){
if (((part[0].type==PART_TYPE_FLL)||(part[0].type==PART_TYPE_FLH))){
/* goto floppy volume */
return change_curdir("/floppy",0,NULL,1); /* NULL,1: check last */
}else if (part[0].type==PART_TYPE_HD9){
/* goto fake partition A */
return change_curdir("A",0,NULL,1); /* NULL,1: check last */
}
}
}
return 0;
}
void
save_curdir(int modflag)
{
savecurdiskp=curdiskp;
savecurpartp=curpartp;
savecurvolp=curvolp;
if (!modflag){
/* will not modify volumes => OK to save and restore buffer */
savecurvol_buf=curvol_buf;
}else{
/* save name */
if (curvolp!=NULL){
strcpy(savecurvolname,curvolp->name);
/* save index for case of empty volume name */
savecurvolindex=curvolp->index;
}
}
savecurvolmodflag=modflag;
}
void
restore_curdir(void)
{
char *np;
/* Note: OS keeps track of changes, no need to reload */
curdiskp=savecurdiskp;
/* Note: part[] keeps track of changes, no need to reload */
curpartp=savecurpartp;
if ((curpartp!=NULL)&&(curpartp->valid==0)){
/* could happen */
/* goto disk */
curpartp=NULL;
savecurvolp=NULL;
savecurvolmodflag=0;
PRINTF_OUT("partition has changed, now in upper disk\n");
/* XXX just stay in partition */
}
/* Note: only one volume buffer, saved contents might be out-of-date (e.g. rename, delete, create)!!! */
curvolp=savecurvolp;
if (!savecurvolmodflag){
/* has not modified volumes => OK to save and restore buffer */
curvol_buf=savecurvol_buf;
}else{
/* volume buffer could be out-of-date, must reload */
if (curvolp!=NULL){
curvolp=NULL; /* goto partition */
if (savecurvolname[0]=='\0'){ /* empty volume name? */
np=NULL; /* => change_curdir() below will use savecurvolindex */
}else{
np=savecurvolname; /* => change_curdir() below will use savecurvolname */
}
if (change_curdir(np,savecurvolindex,NULL,1)<0){ /* 1: check */
/* could happen */
PRINTF_OUT("volume has changed, now in upper partition\n");
/* XXX just stay in partition */
}
}
}
}
void
curdir_info(int verbose,char *pathbuf)
{
static char tmppathbuf[DIRNAMEBUF_LEN+1]; /* +1 for '\0' */
int pathprintflag;
u_int pathlen;
struct vol_s tmpvol;
u_int vi;
u_int ai;
if (pathbuf==NULL){
pathbuf=tmppathbuf;
pathprintflag=1;
}else{
pathprintflag=verbose;
}
sprintf(pathbuf,"/");
if (curdiskp!=NULL){
pathlen=1;
sprintf(pathbuf+pathlen,"disk%u",curdiskp->index);
if (curpartp!=NULL){
pathlen=(u_int)strlen(pathbuf);
if (curpartp->type==PART_TYPE_DD){
if (curpartp->letter==0){
sprintf(pathbuf+pathlen,"/DD");
}else{
sprintf(pathbuf+pathlen,"/DD%u",(u_int)curpartp->letter);
}
}else{
sprintf(pathbuf+pathlen,"/%c",curpartp->letter);
}
if (curvolp!=NULL){
pathlen=(u_int)strlen(pathbuf);
sprintf(pathbuf+pathlen,"/%s",curvolp->name);
}
}
}
if (pathprintflag){
PRINTF_OUT("%s",pathbuf);
}
if (verbose){
PRINTF_OUT("\n");
if (curvolp!=NULL){
ai=0; /* volume alias number unknown */
if ((curpartp!=NULL)&&(curpartp->type==PART_TYPE_HD9)){
/* S900 harddisk */
/* determine volume alias number */
ai=1; /* start number */
/* add number of active volumes in partition before current volume */
for (vi=0;(vi<curvolp->index)&&(vi<curpartp->volnummax);vi++){
/* try to get volume */
if (akai_get_vol(curpartp,&tmpvol,vi)<0){
continue; /* next volume */
}
ai++; /* one more active volume */
}
}
akai_vol_info(curvolp,ai,1); /* 1: verbose */
}else if (curpartp!=NULL){
akai_part_info(curpartp,1); /* 1: verbose */
}else if (curdiskp!=NULL){
akai_disk_info(curdiskp,1); /* 1: verbose */
}else{
PRINTF_OUT("disks: %u\n",disk_num);
}
}
}
void
list_curdir(int recflag)
{
if (curdiskp==NULL){
akai_list_alldisks(recflag,curfiltertag);
return;
}
if (curpartp==NULL){
akai_list_disk(curdiskp,recflag,curfiltertag);
return;
}
if (curvolp==NULL){
akai_list_part(curpartp,recflag,curfiltertag);
return;
}
akai_list_vol(curvolp,curfiltertag);
}
void
list_curfiltertags(void)
{
u_int i;
u_int noneflag;
PRINTF_OUT("filter tags: ");
noneflag=1; /* none so far */
for (i=0;i<AKAI_FILE_TAGNUM;i++){
if ((curfiltertag[i]!=AKAI_FILE_TAGFREE)&&(curfiltertag[i]!=AKAI_FILE_TAGS1000)){ /* not free? */
PRINTF_OUT("%02u ",curfiltertag[i]);
noneflag=0;
}
}
if (noneflag){
PRINTF_OUT("none");
}
PRINTF_OUT("\n");
}
int
copy_file(struct file_s *srcfp,struct vol_s *dstvp,struct file_s *dstfp,u_int dstindex,char *dstname,int delflag)
{
struct file_s tmpfile;
u_char *tmpbuf;
int existsflag;
if ((srcfp==NULL)||(dstvp==NULL)){
return -1;
}
if (dstname==NULL){ /* no user-supplied name? */
dstname=srcfp->name;
}
/* allocate buffer */
if ((tmpbuf=(u_char *)malloc(srcfp->size))==NULL){
PERROR("malloc");
return -1;
}
/* check if destination file already exists */
existsflag=0;
if (dstindex==AKAI_CREATE_FILE_NOINDEX){ /* no user-supplied index? */
/* check if file name already used in destination volume */
if (akai_find_file(dstvp,&tmpfile,dstname)==0){
existsflag=1;
}
}else{
/* check if file with given index already exists in destination volume */
if (akai_get_file(dstvp,&tmpfile,dstindex)==0){
existsflag=1;
}
}
if (existsflag){
/* same file? Note: same partition and same block should be unique */
if ((srcfp->volp->partp==tmpfile.volp->partp)&&(srcfp->bstart==tmpfile.bstart)){
PRINTF_ERR("cannot copy to same file\n");
free(tmpbuf);
return -1;
}
/* exists */
if (delflag){
/* delete file */
if (akai_delete_file(&tmpfile)<0){
PRINTF_ERR("cannot overwrite existing file\n");
free(tmpbuf);
return -1;
}
}else{
PRINTF_OUT("file name already used\n");
free(tmpbuf);
return -1;
}
}
/* create file */
/* Note: akai_create_file() will correct osver if necessary */
if (akai_create_file(dstvp,&tmpfile,srcfp->size,dstindex,dstname,
srcfp->osver, /* default: from source file */
(srcfp->volp->type==AKAI_VOL_TYPE_S900)?NULL:srcfp->tag)<0){ /* no tags from S900 */
PRINTF_ERR("cannot create file\n");
free(tmpbuf);
return -1;
}
if (dstfp!=NULL){
/* copy for information */
*dstfp=tmpfile;
}
/* read file */
if (akai_read_file(0,tmpbuf,srcfp,0,srcfp->size)<0){
PRINTF_OUT("read error\n");
free(tmpbuf);
return -1;
}
/* write file */
if (akai_write_file(0,tmpbuf,&tmpfile,0,tmpfile.size)<0){
PRINTF_OUT("write error\n");
free(tmpbuf);
return -1;
}
free(tmpbuf);
return 0;
}
int
copy_vol_allfiles(struct vol_s *srcvp,struct part_s *dstpp,char *dstname,int delflag,int verbose)
{
struct vol_s tmpvol;
struct file_s tmpfile;
u_int fi;
if ((srcvp==NULL)||(dstpp==NULL)){
return -1;
}
if (dstpp->type==PART_TYPE_DD){
return -1;
}
if (dstname==NULL){ /* no user-supplied name? */
dstname=srcvp->name;
}
/* check if destination volume already exists */
if (akai_find_vol(dstpp,&tmpvol,dstname)<0){
/* does not exist (or error in finding it, don't care) */
/* create volume */
if (akai_create_vol(dstpp,&tmpvol,
srcvp->type,
AKAI_CREATE_VOL_NOINDEX,
dstname,
srcvp->lnum,
srcvp->param)<0){
PRINTF_ERR("cannot create destination volume\n");
return -1;
}
}else{
/* volume already exists */
/* copy load number and volume parameters */
if (akai_rename_vol(&tmpvol,NULL,
srcvp->lnum,
srcvp->osver,
srcvp->param)<0){
PRINTF_ERR("cannot update volume\n");
return -1;
}
}
/* same volume? Note: same partition and same block should be unique */
if ((srcvp->partp==tmpvol.partp)&&(srcvp->dirblk[0]==tmpvol.dirblk[0])){
PRINTF_ERR("cannot copy into same volume\n");
return -1;
}
/* files in volume directory */
for (fi=0;fi<srcvp->fimax;fi++){
/* get source file */
if (akai_get_file(srcvp,&tmpfile,fi)<0){
continue; /* next file */
}
if (verbose>0){
if (verbose>1){
PRINTF_OUT("%s/",srcvp->name);
}
PRINTF_OUT("%s\n",tmpfile.name);
}
if (copy_file(&tmpfile,&tmpvol,NULL,AKAI_CREATE_FILE_NOINDEX,NULL,delflag)<0){
return -1;
}
}
return 0;
}
int
copy_part_allvols(struct part_s *srcpp,struct part_s *dstpp,int delflag,int verbose)
{
u_int vi;
struct vol_s tmpvol;
if ((srcpp==NULL)||(dstpp==NULL)){
return -1;
}
if ((srcpp->type==PART_TYPE_DD)||(dstpp->type==PART_TYPE_DD)){
return -1;
}
/* same partition? Note: partition pointer is unique */
if (srcpp==dstpp){
PRINTF_ERR("cannot copy into same partition\n");
return -1;
}
/* volumes in root directory */
for (vi=0;(vi<srcpp->volnummax)&&(vi<dstpp->volnummax);vi++){
/* get volume */
if (akai_get_vol(srcpp,&tmpvol,vi)<0){
continue; /* next volume */
}
if (verbose>1){
PRINTF_OUT("%s/\n",tmpvol.name);
}
/* copy all files in volume */
if (copy_vol_allfiles(&tmpvol,dstpp,NULL,delflag,verbose)<0){
return -1;
}
}
return 0;
}
int
check_curnosamplervol(void)
{
if (curdiskp==NULL){ /* no disk? */
return 1;
}
if (curpartp==NULL){ /* no partition? */
return 1;
}
#if 1
/* XXX actually, curvolp==NULL should suffice */
if (curpartp->type==PART_TYPE_DD){ /* DD partition? */
return 1;
}
#endif
if (curvolp==NULL){ /* no sampler volume? */
return 1;
}
/* now, inside a sampler volume */
return 0;
}
int
check_curnosamplerpart(void)
{
if (curdiskp==NULL){ /* no disk? */
return 1;
}
if (curpartp==NULL){ /* no partition? */
return 1;
}
if (curpartp->type==PART_TYPE_DD){ /* DD partition? */
return 1;
}
if (curvolp!=NULL){ /* sampler volume? */
return 1;
}
/* now, on sampler partition level */
return 0;
}
int
check_curnoddpart(void)
{
if (curdiskp==NULL){ /* no disk? */
return 1;
}
if (curpartp==NULL){ /* no partition? */
return 1;
}
if (curpartp->type!=PART_TYPE_DD){ /* no DD partition? */
return 1;
}
/* now, on DD partition level */
return 0;
}
int
check_curnopart(void)
{
if (curdiskp==NULL){ /* no disk? */
return 1;
}
if (curpartp==NULL){ /* no partition? */
return 1;
}
if (curvolp!=NULL){ /* sampler volume? */
return 1;
}
/* now, on partition level (sampler or DD) */
return 0;
}
/* EOF */