On 3/6/2013 11:01 AM, Dave Wade wrote:
On 06/03/2013 14:52, Glen Slick wrote:
<snip>
I'm sure there a many variations of this sort of code out there. I could
send you the code I use if you're interested.
There is also ST.EXE here for MS-DOS you could look at:
http://www.dbit.com/pub/ibmpc/util/
-Glen
The Hercules IBM370/390/z emulator (
www.hercules-390-eu) includes a
tapecopy utility that will copy a SCSI tape to "aws" format and back
to tape.
Not sure how AWS compares with "tap" format but it preserves the
content of tapes, including tape marks and has forward and backwards
pointers for emulators that read backwards.
The program below works on solaris with the mtio interface.
It reads each record into an individual file. the name on the record is
FFFF-RRRR where FFFF is the file number and RRRR is the record number.
A tape or file mark is a 0 length file. You have to tweak it manually
to allow for three tape mark EOT format, but other than that it
preserves the record format.
I have a program which also goes from this format, which is pretty much
universal to the tap format which Al K uses for his archiving. There are
tape utilities to go from tap format to AWS and back written by Jay
Maynard. I am not sure it Jay's utilities are the same as the mentioned
SCSI to aws or not.
both are viable archival methods. I find this methods allows very
simple tools to get into tape data and examine it, but it is bulky from
the unix system point of view, eating up a lot of directory and inode
real estate.
tapread.c ***************************
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
/*
*
copyright jim stephens 2006
please check with me before passing this on
tapread at
jwsss.com
tread reads files from tape device onto
fixed storage.
Each tape record is written as a file on the disk, in
the current directory. creation of separate directories
for each tape is left as an exercise for the user to manage.
Each file is named for the file number (tape file, determined
by counting EOF marks from tape) and record number. Each
field is padded with leading zeros, and becomes the file name
by separateing them with a "-" character.
The counters start at 1 (file number) and record number 1.
the first record on the tape is therfore 0001-0001
a 0 length record is a file mark, so each file will be
on the tape will record at least one disk file.
Tapes are assumed to end when two consecutive file
marks are read, with no intervening data record.
Most tape drive / formatter combinations require a read
record length of 18 bytes, or the data is ignored.
This program has to be modified to handle DEC format
tapes which end with three file marks, with file
separation being by 2 consecutive file marks, and
internal file marks (within tape files) being allowable.
Current tape library relies on Sun libraries to run.
The system calls to set the maximum tape record size,
and retrieve the size of each record read.
There are equivalent ones in the MT libs for linux.
*
*/
struct mtop mt_command;
struct mtget mt_status;
#define BUFLEN 32768
int in_fd;
int out_fd;
int fmcntr;
int rccntr;
void
mtrew()
{
mt_command.mt_op = MTREW;
mt_command.mt_count = 0;
ioctl(in_fd, MTIOCTOP, &mt_command);
ioctl(in_fd, MTIOCGET, (char *)&mt_status);
/*sts = ioctl(in_fd, */
}
void
mttsize()
{
mt_command.mt_op = MTGRSZ;
ioctl(in_fd, MTIOCTOP, &mt_command);
ioctl(in_fd, MTIOCGET, (char *)&mt_status);
printf("record size is %x\n", mt_command.mt_count);
}
void
mtstatus()
{
printf("mt_type %x\n",mt_status.mt_type);
printf("mt_dsreg %x\n",mt_status.mt_dsreg);
printf("mt_erreg %x\n",mt_status.mt_erreg);
printf("mt_resid %x\n",mt_status.mt_resid);
printf("mt_fileno %x\n",mt_status.mt_resid);
printf("mt_blkno %x\n",mt_status.mt_blkno);
printf("mt_flags %x\n",mt_status.mt_flags);
printf("mt_bf %x\n",mt_status.mt_bf);
}
void
main(int argc, char *argv[])
{
char fname[500] = "/dev/rmt/0b";
char outname[] = " - ";
int i,j;
char buf[32768];
int lim;
int bsize;
int fmflg = 0;
int doing_file = 1;
int fmcnt = 0;
if( (in_fd = open(fname,O_RDONLY)) == -1)
{
printf("error opening file\n");
exit(1);
}
fmcntr = 1;
rccntr = 1;
mtrew();
mttsize();
mtstatus();
i=1;
for(;;)
{
while(doing_file)
{
bsize = read(in_fd, buf, BUFLEN);
sprintf(fname,"%4.4i",fmcntr);
strncpy(outname,fname,4);
sprintf(fname,"%4.4i", rccntr);
strncpy(&outname[5],fname,4);
outname[9] = '\0';
outname[4] = '-';
if( (out_fd = open(outname, O_RDWR | O_CREAT)) == -1)
{
printf("error opening output file\n");
}
write(out_fd, buf,bsize);
close(out_fd);
printf("%4.4x " ,bsize);
if(bsize == 0)
{
doing_file = 0;
if(fmflg)
{
printf("eot %i files\n", fmcnt);
exit(1);
}
}
else
{
fmflg = 0;
}
if(doing_file == 0) break;
printf("%2.2i ", i);
lim = bsize;
if(bsize > 40) lim=40;
for(j=0;j<lim;j++)
{
printf("%2.2X",
buf[j] & 0x000000ff);
}
printf("\n");
//mtstatus();
i=i+1;
rccntr=rccntr+1;
}
i=1;
rccntr = 1;
fmcntr = fmcntr+1;
fmflg = 1; // to detect eom
printf("EOF %i\n", fmcnt);
fmcnt = fmcnt + 1;
doing_file = 1;
}
}
tape2tap.c **************************************************
/////////////////////////////
// utility to read .tap files and parse into records
//
// usage: tapread <filename>
// output: file number, and record number + record sizes to stdout
//
// limitations: 100000 byte record size maximum (can be changed)
/////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/wait.h>
/////////////////////////////
#define TAPERECSIZE 100000
/////////////////////////////
FILE *scriptptr;
FILE *tapfile;
int recsize;
char taperec[TAPERECSIZE];
char tapepath[2000];
int filenum;
int recnum;
char recfilename[2000];
/////////////////////////////
void
usage(char *pgmname)
{
printf("usage: %s input tape file\n", pgmname);
}
/////////////////////////////
//
// read tape record
// return 0 if record
// return 1 if tape mark
//
// tape format is: <record size><data><record size>.... <end of
file>
// assumed to start at state BOT, beginning of a record
/////////////////////////////
int
gettaperec(int *parmsize, char *record)
{
int tapemark = 0;
int fileeof;
int taprecl;
sprintf( recfilename, "%s/%4.4i-%4.4i", tapepath, filenum, recnum);
printf("read %s\n", recfilename );
if( (scriptptr = fopen( recfilename, "rb")) == NULL)
{
printf(" error at record %s\n", recfilename );
// if tape output file open, close it
if( tapfile != NULL)
{
fclose(tapfile);
}
exit(1);
}
taprecl = fread( taperec , 1, TAPERECSIZE, scriptptr);
fclose( scriptptr );
if( taprecl == 0)
{
tapemark=1;
printf("file end reached\n");
}
*parmsize = taprecl;
recsize = taprecl;
return(tapemark);
}
/////////////////////////////
// write tape mark, which is 0x00000000
/////////////////////////////
void
putfilemark(void)
{
int tapemark = 0;
// write tape mark, which is 0x00000000
fwrite(&tapemark, 4, 1, tapfile);
return;
}
void
putrec(void)
{
// put out record size
fwrite(&recsize, 4, 1, tapfile);
// output record
fwrite(&taperec, recsize, 1, tapfile);
// output following record size
fwrite(&recsize, 4, 1, tapfile);
}
/////////////////////////////
int
main(int argc, char *argv[])
{
int exitflag = 1;
int lastrecwastapemark = 0;
int lastrecmark;
int filecount = 1;
int reccount = 0;
if(argc < 2)
{
usage( argv[0] );
exit(1);
}
printf("reading %s tape file\n", argv[1]);
strcpy( tapepath, argv[1]);
filenum = 1;
recnum = 1;
if( (tapfile = fopen("tapfile", "wb" )) == NULL)
{
printf("problem opening out file tapfile\n");
exit(1);
}
while( exitflag )
{
//exitflag = 0;
lastrecmark = gettaperec( &recsize, taperec );
if( lastrecwastapemark && lastrecmark )
{
putfilemark();
printf("double filemark\n");
exitflag = 0;
}
if(lastrecmark)
{
lastrecwastapemark = 1;
filecount+= 1;
filenum+=1;
reccount = 0;
recnum=1;
putfilemark();
printf("file mark\n");
}
else
{
lastrecwastapemark = 0;
recnum+=1;
reccount+=1;
putrec();
}
if( !lastrecmark)
printf("record %4.4i:%4.4i size is %i\n", filecount, reccount,
recsize );
}
}