]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cvs/src/find_names.c
This commit was generated by cvs2svn to compensate for changes in r171682,
[FreeBSD/FreeBSD.git] / contrib / cvs / src / find_names.c
1 /*
2  * Copyright (c) 1992, Brian Berliner and Jeff Polk
3  * Copyright (c) 1989-1992, Brian Berliner
4  * 
5  * You may distribute under the terms of the GNU General Public License as
6  * specified in the README file that comes with the CVS source distribution.
7  * 
8  * Find Names
9  * 
10  * Finds all the pertinent file names, both from the administration and from the
11  * repository
12  * 
13  * Find Dirs
14  * 
15  * Finds all pertinent sub-directories of the checked out instantiation and the
16  * repository (and optionally the attic)
17  */
18
19 #include "cvs.h"
20
21 static int find_dirs PROTO((char *dir, List * list, int checkadm,
22                             List *entries));
23 static int find_rcs PROTO((char *dir, List * list));
24 static int add_subdir_proc PROTO((Node *, void *));
25 static int register_subdir_proc PROTO((Node *, void *));
26
27 /*
28  * add the key from entry on entries list to the files list
29  */
30 static int add_entries_proc PROTO((Node *, void *));
31 static int
32 add_entries_proc (node, closure)
33      Node *node;
34      void *closure;
35 {
36     Node *fnode;
37     List *filelist = closure;
38     Entnode *entnode = node->data;
39
40     if (entnode->type != ENT_FILE)
41         return (0);
42
43     fnode = getnode ();
44     fnode->type = FILES;
45     fnode->key = xstrdup (node->key);
46     if (addnode (filelist, fnode) != 0)
47         freenode (fnode);
48     return (0);
49 }
50
51 /* Find files in the repository and/or working directory.  On error,
52    may either print a nonfatal error and return NULL, or just give
53    a fatal error.  On success, return non-NULL (even if it is an empty
54    list).  */
55
56 List *
57 Find_Names (repository, which, aflag, optentries)
58     char *repository;
59     int which;
60     int aflag;
61     List **optentries;
62 {
63     List *entries;
64     List *files;
65
66     /* make a list for the files */
67     files = getlist ();
68
69     /* look at entries (if necessary) */
70     if (which & W_LOCAL)
71     {
72         /* parse the entries file (if it exists) */
73         entries = Entries_Open (aflag, NULL);
74         if (entries != NULL)
75         {
76             /* walk the entries file adding elements to the files list */
77             (void) walklist (entries, add_entries_proc, files);
78
79             /* if our caller wanted the entries list, return it; else free it */
80             if (optentries != NULL)
81                 *optentries = entries;
82             else
83                 Entries_Close (entries);
84         }
85     }
86
87     if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT))
88     {
89         /* search the repository */
90         if (find_rcs (repository, files) != 0)
91         {
92             error (0, errno, "cannot open directory %s", repository);
93             goto error_exit;
94         }
95
96         /* search the attic too */
97         if (which & W_ATTIC)
98         {
99             char *dir;
100             dir = xmalloc (strlen (repository) + sizeof (CVSATTIC) + 10);
101             (void) sprintf (dir, "%s/%s", repository, CVSATTIC);
102             if (find_rcs (dir, files) != 0
103                 && !existence_error (errno))
104                 /* For now keep this a fatal error, seems less useful
105                    for access control than the case above.  */
106                 error (1, errno, "cannot open directory %s", dir);
107             free (dir);
108         }
109     }
110
111     /* sort the list into alphabetical order and return it */
112     sortlist (files, fsortcmp);
113     return (files);
114  error_exit:
115     dellist (&files);
116     return NULL;
117 }
118
119 /*
120  * Add an entry from the subdirs list to the directories list.  This
121  * is called via walklist.
122  */
123
124 static int
125 add_subdir_proc (p, closure)
126      Node *p;
127      void *closure;
128 {
129     List *dirlist = closure;
130     Entnode *entnode = p->data;
131     Node *dnode;
132
133     if (entnode->type != ENT_SUBDIR)
134         return 0;
135
136     dnode = getnode ();
137     dnode->type = DIRS;
138     dnode->key = xstrdup (entnode->user);
139     if (addnode (dirlist, dnode) != 0)
140         freenode (dnode);
141     return 0;
142 }
143
144 /*
145  * Register a subdirectory.  This is called via walklist.
146  */
147
148 /*ARGSUSED*/
149 static int
150 register_subdir_proc (p, closure)
151      Node *p;
152      void *closure;
153 {
154     List *entries = (List *) closure;
155
156     Subdir_Register (entries, (char *) NULL, p->key);
157     return 0;
158 }
159
160 /*
161  * create a list of directories to traverse from the current directory
162  */
163 List *
164 Find_Directories (repository, which, entries)
165     char *repository;
166     int which;
167     List *entries;
168 {
169     List *dirlist;
170
171     /* make a list for the directories */
172     dirlist = getlist ();
173
174     /* find the local ones */
175     if (which & W_LOCAL)
176     {
177         List *tmpentries;
178         struct stickydirtag *sdtp;
179
180         /* Look through the Entries file.  */
181
182         if (entries != NULL)
183             tmpentries = entries;
184         else if (isfile (CVSADM_ENT))
185             tmpentries = Entries_Open (0, NULL);
186         else
187             tmpentries = NULL;
188
189         if (tmpentries != NULL)
190             sdtp = tmpentries->list->data;
191
192         /* If we do have an entries list, then if sdtp is NULL, or if
193            sdtp->subdirs is nonzero, all subdirectory information is
194            recorded in the entries list.  */
195         if (tmpentries != NULL && (sdtp == NULL || sdtp->subdirs))
196             walklist (tmpentries, add_subdir_proc, (void *) dirlist);
197         else
198         {
199             /* This is an old working directory, in which subdirectory
200                information is not recorded in the Entries file.  Find
201                the subdirectories the hard way, and, if possible, add
202                it to the Entries file for next time.  */
203
204             /* FIXME-maybe: find_dirs is bogus for this usage because
205                it skips CVSATTIC and CVSLCK directories--those names
206                should be special only in the repository.  However, in
207                the interests of not perturbing this code, we probably
208                should leave well enough alone unless we want to write
209                a sanity.sh test case (which would operate by manually
210                hacking on the CVS/Entries file).  */
211
212             if (find_dirs (".", dirlist, 1, tmpentries) != 0)
213                 error (1, errno, "cannot open current directory");
214             if (tmpentries != NULL)
215             {
216                 if (! list_isempty (dirlist))
217                     walklist (dirlist, register_subdir_proc,
218                               (void *) tmpentries);
219                 else
220                     Subdirs_Known (tmpentries);
221             }
222         }
223
224         if (entries == NULL && tmpentries != NULL)
225             Entries_Close (tmpentries);
226     }
227
228     /* look for sub-dirs in the repository */
229     if ((which & W_REPOS) && repository)
230     {
231         /* search the repository */
232         if (find_dirs (repository, dirlist, 0, entries) != 0)
233             error (1, errno, "cannot open directory %s", repository);
234
235         /* We don't need to look in the attic because directories
236            never go in the attic.  In the future, there hopefully will
237            be a better mechanism for detecting whether a directory in
238            the repository is alive or dead; it may or may not involve
239            moving directories to the attic.  */
240     }
241
242     /* sort the list into alphabetical order and return it */
243     sortlist (dirlist, fsortcmp);
244     return (dirlist);
245 }
246
247 /*
248  * Finds all the ,v files in the argument directory, and adds them to the
249  * files list.  Returns 0 for success and non-zero if the argument directory
250  * cannot be opened, in which case errno is set to indicate the error.
251  * In the error case LIST is left in some reasonable state (unchanged, or
252  * containing the files which were found before the error occurred).
253  */
254 static int
255 find_rcs (dir, list)
256     char *dir;
257     List *list;
258 {
259     Node *p;
260     struct dirent *dp;
261     DIR *dirp;
262
263     /* set up to read the dir */
264     if ((dirp = CVS_OPENDIR (dir)) == NULL)
265         return (1);
266
267     /* read the dir, grabbing the ,v files */
268     errno = 0;
269     while ((dp = CVS_READDIR (dirp)) != NULL)
270     {
271         if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0) 
272         {
273             char *comma;
274
275             comma = strrchr (dp->d_name, ',');  /* strip the ,v */
276             *comma = '\0';
277             p = getnode ();
278             p->type = FILES;
279             p->key = xstrdup (dp->d_name);
280             if (addnode (list, p) != 0)
281                 freenode (p);
282         }
283         errno = 0;
284     }
285     if (errno != 0)
286     {
287         int save_errno = errno;
288         (void) CVS_CLOSEDIR (dirp);
289         errno = save_errno;
290         return 1;
291     }
292     (void) CVS_CLOSEDIR (dirp);
293     return (0);
294 }
295
296 /*
297  * Finds all the subdirectories of the argument dir and adds them to
298  * the specified list.  Sub-directories without a CVS administration
299  * directory are optionally ignored.  If ENTRIES is not NULL, all
300  * files on the list are ignored.  Returns 0 for success or 1 on
301  * error, in which case errno is set to indicate the error.
302  */
303 static int
304 find_dirs (dir, list, checkadm, entries)
305     char *dir;
306     List *list;
307     int checkadm;
308     List *entries;
309 {
310     Node *p;
311     char *tmp = NULL;
312     size_t tmp_size = 0;
313     struct dirent *dp;
314     DIR *dirp;
315     int skip_emptydir = 0;
316
317     /* First figure out whether we need to skip directories named
318        Emptydir.  Except in the CVSNULLREPOS case, Emptydir is just
319        a normal directory name.  */
320     if (isabsolute (dir)
321         && strncmp (dir, current_parsed_root->directory, strlen (current_parsed_root->directory)) == 0
322         && ISDIRSEP (dir[strlen (current_parsed_root->directory)])
323         && strcmp (dir + strlen (current_parsed_root->directory) + 1, CVSROOTADM) == 0)
324         skip_emptydir = 1;
325
326     /* set up to read the dir */
327     if ((dirp = CVS_OPENDIR (dir)) == NULL)
328         return (1);
329
330     /* read the dir, grabbing sub-dirs */
331     errno = 0;
332     while ((dp = CVS_READDIR (dirp)) != NULL)
333     {
334         if (strcmp (dp->d_name, ".") == 0 ||
335             strcmp (dp->d_name, "..") == 0 ||
336             strcmp (dp->d_name, CVSATTIC) == 0 ||
337             strcmp (dp->d_name, CVSLCK) == 0 ||
338             strcmp (dp->d_name, CVSREP) == 0)
339             goto do_it_again;
340
341         /* findnode() is going to be significantly faster than stat()
342            because it involves no system calls.  That is why we bother
343            with the entries argument, and why we check this first.  */
344         if (entries != NULL && findnode (entries, dp->d_name) != NULL)
345             goto do_it_again;
346
347         if (skip_emptydir
348             && strcmp (dp->d_name, CVSNULLREPOS) == 0)
349             goto do_it_again;
350
351 #ifdef DT_DIR
352         if (dp->d_type != DT_DIR) 
353         {
354             if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
355                 goto do_it_again;
356 #endif
357             /* don't bother stating ,v files */
358             if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
359                 goto do_it_again;
360
361             expand_string (&tmp,
362                            &tmp_size,
363                            strlen (dir) + strlen (dp->d_name) + 10);
364             sprintf (tmp, "%s/%s", dir, dp->d_name);
365             if (!isdir (tmp))
366                 goto do_it_again;
367
368 #ifdef DT_DIR
369         }
370 #endif
371
372         /* check for administration directories (if needed) */
373         if (checkadm)
374         {
375             /* blow off symbolic links to dirs in local dir */
376 #ifdef DT_DIR
377             if (dp->d_type != DT_DIR)
378             {
379                 /* we're either unknown or a symlink at this point */
380                 if (dp->d_type == DT_LNK)
381                     goto do_it_again;
382 #endif
383                 /* Note that we only get here if we already set tmp
384                    above.  */
385                 if (islink (tmp))
386                     goto do_it_again;
387 #ifdef DT_DIR
388             }
389 #endif
390
391             /* check for new style */
392             expand_string (&tmp,
393                            &tmp_size,
394                            (strlen (dir) + strlen (dp->d_name)
395                             + sizeof (CVSADM) + 10));
396             (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
397             if (!isdir (tmp))
398                 goto do_it_again;
399         }
400
401         /* put it in the list */
402         p = getnode ();
403         p->type = DIRS;
404         p->key = xstrdup (dp->d_name);
405         if (addnode (list, p) != 0)
406             freenode (p);
407
408     do_it_again:
409         errno = 0;
410     }
411     if (errno != 0)
412     {
413         int save_errno = errno;
414         (void) CVS_CLOSEDIR (dirp);
415         errno = save_errno;
416         return 1;
417     }
418     (void) CVS_CLOSEDIR (dirp);
419     if (tmp != NULL)
420         free (tmp);
421     return (0);
422 }