4.3 Tahoe rrestore bug

David P. Zimmerman dpz at dorm.rutgers.edu
Mon Nov 21 10:26:14 AEST 1988


In article <23669 at pprg.unm.edu> cyrus at pprg.unm.edu (Tait Cyrus) writes:

> I am trying to get the  4.3 Tahoe dump/restore/rmt stuff to run
> uder SunOS 3.5.  rdump seems to work fine, but rrestore does not.

Well, that doesn't make it a bug, does it?  BSD4.3 and SunOS 3.x are
different beasts, right down to the opendir() library call.  Here's my
fixes to the 4.3BSD [r]restore to make it work under SunOS3.x (and
also on Celerity 1200s and Pyramids).  You can see what I've changed,
and a bit of examination will explain why (RTFSC :-).

						David

:	This is a shell archive.
:	Remove everything above this line and
:	run the following text with /bin/sh to create:
:	README
:	Makefile.diff
:	dirs.c.diff
:	dumprestore.h.diff
:	interactive.c.diff
:	main.c.diff
:	restore.h.diff
:	tape.c.diff
:	opendir.c
:	telldir.c
: This archive created: Sun Nov 20 19:24:15 1988
cat << 'SHAR_EOF' > README
dpz's changes to the standard 4.3BSD restore for compatible Sun SunOS
3.x, Sun SunOS 4.0, Pyramid OSx4.1, and Celerity 3.4 restores:

	- replacing various #include files with equivalents
	- adding DIRBLKSIZ #define, making it largest DEV_BSIZE of all
	  architectures
	- copying DIR struct definition to RST_DIR, changing char
	  *dd_buf in it to char dd_buf[DIRBLKSIZ], changing all
	  routines that use DIR to use RST_DIR
	- copying 4.3 opendir() to rst_4_3_opendir() and changing
	  appropriate routines to call that instead of opendir()
	- copying 4.3 telldir() to rst_4_3_telldir(), changing
	  appropriate routines to call that instead of telldir()

	- compile on Sun SunOS 4.0 with -DSUNOS4 in Makefile and link
	  statically
	- generalizing "struct direct" to a typedef, since SunOS 4.0
	  has a field in it that doesn't exist on disk

	- adding/modifying /usr/include/protocols/dumprestore.h:
		- have TP_BSIZE equal the largest disk block size
		  across all three architectures (2048 in this case)
		- adjusting NTREC and HIGHDENSITYTREC down to balance
		  my higher TP_BSIZE
		- adjusting DUMPOUTFMT and DUMPINFMT to have the 
		  highest number across all three architectures for %XXs
		- adding CARTRIDGETREC for some reason

Frills:
	- modifying Makefile so ${CFLAGS} is included in final .o combining
	- adding Gary Winiger's epoch dump date mod (his comments below)
	- adding Gary Winiger's interactive.c seg violation mods (cmts below)

From: gww at elxsi.UUCP (Gary Winiger)

When restore lists the dates the the dump encompases such as with the
-t option, it will list the epoch date for the from date of a level 0
dump.

From: gww at elxsi.UUCP (Gary Winiger)

When running /etc/restore in interactive mode, any attempt to
reference a subdirectory will cause a segmentation violation on
systems that do not permit dereferencing a NULL pointer.
SHAR_EOF
cat << 'SHAR_EOF' > Makefile.diff
*** Makefile.ORIG	Sat Jan  9 16:27:02 1988
--- Makefile	Sat Jan  9 16:26:58 1988
***************
*** 16,22 ****
  	cc ${LDFLAGS} ${CFLAGS} -o restore ${OBJS} tape.o
  
  rrestore: ${OBJS} rtape.o dumprmt.o
! 	cc ${LDFLAGS} -o rrestore ${OBJS} rtape.o dumprmt.o
  
  rtape.o: tape.c
  	cp tape.c rtape.c
