summary refs log tree commit diff
path: root/sysdeps/unix/opendir.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/opendir.c')
-rw-r--r--sysdeps/unix/opendir.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/sysdeps/unix/opendir.c b/sysdeps/unix/opendir.c
index 0a116247d2..92029c6547 100644
--- a/sysdeps/unix/opendir.c
+++ b/sysdeps/unix/opendir.c
@@ -171,6 +171,8 @@ __alloc_dir (int fd, bool close_fd, const struct stat64 *statp)
 	goto lose;
     }
 
+  const size_t default_allocation = (BUFSIZ < sizeof (struct dirent64)
+				     ? sizeof (struct dirent64) : BUFSIZ);
   size_t allocation;
 #ifdef _STATBUF_ST_BLKSIZE
   if (__builtin_expect ((size_t) statp->st_blksize >= sizeof (struct dirent64),
@@ -178,20 +180,30 @@ __alloc_dir (int fd, bool close_fd, const struct stat64 *statp)
     allocation = statp->st_blksize;
   else
 #endif
-    allocation = (BUFSIZ < sizeof (struct dirent64)
-		  ? sizeof (struct dirent64) : BUFSIZ);
+    allocation = default_allocation;
 
   DIR *dirp = (DIR *) malloc (sizeof (DIR) + allocation);
   if (dirp == NULL)
-  lose:
     {
-      if (close_fd)
+#ifdef _STATBUF_ST_BLKSIZE
+      if (allocation == statp->st_blksize
+	  && allocation != default_allocation)
 	{
-	  int save_errno = errno;
-	  close_not_cancel_no_status (fd);
-	  __set_errno (save_errno);
+	  allocation = default_allocation;
+	  dirp = (DIR *) malloc (sizeof (DIR) + allocation);
+	}
+      if (dirp == NULL)
+#endif
+      lose:
+	{
+	  if (close_fd)
+	    {
+	      int save_errno = errno;
+	      close_not_cancel_no_status (fd);
+	      __set_errno (save_errno);
+	    }
+	  return NULL;
 	}
-      return NULL;
     }
 
   dirp->fd = fd;