[comp.os.minix] getdents.c bug fix, fixes new ls also

culberts@hpccc.HP.COM (Bruce Culbertson) (08/24/89)

Bravo for the new ls -- it is a big improvement.  Several people have noticed
that it fails on large directories, though.  The problem is actually in
the library file getdents.c.  The cdiff below seems to fix the problem on
my system.  It should now work for directories of arbitrary size and there
should no longer be any special requirements on the size of the buffer
passed to getdents().  Previously, readdir() passed a buffer which was
too small to work with the original getdents().

A small nit I have with both the new and old ls's: the long format expects
user id's to be at most 6 characters.  My user id (culberts) fouls up the
columns.

Bruce Culbertson
culberts@hplabs.hp.com
--------------------------------  cut here  --------------------------------
*** getdents.old	Thu Aug 24 09:04:24 1989
--- getdents.c	Thu Aug 24 09:09:22 1989
***************
*** 100,107 ****
  #endif
  
  #ifndef DIRBLKSIZ
! #define	DIRBLKSIZ	4096		/* directory file read buffer size */
  #endif
  
  #ifndef NULL
  #define	NULL	0
--- 100,117 ----
  #endif
  
  #ifndef DIRBLKSIZ
! /* directory file read buffer size
!  * For directory files with fixed sized records, this should be a
!  * multiple of the record size.  For variable sized records, this code
!  * is probably unreliable if the directory is larger than DIRBLKSIZ --
!  * so make DIRBLKSIZ big.
!  */
! #ifdef UFS
! #define	DIRBLKSIZ (64*sizeof(struct direct))
! #else
! #define	DIRBLKSIZ 4096
  #endif
+ #endif
  
  #ifndef NULL
  #define	NULL	0
***************
*** 275,282 ****
  
  				if ( (char *)bp + reclen > &buf[nbyte] )
  					{
! 					errno = EINVAL;
! 					return -1;	/* buf too small */
  					}
  
  				bp->d_ino = dp->d_fileno;
--- 285,301 ----
  
  				if ( (char *)bp + reclen > &buf[nbyte] )
  					{
! 					/* buf too small, lseek so we get the
! 					 * rest on next call to getdents() 
! 					 */
! 					if (lseek (fildes,
! 					(long)((char *)dp-u.dblk),
! 					SEEK_CUR) < 0)
! 						{
! 						/* errno set by lseek */
! 						return -1;
! 						}
! 					break;
  					}
  
  				bp->d_ino = dp->d_fileno;

culberts@hpccc.HP.COM (Bruce Culbertson) (08/29/89)

I regret to say that the original bug fix I posted for getdents.c was
not entirely correct.  Previously I tested it with readdir(), which
unfortunately did not expose the problem which still existed.  I have
tested the new version with a good sampling of directory sizes and
buffer sizes.  I hope this will be my last message on this subject!
This cdif is relative to the original 1.4a version.

Bruce Culbertson
culberts@hplabs.hp.com
---------------------------------  cut  ----------------------------------
*** getdents.old	Thu Aug 24 09:04:24 1989
--- getdents.c	Thu Aug 24 18:28:17 1989
***************
*** 100,107 ****
  #endif
  
  #ifndef DIRBLKSIZ
! #define	DIRBLKSIZ	4096		/* directory file read buffer size */
  #endif
  
  #ifndef NULL
  #define	NULL	0
--- 100,117 ----
  #endif
  
  #ifndef DIRBLKSIZ
! /* directory file read buffer size
!  * For directory files with fixed sized records, this should be a
!  * multiple of the record size.  For variable sized records, this code
!  * is probably unreliable if the directory is larger than DIRBLKSIZ --
!  * so make DIRBLKSIZ big.
!  */
! #ifdef UFS
! #define	DIRBLKSIZ (64*sizeof(struct direct))
! #else
! #define	DIRBLKSIZ 4096
  #endif
+ #endif
  
  #ifndef NULL
  #define	NULL	0
***************
*** 109,114 ****
--- 119,125 ----
  
  #ifndef SEEK_CUR
  #define	SEEK_CUR	1
+ #define	SEEK_SET	0
  #endif
  
  #ifndef S_ISDIR				/* macro to test for directory file */
***************
*** 275,282 ****
  
  				if ( (char *)bp + reclen > &buf[nbyte] )
  					{
! 					errno = EINVAL;
! 					return -1;	/* buf too small */
  					}
  
  				bp->d_ino = dp->d_fileno;
--- 286,302 ----
  
  				if ( (char *)bp + reclen > &buf[nbyte] )
  					{
! 					/* buf too small, lseek so we get the
! 					 * rest on next call to getdents() 
! 					 */
! 					if (lseek (fildes,
! 					(long)((char *)dp-u.dblk+offset),
! 					SEEK_SET) < 0)
! 						{
! 						/* errno set by lseek */
! 						return -1;
! 						}
! 					break;
  					}
  
  				bp->d_ino = dp->d_fileno;