find_names.c revision 34461
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 21static int find_dirs PROTO((char *dir, List * list, int checkadm, 22 List *entries)); 23static int find_rcs PROTO((char *dir, List * list)); 24static int add_subdir_proc PROTO((Node *, void *)); 25static int register_subdir_proc PROTO((Node *, void *)); 26 27static List *filelist; 28 29/* 30 * add the key from entry on entries list to the files list 31 */ 32static int add_entries_proc PROTO((Node *, void *)); 33static int 34add_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 53List * 54Find_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 111static int 112add_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*/ 137static int 138register_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 */ 151List * 152Find_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 */ 240static int 241find_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 */ 280static int 281find_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} 389