--- 16,22 ----
  	cc ${LDFLAGS} ${CFLAGS} -o restore ${OBJS} tape.o
  
  rrestore: ${OBJS} rtape.o dumprmt.o
! 	cc ${LDFLAGS} ${CFLAGS} -o rrestore ${OBJS} rtape.o dumprmt.o
  
  rtape.o: tape.c
  	cp tape.c rtape.c
SHAR_EOF
cat << 'SHAR_EOF' > dirs.c.diff
*** dirs.c.ORIG	Sat Jan  9 16:27:02 1988
--- dirs.c	Wed Aug 17 17:39:13 1988
***************
*** 43,53 ****
   */
  static daddr_t	seekpt;
  static FILE	*df, *mf;
! static DIR	*dirp;
  static char	dirfile[32] = "#";	/* No file */
  static char	modefile[32] = "#";	/* No file */
  extern ino_t	search();
! struct direct 	*rst_readdir();
  extern void 	rst_seekdir();
  
  /*
--- 43,54 ----
   */
  static daddr_t	seekpt;
  static FILE	*df, *mf;
! static RST_DIR	*dirp;
  static char	dirfile[32] = "#";	/* No file */
  static char	modefile[32] = "#";	/* No file */
  extern ino_t	search();
! RST_DIR		*rst_4_3_opendir();
! UNIXDIRECT 	*rst_readdir();
  extern void 	rst_seekdir();
  
  /*
***************
*** 71,77 ****
  	register int i;
  	register struct dinode *ip;
  	struct inotab *itp;
! 	struct direct nulldir;
  	int putdir(), null();
  
  	vprintf(stdout, "Extract directories from tape\n");
--- 72,78 ----
  	register int i;
  	register struct dinode *ip;
  	struct inotab *itp;
! 	UNIXDIRECT nulldir;
  	int putdir(), null();
  
  	vprintf(stdout, "Extract directories from tape\n");
***************
*** 105,111 ****
  		ip = curfile.dip;
  		if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
  			(void) fclose(df);
! 			dirp = opendir(dirfile);
  			if (dirp == NULL)
  				perror("opendir");
  			if (mf != NULL)
--- 106,112 ----
  		ip = curfile.dip;
  		if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
  			(void) fclose(df);
! 			dirp = rst_4_3_opendir(dirfile);
  			if (dirp == NULL)
  				perror("opendir");
  			if (mf != NULL)
***************
*** 144,150 ****
  	long (*todo)();
  {
  	register struct inotab *itp;
! 	register struct direct *dp;
  	register struct entry *np;
  	int namelen;
  	daddr_t bpt;
--- 145,151 ----
  	long (*todo)();
  {
  	register struct inotab *itp;
! 	register UNIXDIRECT *dp;
  	register struct entry *np;
  	int namelen;
  	daddr_t bpt;
***************
*** 182,188 ****
  	else
  		fprintf(stderr, "Warning: `..' missing from directory %s\n",
  			pname);
! 	bpt = telldir(dirp);
  	/*
  	 * a zero inode signals end of directory
  	 */
--- 183,189 ----
  	else
  		fprintf(stderr, "Warning: `..' missing from directory %s\n",
  			pname);
! 	bpt = rst_4_3_telldir(dirp);
  	/*
  	 * a zero inode signals end of directory
  	 */
***************
*** 197,203 ****
  			rst_seekdir(dirp, bpt, itp->t_seekpt);
  		}
  		dp = rst_readdir(dirp);
! 		bpt = telldir(dirp);
  	}
  	if (dp == NULL)
  		fprintf(stderr, "corrupted directory: %s.\n", locname);
--- 198,204 ----
  			rst_seekdir(dirp, bpt, itp->t_seekpt);
  		}
  		dp = rst_readdir(dirp);
! 		bpt = rst_4_3_telldir(dirp);
  	}
  	if (dp == NULL)
  		fprintf(stderr, "corrupted directory: %s.\n", locname);
