[comp.periphs.scsi] using SCSI tape in read/write mode

del@fnx.UUCP (Dag Erik Lindberg) (11/07/90)

I have decided to write a tape archiving utility and am having some
problems figuring out how to use the tape drive. Some background:

What I need is approximately the functional equivalent of 'tar r'
to append files to the end of an archive tape.  Unfortunately, 'tar r'
does not allow blocking factors, and without the blocking start/stop
of the tape is absurd.  While the lost data from inter-record spacing
is not a problem, time to write a file and wear-and-tear on the drive
are objectionable.

I have come up with several approaches for this utility, and I am
currently favoring writing a (fixed size) tape directory to the
front of the tape with pointers to the files on the tape and the
start point for the next file to be written.

Here is the problem:

1) If I make a loop to write 30 x 1k records containing "Record #x",
   rewind the tape, and read 30 records, printf()ing each, there 
   is no problem.  Rewind again, read 15 records, write one record
   containing "Record 15 modified" and rewind the tape.  Now read
   30 records and printf().  Hmmm, nobody got modified.  The write()
   did not return an error.  What am I doing wrong?
2) I have used ioctl()'s to write EOF marks to the tape, and then
   tried to skip 'x' of them with the appropriate ioctl().  This
   does not seem to get me to the correct record #.  For example,
   I write 30 x 1k records containing only "Record #x", with an
   ioctl() in between each one, rewind the tape, then skip 15 of
   them.  Read one and printf the contents.  I seem to come up 
   around #10.

The system is ISC 2.0.2, the tape drive is an Archive 2150s on 1542.
I don't have the code around anymore which demonstrates #2 above, but
here is the hack I've been using to experiment with #1:


#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/gentape.h>

#define NUMRECS 30

struct tc_parms tcp;

main()
{
	char buf[1024],buf1[1024];
	int fd, x;
	/* Note that I am opening the tape in read/write mode. */
	fd = open("/dev/mt0",O_RDWR|O_EXCL);
	strcpy(buf1,"This is a string in the tape output buffer.\n");
	ioctl(fd,TC_REWIND);
	/* Initialize the tape with 30 records. */
	for (x=0; x<NUMRECS; x++) {
printf("Writing buffer %d.\n",x);
		sprintf(buf1,"This is new buffer #%d\n",x);
		if (write(fd,buf1,1024) < 1024)
			printf("Error on write.\n");
#if 0		/* I tried this once to see if I could make file marks. */
		close(fd);
		open("/dev/nmt0",O_RDWR|O_EXCL|O_SYNC);
#endif
	}
  	/* Now done writing the the 30 records.  I am not currently closing
   	   the tape device, but my experience so far indicates it doesn't
	   really make any difference.
	*/
printf("Rewinding\n");
	ioctl(fd,TC_REWIND);

	/* What I want to do here is change one record approximately half
	   way through the tape.  Note that I don't really care if any
	   of the data past the point I make the write operation is
	   trashed, since my application will only ever *append* to the
	   tape.  The point is that I can't get the write() to do
	   anything.
	*/
	for (x=0; x<NUMRECS/2; x++) {
		int err;
		err = read(fd,buf,1024);
		if (err < 1024) {
printf("Error on read...\n");
			ioctl(fd,TC_SEOF,1);
			read(fd,buf,1024);
		}
		printf("Read: %s",buf);
	}
printf("Writing overlay buffer...\n");
	/* This doesn't seem to do anything usefull.... */
	ioctl(fd,TC_WFM);
	/* Either does this :-) */
	ioctl(fd,TC_GETPARMS,&tcp);
	printf("speed: %d, flags: %x, type: %d, recsize: %d\n",
		tcp.tcp_speed, tcp.tcp_flags, tcp.tcp_medtype, tcp.tcp_recsiz);
	strcpy(buf1,"Overlayed buffer.");
	
	/* Neither of these writes gives an error. */
	if (write(fd,buf1,1024) < 1024)
		printf("Error on first write.\n");
	if (write(fd,buf1,1024) < 1024)
		printf("Error on second write.\n");

printf("Rewind...\n");
	ioctl(fd,TC_REWIND);
	/* Note that all the records are read back.... none are changed. */
	for (x=0; x<NUMRECS; x++) {
		int err;
		err = read(fd,buf,1024);
		if (err < 1024) {
printf("Error on read...\n");
			ioctl(fd,TC_SEOF,1);
			read(fd,buf,1024);
		}
		printf("Read: %s",buf);
	}
	ioctl(fd,TC_REWIND);
}

So, the question comes down to, how does tar do it?  I have tried tar, and
it does in fact append to an archive, it just takes so long to get to the
end of the archive I can't even imagine trying to add a file to the end
of a 130 Meg collection.  Everything I try just seems to drop the bits
in a bucket somewhere...  Suggestions appreciated...


-- 
del AKA Erik Lindberg                             uunet!pilchuck!fnx!del
                          Who is John Galt?