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