Files
akai-utils/third_party/akaiutil/akaiutil_tar.c
T
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

1236 lines
34 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"
#include "akaiutil_tar.h"
u_int
tar_checksum(u_char *hp)
{
u_int sum;
u_int i;
int zeroflag;
if (hp==NULL){
return 0;
}
sum=0;
zeroflag=1; /* still all zeroes */
for (i=0;i<sizeof(struct tar_head_s);i++){
if (hp[i]!=0){
zeroflag=0;
}
if ((i>=148)&&(i<156)){ /* treat chksum field */
sum+=(u_int)' '; /* space */
}else{
sum+=(u_int)hp[i];
}
}
/* Note: sum is always >0 !!! */
if (zeroflag){
sum=0; /* unique value, see comment above */
}
return sum;
}
int
tar_export(int fd,struct disk_s *dp,struct part_s *pp,struct vol_s *vp,struct file_s *fp,u_int ti,u_int flags,int verbose,u_char *filtertagp)
{
struct tar_head_s tarhd;
u_int chksum;
u_int size;
u_int n;
u_char buf[TAR_BLOCKSIZE];
int wavret;
char *wavname;
int wavconvflag;
/* DD take */
u_int ddcstarts,ddcstarte;
u_int ddcsizes,ddcsizee;
struct akai_ddtake_s ddt;
if (fd<0){
return -1;
}
if ((flags&(TAR_EXPORT_DISK|TAR_EXPORT_PART|TAR_EXPORT_VOL|TAR_EXPORT_ANYFILE))==0){
return -1;
}
size=0;
ddcstarts=0;
ddcstarte=0;
ddcsizes=0;
ddcsizee=0;
wavconvflag=0;
/* create tar header */
bzero(&tarhd,sizeof(struct tar_head_s));
/* name */
/* XXX should always fit */
if (flags&TAR_EXPORT_DISK){
/* disk */
if (dp==NULL){
return -1;
}
sprintf(tarhd.name,"disk%u/",dp->index);
}
if (flags&TAR_EXPORT_PART){
/* partition */
if (pp==NULL){
return -1;
}
if (pp->type==PART_TYPE_DD){
/* harddisk DD partition */
if (pp->letter==0){
sprintf(tarhd.name+strlen(tarhd.name),"DD/");
}else{
sprintf(tarhd.name+strlen(tarhd.name),"DD%u/",(u_int)pp->letter);
}
}else{
/* sampler partition */
sprintf(tarhd.name+strlen(tarhd.name),"%c/",pp->letter);
}
}
if (flags&TAR_EXPORT_VOL){
/* sampler volume */
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)){
return -1;
}
sprintf(tarhd.name+strlen(tarhd.name),"%s/",vp->name);
if ((flags&TAR_EXPORT_ANYFILE)==0){ /* not a file? */
/* XXX use devmajor field for type */
sprintf(tarhd.devmajor,"%07o",vp->type);
/* XXX use devminor field for load number */
sprintf(tarhd.devminor,"%07o",vp->lnum);
#ifndef TAR_NOVOLPARAMTARHD
if (vp->param!=NULL){
/* XXX use linkname for volume parameters */
tarhd.linkname[0]='\0'; /* XXX magic, also empty linkname string */
tarhd.linkname[1]='P'; /* XXX magic */
bcopy(vp->param,
&tarhd.linkname[0]+2, /* XXX +2: linkname starts with magic */
sizeof(struct akai_volparam_s)); /* XXX should fit */
}
#endif
}
}
if (flags&TAR_EXPORT_DDFILE){
/* DD take */
if (flags&TAR_EXPORT_WAV){
wavret=akai_take2wav(pp,ti,fd,&size,&wavname,TAKE2WAV_CHECK);
if (wavret<0){ /* error? */
#if 1
return 0; /* skip this file w/o error */
#else
return -1;
#endif
}
strcpy(tarhd.name+strlen(tarhd.name),wavname);
wavconvflag=1;
}
if (!wavconvflag){
char fnamebuf[AKAI_NAME_LEN+4+1]; /* name (ASCII), +4 for ".<type>", +1 for '\0' */
/* index */
if (ti>=AKAI_DDTAKE_MAXNUM){
return 0; /* skip this file w/o error */
}
if (pp->head.dd.take[ti].stat==AKAI_DDTAKESTAT_FREE){ /* free? */
return 0; /* skip this file w/o error */
}
/* clusters */
ddcstarts=(pp->head.dd.take[ti].cstarts[1]<<8)
+pp->head.dd.take[ti].cstarts[0];
ddcstarte=(pp->head.dd.take[ti].cstarte[1]<<8)
+pp->head.dd.take[ti].cstarte[0];
/* determine csizes (sample clusters) and csizee (envelope clusters) */
if (ddcstarts!=0){ /* sample not empty? */
ddcsizes=akai_count_ddfatchain(pp,ddcstarts);
}else{
ddcsizes=0;
}
if (ddcstarte!=0){ /* envelope not empty? */
ddcsizee=akai_count_ddfatchain(pp,ddcstarte);
}else{
ddcsizee=0;
}
/* name */
akai2ascii_name(pp->head.dd.take[ti].name,fnamebuf,0); /* 0: not S900 */
strcpy(fnamebuf+strlen(fnamebuf),AKAI_DDTAKE_FNAMEEND);
strcpy(tarhd.name+strlen(tarhd.name),fnamebuf);
/* get DD take header (DD directory entry) */
bcopy(&pp->head.dd.take[ti],&ddt,sizeof(struct akai_ddtake_s));
/* XXX use cstarts/cstarte fields in DD take header for csizes/csizee */
ddt.cstarts[1]=0xff&(ddcsizes>>8);
ddt.cstarts[0]=0xff&ddcsizes;
ddt.cstarte[1]=0xff&(ddcsizee>>8);
ddt.cstarte[0]=0xff&ddcsizee;
/* size in bytes */
size=sizeof(struct akai_ddtake_s)+(ddcsizes+ddcsizee)*AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE;
}
}
if (flags&TAR_EXPORT_FILE){
/* sampler file */
if ((fp==NULL)||(fp->type==AKAI_FTYPE_FREE)){
return -1;
}
/* test if tag-filter matches */
if (akai_match_filetags(filtertagp,fp->tag)<0){ /* no match? */
return 0; /* skip this file w/o error */
}
if (flags&TAR_EXPORT_WAV){
wavret=akai_sample2wav(fp,fd,&size,&wavname,SAMPLE2WAV_CHECK);
if (wavret<0){ /* error? */
#if 1
return 0; /* skip this file w/o error */
#else
return -1;
#endif
}
if (wavret==0){
/* file is a valid sample file */
strcpy(tarhd.name+strlen(tarhd.name),wavname);
wavconvflag=1;
} /* else: file is not a sample file, export without WAV conversion */
}
if (!wavconvflag){
strcpy(tarhd.name+strlen(tarhd.name),fp->name);
size=fp->size;
}
/* XXX use devmajor field for osver */
if (wavconvflag&&(fp->type==AKAI_SAMPLE900_FTYPE)){ /* WAV conversion of S900 sample file? */
/* WAV is non-compressed, must use osver for S900 non-compressed sample format */
sprintf(tarhd.devmajor,"%07o",AKAI_OSVER_S900VOL); /* XXX */
}else{
sprintf(tarhd.devmajor,"%07o",fp->osver); /* XXX */
}
if ((fp->volp!=NULL)
&&((fp->volp->type==AKAI_VOL_TYPE_S3000)||(fp->volp->type==AKAI_VOL_TYPE_CD3000))){
/* XXX use linkname for file tags */
tarhd.linkname[0]='\0'; /* XXX magic, also empty linkname string */
tarhd.linkname[1]='T'; /* XXX magic */
bcopy(fp->tag,
&tarhd.linkname[0]+2, /* XXX +2: linkname starts with magic */
AKAI_FILE_TAGNUM); /* XXX should fit */
}
}
#ifndef TAR_NOTAGSFILE
#ifndef TAR_TAGSFILENAME
#define TAR_TAGSFILENAME "TAGS.DAT"
#endif
if (flags&TAR_EXPORT_TAGSFILE){
/* tags-file */
if ((pp==NULL)||(pp->type!=PART_TYPE_HD) /* not in S1000/S3000 harddisk partition on partition level? */
||(strncmp(AKAI_PARTHEAD_TAGSMAGIC,(char *)pp->head.hd.tagsmagic,4)!=0)){
#if 1
return 0; /* skip this file w/o error */
#else
return -1;
#endif
}
strcpy(tarhd.name+strlen(tarhd.name),TAR_TAGSFILENAME);
size=4+AKAI_PARTHEAD_TAGNUM*AKAI_NAME_LEN; /* tags magic and tag names */;
}
#endif
#ifndef TAR_NOVOLPARAMFILE
#ifndef TAR_VOLPARAMFILENAME
#define TAR_VOLPARAMFILENAME "VOLPARAM.DAT"
#endif
if (flags&TAR_EXPORT_VOLPARAMFILE){
/* volparam-file */
if ((vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)||(vp->param==NULL)){
#if 1
return 0; /* skip this file w/o error */
#else
return -1;
#endif
}
strcpy(tarhd.name+strlen(tarhd.name),TAR_VOLPARAMFILENAME);
size=sizeof(struct akai_volparam_s);
}
#endif
if (verbose){
PRINTF_OUT("%s\n",tarhd.name);
FLUSH_ALL;
}
/* mode, uid, gid */
if (flags&TAR_EXPORT_ANYFILE){ /* file? */
sprintf(tarhd.mode,"%07o",0600); /* XXX -rw------- */
}else{
/* directory */
sprintf(tarhd.mode,"%07o",0700); /* XXX -rwx------ */
}
sprintf(tarhd.uid,"%07o",0); /* XXX */
sprintf(tarhd.gid,"%07o",0); /* XXX */
/* size */
sprintf(tarhd.size,"%011o",size);
/* mtime */
sprintf(tarhd.mtime,"%011o",(u_int)time(NULL)); /* XXX */
/* space */
tarhd.space=' ';
/* type */
if (flags&TAR_EXPORT_ANYFILE){ /* file? */
tarhd.type=TAR_TYPE_REG;
}else{
/* directory */
tarhd.type=TAR_TYPE_DIR;
}
/* magic */
bcopy(TAR_USTAR,tarhd.ustar,8);
/* user name */
#ifndef TAR_UNAME
#define TAR_UNAME "AKAI"
#endif
strcpy(tarhd.uname,TAR_UNAME);
/* group name */
#ifndef TAR_GNAME
#define TAR_GNAME "AKAI"
#endif
strcpy(tarhd.gname,TAR_GNAME);
/* checksum */
chksum=tar_checksum((u_char *)&tarhd);
sprintf(tarhd.chksum,"%06o",chksum);
/* write tar header */
if (WRITE(fd,(void *)&tarhd,sizeof(struct tar_head_s))!=sizeof(struct tar_head_s)){
PRINTF_ERR("cannot write tar header\n");
return -1;
}
if ((flags&TAR_EXPORT_ANYFILE)==0){ /* not a file? */
return 0; /* done */
}
if (flags&TAR_EXPORT_DDFILE){
/* export DD take */
if (wavconvflag){
if (akai_take2wav(pp,ti,fd,NULL,NULL,SAMPLE2WAV_EXPORT)<0){
return -1;
}
}else{
if (akai_export_take(fd,pp,&ddt,ddcsizes,ddcsizee,ddcstarts,ddcstarte)<0){
PRINTF_ERR("cannot export take\n");
return -1;
}
}
}
if (flags&TAR_EXPORT_FILE){
/* export sampler file */
if (wavconvflag){
if (akai_sample2wav(fp,fd,NULL,NULL,SAMPLE2WAV_EXPORT)<0){
return -1;
}
}else{
if (akai_read_file(fd,NULL,fp,0,fp->size)<0){
return -1;
}
}
}
#ifndef TAR_NOTAGSFILE
if (flags&TAR_EXPORT_TAGSFILE){
/* export tags-file */
if (WRITE(fd,(void *)pp->head.hd.tagsmagic,size)!=(int)size){
PRINTF_ERR("cannot export tags-file\n");
return -1;
}
}
#endif
#ifndef TAR_NOVOLPARAMFILE
if (flags&TAR_EXPORT_VOLPARAMFILE){
/* export volparam-file */
if (WRITE(fd,(void *)vp->param,size)!=(int)size){
PRINTF_ERR("cannot export volparam-file\n");
return -1;
}
}
#endif
/* fill rest of TAR_BLOCKSIZE bytes */
n=size%TAR_BLOCKSIZE;
n=(TAR_BLOCKSIZE-n)%TAR_BLOCKSIZE;
if (n>0){
bzero(buf,n);
/* write */
if (WRITE(fd,(void *)buf,n)!=(int)n){
PRINTF_ERR("cannot write rest of block\n");
return -1;
}
}
return 0;
}
int
tar_export_vol(int fd,struct vol_s *vp,u_int flags,int verbose,u_char *filtertagp)
{
u_int fi;
struct file_s tmpfile; /* current file */
if ((fd<0)||(vp==NULL)||(vp->type==AKAI_VOL_TYPE_INACT)||(vp->partp==NULL)||(!vp->partp->valid)){
return -1;
}
#ifndef TAR_NOVOLPARAMFILE
if (vp->param!=NULL){
/* export volparam-file */
if (tar_export(fd,vp->partp->diskp,vp->partp,vp,NULL,0,flags|TAR_EXPORT_VOLPARAMFILE,verbose,NULL)){
return -1;
}
}
#endif
/* files in volume directory */
for (fi=0;fi<vp->fimax;fi++){
/* get file */
if (akai_get_file(vp,&tmpfile,fi)<0){
continue; /* XXX ignore error, next file */
}
#if 1
if (akai_check_fatblk(tmpfile.bstart,vp->partp->bsize,vp->partp->bsyssize)<0){ /* invalid? */
if (verbose){
PRINTF_OUT("file %u has invalid start block, skipping file\n",tmpfile.index+1);
FLUSH_ALL;
}
continue; /* XXX ignore error, next file */
}
#endif
/* export [part/volume/]file */
if (tar_export(fd,vp->partp->diskp,vp->partp,vp,&tmpfile,0,flags|TAR_EXPORT_FILE,verbose,filtertagp)){
return -1;
}
}
return 0;
}
int
tar_export_part(int fd,struct part_s *pp,u_int flags,int verbose,u_char *filtertagp)
{
u_int vi;
struct vol_s tmpvol; /* current volume */
if ((fd<0)||(pp==NULL)||(!pp->valid)){
return -1;
}
if (pp->type==PART_TYPE_DD){
/* harddisk DD partition */
/* export all DD takes */
u_int ti;
for (ti=0;ti<AKAI_DDTAKE_MAXNUM;ti++){
if (pp->head.dd.take[ti].stat==AKAI_DDTAKESTAT_FREE){ /* free? */
continue; /* next */
}
if (tar_export(fd,pp->diskp,pp,NULL,NULL,ti,flags|TAR_EXPORT_DDFILE,verbose,filtertagp)){
return -1;
}
}
}
/* now, sampler partition */
#ifndef TAR_NOTAGSFILE
if (pp->type==PART_TYPE_HD){ /* in S1000/S3000 harddisk partition? */
/* export tags-file */
/* Note: tar_export() will check for valid tags magic */
if (tar_export(fd,pp->diskp,pp,NULL,NULL,0,flags|TAR_EXPORT_TAGSFILE,verbose,NULL)){
return -1;
}
}
#endif
/* volumes in root directory of partition */
for (vi=0;vi<pp->volnummax;vi++){
/* get volume */
if (akai_get_vol(pp,&tmpvol,vi)<0){
continue; /* XXX ignore error, next volume */
}
if ((tmpvol.type!=AKAI_VOL_TYPE_S900)
&&(tmpvol.type!=AKAI_VOL_TYPE_S1000)
&&(tmpvol.type!=AKAI_VOL_TYPE_S3000)
&&(tmpvol.type!=AKAI_VOL_TYPE_CD3000)){
continue; /* next volume */
}
/* create vol/ */
if (tar_export(fd,pp->diskp,pp,&tmpvol,NULL,0,flags|TAR_EXPORT_VOL,verbose,NULL)){
return -1;
}
/* export volume */
if (tar_export_vol(fd,&tmpvol,flags|TAR_EXPORT_VOL,verbose,filtertagp)<0){
return -1;
}
}
return 0;
}
int
tar_export_disk(int fd,struct disk_s *dp,u_int flags,int verbose,u_char *filtertagp)
{
u_int pi;
if ((fd<0)||(dp==NULL)){
return -1;
}
/* partitions on disk */
for (pi=0;pi<part_num;pi++){
if (part[pi].diskp!=dp){ /* partition not on disk? */
continue; /* next partition */
}
/* create part/ */
if (tar_export(fd,part[pi].diskp,&part[pi],NULL,NULL,0,flags|TAR_EXPORT_PART,verbose,NULL)){
return -1;
}
/* export partition (sampler or DD) */
if (tar_export_part(fd,&part[pi],flags|TAR_EXPORT_PART,verbose,filtertagp)<0){
return -1;
}
}
return 0;
}
int
tar_export_alldisks(int fd,u_int flags,int verbose,u_char *filtertagp)
{
u_int i;
if (fd<0){
return -1;
}
/* all disks */
for (i=0;i<disk_num;i++){
/* create disk/ */
if (tar_export(fd,&disk[i],NULL,NULL,NULL,0,flags|TAR_EXPORT_DISK,verbose,NULL)){
return -1;
}
/* export disk */
if (tar_export_disk(fd,&disk[i],flags|TAR_EXPORT_DISK,verbose,filtertagp)<0){
return -1;
}
}
return 0;
}
int
tar_export_curdir(int fd,int verbose,u_int flags)
{
if (fd<0){
return -1;
}
if (curdiskp==NULL){ /* no disk? */
/* now, on system level */
return tar_export_alldisks(fd,flags,verbose,curfiltertag);
}
if (curpartp==NULL){ /* no partition? */
/* now, on disk */
return tar_export_disk(fd,curdiskp,flags,verbose,curfiltertag);
}
if (curvolp==NULL){ /* no sampler volume? */
/* now, in partition (sampler or DD) */
return tar_export_part(fd,curpartp,flags,verbose,curfiltertag);
}
/* now, in sampler volume */
return tar_export_vol(fd,curvolp,flags,verbose,curfiltertag);
}
int
tar_export_tailzero(int fd)
{
u_char buf[TAR_TAILZERO_BLOCKS*TAR_BLOCKSIZE];
/* zero blocks */
bzero(buf,TAR_TAILZERO_BLOCKS*TAR_BLOCKSIZE);
/* write blocks */
if (WRITE(fd,buf,TAR_TAILZERO_BLOCKS*TAR_BLOCKSIZE)!=TAR_TAILZERO_BLOCKS*TAR_BLOCKSIZE){
PRINTF_ERR("cannot write zero blocks\n");
return -1;
}
return 0;
}
int
tar_import_curdir(int fd,u_int vtype0,int verbose,u_int flags)
{
struct tar_head_s tarhd;
u_int byteend,skip;
u_int chksum,chksum0;
u_int nlen;
u_int l;
int i;
int ret;
struct vol_s tmpvol;
struct file_s tmpfile;
u_int vtype,lnum;
u_int ftype;
u_int osver;
u_char *tagp;
struct akai_volparam_s *parp;
u_int wavbcount;
int wavret;
u_int ti;
u_int csizes,csizee;
u_int tsize;
struct akai_ddtake_s t;
save_curdir(1); /* 1: could be modifications */
/* interpret tar file */
skip=0;
ret=-1; /* no success so far */
for (;;){
if (verbose){
FLUSH_ALL;
}
restore_curdir();
/* skip if necessary */
if (skip>0){
/* skip file */
if (LSEEK64(fd,(OFF64_T)skip,SEEK_CUR)<0){
PERROR("lseek");
ret=-1;
goto tar_import_done;
}
}
skip=0;
/* read header */
/* XXX size must not exceed SSIZE_MAX! */
ret=(int)READ(fd,(void *)&tarhd,sizeof(struct tar_head_s));
if (ret==0){
/* end of file */
ret=0; /* success */
goto tar_import_done;
}else if (ret!=sizeof(struct tar_head_s)){
PRINTF_ERR("cannot read tar header\n");
ret=-1;
goto tar_import_done;
}
/* check header */
chksum0=tar_checksum((u_char *)&tarhd);
if (chksum0==0){ /* all zero block? */
/* XXX ignore */
continue; /* next */
}
/* checksum */
if ((sscanf(tarhd.chksum,"%o",&chksum)!=1)||(chksum!=chksum0)){
PRINTF_OUT("checksum error in next header\n");
FLUSH_ALL;
ret=-1;
goto tar_import_done;
}
/* get size */
byteend=0; /* default */
sscanf(tarhd.size,"%o",&byteend);
/* Note: if sscanf finds nothing, vtype remains! */
/* skip rest of full TAR_BLOCKSIZE */
skip=byteend%TAR_BLOCKSIZE;
skip=(TAR_BLOCKSIZE-skip)%TAR_BLOCKSIZE;
/* check type */
if ((tarhd.type!=TAR_TYPE_DIR)
&&(tarhd.type!=TAR_TYPE_REG)
&&(tarhd.type!=TAR_TYPE_REG0)){
skip+=byteend; /* skip file */
continue; /* next */
}
/* now, directory or regular file */
/* get name */
if (verbose){
PRINTF_OUT("%s\n",tarhd.name);
FLUSH_ALL;
}
l=(u_int)strlen(tarhd.name);
/* correct name if directory */
if ((tarhd.type==TAR_TYPE_DIR)&&(l>0)&&(tarhd.name[l-1]=='/')){
tarhd.name[l-1]='\0'; /* terminate */
l--;
}
if (l==0){
if (verbose){
PRINTF_OUT("empty name, skipping file\n");
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
/* XXX ignore other tarhd elements */
/* change to upper level directory */
/* Note: will be undone upon exit or next for-loop iteration */
save_curdir(1); /* 1: could be modifications */
if (change_curdir(tarhd.name,0,dirnamebuf,0)<0){
PRINTF_ERR("directory not found\n");
ret=-1;
goto tar_import_done;
}
/* parse type further */
if (tarhd.type==TAR_TYPE_DIR){
/* directory */
if (curdiskp==NULL){
/* on system level */
/* Note: no need to create disk, but must check if exists!!! */
if ((strncasecmp(dirnamebuf,"disk",4)==0)&&(strlen(dirnamebuf)>=5)){
i=atoi(dirnamebuf+4);
}else{
i=-1; /* invalid */
}
if ((i<0)||(i>=(int)disk_num)){
PRINTF_ERR("disk does not exist\n");
ret=-1;
goto tar_import_done;
}
}else if (curpartp==NULL){
/* on disk level */
/* Note: no need to create partition, but must check if exists!!! */
if (akai_find_part(curdiskp,dirnamebuf)==NULL){
PRINTF_ERR("partition does not exist\n");
ret=-1;
goto tar_import_done;
}
}else{
/* on partition level */
if (curpartp->type==PART_TYPE_DD){
/* harddisk DD partition */
PRINTF_ERR("no directory allowed in DD-partition\n");
ret=-1;
goto tar_import_done;
}
/* now, sampler partition */
if (curvolp!=NULL){ /* already in volume? */
PRINTF_ERR("no directory allowed in volume\n");
ret=-1;
goto tar_import_done;
}
/* load number */
lnum=AKAI_VOL_LNUM_OFF; /* default */
/* XXX use devminor field for load number */
sscanf(tarhd.devminor,"%o",&lnum);
/* Note: if sscanf finds nothing, lnum remains! */
/* correct lnum */
if ((lnum!=AKAI_VOL_LNUM_OFF)
&&((lnum<AKAI_VOL_LNUM_MIN)||(lnum>AKAI_VOL_LNUM_MAX))){
lnum=AKAI_VOL_LNUM_OFF; /* XXX default */
}
/* volume parameters */
parp=NULL; /* default volume parameters or keep old ones */
#ifndef TAR_NOVOLPARAMTARHD
/* XXX use linkname for volume parameters */
if ((tarhd.linkname[0]=='\0')&&(tarhd.linkname[1]=='P')){ /* XXX correct magic? */
parp=(struct akai_volparam_s *)(&tarhd.linkname[0]+2); /* XXX +2: linkname starts with magic */
}
#endif
/* check if destination volume already exists */
if (akai_find_vol(curpartp,&tmpvol,dirnamebuf)<0){
/* does not exist (or error in finding it, don't care) */
/* user-supplied volume type, Note: will be corrected below if bad or inactive */
vtype=vtype0;
if (vtype0==AKAI_VOL_TYPE_INACT){ /* no user-supplied type? */
/* XXX use devmajor field for type */
sscanf(tarhd.devmajor,"%o",&vtype);
/* Note: if sscanf finds nothing, vtype remains! */
/* correct vtype */
if (curpartp->type==PART_TYPE_HD9){
vtype=AKAI_VOL_TYPE_S900;
}else if ((vtype!=AKAI_VOL_TYPE_S1000)
&&(vtype!=AKAI_VOL_TYPE_S3000)
&&(vtype!=AKAI_VOL_TYPE_CD3000)){
vtype=AKAI_VOL_TYPE_S1000; /* XXX default */
}
}
/* create volume */
if (akai_create_vol(curpartp,&tmpvol,vtype,AKAI_CREATE_VOL_NOINDEX,dirnamebuf,lnum,parp)<0){
PRINTF_ERR("cannot create volume\n");
ret=-1;
goto tar_import_done;
}
}else{
/* volume already exists */
/* Note: keep volume type (even if user-supplied type) */
/* XXX use devminor field for load number */
if (tarhd.devminor[0]==0x00){ /* no load number? */
lnum=tmpvol.lnum; /* keep old value */
}
osver=tmpvol.osver; /* keep old value */
/* update load number and optional volume parameters */
if (akai_rename_vol(&tmpvol,NULL,lnum,osver,parp)<0){
PRINTF_ERR("cannot update volume\n");
ret=-1;
goto tar_import_done;
}
}
if ((tmpvol.param!=NULL)&&(parp!=NULL)&&verbose){
PRINTF_OUT("volume parameters imported\n");
FLUSH_ALL;
}
}
skip+=byteend; /* skip file */
continue; /* next */
}
/* now, regular file */
nlen=(u_int)strlen(dirnamebuf);
#ifndef TAR_NOTAGSFILE
/* handle tags-file */
if (strcmp(dirnamebuf,TAR_TAGSFILENAME)==0){
if ((curpartp!=NULL)&&(curpartp->type==PART_TYPE_HD)&&(curvolp==NULL)){ /* in S1000/S3000 harddisk partition on partition level? */
if (byteend==(4+AKAI_PARTHEAD_TAGNUM*AKAI_NAME_LEN)){ /* valid file size? (Note: tags magic and tag names) */
/* read tags-file into partition header */
if (READ(fd,(void *)curpartp->head.hd.tagsmagic,byteend)!=(int)byteend){
PRINTF_ERR("cannot read tags-file\n");
ret=-1;
goto tar_import_done;
}
/* XXX no check if valid tags magic */
/* write partition header */
if (akai_io_blks(curpartp,(u_char *)&curpartp->head.hd,
0,
AKAI_PARTHEAD_BLKS,
1,IO_BLKS_WRITE)<0){ /* 1: allocate cache if possible */
PRINTF_ERR("cannot write partition header\n");
ret=-1;
goto tar_import_done;
}
if (verbose){
PRINTF_OUT("tags imported\n");
FLUSH_ALL;
}
}else{
if (verbose){
PRINTF_OUT("invalid file size of tags-file, skipping file\n");
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
}else{
if (verbose){
PRINTF_OUT("tags-file must be on partition level of S1000/S3000 harddisk, skipping file\n");
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
continue; /* next */
}
#endif
#ifndef TAR_NOVOLPARAMFILE
/* handle volparam-file */
if (strcmp(dirnamebuf,TAR_VOLPARAMFILENAME)==0){
if ((curvolp!=NULL)&&(curvolp->param!=NULL)){ /* on volume level and volume has parameters? */
if (byteend==sizeof(struct akai_volparam_s)){ /* valid file size? */
/* read volparam-file into volume */
if (READ(fd,(void *)curvolp->param,byteend)!=(int)byteend){
PRINTF_ERR("cannot read volparam-file\n");
ret=-1;
goto tar_import_done;
}
/* update volume */
if (akai_rename_vol(curvolp,NULL,curvolp->lnum,curvolp->osver,curvolp->param)<0){
PRINTF_ERR("cannot update volume\n");
ret=-1;
goto tar_import_done;
}
if ((curvolp->param!=NULL)&&verbose){
PRINTF_OUT("volume parameters imported\n");
FLUSH_ALL;
}
}else{
if (verbose){
PRINTF_OUT("invalid file size of volparam-file, skipping file\n");
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
}else{
if (verbose){
if (curvolp==NULL){
PRINTF_OUT("volparam-file must be on volume level, skipping file\n");
}else{
PRINTF_OUT("volume has no parameters, skipping file\n");
}
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
continue; /* next */
}
#endif
#ifndef TAR_NOVOLINFO1FILE
#ifndef TAR_VOLINFO1FILENAME
#define TAR_VOLINFO1FILENAME "VOLINFO1.DAT"
#endif
#ifndef TAR_VOLINFO1FILE_SKIPB
#define TAR_VOLINFO1FILE_SKIPB 0x0010 /* number of bytes to skip in volinfo1-file */
#endif
/* handle volinfo1-file */
if (strcmp(dirnamebuf,TAR_VOLINFO1FILENAME)==0){
if ((curvolp!=NULL)&&(curvolp->param!=NULL)){ /* on volume level and volume has parameters? */
if (byteend==(TAR_VOLINFO1FILE_SKIPB+sizeof(struct akai_volparam_s))){ /* valid file size? */
if (LSEEK64(fd,(OFF64_T)TAR_VOLINFO1FILE_SKIPB,SEEK_CUR)<0){
PERROR("lseek");
ret=-1;
goto tar_import_done;
}
/* read volume parameters from volinfo1-file into volume */
l=sizeof(struct akai_volparam_s);
if (READ(fd,(void *)curvolp->param,l)!=(int)l){
PRINTF_ERR("cannot read volinfo1-file\n");
ret=-1;
goto tar_import_done;
}
/* update volume */
if (akai_rename_vol(curvolp,NULL,curvolp->lnum,curvolp->osver,curvolp->param)<0){
PRINTF_ERR("cannot update volume\n");
ret=-1;
goto tar_import_done;
}
if (verbose){
PRINTF_OUT("volume parameters imported\n");
FLUSH_ALL;
}
}else{
if (verbose){
PRINTF_OUT("invalid file size of volinfo1-file, skipping file\n");
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
}else{
if (verbose){
if (curvolp==NULL){
PRINTF_OUT("volinfo1-file must be on volume level, skipping file\n");
}else{
PRINTF_OUT("volume has no parameters, skipping file\n");
}
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
continue; /* next */
}
#endif
#ifndef TAR_NOSKIPDATFILE
/* skip dat-files */
if ((nlen>=4)&&(strncasecmp(dirnamebuf+nlen-4,".dat",4)==0)){
if (verbose){
PRINTF_OUT("skipping dat-file\n");
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
#endif
if (curpartp==NULL){
PRINTF_ERR("no files allowed on disk level\n");
ret=-1;
goto tar_import_done;
}
if (curpartp->type==PART_TYPE_DD){
/* harddisk DD partition */
/* import DD take */
if ((flags&TAR_IMPORT_WAV)&&(nlen>=4)&&(strncasecmp(dirnamebuf+nlen-4,".wav",4)==0)){
/* convert WAV file into DD take */
/* find free index */
for (ti=0;ti<AKAI_DDTAKE_MAXNUM;ti++){
/* take */
if (curpartp->head.dd.take[ti].stat==AKAI_DDTAKESTAT_FREE){ /* free? */
break; /* done */
}
}
if (ti==AKAI_DDTAKE_MAXNUM){ /* no free index? */
PRINTF_ERR("no free take index\n");
ret=-1;
goto tar_import_done;
}
/* Note: don't check if name already used, create new DD take */
wavret=akai_wav2take(fd,dirnamebuf,
curpartp,
ti,
&wavbcount,
0);
if ((wavret<0)||(byteend<wavbcount)){ /* error? */
ret=-1;
goto tar_import_done;
}
skip+=byteend-wavbcount; /* skip unread rest */
continue; /* file done, next */
}
/* check file name */
if ((nlen<3)||(strcmp(dirnamebuf+nlen-3,AKAI_DDTAKE_FNAMEEND)!=0)){
PRINTF_ERR("invalid file name for DD take, skipping file\n");
skip+=byteend; /* skip file */
continue; /* next */
}
/* find free index */
for (ti=0;ti<AKAI_DDTAKE_MAXNUM;ti++){
/* take */
if (curpartp->head.dd.take[ti].stat==AKAI_DDTAKESTAT_FREE){ /* free? */
break; /* done */
}
}
if (ti==AKAI_DDTAKE_MAXNUM){ /* no free index? */
PRINTF_ERR("no free take index\n");
ret=-1;
goto tar_import_done;
}
/* get DD take header (DD directory entry) */
if (READ(fd,&t,sizeof(struct akai_ddtake_s))!=(int)sizeof(struct akai_ddtake_s)){
PRINTF_ERR("cannot read DD take header\n");
ret=-1;
goto tar_import_done;
}
/* get csizes (sample clusters) and csizee (envelope clusters) */
/* XXX use cstarts/cstarte fields in DD take header for csizes/csizee */
csizes=(t.cstarts[1]<<8)
+t.cstarts[0];
csizee=(t.cstarte[1]<<8)
+t.cstarte[0];
/* Note: akai_import_take() will increase csizee if required */
/* XXX preliminary check of csizes+csizee */
if ((csizes+csizee)*AKAI_DDPART_CBLKS>curpartp->bfree){
PRINTF_ERR("not enough space left\n");
ret=-1;
goto tar_import_done;
}
/* size in bytes */
tsize=sizeof(struct akai_ddtake_s)+(csizes+csizee)*AKAI_DDPART_CBLKS*AKAI_HD_BLOCKSIZE;
if (tsize>byteend){
PRINTF_ERR("inconsistent size\n");
ret=-1;
goto tar_import_done;
}
/* import take */
/* Note: akai_import_take() will increase csizee if required */
/* Note: akai_import_take() keeps name in DD take header */
/* Note: don't check if name already used, create new DD take */
if (akai_import_take(fd,curpartp,&t,ti,csizes,csizee)<0){
PRINTF_ERR("cannot import take\n");
ret=-1;
goto tar_import_done;
}
/* skip unread rest */
skip+=byteend-tsize;
continue; /* next */
}
/* now, sampler partition */
if (curvolp==NULL){ /* not in volume? */
PRINTF_ERR("files only allowed in volume\n");
ret=-1;
goto tar_import_done;
}
#if 0
skip+=byteend; /* skip file */
continue; /* next */
#endif
/* import file */
/* default osver */
osver=curvolp->osver; /* default: from volume */
if (vtype0==AKAI_VOL_TYPE_INACT){ /* no user-supplied type? */
/* XXX use devmajor field for osver */
sscanf(tarhd.devmajor,"%o",&osver);
}else if (vtype0==AKAI_VOL_TYPE_S900){
osver=0; /* non-compressed, akai_create_file() will correct osver if necessary */
}else if ((vtype0==AKAI_VOL_TYPE_S3000)||(vtype0==AKAI_VOL_TYPE_CD3000)){
osver=AKAI_OSVER_S3000MAX; /* XXX */
}else{
osver=AKAI_OSVER_S1000MAX; /* XXX */
}
/* Note: if sscanf finds nothing, osver remains! */
/* default tags */
tagp=NULL;
if ((curvolp->type==AKAI_VOL_TYPE_S3000)||(curvolp->type==AKAI_VOL_TYPE_CD3000)){
/* XXX use linkname for file tags */
if ((tarhd.linkname[0]=='\0')&&(tarhd.linkname[1]=='T')){ /* XXX correct magic? */
tagp=(u_char *)&tarhd.linkname[2];/* XXX +2: linkname starts with magic */
/* XXX no check for valid tag entries */
akai_sort_filetags(tagp);
}
}
if ((flags&TAR_IMPORT_WAV)&&(nlen>=4)&&(strncasecmp(dirnamebuf+nlen-4,".wav",4)==0)){
/* convert WAV file into sample file */
/* sample file type */
if (flags&(TAR_IMPORT_WAVS9|TAR_IMPORT_WAVS9C)){
/* S900 sample */
ftype=AKAI_SAMPLE900_FTYPE;
}else if (flags&TAR_IMPORT_WAVS1){
/* S1000 sample */
ftype=AKAI_SAMPLE1000_FTYPE;
}else if (flags&TAR_IMPORT_WAVS3){
/* S3000 sample */
ftype=AKAI_SAMPLE3000_FTYPE;
}else{
ftype=AKAI_FTYPE_FREE; /* invalid: derive sample file type from volume type/file osver */
/* Note: if S900 sample, use non-compressed sample format */
}
/* Note: akai_wav2sample() will correct osver if necessary */
wavret=akai_wav2sample(fd,dirnamebuf,
curvolp,
AKAI_CREATE_FILE_NOINDEX,
ftype,
(flags&TAR_IMPORT_WAVS9C)?1:0, /* if S900 sample, use compressed/non-compressed sample format */
osver,
tagp,
&wavbcount,
WAV2SAMPLE_OVERWRITE);
if ((wavret<0)||(byteend<wavbcount)){ /* error? */
ret=-1;
goto tar_import_done;
}
skip+=byteend-wavbcount; /* skip unread rest */
continue; /* file done, next */
}
#if 1
{
static u_char anamebuf[AKAI_NAME_LEN+4+1]; /* +4 for ".<type>", +1 for '\0' */
u_int osver;
/* skip file with invalid name/type */
if (ascii2akai_filename(dirnamebuf,anamebuf,&osver,curvolp->type==AKAI_VOL_TYPE_S900)==AKAI_FTYPE_FREE){
if (verbose){
PRINTF_OUT("invalid file name/type, skipping file\n");
FLUSH_ALL;
}
skip+=byteend; /* skip file */
continue; /* next */
}
}
#endif
/* check if destination file already exists */
if (akai_find_file(curvolp,&tmpfile,dirnamebuf)==0){
/* exists */
/* delete file */
if (akai_delete_file(&tmpfile)<0){
PRINTF_ERR("cannot overwrite existing file\n");
ret=-1;
goto tar_import_done;
}
}
/* create destination file */
/* Note: akai_create_file() will correct osver if necessary */
if (akai_create_file(curvolp,
&tmpfile,
byteend,
AKAI_CREATE_FILE_NOINDEX,
dirnamebuf,
osver,
tagp)<0){
PRINTF_ERR("cannot create file\n");
ret=-1;
goto tar_import_done;
}
/* import file */
if (akai_write_file(fd,NULL,&tmpfile,0,tmpfile.size)<0){
ret=-1;
goto tar_import_done;
}
if ((curvolp->type==AKAI_VOL_TYPE_S900)&&(tmpfile.osver!=0) /* compressed file in S900 volume? */
&&(osver==0)){ /* and supplied/determined osver is incompatible? */
/* update uncompr value */
akai_s900comprfile_updateuncompr(&tmpfile); /* ignore error */
}
#if 1
/* fix name in header (if necessary) */
akai_fixramname(&tmpfile); /* ignore error */
#endif
}
tar_import_done:
restore_curdir();
return ret;
}
/* EOF */