Properly reread entry after failure in nss_files getent function (bug 18991)

	* nss/nss_files/files-XXX.c (position, need_reread): New
	variables.
	(CONCAT(_nss_files_set,ENTNAME)): Initialize them.
	(CONCAT(_nss_files_get,ENTNAME_r)): Likewise.  Reposition stream
	if last call was uncessful.
	* nss/nss_files/files-alias.c (position, need_reread): New
	variables.
	(_nss_files_setaliasent): Initialize them.
	(_nss_files_getaliasent_r): Likewise.  Reposition stream if last
	call was uncessful.

Index: glibc-2.11.3/nss/nss_files/files-XXX.c
===================================================================
--- glibc-2.11.3.orig/nss/nss_files/files-XXX.c
+++ glibc-2.11.3/nss/nss_files/files-XXX.c
@@ -65,6 +65,10 @@ __libc_lock_define_initialized (static,
 /* Maintenance of the shared stream open on the database file.  */
 
 static FILE *stream;
+/* Position after the last sucessfully read entry.  */
+static fpos_t position;
+/* Whether we need to reread the last entry on the next call.  */
+static bool need_reread;
 
 /* Open database file if not already opened.  */
 static enum nss_status
@@ -131,6 +135,15 @@ CONCAT(_nss_files_set,ENTNAME) (int stay
 
   status = internal_setent (&stream);
 
+  if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+    {
+      fclose (stream);
+      stream = NULL;
+      status = NSS_STATUS_UNAVAIL;
+    }
+
+  need_reread = false;
+
   __libc_lock_unlock (lock);
 
   return status;
@@ -286,11 +299,42 @@ CONCAT(_nss_files_get,ENTNAME_r) (struct
       status = internal_setent (&stream);
 
       __set_errno (save_errno);
+
+      if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+	{
+	  fclose (stream);
+	  stream = NULL;
+	  status = NSS_STATUS_UNAVAIL;
+	}
+      need_reread = false;
     }
 
   if (status == NSS_STATUS_SUCCESS)
-    status = internal_getent (stream, result, buffer, buflen, errnop
-			      H_ERRNO_ARG EXTRA_ARGS_VALUE);
+    {
+      /* Reposition the stream if the last call was unsucessful.  */
+      if (need_reread)
+	{
+	  if (fsetpos (stream, &position) < 0)
+	    status = NSS_STATUS_UNAVAIL;
+	  else
+	    need_reread = false;
+	}
+    }
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      status = internal_getent (stream, result, buffer, buflen, errnop
+				H_ERRNO_ARG EXTRA_ARGS_VALUE);
+
+      /* Remember this position if we were successful.  If the
+	 operation failed we give the user a chance to repeat the
+	 operation (perhaps the buffer was too small).  */
+      if (status == NSS_STATUS_SUCCESS)
+	fgetpos (stream, &position);
+      else
+	/* We must make sure we reposition the stream the next call.  */
+	need_reread = true;
+    }
 
   __libc_lock_unlock (lock);
 
Index: glibc-2.11.3/nss/nss_files/files-alias.c
===================================================================
--- glibc-2.11.3.orig/nss/nss_files/files-alias.c
+++ glibc-2.11.3/nss/nss_files/files-alias.c
@@ -37,6 +37,10 @@ __libc_lock_define_initialized (static,
 /* Maintenance of the shared stream open on the database file.  */
 
 static FILE *stream;
+/* Position after the last sucessfully read entry.  */
+static fpos_t position;
+/* Whether we need to reread the last entry on the next call.  */
+static bool need_reread;
 
 
 static enum nss_status
@@ -103,6 +107,15 @@ _nss_files_setaliasent (void)
 
   status = internal_setent (&stream);
 
+  if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+    {
+      fclose (stream);
+      stream = NULL;
+      status = NSS_STATUS_UNAVAIL;
+    }
+
+  need_reread = false;
+
   __libc_lock_unlock (lock);
 
   return status;
@@ -387,7 +400,29 @@ _nss_files_getaliasent_r (struct aliasen
 
   /* Be prepared that the set*ent function was not called before.  */
   if (stream == NULL)
-    status = internal_setent (&stream);
+    {
+      status = internal_setent (&stream);
+
+      if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+	{
+	  fclose (stream);
+	  stream = NULL;
+	  status = NSS_STATUS_UNAVAIL;
+	}
+      need_reread = false;
+    }
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      /* Reposition the stream if the last call way unsucessful.  */
+      if (need_reread)
+	{
+	  if (fsetpos (stream, &position) < 0)
+	    status = NSS_STATUS_UNAVAIL;
+	  else
+	    need_reread = false;
+	}
+    }
 
   if (status == NSS_STATUS_SUCCESS)
     {
@@ -397,6 +432,12 @@ _nss_files_getaliasent_r (struct aliasen
       do
 	status = get_next_alias (stream, NULL, result, buffer, buflen, errnop);
       while (status == NSS_STATUS_RETURN);
+
+      /* If we successfully read an entry remember this position.  */
+      if (status == NSS_STATUS_SUCCESS)
+	fgetpos (stream, &position);
+      else
+	need_reread = true;
     }
 
   __libc_lock_unlock (lock);
