Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!husc6!hao!ames!aurora!labrea!decwrl!pyramid!prls!philabs!micomvax!musocs!mcgill-vision!mouse
From: mouse@mcgill-vision.UUCP (der Mouse)
Newsgroups: comp.sources.bugs
Subject: copytape fix allowing network operation
Message-ID: <922@mcgill-vision.UUCP>
Date: Fri, 20-Nov-87 23:00:28 EST
Article-I.D.: mcgill-v.922
Posted: Fri Nov 20 23:00:28 1987
Date-Received: Fri, 27-Nov-87 00:10:10 EST
Organization: McGill University, Montreal
Lines: 120

The copytape program posted to comp.sources.unix is a very nice and
extremely useful program.  However, when it was updated recently to fix
some bugs, some other bugs were introduced.  While it may be true that

% copytape /dev/rmt8 /dev/rmt9

or

% copytape /dev/rmt8 tempfile
(switch tapes)
% copytape tempfile /dev/rmt8

will work, it is not true that

% copytape < /dev/rmt8 | rsh othermachine copytape \> /dev/rmt8

works.  This is because an assumption about the nature of data files is
made that is valid for real files but not for network connections or
pipes....  When read(...,n,...) is done on a file, the system
guarantees that if (at least) n bytes remain before end-of-file, the
read will read all n.  With a pipe or a network connection, this is not
the case.  Here is a fix to copytape to make it work across network
connections or pipes:

*** copytape.c.original	Fri Nov 20 22:42:38 1987
--- copytape.c	Fri Nov 20 22:30:01 1987
***************
*** 193,199 ****
--- 193,234 ----
      exit(0);
  }
  
+ /* When reading from a file, read(...,n,...) is guaranteed to return
+    n bytes if they are present.  When reading from a pipe or a network
+    connection, this is not the case.  Hence.... */
+ int Read(fd,buf,n)
+ int fd;
+ char *buf;
+ int n;
+ {
+  int left;
+  char *bp;
+  int did;
+  int nr;
  
+  bp = buf;
+  left = n;
+  did = 0;
+  while (left > 0)
+   { nr = read(fd,bp,left);
+     if (nr < 0)
+      { if (did == 0)
+ 	{ did = -1;
+ 	}
+        break;
+      }
+     else if (nr == 0)
+      { break;
+      }
+     else
+      { did += nr;
+        bp += nr;
+        left -= nr;
+      }
+   }
+  return(did);
+ }
+ 
  /*
   * Input up to 256K from a file or tape. If input file is a tape, then
   * do markcount stuff.  Input record length will be supplied by the
***************
*** 229,249 ****
  	};
      }
      /* Input is really a data file. */
!     l2 = read(fd, header, 5);
      if (l2 != 5 || strncmp(header, "CPTP:", 5) != 0)
  	return FORMAT_ERROR;
  
!     l2 = read(fd, header, 4);
      if (strncmp(header, "BLK ", 4) == 0) {
! 	l2 = read(fd, header, 7);
  	if (l2 != 7)
  	    return FORMAT_ERROR;
  	header[6] = '\0';
  	len = atoi(header);
! 	l2 = read(fd, tapebuf, len);
  	if (l2 != len)
  	    return FORMAT_ERROR;
! 	read(fd, header, 1);	/* skip trailing newline */
      } else if (strncmp(header, "MRK\n", 4) == 0)
  	return TAPE_MARK;
      else if (strncmp(header, "EOT\n", 4) == 0)
--- 264,284 ----
  	};
      }
      /* Input is really a data file. */
!     l2 = Read(fd, header, 5);
      if (l2 != 5 || strncmp(header, "CPTP:", 5) != 0)
  	return FORMAT_ERROR;
  
!     l2 = Read(fd, header, 4);
      if (strncmp(header, "BLK ", 4) == 0) {
! 	l2 = Read(fd, header, 7);
  	if (l2 != 7)
  	    return FORMAT_ERROR;
  	header[6] = '\0';
  	len = atoi(header);
! 	l2 = Read(fd, tapebuf, len);
  	if (l2 != len)
  	    return FORMAT_ERROR;
! 	Read(fd, header, 1);	/* skip trailing newline */
      } else if (strncmp(header, "MRK\n", 4) == 0)
  	return TAPE_MARK;
      else if (strncmp(header, "EOT\n", 4) == 0)

					der Mouse

				(mouse@mcgill-vision.uucp)