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;