diff options
author | Joris Vink <joris@cvs.openbsd.org> | 2005-04-25 21:58:33 +0000 |
---|---|---|
committer | Joris Vink <joris@cvs.openbsd.org> | 2005-04-25 21:58:33 +0000 |
commit | 29d8219ccaa4e8c0e0bda5a6c38968c8f2f4bd80 (patch) | |
tree | 7e87fa7256f81cc7795d608cbc17af08879cd2ba /usr.bin/cvs/file.c | |
parent | 354cfe49db3c80c9b4f11a9047b573b01c3824b0 (diff) |
first part of file API changes:
- fix our behaviour regarding directories or files in a different
directory than we currently are as arguments to commands, this
allows stuff like "cvs status sys/arch/i386/Makefile" to work.
- when parsing a pathname only load the needed nodes of the path
instead of loading *everything* in memory.
the next step in this is to merge the collection and callback
execution together.
ok jfb@, xsa@
Diffstat (limited to 'usr.bin/cvs/file.c')
-rw-r--r-- | usr.bin/cvs/file.c | 294 |
1 files changed, 179 insertions, 115 deletions
diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c index bf3b037efcd..384990974e7 100644 --- a/usr.bin/cvs/file.c +++ b/usr.bin/cvs/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.67 2005/04/22 15:16:15 joris Exp $ */ +/* $OpenBSD: file.c,v 1.68 2005/04/25 21:58:32 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -107,7 +107,8 @@ static RCSNUM *cvs_addedrev; TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats; -static int cvs_file_getdir (CVSFILE *, int); +static int cvs_load_dirinfo (CVSFILE *); +static int cvs_file_getdir (CVSFILE *, int, char *); static int cvs_file_sort (struct cvs_flist *, u_int); static int cvs_file_cmp (const void *, const void *); static int cvs_file_cmpname (const char *, const char *); @@ -346,7 +347,10 @@ cvs_file_copy(CVSFILE *orig) CVSFILE* cvs_file_get(const char *path, int flags) { - return cvs_file_lget(path, flags, NULL, NULL); + char *files[1]; + + files[0] = path; + return cvs_file_getspec(files, 1, flags); } @@ -362,43 +366,57 @@ CVSFILE* cvs_file_getspec(char **fspec, int fsn, int flags) { int i; + int pwd; char *sp, *np, pcopy[MAXPATHLEN]; - CVSFILE *base, *cf, *nf; + CVSFILE *base, *nf; + CVSENTRIES *entfile; + struct cvs_ent *ent; - base = cvs_file_get(".", 0); + entfile = cvs_ent_open(".", O_RDONLY); + base = cvs_file_lget(".", 0, NULL, NULL); if (base == NULL) return (NULL); for (i = 0; i < fsn; i++) { strlcpy(pcopy, fspec[i], sizeof(pcopy)); - cf = base; sp = pcopy; + pwd = (!strcmp(pcopy, ".")); - do { - np = strchr(sp, '/'); - if (np != NULL) - *np = '\0'; - nf = cvs_file_find(cf, sp); + np = strchr(sp, '/'); + if (np != NULL) + *np = '\0'; + + if (pwd) { + nf = base; + } else { + nf = cvs_file_find(base, pcopy); if (nf == NULL) { - nf = cvs_file_lget(pcopy, 0, cf, NULL); + if (entfile != NULL) + ent = cvs_ent_get(entfile, pcopy); + else + ent = NULL; + nf = cvs_file_lget(pcopy, 0, base, ent); if (nf == NULL) { cvs_file_free(base); return (NULL); } - if (cvs_file_attach(cf, nf) < 0) { + if (cvs_file_attach(base, nf) < 0) { cvs_file_free(base); return (NULL); } } + } - if (np != NULL) { - *np = '/'; - sp = np + 1; - } + if (nf->cf_type == DT_DIR) { + if (np != NULL) + *np++; - cf = nf; - } while (np != NULL); + if (cvs_file_getdir(nf, flags, np) < 0) { + cvs_file_free(base); + return (NULL); + } + } } return (base); @@ -523,41 +541,22 @@ cvs_file_attach(CVSFILE *parent, CVSFILE *file) /* - * cvs_file_getdir() - * - * Get a cvs directory structure for the directory whose path is <dir>. - * This function should not free the directory information on error, as this - * is performed by cvs_file_free(). + * Load directory information */ static int -cvs_file_getdir(CVSFILE *cf, int flags) +cvs_load_dirinfo(CVSFILE *cf) { - int ret, fd, l; - u_int ndirs, nfiles; - long base; - u_char *dp, *ep; - char fbuf[2048], pbuf[MAXPATHLEN], fpath[MAXPATHLEN]; - struct dirent *ent; - CVSFILE *cfp; - CVSENTRIES *entfile; + char fpath[MAXPATHLEN]; + char pbuf[MAXPATHLEN]; struct stat st; - struct cvs_ent *cvsent; - struct cvs_flist dirs; - - ndirs = 0; - nfiles = 0; - SIMPLEQ_INIT(&dirs); + int l; cvs_file_getpath(cf, fpath, sizeof(fpath)); - cf->cf_root = cvsroot_get(fpath); if (cf->cf_root == NULL) return (-1); if (cf->cf_cvstat != CVS_FST_UNKNOWN) { - if (flags & CF_MKADMIN) - cvs_mkadmin(cf, 0755); - /* if the CVS administrative directory exists, load the info */ l = snprintf(pbuf, sizeof(pbuf), "%s/" CVS_PATH_CVSDIR, fpath); if (l == -1 || l >= (int)sizeof(pbuf)) { @@ -575,132 +574,197 @@ cvs_file_getdir(CVSFILE *cf, int flags) return (-1); } } + } + } - entfile = cvs_ent_open(fpath, O_RDONLY); + return (0); +} + +/* + * cvs_file_getdir() + * + * Get a cvs directory structure for the directory whose path is <dir>. + * This function should not free the directory information on error, as this + * is performed by cvs_file_free(). + */ +static int +cvs_file_getdir(CVSFILE *cf, int flags, char *path) +{ + int l; + int check_entry; + u_int ndirs, nfiles; + char *cur, *np; + char pbuf[MAXPATHLEN], fpath[MAXPATHLEN]; + struct dirent *ent; + CVSFILE *cfp, *moo; + struct cvs_ent *cvsent; + struct cvs_flist dirs; + DIR *dirp; + CVSENTRIES *entfile; + + moo = NULL; + check_entry = ndirs = nfiles = 0; + SIMPLEQ_INIT(&dirs); + + cvs_file_getpath(cf, fpath, sizeof(fpath)); + entfile = cvs_ent_open(fpath, O_RDONLY); + + cf->cf_root = cvsroot_get(fpath); + if (cf->cf_root == NULL) + return (-1); + + cur = np = NULL; + if (path != NULL) { + cur = strchr(path, '/'); + if (cur != NULL) { + *cur = '\0'; + np = cur + 1; + if (np != NULL && *np == '\0') + np = NULL; } } if ((flags & CF_KNOWN) && (cf->cf_cvstat == CVS_FST_UNKNOWN)) return (0); - fd = open(fpath, O_RDONLY); - if (fd == -1) { - cvs_log(LP_ERRNO, "failed to open `%s'", fpath); + dirp = opendir(fpath); + if (dirp == NULL) { + cvs_log(LP_ERRNO, "failed to open directory %s", fpath); return (-1); } - /* To load all files, we first get the entries for the directory and - * load the information for each of those entries. The handle to - * the Entries file kept in the directory data is only temporary and - * the files should remove their entry when they use it. After all - * files in the directory have been processed, the Entries handle - * should only be left with those entries for which no real file - * exists. We then build file structures for those files too, as - * we will likely receive fresh copies from the server as part of the - * response. - */ - do { - ret = getdirentries(fd, fbuf, sizeof(fbuf), &base); - if (ret == -1) { - cvs_log(LP_ERRNO, "failed to get directory entries"); - (void)close(fd); - return (-1); - } + while ((ent = readdir(dirp)) != NULL) { + if (!strcmp(ent->d_name, ".") || + !strcmp(ent->d_name, "..")) + continue; - dp = fbuf; - ep = fbuf + (size_t)ret; - while (dp < ep) { - ent = (struct dirent *)dp; - dp += ent->d_reclen; - if (ent->d_fileno == 0) - continue; + if ((flags & CF_IGNORE) && cvs_file_chkign(ent->d_name)) + continue; - if ((flags & CF_IGNORE) && cvs_file_chkign(ent->d_name)) - continue; + if ((flags & CF_NOSYMS) && (ent->d_type == DT_LNK)) + continue; - if ((flags & CF_NOSYMS) && (ent->d_type == DT_LNK)) - continue; + if (!(flags & CF_RECURSE) && (ent->d_type == DT_DIR)) { + if (entfile != NULL) + (void)cvs_ent_remove(entfile, + ent->d_name); + continue; + } - if (!(flags & CF_RECURSE) && (ent->d_type == DT_DIR)) { - if (entfile != NULL) - (void)cvs_ent_remove(entfile, - ent->d_name); + if (path != NULL) { + if (strcmp(path, ent->d_name)) continue; - } + } - l = snprintf(pbuf, sizeof(pbuf), "%s/%s", fpath, - ent->d_name); - if (l == -1 || l >= (int)sizeof(pbuf)) { - errno = ENAMETOOLONG; - cvs_log(LP_ERRNO, "%s", pbuf); - - (void)close(fd); - return (-1); - } + l = snprintf(pbuf, sizeof(pbuf), "%s/%s", fpath, + ent->d_name); + if (l == -1 || l >= (int)sizeof(pbuf)) { + errno = ENAMETOOLONG; + cvs_log(LP_ERRNO, "%s", pbuf); + closedir(dirp); + return (-1); + } + cfp = cvs_file_find(cf, ent->d_name); + if (cfp == NULL) { if (entfile != NULL) cvsent = cvs_ent_get(entfile, ent->d_name); cfp = cvs_file_lget(pbuf, flags, cf, cvsent); + if (cfp == NULL) { - (void)close(fd); + closedir(dirp); return (-1); } if (entfile != NULL) cvs_ent_remove(entfile, cfp->cf_name); - if (cfp->cf_type == DT_DIR) { - SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list); - ndirs++; - } else { + if (cfp->cf_type != DT_DIR) { SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, - cf_list); + cf_list); nfiles++; } + } else { + cfp->cf_flags |= CVS_GDIR_IGNORE; } - } while (ret > 0); - if (entfile != NULL) { - /* now create file structure for files which have an - * entry in the Entries file but no file on disk - */ + if (cfp->cf_type == DT_DIR) { + ndirs++; + SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list); + } + + if (path != NULL) { + check_entry = 0; + break; + } + } + + closedir(dirp); + + if (entfile != NULL && check_entry) { while ((cvsent = cvs_ent_next(entfile)) != NULL) { + if (path != NULL) { + if (strcmp(cvsent->ce_name, path)) + continue; + } + l = snprintf(pbuf, sizeof(pbuf), "%s/%s", fpath, cvsent->ce_name); if (l == -1 || l >= (int)sizeof(pbuf)) { errno = ENAMETOOLONG; cvs_log(LP_ERRNO, "%s", pbuf); - - (void)close(fd); return (-1); } - cfp = cvs_file_lget(pbuf, flags, cf, cvsent); - if (cfp != NULL) { - if (cfp->cf_type == DT_DIR) { - SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list); - ndirs++; - } else { - SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, - cf_list); + cfp = cvs_file_find(cf, cvsent->ce_name); + if (cfp == NULL) { + cfp = cvs_file_lget(pbuf, flags, cf, cvsent); + if (cfp == NULL) + continue; + + if (cfp->cf_type != DT_DIR) { + SIMPLEQ_INSERT_TAIL(&(cf->cf_files), + cfp, cf_list); nfiles++; } + } else { + cfp->cf_flags |= CVS_GDIR_IGNORE; + } + + if (cfp->cf_type == DT_DIR) { + ndirs++; + SIMPLEQ_INSERT_TAIL(&dirs, cfp, + cf_list); } + + if (path != NULL) + break; } cvs_ent_close(entfile); } if (flags & CF_SORT) { - cvs_file_sort(&(cf->cf_files), nfiles); - cvs_file_sort(&dirs, ndirs); + if (nfiles > 0) + cvs_file_sort(&(cf->cf_files), nfiles); + if (ndirs > 0) + cvs_file_sort(&dirs, ndirs); } while (!SIMPLEQ_EMPTY(&dirs)) { cfp = SIMPLEQ_FIRST(&dirs); SIMPLEQ_REMOVE_HEAD(&dirs, cf_list); - SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list); + + if (!(cfp->cf_flags & CVS_GDIR_IGNORE)) + SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list); + else + cfp->cf_flags &= ~CVS_GDIR_IGNORE; + + if (cvs_file_getdir(cfp, flags, np) < 0) { + cvs_log(LP_ERROR, "failed to get %s", + CVS_FILE_NAME(cfp)); + continue; + } } - (void)close(fd); return (0); } @@ -947,7 +1011,7 @@ cvs_file_lget(const char *path, int flags, CVSFILE *parent, struct cvs_ent *ent) ent->ce_rev = NULL; } - if ((cfp->cf_type == DT_DIR) && (cvs_file_getdir(cfp, flags) < 0)) { + if ((cfp->cf_type == DT_DIR) && (cvs_load_dirinfo(cfp) < 0)) { cvs_file_free(cfp); return (NULL); } |