]> git.ipfire.org Git - thirdparty/make.git/commitdiff
Formerly dir.c.~4~
authorRoland McGrath <roland@redhat.com>
Fri, 9 Oct 1992 17:35:07 +0000 (17:35 +0000)
committerRoland McGrath <roland@redhat.com>
Fri, 9 Oct 1992 17:35:07 +0000 (17:35 +0000)
dir.c

diff --git a/dir.c b/dir.c
index 94c00bc37ec9d902b6896f57715c197910e7a769..d863c5d945c6e62359a85c695d4d77e4c8203b71 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -53,21 +53,39 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #else
 #define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
 #endif /* POSIX */
-
+\f
 /* Hash table of directories.  */
 
-struct directory
+#ifndef        DIRECTORY_BUCKETS
+#define DIRECTORY_BUCKETS 199
+#endif
+
+struct directory_contents
   {
-    struct directory *next;
-    char *name;                        /* Name of the directory.  */
+    struct directory_contents *next;
+
+    int dev, ino;              /* Device and inode numbers of this dir.  */
+
     struct dirfile **files;    /* Files in this directory.  */
     DIR *dirstream;            /* Stream reading this directory.  */
   };
 
-#ifndef        DIRECTORY_BUCKETS
-#define DIRECTORY_BUCKETS 23
-#endif
+/* Table of directory contents hashed by device and inode number.  */
+static struct directory_contents *directories_contents[DIRECTORY_BUCKETS];
 
+struct directory
+  {
+    struct directory *next;
+
+    char *name;                        /* Name of the directory.  */
+
+    /* The directory's contents.  This data may be shared by several
+       entries in the hash table, which refer to the same directory
+       (identified uniquely by `dev' and `ino') under different names.  */
+    struct directory_contents *contents;
+  };
+
+/* Table of directories hashed by name.  */
 static struct directory *directories[DIRECTORY_BUCKETS];
 
 
@@ -88,9 +106,11 @@ struct dirfile
   };
 
 #ifndef        DIRFILE_BUCKETS
-#define DIRFILE_BUCKETS 1007
+#define DIRFILE_BUCKETS 107
 #endif
 \f
+static int dir_contents_file_exists_p ();
+
 /* Find the directory named NAME and return its `struct directory'.  */
 
 static struct directory *
@@ -111,54 +131,93 @@ find_directory (name)
 
   if (dir == 0)
     {
-      /* The directory was not found.  Create a new entry
-        for it and start its directory stream reading.  */
+      struct stat st;
+
+      /* The directory was not found.  Create a new entry for it.  */
+
       dir = (struct directory *) xmalloc (sizeof (struct directory));
       dir->next = directories[hash];
       directories[hash] = dir;
       dir->name = savestring (name, p - name);
-      dir->dirstream = opendir (name);
-      if (dir->dirstream == 0)
-       /* Couldn't open the directory.  Mark this by
-          setting the `files' member to a nil pointer.  */
-       dir->files = 0;
+
+      /* The directory is not in the name hash table.
+        Find its device and inode numbers, and look it up by them.  */
+
+      if (stat (name, &st) < 0)
+       /* Couldn't stat the directory.  Mark this by
+          setting the `contents' member to a nil pointer.  */
+       dir->contents = 0;
       else
        {
-         /* Allocate an array of hash buckets for files and zero it.  */
-         dir->files = (struct dirfile **)
-           xmalloc (sizeof (struct dirfile) * DIRFILE_BUCKETS);
-         bzero ((char *) dir->files,
-                sizeof (struct dirfile) * DIRFILE_BUCKETS);
-
-         /* Keep track of how many directories are open.  */
-         ++open_directories;
-         if (open_directories == MAX_OPEN_DIRECTORIES)
-           /* Read the entire directory and then close it.  */
-           (void) dir_file_exists_p (dir->name, (char *) 0);
+         /* Search the contents hash table; device and inode are the key.  */
+
+         struct directory_contents *dc;
+
+         hash = ((unsigned int) st.st_dev << 16) | (unsigned int) st.st_ino;
+         hash %= DIRECTORY_BUCKETS;
+
+         for (dc = directories_contents[hash]; dc != 0; dc = dc->next)
+           if (dc->dev == st.st_dev && dc->ino == st.st_ino)
+             break;
+
+         if (dc == 0)
+           {
+             /* Nope; this really is a directory we haven't seen before.  */
+
+             dc = (struct directory_contents *)
+               xmalloc (sizeof (struct directory_contents));
+
+             /* Enter it in the contents hash table.  */
+             dc->dev = st.st_dev;
+             dc->ino = st.st_ino;
+             dc->next = directories_contents[hash];
+             directories_contents[hash] = dc;
+
+             dc->dirstream = opendir (name);
+             if (dc->dirstream == 0)
+               /* Couldn't open the directory.  Mark this by
+                  setting the `files' member to a nil pointer.  */
+               dc->files = 0;
+             else
+               {
+                 /* Allocate an array of buckets for files and zero it.  */
+                 dc->files = (struct dirfile **)
+                   xmalloc (sizeof (struct dirfile *) * DIRFILE_BUCKETS);
+                 bzero ((char *) dc->files,
+                        sizeof (struct dirfile *) * DIRFILE_BUCKETS);
+
+                 /* Keep track of how many directories are open.  */
+                 ++open_directories;
+                 if (open_directories == MAX_OPEN_DIRECTORIES)
+                   /* We have too many directories open already.
+                      Read the entire directory and then close it.  */
+                   (void) dir_contents_file_exists_p (dc, (char *) 0);
+               }
+           }
+
+         /* Point the name-hashed entry for DIR at its contents data.  */
+         dir->contents = dc;
        }
     }
 
   return dir;
 }
 \f
