/* mtcopy.c Copyright (c) Kapteyn Laboratorium Groningen 1990 All Rights Reserved. #> mtcopy.dc1 Program: MTCOPY Purpose: Copies selected files from one tape device to another tape device. Tape device can be a real tape unit or a directory on disk. Category: TAPES, UTILITY File: mtcopy.c Author: K.G. Begeman Keywords: INTAPE= Input tape device [list of all devices] Name of tape device where to copy files from. The list is extracted from the local file $gip_loc/mtdevices. If your tape is not in the list, you can enter the full device specification, e.g. INTAPE=/dev/rmt/0mn OUTTAPE= Output tape device [list of all devices] Name of tape device where to copy files to. See also at INTAPE= INFILES= Files on input tape device which should be copied [all files] When the default is used, files are copied from the input tape until an empty file is found (two subsequent tape marks). Note that filenumber zero indicates the current file, file number 1 the next file and file number -1 the previous file. SKIP= Number of files to skip on OUTTAPE [SKIP to End of Info] The first input file will be stored at this location, the second at the next location etc. Note that for new (empty) tapes you should give SKIP=0. INREWIND= Rewind INTAPE after copying [YES] OUTREWIND= Rewind OUTTAPE after copying [NO] If NO, the outtape will be positioned between the last two tapemarks, so that you can easily add other files. ** REBLOCK= New blocking factor on output tape device. If the last block of a file is not completely filled, it will be padded with zeroes [blocking as on input tape device]. Updates: Apr 24, 1990: KGB, Document created. Feb 8, 1993: KGB, Skip till EOI implemented. Oct 26, 1993: KGB, Keyword INREWIND= added. Feb 23, 2001: VOG, Small changes in documentation. #< */ #include "stdio.h" /* */ #include "string.h" /* */ #include "ctype.h" /* */ #include "stdlib.h" /* */ #include "gipsyc.h" /* GIPSY definitions and symbols */ #include "cmain.h" /* C main program */ #include "init.h" /* define init_c */ #include "finis.h" /* define finis_c */ #include "anyout.h" /* define anyout_c */ #include "error.h" /* define error_c */ #include "nelc.h" /* define nelc_c */ #include "status.h" /* define status_c */ #include "userint.h" /* define userint_c */ #include "userlog.h" /* define userlog_c */ #include "usertext.h" /* define usertext_c */ /* Now declare the tape io routines: */ extern fint mtopen_c( fchar ); extern fint mtclose_c( fint * ); extern fint mtrew_c( fint * ); extern fint mtread_c( fint *, char *, fint * ); extern fint mtwrite_c( fint *, char *, fint * ); extern fint mtweof_c( fint *, fint * ); extern fint mtfsf_c( fint *, fint * ); extern fint mtbsf_c( fint *, fint * ); extern fint mtfsr_c( fint *, fint * ); extern fint mtbsr_c( fint *, fint * ); extern fint mtname_c( fint *, fchar ); #define finit(d,s) (d.a=s,d.l=sizeof(s)) #define INREWIND_KEY tofchar("INREWIND=") #define INREWIND_MES tofchar("Rewind INTAPE after copying? [YES]" ) #define INTAPE_DEV tofchar("?INTAPE=Input tape device [list of all devices]") #define INTAPE_ERR tofchar("No such device or device not available") #define OUTREWIND_KEY tofchar("OUTREWIND=") #define OUTREWIND_MES tofchar("Rewind OUTTAPE after copying? [NO]") #define OUTTAPE_DEV tofchar("?OUTTAPE=Output tape device [list of all devices]") #define OUTTAPE_ERR tofchar("No such device or device not available") #define INFILES_KEY tofchar("INFILES=") #define INFILES_MES tofchar("File numbers to copy [all files]") #define SKIP_KEY tofchar("SKIP=") #define SKIP_MES tofchar("Number of files to skip on OUTTAPE [Skip to EOI]") #define REBLOCK_KEY tofchar("REBLOCK=") #define REBLOCK_MES tofchar("Blocking factor on output tape [no reblock]") #define REBLOCK_ERR tofchar("Illegal blocking factor") #define VERSION "0.3" #define MAXTXTLEN 80 /* max length of text strings */ #define MAXFILES 1000 /* max number of files we allow */ #define MINBLOCKSIZE 28800 /* initial size tape blocking */ MAIN_PROGRAM_ENTRY /* here is where we start */ { bool rewind1; /* rewind INTAPE */ bool rewind2; /* rewind OUTTAPE */ char buf1[MAXTXTLEN]; /* buffer for name of INTAPE */ char buf2[MAXTXTLEN]; /* buffer for name of OUTTAPE */ char *dat1 = NULL; /* pointer to input data */ char *dat2 = NULL; /* pointer to output data */ char text[MAXTXTLEN]; /* buffer for text strings */ fchar tape1; /* points to buf1 */ fchar tape2; /* points to buf2 */ fint nbyt1; /* number of bytes read */ fint nbyt2; /* number of bytes written */ fint ndat1; /* number of bytes in dat1 */ fint ndat2; /* number of bytes in dat2 */ fint mtid1; /* device id INTAPE */ fint mtid2; /* device id OUTTAPE */ fint fatal = 4; /* fatal error */ fint files[MAXFILES]; /* buffer for input file numbers */ fint nfil1; /* number of files to copy */ fint nfil2; /* number of first output file */ fint one = 1; /* just one */ fint deflev; /* default level for userxxx */ fint nitems; /* item counter */ fint reblock; /* reblocking factor */ fint ndone = 0; /* bytes read */ fint ncur1; /* current input file number */ fint ncur2; /* current output file number */ fint mterr1 = 0; /* error return from INTAPE */ fint mterr2 = 0; /* error return from OUTTAPE */ fint screen = 1; /* output to screen */ /* * set up the character strings for the device names and create * the buffers for input and output data. */ finit(tape1,buf1); finit(tape2,buf2); dat1 = realloc( dat1, sizeof( char ) * MINBLOCKSIZE ); ndat1 = MINBLOCKSIZE; dat2 = realloc( dat2, sizeof( char ) * MINBLOCKSIZE ); ndat2 = MINBLOCKSIZE; init_c( ); /* get in touch with HERMES */ IDENTIFICATION("MTCOPY",VERSION); /* this we are */ if (dat1 == NULL || dat2 == NULL) { /* error */ error_c( &fatal, tofchar( "Memory allocation problems!" ) ); } if ((mtid1 = mtopen_c( INTAPE_DEV )) < 0) { /* open INTAPE */ error_c( &fatal, INTAPE_ERR ); /* display error message */ finis_c( ); /* quit */ } mtname_c( &mtid1, tape1 ); /* get device name INTAPE */ if ((mtid2 = mtopen_c( OUTTAPE_DEV )) < 0) { /* open OUTTAPE */ error_c( &fatal, OUTTAPE_ERR ); /* display error message */ finis_c( ); /* quit */ } mtname_c( &mtid2, tape2 ); /* get device name OUTTAPE */ deflev = 1; /* default level */ nitems = MAXFILES; /* max number of files */ nfil1 = userint_c( files, &nitems, &deflev, INFILES_KEY, INFILES_MES ); deflev = 1; /* default level */ nitems = 1; /* max number of items */ ncur1 = 0; /* current input file number */ ncur2 = 0; /* current output file number */ if (!userint_c( &nfil2, &nitems, &deflev, SKIP_KEY, SKIP_MES )) { /* * First we try to skip a TM backwards. We might already be at EOI * so we don't want to destroy anything. */ mterr2 = mtbsf_c( &mtid2, &one ); /* skip TM backwards */ if ( mterr2 == 1 ) { /* done */ ncur2--; /* decrease counter */ } else if ( mterr2 == 0 ) { /* at BOT */ anyout_c( &screen, tofchar( "Tape at BOT" ) ); } else { /* an error */ sprintf( text, "MTBSF error %d", mterr2 ); error_c( &fatal, tofchar( text ) ); /* show user */ } /* * Next we try to find EOI by skipping a TM and reading the next * record. If the read returns 0, we have found EOI. */ while ( ( ( mterr2 = mtfsf_c( &mtid2, &one ) ) == 1 ) && ( ( ndone = mtread_c( &mtid2, dat2, &one ) ) > 0 ) ) { ncur2++; /* increase */ } if ( ndone == -2 ) ndone = 0; /* EOD/EOT not fatal! */ if (( mterr2 == 1 ) && ( ndone == 0 )) { /* okay */ sprintf( text, "Skipped %d files forward", ++ncur2 ); anyout_c( &screen, tofchar( text ) ); /* show user */ mterr2 = mtbsf_c( &mtid2, &one ); /* one TM back */ } if (( mterr2 != 1 ) || ( ndone != 0 )) { /* an error */ sprintf( text, "MTFSF error %d, MTREAD error %d", mterr2, ndone ); error_c( &fatal, tofchar( text ) ); /* show user */ } } else if (nfil2 > 0) { /* position output tape */ mterr2 = mtfsf_c( &mtid2, &nfil2 ); /* skip forward */ if (mterr2 >= 0) { /* okay */ ncur2 = mterr2; /* file counter */ sprintf( text, "Skipped %d files forward", ncur2 ); anyout_c( &screen, tofchar( text ) ); /* show user */ } else { /* error */ sprintf( text, "MTFSF error %d", mterr2 ); error_c( &fatal, tofchar( text ) ); /* show user */ } } else if (nfil2 < 0) { /* skip backward */ nfil2 = 1 - nfil2; /* new count */ if ((mterr2 = mtbsf_c( &mtid2, &nfil2 )) == nfil2) { ncur2 = 1 - mterr2; /* current position */ mterr2 = mtfsf_c( &mtid2, &one ); /* forward skip one tape mark */ if (mterr2 != 1) { /* error */ sprintf( text, "MTFSF error %d", mterr2 ); error_c( &fatal, tofchar( text ) ); /* show user */ } sprintf( text, "Skipped %d files backward", ncur2 ); anyout_c( &screen, tofchar( text ) ); /* show user */ } else if (mterr2 >= 0 ) { /* backwards into BOT */ ncur2 = 0; /* BOT */ anyout_c( &screen, tofchar( "Tape at BOT" ) ); sprintf( text, "Skipped %d files backward", mterr2 ); anyout_c( &screen, tofchar( text ) ); /* show user */ } else { /* an error */ sprintf( text, "MTBSF error %d", mterr2 ); error_c( &fatal, tofchar( text ) ); /* show user */ } } deflev = 1; /* default allowed */ nitems = 1; /* number of items */ rewind1 = TRUE; /* the default */ userlog_c( &rewind1, &nitems, &deflev, INREWIND_KEY, INREWIND_MES ); deflev = 1; /* default allowed */ nitems = 1; /* number of items */ rewind2 = FALSE; /* the default */ userlog_c( &rewind2, &nitems, &deflev, OUTREWIND_KEY, OUTREWIND_MES ); deflev = 2; /* default and hidden */ nitems = 1; /* max number of items */ if (!userint_c( &reblock, &nitems, &deflev, REBLOCK_KEY, REBLOCK_MES )) { reblock = 0; /* default */ } if (reblock < 0) { error_c( &fatal, REBLOCK_ERR ); /* display error message */ finis_c( ); /* quit */ } if (reblock) { /* create space */ dat2 = realloc( dat2, sizeof( char ) * reblock ); if (dat2 == NULL) { /* error */ error_c( &fatal, tofchar( "Memory allocation problems!" ) ); } } ndone = 0; /* reset number of files copied */ do { /* loop to copy files */ fint nout = 0; fint nread = 0; fint nrec1 = 0; fint nrec2 = 0; if (nfil1) { /* position tape if read not sequential */ fint nfsf = files[ndone] - ncur1; /* number of files to skip forward */ if (nfsf > 0) { /* skip forward */ mterr1 = mtfsf_c( &mtid1, &nfsf ); } else if (nfsf < 0) { /* skip backward */ nfsf = 1 - nfsf; if ((mterr1 = mtbsf_c( &mtid1, &nfsf )) == nfsf) { nfsf = 1; mterr1 = mtfsf_c( &mtid1, &nfsf ); } } ncur1 = files[ndone]; /* current file number */ } nbyt1 = nbyt2 = 0; /* reset */ (void) sprintf( text, "Copy from %.*s (%d) to %.*s (%d)", (int) nelc_c( tape1 ), tape1.a, ncur1, (int) nelc_c( tape2 ), tape2.a, ncur2 ); status_c( tofchar( text ) ); while ((mterr1 = mtread_c( &mtid1, dat1, &ndat1 )) > 0) { /* read */ if (mterr1 > ndat1) { /* record too large */ ndat1 = mterr1; dat1 = realloc( dat1, sizeof( char ) * ndat1 ); /* larger buffer */ if (dat1 == NULL) { /* error */ error_c( &fatal, tofchar( "Memory allocation problems!" ) ); } if (!reblock) { /* increase out buffer accordingly */ ndat2 = ndat1; dat2 = realloc( dat2, sizeof( char ) * ndat2 ); if (dat2 == NULL) { /* error */ error_c( &fatal, tofchar( "Memory allocation problems!" ) ); } } nitems = 1; /* try to reread last record */ if ((mterr1 = mtbsr_c( &mtid1, &nitems )) != nitems) break; if ((mterr1 = mtread_c( &mtid1, dat1, &ndat1 )) < 0) break; } nbyt1 += mterr1; /* number of bytes read */ nrec1 += 1; /* next input record */ nread = mterr1; /* number of bytes read */ if (reblock) { /* loop for reblocking */ fint nmove; fint noff1 = 0; while ((nmove = ((nout + mterr1 - noff1) > reblock ? (reblock - nout) : (mterr1 - noff1)))) { (void) memmove( &dat2[nout], &dat1[noff1], nmove ); /* move */ noff1 += nmove; nout += nmove; if (nout == reblock) { /* write to output tape device */ if ((mterr2 = mtwrite_c( &mtid2, dat2, &nout )) != nout) break; nbyt2 += mterr2; /* number of bytes written */ nrec2 += 1; nout = 0; } } if (mterr2 < 0) break; } else { if ((mterr2 = mtwrite_c( &mtid2, dat1, &mterr1 )) != mterr1) break; nbyt2 += mterr2; /* number of bytes written */ nrec2 += 1; } } if (mterr1 >= 0 && mterr2 >= 0) { /* end-of-file enncur2ered */ if (reblock && nout) { (void) memset( &dat2[nout], 0, reblock - nout ); if ((mterr2 = mtwrite_c( &mtid2, dat2, &reblock )) != reblock) break; nbyt2 += mterr2; /* number of bytes written */ nrec2 += 1; } if (!nfil1 && !nrec1) break; /* end-of-information */ (void) mtweof_c( &mtid2, &nitems ); (void) sprintf( text, "Input FILE number : %8d (%8d records, %8d bytes)", ncur1, nrec1, nbyt1 ); anyout_c( &screen, tofchar( text ) ); (void) sprintf( text, "Output FILE number : %8d (%8d records, %8d bytes)", ncur2, nrec2, nbyt2 ); anyout_c( &screen, tofchar( text ) ); ncur1 += 1; /* next input file */ ncur2 += 1; /* next output file */ } else { break; } } while (++ndone != nfil1); /* loop until all files copied */ if (mterr1 < 0) { /* error on tape1 */ (void) sprintf( text, "Error (%d) on input tape device", mterr1 ); anyout_c( &screen, tofchar( text ) ); } if (mterr2 < 0) { (void) sprintf( text, "Error (%d) on output tape device", mterr2 ); anyout_c( &screen, tofchar( text ) ); } nitems = 1; (void) mtweof_c( &mtid2, &nitems ); /* write final tape mark */ if (tobool(rewind1)) { /* rewind tape 1 ? */ (void) mtrew_c( &mtid1 ); /* rewind tape 1 */ } if (tobool(rewind2)) { /* rewind tape 2 ? */ (void) mtrew_c( &mtid2 ); /* rewind tape 2 */ } else { /* no rewind */ (void) mtbsf_c( &mtid2, &one ); /* one tapemake back */ } (void) mtclose_c( &mtid1 ); /* close tape 1 */ (void) mtclose_c( &mtid2 ); /* close tape 2 */ finis_c( ); /* we quit */ return( EXIT_SUCCESS ); }