Article View: comp.arch.storage
Article #369tape2disk.c and disk2tape.c
From: Ed Hamrick
Date: Thu, 19 May 1994 16:03
Date: Thu, 19 May 1994 16:03
384 lines
11649 bytes
11649 bytes
In article <2rfr8p$41t@netnews.upenn.edu>,
Kirsten Starcher <kirsten@ssc.sas.upenn.edu> wrote:
>We have a large number of IBM mainframe 9-track tapes, both labelled
>and unlabelled, that we would like to transcribe to our RS/6000s. Does
>anyone know of a script or program that we could use to make a dumb
>copy of the tapes to online storage? (Preserving record length and
>block size.)
Attached is a program that transcribes a tape to a disk file
(tape2disk.c) and a program that does the reverse (disk2tape.c).
These programs were written to use the async I/O capability of
ConvexOS in order to get higher performance by overlapping disk
and tape I/O. You'll have to change a few lines to adapt to AIX.
Regards,
Ed Hamrick
/*
* tape2disk - Utility to copy a tape to a disk file (or pipe)
*
* This program copies an entire mag tape to a disk file (or pipe)
* in a way that the tape can be completely reconstructed from the
* disk file.
*
* The disk format is relatively simple. For each tape record, a 4-byte
* record length is stored, followed by the data. For each end of file
* mark, a zero is stored. For each error reading the tape, a negative
* one is stored.
*
* The companion program disk2tape rewrites a tape from the disk file.
*
* At the front of each disk file is a single 80-byte record containing
* a comment for self-identification of the file.
*
* Usage:
*
* tape2disk tape disk comment
*
* if disk is "-", then output will be written to stdout
*
* Limitations:
*
* The maximum record length handled by this program is 256 KBytes. This
* is the maximum length supported by the 3490 and Metrum tape drives.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
/* Maximum data block size */
#define BUFFER_SIZE (256*1024)
/* Length of the initial label */
#define LABEL_SIZE 80
/* Number of sequential EOF's or errors that will terminate reading */
#define EOF_THRESHOLD 2
int act; /* Currently active I/O buffer */
int eof; /* Number of sequential EOF's or errors */
int len; /* Length of disk record */
int fil; /* File number (starts at 0) */
int rec; /* Record number (starts at 0) */
long long byt; /* Total number of bytes */
struct {
int ret; /* Value returned from read() */
char buf[BUFFER_SIZE]; /* Data returned from read() */
} tap[2];
char hdr[LABEL_SIZE]; /* 80 byte file label */
long long itod() {
struct timeval tp;
gettimeofday(&tp,0);
return (((long long)(tp.tv_sec) % 86400) * 1000 +
tp.tv_usec / 1000);
}
main (int argc, char **argv) {
int tape_fd; /* Tape file descriptor */
int disk_fd; /* Disk file descriptor */
long long t1,t2; /* Start and end times */
int first; /* Flag for first time through loop */
if (argc != 4) {
fprintf(stderr,"Usage: tape2disk tape disk comment\n");
exit(1);
}
memset(hdr, ' ', LABEL_SIZE);
memcpy(hdr, argv[3], strlen(argv[3]));
tape_fd = open(argv[1],O_RDONLY);
if (!strcmp(argv[2],"-")) {
disk_fd = fileno(stdout);
}
else {
disk_fd = open(argv[2],O_RDWR|O_CREAT, 0755);
}
fcntl(tape_fd,F_SETFL,_FASIO);
fcntl(disk_fd,F_SETFL,O_LARGEFILE);
if (write(disk_fd, hdr, LABEL_SIZE) != LABEL_SIZE) {
fprintf(stderr,"Error writing disk file\n");
exit(1);
}
act = 0;
eof = 0;
fil = 0;
rec = 0;
byt = 0;
first = 1;
t1 = itod();
do {
if (read(tape_fd,tap[act].buf,BUFFER_SIZE) != BUFFER_SIZE) {
fprintf(stderr,"Error starting tape I/O on file %d record %d errno %d\n",
fil, rec, errno);
exit(1);
}
if (!first) { /* If not first time */
if (tap[act^1].ret < 0) { /* if it got an error */
len = 4; /* only store ret code */
fprintf(stderr,"Error reading file %d record %d errno %d\n",
fil, rec, errno);
}
else { /* if no error */
len = 4 + tap[act^1].ret; /* store len + data */
if (len == 4) { /* if an EOF mark */
fil++; /* update file no */
rec = 0; /* reset record no */
}
else { /* if a normal record */
rec++; /* update record no */
byt += len-4; /* update byte count */
}
}
if (len == 4) { /* if not a data record */
eof++; /* update eof count */
}
else { /* if a data record */
eof = 0; /* clear eof count */
}
if (write(disk_fd, &tap[act^1].ret, len) != len) { /* write the disk */
fprintf(stderr,"Error writing disk on file %d record %d errno %d\n",
fil, rec, errno);
exit(1);
}
if (eof >= EOF_THRESHOLD) { /* All done with copy */
t2 = itod();
fprintf(stderr,"Copied %d files %lld bytes at %d Bytes/sec\n",
fil, byt, (int) (byt/(t2-t1)));
exit(0);
}
}
else {
first = 0;
}
tap[act].ret = asiostat(tape_fd); /* Wait for tape I/O complete */
act ^= 1; /* Update active buffer num */
} while (1);
}
/*
* disk2tape - Utility to copy a disk file (or pipe) to a tape
*
* This program copies a disk file (or pipe) to an entire tape. It
* restores the tape image that was produced by the tape2disk program.
*
* The disk format is relatively simple. For each tape record, a 4-byte
* record length is stored, followed by the data. For each end of file
* mark, a zero is stored. For each error reading the tape, a negative
* one is stored.
*
* At the front of each disk file is a single 80-byte record containing
* a comment for self-identification of the file.
*
* Usage:
*
* disk2tape disk tape
*
* if disk is "-", then input will come from stdin
*
* Limitations:
*
* The maximum record length handled by this program is 256 KBytes. This
* is the maximum length supported by the 3490 and Metrum tape drives.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <fcntl.h>
#include <errno.h>
/* Maximum data block size */
#define BUFFER_SIZE (256*1024)
/* Length of the initial label */
#define LABEL_SIZE 80
int act; /* Currently active I/O buffer */
int len; /* Length of disk record */
int fil; /* File number (starts at 0) */
int rec; /* Record number (starts at 0) */
long long byt; /* Total number of bytes */
struct {
int len; /* Length of buffer to write */
char buf[BUFFER_SIZE]; /* Data to write */
} tap[2];
char hdr[LABEL_SIZE]; /* 80 byte file label */
long long itod() {
struct timeval tp;
gettimeofday(&tp,0);
return (((long long)(tp.tv_sec) % 86400) * 1000 +
tp.tv_usec / 1000);
}
/*
* Note that a special read routine is needed for reading from
* a pipe because in general, a read can return successfully with
* fewer bytes read than requested. The read routine must be
* synchronous for this reason.
*/
static int pipe_read(int pipe_fd, char *pipe_buf, int pipe_siz) {
int tot = 0;
int siz;
while (tot < pipe_siz) {
siz = read(pipe_fd, pipe_buf+tot, pipe_siz-tot);
if (siz < 0) return siz;
if (siz == 0) return tot;
tot += siz;
}
return tot;
}
main (int argc, char **argv) {
int tape_fd; /* Tape file descriptor */
int disk_fd; /* Disk file descriptor */
int i, j;
long long t1,t2; /* Start and end times */
struct mtop weof = {MTWEOF, 1};
if (argc != 3) {
fprintf(stderr,"Usage: disk2tape disk tape\n");
exit(1);
}
memset(hdr, ' ', LABEL_SIZE);
if (!strcmp(argv[1],"-")) {
disk_fd = fileno(stdin);
}
else {
disk_fd = open(argv[1],O_RDONLY);
}
tape_fd = open(argv[2],O_RDWR);
fcntl(tape_fd,F_SETFL,_FASIO);
fcntl(disk_fd,F_SETFL,O_LARGEFILE);
if (pipe_read(disk_fd, hdr, LABEL_SIZE) != LABEL_SIZE) {
fprintf(stderr,"Error reading comment from disk file\n");
exit(1);
}
for (i=79; i>=0; i--) {
if (hdr[i] != ' ') break;
}
if (i > 0) {
hdr[i+1] = 0;
fprintf(stderr,"Comment - %s\n",hdr);
}
act = 0;
fil = 0;
rec = 0;
byt = 0;
tap[0].len = 0;
tap[1].len = 0;
t1 = itod();
do {
/* Read info about what should be written to tape */
i = pipe_read(disk_fd, (char *) &tap[act].len, sizeof(int));
if (i < 0) {
fprintf(stderr,"Error reading disk at file %d record %d errno %d\n",
fil, rec, errno);
exit(1);
}
if (i == 0) {
if (tap[act^1].len > 0) {
if (asiostat(tape_fd) != tap[act].len) {
fprintf(stderr,"Error writing tape at file %d record %d errno %d\n",
fil, rec, errno);
exit(1);
}
}
t2 = itod();
fprintf(stderr,"Copied %d files %lld bytes at %d Bytes/sec\n",
fil, byt, (int) (byt*1000/(t2-t1)));
exit(0);
}
if (tap[act].len > 0) {
if (pipe_read(disk_fd, tap[act].buf, tap[act].len) != tap[act].len) {
fprintf(stderr,"Error reading disk at file %d record %d errno %d\n",
fil, rec, errno);
exit(1);
}
}
/* Wait for completion of last write if necessary */
if (tap[act^1].len > 0) {
if (asiostat(tape_fd) != tap[act^1].len ) {
fprintf(stderr,"Error writing tape at file %d record %d errno %d\n",
fil, rec, errno);
exit(1);
}
}
/* Write an eof or start the data write if necessary */
if (tap[act].len < 0) {
fprintf(stderr,"Unable to recreate error at file %d record %d\n",
fil, rec);
}
else if (tap[act].len == 0) {
if (ioctl(tape_fd, MTIOCTOP, &weof) < 0) {
fprintf(stderr,"Error writing eof at file %d record %d errno %d\n",
fil, rec, errno);
exit(1);
}
fil++;
rec = 0;
}
else {
if (write(tape_fd,tap[act].buf,tap[act].len) != tap[act].len) {
fprintf(stderr,"Error writing tape at file %d record %d errno %d\n",
fil, rec, errno);
exit(1);
}
rec++;
byt += tap[act].len;
}
act ^= 1; /* Update active buffer num */
} while (1);
}
Technical Details
Message-ID:
<2rg2kg$k4n@convex.convex.com>Path:
arc1-ca.pugleaf.net!bga.com!news.sprintlink.net!get.hooked.net!decwrl!hookup!yeshua.marcam.com!MathWorks.Com!europa.eng.gtefsd.com!howland.reston.ans.net!darwin.sura.net!convex!hamrickReferences:
<2rfr8p$41t@netnews.upenn.edu>Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: f91da,3c2d8d55e3619294 X-Google-Attributes: gidf91da,public X-Google-Thread: 10e1c8,3c2d8d55e3619294 X-Google-Attributes: gid10e1c8,public X-Google-Thread: 115614,3c2d8d55e3619294 X-Google-Attributes: gid115614,public X-Google-Thread: 10d52b,769441441d1ea0e9,start X-Google-Attributes: gid10d52b,public X-Google-ArrivalTime: 1994-05-19 09:17:56 PST Path: arc1-ca.pugleaf.net!bga.com!news.sprintlink.net!get.hooked.net!decwrl!hookup!yeshua.marcam.com!MathWorks.Com!europa.eng.gtefsd.com!howland.reston.ans.net!darwin.sura.net!convex!hamrick From: hamrick@convex.com (Ed Hamrick) Newsgroups: comp.arch.storage,comp.unix.aix,bit.listserv.aix-l,comp.sys.convex Subject: tape2disk.c and disk2tape.c Date: 19 May 1994 16:03:28 GMT Organization: CONVEX Computer Corp, Richardson, TX USA Lines: 384 Message-ID: <2rg2kg$k4n@convex.convex.com> References: <2rfr8p$41t@netnews.upenn.edu> NNTP-Posting-Host: convex1.convex.com