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 (char *dir, List * list, int checkadm,
23 static int find_rcs (char *dir, List * list);
24 static int add_subdir_proc (Node *, void *);
25 static int register_subdir_proc (Node *, void *);
28 * add the key from entry on entries list to the files list
30 static int add_entries_proc (Node *, void *);
32 add_entries_proc (Node *node, void *closure)
35 List *filelist = closure;
36 Entnode *entnode = node->data;
38 if (entnode->type != ENT_FILE)
43 fnode->key = xstrdup (node->key);
44 if (addnode (filelist, fnode) != 0)
49 /* Find files in the repository and/or working directory. On error,
50 may either print a nonfatal error and return NULL, or just give
51 a fatal error. On success, return non-NULL (even if it is an empty
55 Find_Names (char *repository, int which, int aflag, List **optentries)
60 /* make a list for the files */
63 /* look at entries (if necessary) */
66 /* parse the entries file (if it exists) */
67 entries = Entries_Open (aflag, NULL);
70 /* walk the entries file adding elements to the files list */
71 (void) walklist (entries, add_entries_proc, files);
73 /* if our caller wanted the entries list, return it; else free it */
74 if (optentries != NULL)
75 *optentries = entries;
77 Entries_Close (entries);
81 if ((which & W_REPOS) && repository && !isreadable (CVSADM_ENTSTAT))
83 /* search the repository */
84 if (find_rcs (repository, files) != 0)
86 error (0, errno, "cannot open directory %s",
87 primary_root_inverse_translate (repository));
91 /* search the attic too */
95 dir = xmalloc (strlen (repository) + sizeof (CVSATTIC) + 10);
96 (void) sprintf (dir, "%s/%s", repository, CVSATTIC);
97 if (find_rcs (dir, files) != 0
98 && !existence_error (errno))
99 /* For now keep this a fatal error, seems less useful
100 for access control than the case above. */
101 error (1, errno, "cannot open directory %s",
102 primary_root_inverse_translate (dir));
107 /* sort the list into alphabetical order and return it */
108 sortlist (files, fsortcmp);
116 * Add an entry from the subdirs list to the directories list. This
117 * is called via walklist.
121 add_subdir_proc (Node *p, void *closure)
123 List *dirlist = closure;
124 Entnode *entnode = p->data;
127 if (entnode->type != ENT_SUBDIR)
132 dnode->key = xstrdup (entnode->user);
133 if (addnode (dirlist, dnode) != 0)
139 * Register a subdirectory. This is called via walklist.
144 register_subdir_proc (Node *p, void *closure)
146 List *entries = (List *) closure;
148 Subdir_Register (entries, (char *) NULL, p->key);
153 * create a list of directories to traverse from the current directory
156 Find_Directories (char *repository, int which, List *entries)
160 /* make a list for the directories */
161 dirlist = getlist ();
163 /* find the local ones */
167 struct stickydirtag *sdtp;
169 /* Look through the Entries file. */
172 tmpentries = entries;
173 else if (isfile (CVSADM_ENT))
174 tmpentries = Entries_Open (0, NULL);
178 if (tmpentries != NULL)
179 sdtp = tmpentries->list->data;
181 /* If we do have an entries list, then if sdtp is NULL, or if
182 sdtp->subdirs is nonzero, all subdirectory information is
183 recorded in the entries list. */
184 if (tmpentries != NULL && (sdtp == NULL || sdtp->subdirs))
185 walklist (tmpentries, add_subdir_proc, (void *) dirlist);
188 /* This is an old working directory, in which subdirectory
189 information is not recorded in the Entries file. Find
190 the subdirectories the hard way, and, if possible, add
191 it to the Entries file for next time. */
193 /* FIXME-maybe: find_dirs is bogus for this usage because
194 it skips CVSATTIC and CVSLCK directories--those names
195 should be special only in the repository. However, in
196 the interests of not perturbing this code, we probably
197 should leave well enough alone unless we want to write
198 a sanity.sh test case (which would operate by manually
199 hacking on the CVS/Entries file). */
201 if (find_dirs (".", dirlist, 1, tmpentries) != 0)
202 error (1, errno, "cannot open current directory");
203 if (tmpentries != NULL)
205 if (! list_isempty (dirlist))
206 walklist (dirlist, register_subdir_proc,
207 (void *) tmpentries);
209 Subdirs_Known (tmpentries);
213 if (entries == NULL && tmpentries != NULL)
214 Entries_Close (tmpentries);
217 /* look for sub-dirs in the repository */
218 if ((which & W_REPOS) && repository)
220 /* search the repository */
221 if (find_dirs (repository, dirlist, 0, entries) != 0)
222 error (1, errno, "cannot open directory %s", repository);
224 /* We don't need to look in the attic because directories
225 never go in the attic. In the future, there hopefully will
226 be a better mechanism for detecting whether a directory in
227 the repository is alive or dead; it may or may not involve
228 moving directories to the attic. */
231 /* sort the list into alphabetical order and return it */
232 sortlist (dirlist, fsortcmp);
237 * Finds all the ,v files in the argument directory, and adds them to the
238 * files list. Returns 0 for success and non-zero if the argument directory
239 * cannot be opened, in which case errno is set to indicate the error.
240 * In the error case LIST is left in some reasonable state (unchanged, or
241 * containing the files which were found before the error occurred).
244 find_rcs (char *dir, List *list)
250 /* set up to read the dir */
251 if ((dirp = CVS_OPENDIR (dir)) == NULL)
254 /* read the dir, grabbing the ,v files */
256 while ((dp = CVS_READDIR (dirp)) != NULL)
258 if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
262 comma = strrchr (dp->d_name, ','); /* strip the ,v */
266 p->key = xstrdup (dp->d_name);
267 if (addnode (list, p) != 0)
274 int save_errno = errno;
275 (void) CVS_CLOSEDIR (dirp);
279 (void) CVS_CLOSEDIR (dirp);
284 * Finds all the subdirectories of the argument dir and adds them to
285 * the specified list. Sub-directories without a CVS administration
286 * directory are optionally ignored. If ENTRIES is not NULL, all
287 * files on the list are ignored. Returns 0 for success or 1 on
288 * error, in which case errno is set to indicate the error.
291 find_dirs (char *dir, List *list, int checkadm, List *entries)
298 int skip_emptydir = 0;
300 /* First figure out whether we need to skip directories named
301 Emptydir. Except in the CVSNULLREPOS case, Emptydir is just
302 a normal directory name. */
304 && strncmp (dir, current_parsed_root->directory, strlen (current_parsed_root->directory)) == 0
305 && ISSLASH (dir[strlen (current_parsed_root->directory)])
306 && strcmp (dir + strlen (current_parsed_root->directory) + 1, CVSROOTADM) == 0)
309 /* set up to read the dir */
310 if ((dirp = CVS_OPENDIR (dir)) == NULL)
313 /* read the dir, grabbing sub-dirs */
315 while ((dp = CVS_READDIR (dirp)) != NULL)
317 if (strcmp (dp->d_name, ".") == 0 ||
318 strcmp (dp->d_name, "..") == 0 ||
319 strcmp (dp->d_name, CVSATTIC) == 0 ||
320 strcmp (dp->d_name, CVSLCK) == 0 ||
321 strcmp (dp->d_name, CVSREP) == 0)
324 /* findnode() is going to be significantly faster than stat()
325 because it involves no system calls. That is why we bother
326 with the entries argument, and why we check this first. */
327 if (entries != NULL && findnode (entries, dp->d_name) != NULL)
331 && strcmp (dp->d_name, CVSNULLREPOS) == 0)
335 if (dp->d_type != DT_DIR)
337 if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
340 /* don't bother stating ,v files */
341 if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0)
346 strlen (dir) + strlen (dp->d_name) + 10);
347 sprintf (tmp, "%s/%s", dir, dp->d_name);
355 /* check for administration directories (if needed) */
358 /* blow off symbolic links to dirs in local dir */
360 if (dp->d_type != DT_DIR)
362 /* we're either unknown or a symlink at this point */
363 if (dp->d_type == DT_LNK)
366 /* Note that we only get here if we already set tmp
374 /* check for new style */
377 (strlen (dir) + strlen (dp->d_name)
378 + sizeof (CVSADM) + 10));
379 (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
384 /* put it in the list */
387 p->key = xstrdup (dp->d_name);
388 if (addnode (list, p) != 0)
396 int save_errno = errno;
397 (void) CVS_CLOSEDIR (dirp);
401 (void) CVS_CLOSEDIR (dirp);