Browse Source

(chdir_arg): Use x2nrealloc to reallocate wd.
(get_max_open_files,closeopen): New functions
(chdir_do): Do not use save_cwd if it was already used more than
max_open_files-4 times to avoid running off the file
descriptors.

Sergey Poznyakoff 19 years ago
parent
commit
9869d0ae17
1 changed files with 49 additions and 4 deletions
  1. 49 4
      src/misc.c

+ 49 - 4
src/misc.c

@@ -18,10 +18,13 @@
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include <system.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #include <rmt.h>
 #include "common.h"
 #include <quotearg.h>
 #include <save-cwd.h>
+#include <xgetcwd.h>
 #include <unlinkdir.h>
 #include <utimens.h>
 
@@ -542,8 +545,14 @@ chdir_arg (char const *dir)
 {
   if (wds == wd_alloc)
     {
-      wd_alloc = 2 * (wd_alloc + 1);
-      wd = xrealloc (wd, sizeof *wd * wd_alloc);
+      if (wd_alloc == 0)
+	{
+	  wd_alloc = 2;
+	  wd = xmalloc (sizeof *wd * wd_alloc);
+	}
+      else
+	wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);
+
       if (! wds)
 	{
 	  wd[wds].name = ".";
@@ -568,13 +577,41 @@ chdir_arg (char const *dir)
   return wds++;
 }
 
+/* Return maximum number of open files */
+int
+get_max_open_files ()
+{
+#if defined _SC_OPEN_MAX
+  return sysconf (_SC_OPEN_MAX);
+#elif defined RLIMIT_NOFILE
+  struct rlimit rlim;
+
+  if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
+    return rlim.rlim_max;
+#elif defined HAVE_GETDTABLESIZE
+  return getdtablesize ();
+#endif
+  return -1;
+}
+
+/* Close all descriptors, except the first three */
+void
+closeopen ()
+{
+  int i;
+
+  for (i = get_max_open_files () - 1; i > 2; i--)
+    close (i);
+}
+  
 /* Change to directory I.  If I is 0, change to the initial working
    directory; otherwise, I must be a value returned by chdir_arg.  */
 void
 chdir_do (int i)
 {
   static int previous;
-
+  static int saved_count;
+  
   if (previous != i)
     {
       struct wd *prev = &wd[previous];
@@ -583,7 +620,15 @@ chdir_do (int i)
       if (! prev->saved)
 	{
 	  prev->saved = 1;
-	  if (save_cwd (&prev->saved_cwd) != 0)
+	  saved_count++;
+	  /* Make sure we still have at least one descriptor available */
+	  if (saved_count >= get_max_open_files () - 4)
+	    {
+	      /* Force restore_cwd to use chdir_long */
+	      prev->saved_cwd.desc = -1;
+	      prev->saved_cwd.name = xgetcwd ();
+	    }
+	  else if (save_cwd (&prev->saved_cwd) != 0)
 	    FATAL_ERROR ((0, 0, _("Cannot save working directory")));
 	}