changeset 6439:3fd547210013

* getcwd.c (__getcwd): Don't assume that system calls after readdir leave errno alone.
author Paul Eggert <eggert@cs.ucla.edu>
date Sun, 30 Oct 2005 01:32:04 +0000
parents f9d5ad5c44c0
children d811a65bfa7a
files lib/ChangeLog lib/getcwd.c
diffstat 2 files changed, 47 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,8 @@
+2005-10-29  Paul Eggert  <eggert@cs.ucla.edu>
+
+	* getcwd.c (__getcwd): Don't assume that system calls after readdir
+	leave errno alone.  Problem reported by Dmitry V. Levin.
+
 2005-10-28  Paul Eggert  <eggert@cs.ucla.edu>
 
 	* savedir.c (savedir): Don't assume that xrealloc etc. leave
--- a/lib/getcwd.c
+++ b/lib/getcwd.c
@@ -201,6 +201,8 @@
       ino_t dotino;
       bool mount_point;
       int parent_status;
+      size_t dirroom;
+      size_t namlen;
 
       /* Look at the parent directory.  */
 #ifdef AT_FDCWD
@@ -241,11 +243,20 @@
 	goto lose;
       dotlist[dotlen++] = '/';
 #endif
-      /* Clear errno to distinguish EOF from error if readdir returns
-	 NULL.  */
-      __set_errno (0);
-      while ((d = __readdir (dirstream)) != NULL)
+      for (;;)
 	{
+	  /* Clear errno to distinguish EOF from error if readdir returns
+	     NULL.  */
+	  __set_errno (0);
+	  d = __readdir (dirstream);
+	  if (d == NULL)
+	    {
+	      if (errno == 0)
+		/* EOF on dirstream, which means that the current directory
+		   has been removed.  */
+		__set_errno (ENOENT);
+	      goto lose;
+	    }
 	  if (d->d_name[0] == '.' &&
 	      (d->d_name[1] == '\0' ||
 	       (d->d_name[1] == '.' && d->d_name[2] == '\0')))
@@ -303,48 +314,38 @@
 		break;
 	    }
 	}
-      if (d == NULL)
+
+      dirroom = dirp - dir;
+      namlen = _D_EXACT_NAMLEN (d);
+
+      if (dirroom <= namlen)
 	{
-	  if (errno == 0)
-	    /* EOF on dirstream, which means that the current directory
-	       has been removed.  */
-	    __set_errno (ENOENT);
-	  goto lose;
-	}
-      else
-	{
-	  size_t dirroom = dirp - dir;
-	  size_t namlen = _D_EXACT_NAMLEN (d);
-
-	  if (dirroom <= namlen)
+	  if (size != 0)
+	    {
+	      __set_errno (ERANGE);
+	      goto lose;
+	    }
+	  else
 	    {
-	      if (size != 0)
-		{
-		  __set_errno (ERANGE);
-		  goto lose;
-		}
-	      else
-		{
-		  char *tmp;
-		  size_t oldsize = allocated;
+	      char *tmp;
+	      size_t oldsize = allocated;
+
+	      allocated += MAX (allocated, namlen);
+	      if (allocated < oldsize
+		  || ! (tmp = realloc (dir, allocated)))
+		goto memory_exhausted;
 
-		  allocated += MAX (allocated, namlen);
-		  if (allocated < oldsize
-		      || ! (tmp = realloc (dir, allocated)))
-		    goto memory_exhausted;
-
-		  /* Move current contents up to the end of the buffer.
-		     This is guaranteed to be non-overlapping.  */
-		  dirp = memcpy (tmp + allocated - (oldsize - dirroom),
-				 tmp + dirroom,
-				 oldsize - dirroom);
-		  dir = tmp;
-		}
+	      /* Move current contents up to the end of the buffer.
+		 This is guaranteed to be non-overlapping.  */
+	      dirp = memcpy (tmp + allocated - (oldsize - dirroom),
+			     tmp + dirroom,
+			     oldsize - dirroom);
+	      dir = tmp;
 	    }
-	  dirp -= namlen;
-	  memcpy (dirp, d->d_name, namlen);
-	  *--dirp = '/';
 	}
+      dirp -= namlen;
+      memcpy (dirp, d->d_name, namlen);
+      *--dirp = '/';
 
       thisdev = dotdev;
       thisino = dotino;