-/* Return 1 if the name FILENAME in directory DIRNAME
-   is entered in the dir hash table.
+/* Return 1 if the name FILENAME is entered in DIR's hash table.
    FILENAME must contain no slashes.  */
 
-int
-dir_file_exists_p (dirname, filename)
-     register char *dirname;
+static int
+dir_contents_file_exists_p (dir, filename)
+     register struct directory_contents *dir;
      register char *filename;
 {
   register unsigned int hash;
   register char *p;
-  register struct directory *dir;
   register struct dirfile *df;
   register struct dirent *d;
-  dir = find_directory (dirname);
 
-  if (dir->files == 0)
-    /* The directory could not be opened.  */
+  if (dir == 0 || dir->files == 0)
+    /* The directory could not be stat'd or opened.  */
     return 0;
 
   hash = 0;
@@ -222,6 +281,19 @@ dir_file_exists_p (dirname, filename)
 
   return 0;
 }
+
+/* Return 1 if the name FILENAME in directory DIRNAME
+   is entered in the dir hash table.
+   FILENAME must contain no slashes.  */
+
+int
+dir_file_exists_p (dirname, filename)
+     register char *dirname;
+     register char *filename;
+{
+  return dir_contents_file_exists_p (find_directory (dirname)->contents,
+                                    filename);
+}
 \f
 /* Return 1 if the file named NAME exists.  */
 
@@ -277,19 +349,30 @@ file_impossible (filename)
     HASH (hash, *p);
   hash %= DIRFILE_BUCKETS;
 
-  if (dir->files == 0)
+  if (dir->contents == 0)
+    {
+      /* The directory could not be stat'd.  We allocate a contents
+        structure for it, but leave it out of the contents hash table.  */
+      dir->contents = (struct directory_contents *)
+       xmalloc (sizeof (struct directory_contents));
+      dir->contents->dev = dir->contents->ino = 0;
+      dir->contents->files = 0;
+    }
+
+  if (dir->contents->files == 0)
     {
       /* The directory was not opened; we must allocate the hash buckets.  */
-      dir->files = (struct dirfile **)
+      dir->contents->files = (struct dirfile **)
        xmalloc (sizeof (struct dirfile) * DIRFILE_BUCKETS);
-      bzero ((char *) dir->files, sizeof (struct dirfile) * DIRFILE_BUCKETS);
+      bzero ((char *) dir->contents->files,
+            sizeof (struct dirfile) * DIRFILE_BUCKETS);
     }
 
   /* Make a new entry and put it in the table.  */
 
   new = (struct dirfile *) xmalloc (sizeof (struct dirfile));
-  new->next = dir->files[hash];
-  dir->files[hash] = new;
+  new->next = dir->contents->files[hash];
+  dir->contents->files[hash] = new;
   new->name = savestring (filename, strlen (filename));
   new->impossible = 1;
 }
@@ -303,22 +386,22 @@ file_impossible_p (filename)
   char *dirend;
   register char *p = filename;
   register unsigned int hash;
-  register struct directory *dir;
+  register struct directory_contents *dir;
   register struct dirfile *next;
 
   dirend = rindex (filename, '/');
   if (dirend == 0)
-    dir = find_directory (".");
+    dir = find_directory (".")->contents;
   else
     {
       char *dirname = (char *) alloca (dirend - filename + 1);
       bcopy (p, dirname, dirend - p);
       dirname[dirend - p] = '\0';
-      dir = find_directory (dirname);
+      dir = find_directory (dirname)->contents;
       p = dirend + 1;
     }
 
-  if (dir->files == 0)
+  if (dir == 0 || dir->files == 0)
     /* There are no files entered for this directory.  */
     return 0;
 
@@ -358,20 +441,24 @@ print_dir_data_base ()
     for (dir = directories[i]; dir != 0; dir = dir->next)
       {
        ++dirs;
-       if (dir->files == 0)
-         printf ("# %s: could not be opened.\n", dir->name);
+       if (dir->contents == 0)
+         printf ("# %s: could not be stat'd.\n", dir->name);
+       else if (dir->contents->files == 0)
+         printf ("# %s (device %d, inode %d): could not be opened.\n",
+                 dir->name, dir->contents->dev, dir->contents->ino);
        else
          {
            register unsigned int f = 0, im = 0;
            register unsigned int j;
            register struct dirfile *df;
            for (j = 0; j < DIRFILE_BUCKETS; ++j)
-             for (df = dir->files[j]; df != 0; df = df->next)
+             for (df = dir->contents->files[j]; df != 0; df = df->next)
                if (df->impossible)
                  ++im;
                else
                  ++f;
-           printf ("# %s: ", dir->name);
+           printf ("# %s (device %d, inode %d): ",
+                   dir->name, dir->contents->dev, dir->contents->ino);
            if (f == 0)
              fputs ("No", stdout);
            else
@@ -382,7 +469,7 @@ print_dir_data_base ()
            else
              printf ("%u", im);
            fputs (" impossibilities", stdout);
-           if (dir->dirstream == 0)
+           if (dir->contents->dirstream == 0)
              puts (".");
            else
              puts (" so far.");