about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/readdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/readdir.c')
-rw-r--r--sysdeps/unix/sysv/linux/readdir.c21
1 files changed, 9 insertions, 12 deletions
diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c
index 72ba895afe..9577c2ebab 100644
--- a/sysdeps/unix/sysv/linux/readdir.c
+++ b/sysdeps/unix/sysv/linux/readdir.c
@@ -75,25 +75,22 @@ __readdir_unlocked (DIR *dirp)
       size_t new_reclen = ALIGN_UP (old_reclen - size_diff,
 				    _Alignof (struct dirent));
 
-      if (!in_ino_t_range (inp->dp64.d_ino)
-	  || !in_off_t_range (inp->dp64.d_off))
+      /* telldir can not return an error, so preallocate a map entry if
+	 d_off can not be used directly.  */
+      if (telldir_need_dirstream (inp->dp64.d_off))
 	{
-	  /* Overflow.  If there was at least one entry before this one,
-	     return them without error, otherwise signal overflow.  */
-	  if (dirp->offset != 0)
-	    {
-	      __lseek64 (dirp->fd, dirp->offset, SEEK_SET);
-	      outp = (void*)(outp->b - dirp->data);
-	      return &outp->dp;
-	    }
-	  __set_errno (EOVERFLOW);
-	  return NULL;
+	  dirstream_loc_add (&dirp->locs, inp->dp64.d_off);
+	  if (dirstream_loc_has_failed (&dirp->locs))
+	    return NULL;
 	}
 
       /* Copy the data from INP and access only OUTP.  */
       const uint64_t d_ino = inp->dp64.d_ino;
       const int64_t d_off = inp->dp64.d_off;
       const uint8_t d_type = inp->dp64.d_type;
+      /* This will clamp both d_off and d_ino values, which is required to
+	 avoid return EOVERFLOW.  The lelldir/seekdir uses the 'locs' value
+	 if the value overflows.  */
       outp->dp.d_ino = d_ino;
       outp->dp.d_off = d_off;
       outp->dp.d_reclen = new_reclen;