2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
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.
10 * Finds all the pertinent file names, both from the administration and from the
15 * Finds all pertinent sub-directories of the checked out instantiation and the
16 * repository (and optionally the attic)
21 static int find_dirs PROTO((char *dir, List * list, int checkadm,
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 *));
28 * add the key from entry on entries list to the files list
30 static int add_entries_proc PROTO((Node *, void *));
32 add_entries_proc (node, closure)
37 List *filelist = closure;
38 Entnode *entnode = node->data;
40 if (entnode->type != ENT_FILE)
45 fnode->key = xstrdup (node->key);
46 if (addnode (filelist, fnode) != 0)
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
57 Find_Names (repository, which, aflag, optentries)
66 /* make a list for the files */
69 /* look at entries (if necessary) */
72 /* parse the entries file (if it exists) */
73 entries = Entries_Open (aflag, NULL);
76 /* walk the entries file adding elements to the files list */
77 (void) walklist (entries, add_entries_proc, files);
79 /* if our caller wanted the entries list, return it; else free it */
80 if (optentries != NULL)
81 *optentries = entries;
83 Entries_Close (entries);
87 if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT))
89 /* search the repository */
90 if (find_rcs (repository, files) != 0)
92 error (0, errno, "cannot open directory %s", repository);
96 /* search the attic too */
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);
111 /* sort the list into alphabetical order and return it */
112 sortlist (files, fsortcmp);
120 * Add an entry from the subdirs list to the directories list. This
121 * is called via walklist.
125 add_subdir_proc (p, closure)
129 List *dirlist = closure;
130 Entnode *entnode = p->data;
133 if (entnode->type != ENT_SUBDIR)
138 dnode->key = xstrdup (entnode->user);
139 if (addnode (dirlist, dnode) != 0)
145 * Register a subdirectory. This is called via walklist.
150 register_subdir_proc (p, closure)
154 List *entries = (List *) closure;
156 Subdir_Register (entries, (char *) NULL, p->key);
161 * create a list of directories to traverse from the current directory
164 Find_Directories (repository, which, entries)
171 /* make a list for the directories */
172 dirlist = getlist ();
174 /* find the local ones */
178 struct stickydirtag *sdtp;
180 /* Look through the Entries file. */
183 tmpentries = entries;
184 else if (isfile (CVSADM_ENT))
185 tmpentries = Entries_Open (0, NULL);
189 if (tmpentries != NULL)
190 sdtp = tmpentries->list->data;
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);
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. */
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). */
212 if (find_dirs (".", dirlist, 1, tmpentries) != 0)
213 error (1, errno, "cannot open current directory");
214 if (tmpentries != NULL)
216 if (! list_isempty (dirlist))
217 walklist (dirlist, register_subdir_proc,
218 (void *) tmpentries);
220 Subdirs_Known (tmpentries);
224 if (entries == NULL && tmpentries != NULL)
225 Entries_Close (tmpentries);
228 /* look for sub-dirs in the repository */
229 if ((which & W_REPOS) && repository)
231 /* search the repository */
232 if (find_dirs (repository, dirlist, 0, entries) != 0)
233 error (1, errno, "cannot open directory %s", repository);
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. */
242 /* sort the list into alphabetical order and return it */
243 sortlist (dirlist, fsortcmp);
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).
263 /* set up to read the dir */
264 if ((dirp = CVS_OPENDIR (dir)) == NULL)
267 /* read the dir, grabbing the ,v files */
269 while ((dp = CVS_READDIR (dirp)) != NULL)
271 if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
275 comma = strrchr (dp->d_name, ','); /* strip the ,v */
279 p->key = xstrdup (dp->d_name);
280 if (addnode (list, p) != 0)
287 int save_errno = errno;
288 (void) CVS_CLOSEDIR (dirp);
292 (void) CVS_CLOSEDIR (dirp);
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.
304 find_dirs (dir, list, checkadm, entries)
315 int skip_emptydir = 0;
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. */
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)
326 /* set up to read the dir */
327 if ((dirp = CVS_OPENDIR (dir)) == NULL)
330 /* read the dir, grabbing sub-dirs */
332 while ((dp = CVS_READDIR (dirp)) != NULL)
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)
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)
348 && strcmp (dp->d_name, CVSNULLREPOS) == 0)
352 if (dp->d_type != DT_DIR)
354 if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
357 /* don't bother stating ,v files */
358 if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
363 strlen (dir) + strlen (dp->d_name) + 10);
364 sprintf (tmp, "%s/%s", dir, dp->d_name);
372 /* check for administration directories (if needed) */
375 /* blow off symbolic links to dirs in local dir */
377 if (dp->d_type != DT_DIR)
379 /* we're either unknown or a symlink at this point */
380 if (dp->d_type == DT_LNK)
383 /* Note that we only get here if we already set tmp
391 /* check for new style */
394 (strlen (dir) + strlen (dp->d_name)
395 + sizeof (CVSADM) + 10));
396 (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
401 /* put it in the list */
404 p->key = xstrdup (dp->d_name);
405 if (addnode (list, p) != 0)
413 int save_errno = errno;
414 (void) CVS_CLOSEDIR (dirp);
418 (void) CVS_CLOSEDIR (dirp);