***************
*** 246,252 ****
  	ino_t	inum;
  	char	*cp;
  {
! 	register struct direct *dp;
  	register struct inotab *itp;
  	int len;
  
--- 247,253 ----
  	ino_t	inum;
  	char	*cp;
  {
! 	register UNIXDIRECT *dp;
  	register struct inotab *itp;
  	int len;
  
***************
*** 270,279 ****
  	char *buf;
  	int size;
  {
! 	struct direct cvtbuf;
  	register struct odirect *odp;
  	struct odirect *eodp;
! 	register struct direct *dp;
  	long loc, i;
  	extern int Bcvt;
  
--- 271,280 ----
  	char *buf;
  	int size;
  {
! 	UNIXDIRECT cvtbuf;
  	register struct odirect *odp;
  	struct odirect *eodp;
! 	register UNIXDIRECT *dp;
  	long loc, i;
  	extern int Bcvt;
  
***************
*** 286,292 ****
  			}
  	} else {
  		for (loc = 0; loc < size; ) {
! 			dp = (struct direct *)(buf + loc);
  			if (Bcvt) {
  				swabst("l2s", (char *) dp);
  			}
--- 287,293 ----
  			}
  	} else {
  		for (loc = 0; loc < size; ) {
! 			dp = (UNIXDIRECT *)(buf + loc);
  			if (Bcvt) {
  				swabst("l2s", (char *) dp);
  			}
***************
*** 314,324 ****
   * add a new directory entry to a file.
   */
  putent(dp)
! 	struct direct *dp;
  {
  	dp->d_reclen = DIRSIZ(dp);
  	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
! 		((struct direct *)(dirbuf + prev))->d_reclen =
  		    DIRBLKSIZ - prev;
  		(void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
  		dirloc = 0;
--- 315,325 ----
   * add a new directory entry to a file.
   */
  putent(dp)
! 	UNIXDIRECT *dp;
  {
  	dp->d_reclen = DIRSIZ(dp);
  	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
! 		((UNIXDIRECT *)(dirbuf + prev))->d_reclen =
  		    DIRBLKSIZ - prev;
  		(void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
  		dirloc = 0;
***************
*** 334,340 ****
  flushent()
  {
  
! 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
  	(void) fwrite(dirbuf, (int)dirloc, 1, df);
  	seekpt = ftell(df);
  	dirloc = 0;
--- 335,341 ----
  flushent()
  {
  
! 	((UNIXDIRECT *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
  	(void) fwrite(dirbuf, (int)dirloc, 1, df);
  	seekpt = ftell(df);
  	dirloc = 0;
***************
*** 342,348 ****
  
  dcvt(odp, ndp)
  	register struct odirect *odp;
! 	register struct direct *ndp;
  {
  
  	bzero((char *)ndp, (long)(sizeof *ndp));
--- 343,349 ----
  
  dcvt(odp, ndp)
  	register struct odirect *odp;
! 	register UNIXDIRECT *ndp;
  {
  
  	bzero((char *)ndp, (long)(sizeof *ndp));
***************
*** 354,360 ****
  
  /*
   * Seek to an entry in a directory.
!  * Only values returned by ``telldir'' should be passed to rst_seekdir.
   * This routine handles many directories in a single file.
   * It takes the base of the directory in the file, plus
   * the desired seek offset into it.
--- 355,361 ----
  
  /*
   * Seek to an entry in a directory.
!  * Only values returned by ``rst_4_3_telldir'' should be passed to rst_seekdir.
   * This routine handles many directories in a single file.
   * It takes the base of the directory in the file, plus
   * the desired seek offset into it.
***************
*** 361,371 ****
   */
  void
  rst_seekdir(dirp, loc, base)
! 	register DIR *dirp;
  	daddr_t loc, base;
  {
  
! 	if (loc == telldir(dirp))
  		return;
  	loc -= base;
  	if (loc < 0)
--- 362,372 ----
   */
  void
  rst_seekdir(dirp, loc, base)
! 	register RST_DIR *dirp;
  	daddr_t loc, base;
  {
  
! 	if (loc == rst_4_3_telldir(dirp))
  		return;
  	loc -= base;
  	if (loc < 0)
***************
*** 379,389 ****
  /*
   * get next entry in a directory.
   */
! struct direct *
  rst_readdir(dirp)
! 	register DIR *dirp;
  {
! 	register struct direct *dp;
  
  	for (;;) {
  		if (dirp->dd_loc == 0) {
--- 380,390 ----
  /*
   * get next entry in a directory.
   */
! UNIXDIRECT *
  rst_readdir(dirp)
! 	register RST_DIR *dirp;
  {
! 	register UNIXDIRECT *dp;
  
  	for (;;) {
  		if (dirp->dd_loc == 0) {
***************
*** 398,404 ****
  			dirp->dd_loc = 0;
  			continue;
  		}
! 		dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
  		if (dp->d_reclen == 0 ||
  		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
  			dprintf(stderr, "corrupted directory: bad reclen %d\n",
--- 399,405 ----
  			dirp->dd_loc = 0;
  			continue;
  		}
! 		dp = (UNIXDIRECT *)(dirp->dd_buf + dirp->dd_loc);
  		if (dp->d_reclen == 0 ||
  		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
  			dprintf(stderr, "corrupted directory: bad reclen %d\n",
***************
*** 417,426 ****
  	}
  }
  
  /*
   * Simulate the opening of a directory
   */
! DIR *
  rst_opendir(name)
  	char *name;
  {
--- 418,431 ----
  	}
  }
  
+ #include "opendir.c"
+ 
+ #include "telldir.c"
+ 
  /*
   * Simulate the opening of a directory
   */
! RST_DIR *
  rst_opendir(name)
  	char *name;
  {
SHAR_EOF
cat << 'SHAR_EOF' > dumprestore.h.diff
*** dumprestore.h.ORIG	Mon Apr 18 21:33:00 1988
--- dumprestore.h	Tue Aug 16 17:08:45 1988
***************
*** 13,26 ****
   * NTREC is the number of TP_BSIZE blocks that are written
   * in each tape record. HIGHDENSITYTREC is the number of
   * TP_BSIZE blocks that are written in each tape record on
!  * 6250 BPI or higher density tapes.
   *
   * TP_NINDIR is the number of indirect pointers in a TS_INODE
   * or TS_ADDR record. Note that it must be a power of two.
   */
! #define TP_BSIZE	1024
! #define NTREC   	10
! #define HIGHDENSITYTREC	32
  #define TP_NINDIR	(TP_BSIZE/2)
  
  #define TS_TAPE 	1
--- 13,29 ----
   * NTREC is the number of TP_BSIZE blocks that are written
   * in each tape record. HIGHDENSITYTREC is the number of
   * TP_BSIZE blocks that are written in each tape record on
!  * 6250 BPI or higher density tapes.  CARTRIDGETREC is the
!  * number of TP_BSIZE blocks that are written in each tape
!  * record on cartridge tapes.
   *
   * TP_NINDIR is the number of indirect pointers in a TS_INODE
   * or TS_ADDR record. Note that it must be a power of two.
   */
! #define TP_BSIZE	2048
! #define NTREC   	5
! #define HIGHDENSITYTREC	16
! #define CARTRIDGETREC	31
  #define TP_NINDIR	(TP_BSIZE/2)
  
  #define TS_TAPE 	1
***************
*** 52,57 ****
  
  #define spcl u_spcl.s_spcl
  
! #define	DUMPOUTFMT	"%-16s %c %s"		/* for printf */
  						/* name, incno, ctime(date) */
! #define	DUMPINFMT	"%16s %c %[^\n]\n"	/* inverse for scanf */
--- 55,60 ----
  
  #define spcl u_spcl.s_spcl
  
! #define	DUMPOUTFMT	"%-22s %c %s"		/* for printf */
  						/* name, incno, ctime(date) */
! #define	DUMPINFMT	"%22s %c %[^\n]\n"	/* inverse for scanf */
SHAR_EOF
cat << 'SHAR_EOF' > interactive.c.diff
*** interactive.c.ORIG	Sat Jan  9 16:27:01 1988
--- interactive.c	Tue Jul 12 17:00:11 1988
***************
*** 398,409 ****
  	register struct arglist *ap;
  {
  	static struct afile single;
  	int size;
  
  	ap->head = ap->last = (struct afile *)0;
  	size = expand(arg, 0, ap);
  	if (size == 0) {
! 		single.fnum = lookupname(arg)->e_ino;
  		single.fname = savename(arg);
  		ap->head = &single;
  		ap->last = ap->head + 1;
--- 398,411 ----
  	register struct arglist *ap;
  {
  	static struct afile single;
+ 	struct entry *ep;
  	int size;
  
  	ap->head = ap->last = (struct afile *)0;
  	size = expand(arg, 0, ap);
  	if (size == 0) {
! 	        ep = lookupname(arg);
! 		single.fnum = ep != NIL ? ep->e_ino : 0;
  		single.fname = savename(arg);
  		ap->head = &single;
  		ap->last = ap->head + 1;
***************
*** 423,432 ****
  	int		count, size;
  	char		dir = 0;
  	char		*rescan = 0;
! 	DIR		*dirp;
  	register char	*s, *cs;
  	int		sindex, rindex, lindex;
! 	struct direct	*dp;
  	register char	slash; 
  	register char	*rs; 
  	register char	c;
--- 425,434 ----
  	int		count, size;
  	char		dir = 0;
  	char		*rescan = 0;
! 	RST_DIR		*dirp;
  	register char	*s, *cs;
  	int		sindex, rindex, lindex;
! 	UNIXDIRECT	*dp;
  	register char	slash; 
  	register char	*rs; 
  	register char	c;
***************
*** 571,577 ****
   * Construct a matched name.
   */
  addg(dp, as1, as3, ap)
! 	struct direct	*dp;
  	char		*as1, *as3;
  	struct arglist	*ap;
  {
--- 573,579 ----
   * Construct a matched name.
   */
  addg(dp, as1, as3, ap)
! 	UNIXDIRECT	*dp;
  	char		*as1, *as3;
  	struct arglist	*ap;
  {
***************
*** 609,618 ****
  	char *basename;
  {
  	register struct afile *fp;
! 	register struct direct *dp;
  	static struct arglist alist = { 0, 0, 0, 0, "ls" };
  	struct afile single;
! 	DIR *dirp;
  
  	if ((dirp = rst_opendir(name)) == NULL) {
  		single.fnum = ino;
--- 611,620 ----
  	char *basename;
  {
  	register struct afile *fp;
! 	register UNIXDIRECT *dp;
  	static struct arglist alist = { 0, 0, 0, 0, "ls" };
  	struct afile single;
! 	RST_DIR *dirp;
  
  	if ((dirp = rst_opendir(name)) == NULL) {
  		single.fnum = ino;
SHAR_EOF
cat << 'SHAR_EOF' > main.c.diff
*** main.c.ORIG	Sat Jan  9 16:27:00 1988
--- main.c	Tue Jul 12 16:39:19 1988
***************
*** 58,64 ****
--- 58,66 ----
  	char *inputdev = "/dev/rmt8";
  	char *symtbl = "./restoresymtable";
  	char name[MAXPATHLEN];
+ #ifndef SUNOS4
  	int (*signal())();
+ #endif
  	extern int onintr();
  
  	if (signal(SIGINT, onintr) == SIG_IGN)
SHAR_EOF
cat << 'SHAR_EOF' > restore.h.diff
*** restore.h.ORIG	Sat Jan  9 16:27:01 1988
--- restore.h	Tue Jul 12 17:02:25 1988
***************
*** 8,17 ****
  
  #include <stdio.h>
  #include <sys/param.h>
! #include <sys/inode.h>
! #include <sys/fs.h>
  #include <sys/dir.h>
  
  /*
   * Flags
   */
--- 8,42 ----
  
  #include <stdio.h>
  #include <sys/param.h>
! #include <sys/time.h>
! #include <sys/vnode.h>
! #include <ufs/inode.h>
! #include <ufs/fs.h>
  #include <sys/dir.h>
  
+ #ifdef SUNOS4
+ typedef struct {
+ 	u_long	d_fileno;		/* file number of entry */
+ 	u_short	d_reclen;		/* length of this record */
+ 	u_short	d_namlen;		/* length of string in d_name */
+ 	char	d_name[MAXNAMLEN + 1];	/* name (up to MAXNAMLEN + 1) */
+ } UNIXDIRECT;
+ #else
+ typedef struct direct UNIXDIRECT;
+ #endif
+ 
+ #define DIRBLKSIZ       2048
+ 
+ typedef struct _rstdirdesc {
+         int     dd_fd;
+         long    dd_loc;
+         long    dd_size;
+ 	long	dd_bbase;
+ 	long	dd_entno;
+ 	long	dd_bsize;
+         char    dd_buf[DIRBLKSIZ];
+ } RST_DIR;
+ 
  /*
   * Flags
   */
***************
*** 76,83 ****
  extern char *flagvalues();
  extern ino_t lowerbnd();
  extern ino_t upperbnd();
! extern DIR *rst_opendir();
! extern struct direct *rst_readdir();
  #define NIL ((struct entry *)(0))
  /*
   * Constants associated with entry structs
--- 101,108 ----
  extern char *flagvalues();
  extern ino_t lowerbnd();
  extern ino_t upperbnd();
! extern RST_DIR *rst_opendir();
! extern UNIXDIRECT *rst_readdir();
  #define NIL ((struct entry *)(0))
  /*
   * Constants associated with entry structs
SHAR_EOF
cat << 'SHAR_EOF' > tape.c.diff
*** tape.c.ORIG	Sat Jan  9 16:27:03 1988
--- tape.c	Sun May 29 19:09:30 1988
***************
*** 153,159 ****
  	}
  	if (vflag || command == 't') {
  		fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
! 		fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
  	}
  	dumptime = spcl.c_ddate;
  	dumpdate = spcl.c_date;
--- 153,161 ----
  	}
  	if (vflag || command == 't') {
  		fprintf(stdout, "Dump   date: %s", ctime(&spcl.c_date));
! 		fprintf(stdout, "Dumped from: %s",
! 			(spcl.c_ddate == (time_t)0)
! 			? "the epoch\n" : ctime(&spcl.c_ddate));
  	}
  	dumptime = spcl.c_ddate;
  	dumpdate = spcl.c_date;
SHAR_EOF
cat << 'SHAR_EOF' > opendir.c
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/*
 * open a directory.
 */
RST_DIR *
rst_4_3_opendir(name)
	char *name;
{
	register RST_DIR *dirp;
	register int fd;

	if ((fd = open(name, 0)) == -1)
		return NULL;
	if ((dirp = (RST_DIR *)malloc(sizeof(RST_DIR))) == NULL) {
		close (fd);
		return NULL;
	}
	dirp->dd_fd = fd;
	dirp->dd_loc = 0;
	return dirp;
}
SHAR_EOF
cat << 'SHAR_EOF' > telldir.c
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/*
 * return a pointer into a directory
 */
long
rst_4_3_telldir(dirp)
	RST_DIR *dirp;
{
	extern long lseek();

	return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
}
SHAR_EOF
:	End of shell archive
exit 0
-- 
David P. Zimmerman, the Dorm Networking Pilot Project, the UUCP Project, etc
dpz at dorm.rutgers.edu          rutgers!dpz          dpzimmerman at zodiac.bitnet



More information about the Comp.bugs.4bsd.ucb-fixes mailing list