Subject: diff fails on any but small directories (+FIX)
Index:	bin/diff/diffdir.c 2.11BSD

Description:
	Doing a "diff directorya directoryb" when either directory
	is not very small fails with and "out of memory" error.

Repeat-By:
	Have two directories comparable in size to /usr/src/sys/sys
	(or the Fortran runtime directories /usr/src/usr.lib/libU77,
	libI77, libF77).  Attempt to "diff" the two directories.

Fix:
	The problem is once again "realloc()".  The loop in setupdir()
	(diffdir.c) which scans the directory to build up the list of
	filenames to be sorted does a realloc() after each and every
	file name!  After each realloc() a malloc() is performed to
	allocate space for the file name - this fragments the memory
	such that the next realloc() must expand the process space.

	It doesn't take many files in a directory to cause 'diff' to
	run out of memory even though sufficient memory exists to
	hold the entire directory (and the filenames in memory) if only
	realloc() weren't used.

	The fix is to quickly prescan the directory and count the number
	of files.  This is not as slow or bad as it would first appear:
	if the directory is small then the scan will be fast, if the 
	directory is large then the scan time doesn't matter because 'diff'
	will at least handle the directory rather than failing with the
	"out of memory" error.

	The inode type 'ino_t' was substituted for 'u_long', this saves
	two bytes per file from having to be malloc'd for each file in a
	directory.  Also the (silly) sccsid[] stuff was ifdef'd out along 
	the way.
-------------------------------------------------------------------------
*** /usr/src/bin/diff/diff.c.old	Thu Apr  3 11:15:34 1986
--- /usr/src/bin/diff/diff.c	Mon Nov 11 16:24:25 1991
***************
*** 1,4 ****
--- 1,6 ----
+ #if	!defined(lint) && defined(DOSCCS)
  static	char sccsid[] = "@(#)diff.c 4.6 4/3/86";
+ #endif
  
  #include "diff.h"
  /*
*** /usr/src/bin/diff/diffdir.c.old	Tue Aug 28 19:38:23 1984
--- /usr/src/bin/diff/diffdir.c	Tue Nov 12 15:16:59 1991
***************
*** 1,4 ****
--- 1,6 ----
+ #if	!defined(lint) && defined(DOSCCS)
  static	char *sccsid = "@(#)diffdir.c	4.9 (Berkeley) 8/28/84";
+ #endif
  
  #include "diff.h"
  /*
***************
*** 12,18 ****
  #define	DIRECT	8		/* Directory */
  
  struct dir {
! 	u_long	d_ino;
  	short	d_reclen;
  	short	d_namlen;
  	char	*d_entry;
--- 14,20 ----
  #define	DIRECT	8		/* Directory */
  
  struct dir {
! 	ino_t	d_ino;
  	short	d_reclen;
  	short	d_namlen;
  	char	*d_entry;
***************
*** 181,187 ****
--- 183,197 ----
  		done();
  	}
  	nitems = 0;
+ #ifdef	pdp11
+ 	while (readdir(dirp))
+ 		nitems++;
+ 	rewinddir(dirp);
+ 	dp = (struct dir *)calloc(nitems+1, sizeof (struct dir));
+ 	nitems = 0;
+ #else
  	dp = (struct dir *)malloc(sizeof (struct dir));
+ #endif
  	if (dp == 0) {
  		fprintf(stderr, "diff: ran out of memory\n");
  		done();
***************
*** 200,205 ****
--- 210,216 ----
  			}
  			strcpy(ep->d_entry, rp->d_name);
  		}
+ #ifndef	pdp11
  		dp = (struct dir *)realloc((char *)dp,
  			(nitems + 1) * sizeof (struct dir));
  		if (dp == 0) {
***************
*** 206,211 ****
--- 217,223 ----
  			fprintf(stderr, "diff: ran out of memory\n");
  			done();
  		}
+ #endif
  	}
  	dp[nitems].d_entry = 0;		/* delimiter */
  	closedir(dirp);
*** /usr/src/bin/diff/diffh.c.old	Sat Jan 11 14:43:14 1986
--- /usr/src/bin/diff/diffh.c	Mon Nov 11 16:25:13 1991
***************
*** 1,4 ****
--- 1,6 ----
+ #if	!defined(lint) && defined(DOSCCS)
  static	char sccsid[] = "@(#)diffh.c 4.4 11/27/85";
+ #endif
  
  #include <stdio.h>
  #include <ctype.h>
*** /usr/src/bin/diff/diffreg.c.old	Thu Feb 12 02:09:58 1987
--- /usr/src/bin/diff/diffreg.c	Mon Nov 11 16:25:35 1991
***************
*** 1,4 ****
--- 1,6 ----
+ #if	!defined(lint) && defined(DOSCCS)
  static	char sccsid[] = "@(#)diffreg.c 4.16 3/29/86";
+ #endif
  
  #include "diff.h"
  /*
