diff options
author | Jean-Francois Brousseau <jfb@cvs.openbsd.org> | 2004-07-23 05:40:33 +0000 |
---|---|---|
committer | Jean-Francois Brousseau <jfb@cvs.openbsd.org> | 2004-07-23 05:40:33 +0000 |
commit | 0818ee82726946bb94b983b7a7861d0daaf73ea7 (patch) | |
tree | 8c076d078b0224c9c30fa466a78315c7b55efd09 /usr.bin/cvs | |
parent | 240cc28967c76b7d64cbafbf5866fafe07f710d8 (diff) |
Revamp the file interface to make life easier
Diffstat (limited to 'usr.bin/cvs')
-rw-r--r-- | usr.bin/cvs/cvs.h | 56 | ||||
-rw-r--r-- | usr.bin/cvs/file.c | 262 |
2 files changed, 308 insertions, 10 deletions
diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h index 54778b82833..a49688203a5 100644 --- a/usr.bin/cvs/cvs.h +++ b/usr.bin/cvs/cvs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cvs.h,v 1.6 2004/07/16 03:08:26 jfb Exp $ */ +/* $OpenBSD: cvs.h,v 1.7 2004/07/23 05:40:32 jfb Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -212,6 +212,10 @@ #define CVS_PATH_ROOTSPEC CVS_PATH_CVSDIR "/Root" +struct cvs_file; +struct cvs_dir; + + struct cvs_op { u_int co_op; uid_t co_uid; /* user performing the operation */ @@ -221,9 +225,6 @@ struct cvs_op { - - - struct cvsroot { u_int cr_method; char *cr_buf; @@ -235,6 +236,42 @@ struct cvsroot { }; +#define CF_STAT 0x01 /* allocate space for file stats */ +#define CF_IGNORE 0x02 /* apply regular ignore rules */ +#define CF_RECURSE 0x04 /* recurse on directory operations */ +#define CF_SORT 0x08 /* all files are sorted alphabetically */ + + +/* + * The cvs_file structure is used to represent any file or directory within + * the CVS tree's hierarchy. The <cf_path> field is a path relative to the + * directory in which the cvs command was executed. The <cf_parent> field + * points back to the parent node in the directory tree structure (it is + * NULL if the directory is at the wd of the command). + * + * If the file's type is DT_DIR, then the <cf_ddat> pointer will point to + * a cvs_dir structure containing data specific to the directory (such as + * the contents of the directory's CVS/Entries, CVS/Root, etc.). + */ + +struct cvs_file { + char *cf_path; + struct cvs_file *cf_parent; /* parent directory (NULL if none) */ + char *cf_name; + u_int cf_type; /* uses values from dirent.h */ + struct stat *cf_stat; + struct cvs_dir *cf_ddat; /* only for directories */ + + LIST_ENTRY(cvs_file) cf_list; +}; + + +struct cvs_dir { + struct cvsroot *cd_root; + char *cd_repo; + LIST_HEAD(cvs_flist, cvs_file) cd_files; +}; + #define CVS_HIST_ADDED 'A' #define CVS_HIST_EXPORT 'E' #define CVS_HIST_RELEASE 'F' @@ -346,10 +383,13 @@ void cvsroot_free (struct cvsroot *); struct cvsroot* cvsroot_get (const char *); -int cvs_file_init (void); -int cvs_file_ignore (const char *); -int cvs_file_isignored (const char *); -char** cvs_file_getv (const char *, int *); +/* from file.c */ +int cvs_file_init (void); +int cvs_file_ignore (const char *); +int cvs_file_isignored (const char *); +char** cvs_file_getv (const char *, int *, int); +struct cvs_file* cvs_file_get (const char *, int); +void cvs_file_free (struct cvs_file *); /* Entries API */ diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c index f34b86f9028..07df1697b16 100644 --- a/usr.bin/cvs/file.c +++ b/usr.bin/cvs/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.2 2004/07/16 03:08:26 jfb Exp $ */ +/* $OpenBSD: file.c,v 1.3 2004/07/23 05:40:32 jfb Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -90,6 +90,13 @@ static const char *cvs_ign_std[] = { TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats; +static struct cvs_dir* cvs_file_getdir (struct cvs_file *, int); +static void cvs_file_freedir (struct cvs_dir *); +static int cvs_file_sort (struct cvs_flist *); +static int cvs_file_cmp (const void *, const void *); + + + /* * cvs_file_init() * @@ -212,7 +219,7 @@ cvs_file_isignored(const char *file) */ char** -cvs_file_getv(const char *dir, int *nfiles) +cvs_file_getv(const char *dir, int *nfiles, int recurse) { int nf, ret, fd; long base; @@ -260,3 +267,254 @@ cvs_file_getv(const char *dir, int *nfiles) return (fvec); } + + +/* + * cvs_file_get() + * + * Load a cvs_file structure with all the information pertaining to the file + * <path>. + * Returns a pointer to the cvs file structure, which must later be freed + * with cvs_file_free(). + */ + +struct cvs_file* +cvs_file_get(const char *path, int flags) +{ + size_t dlen; + struct stat st; + struct cvs_file *cfp; + + printf("cvs_file_get(%s)\n", path); + + if (stat(path, &st) == -1) { + cvs_log(LP_ERRNO, "failed to stat file"); + return (NULL); + } + + cfp = (struct cvs_file *)malloc(sizeof(*cfp)); + if (cfp == NULL) { + cvs_log(LP_ERRNO, "failed to allocate CVS file data"); + return (NULL); + } + memset(cfp, 0, sizeof(*cfp)); + + cfp->cf_path = strdup(path); + if (cfp->cf_path == NULL) { + free(cfp); + return (NULL); + } + + cfp->cf_name = strrchr(cfp->cf_path, '/'); + if (cfp->cf_name == NULL) + cfp->cf_name = cfp->cf_path; + else + cfp->cf_name++; + + /* convert from stat mode to dirent values */ + cfp->cf_type = IFTODT(st.st_mode); + if (cfp->cf_type == DT_DIR) { + cfp->cf_ddat = cvs_file_getdir(cfp, flags); + if (cfp->cf_ddat == NULL) { + cvs_file_free(cfp); + return (NULL); + } + } + + if (flags & CF_STAT) { + cfp->cf_stat = (struct stat *)malloc(sizeof(struct stat)); + if (cfp->cf_stat == NULL) { + cvs_log(LP_ERRNO, "failed to allocate stat structure"); + cvs_file_free(cfp); + return (NULL); + } + + memcpy(cfp->cf_stat, &st, sizeof(struct stat)); + } + + return (cfp); +} + + +/* + * cvs_file_getdir() + * + * Get a cvs directory structure for the directory whose path is <dir>. + */ + +static struct cvs_dir* +cvs_file_getdir(struct cvs_file *cf, int flags) +{ + int nf, ret, fd; + long base; + void *dp, *ep, *tmp; + char fbuf[1024], pbuf[MAXPATHLEN]; + struct dirent *ent; + struct cvs_file *cfp; + struct cvs_dir *cdp; + + cdp = (struct cvs_dir *)malloc(sizeof(*cdp)); + if (cdp == NULL) { + cvs_log(LP_ERRNO, "failed to allocate dir"); + return (NULL); + } + memset(cdp, 0, sizeof(*cdp)); + LIST_INIT(&(cdp->cd_files)); + + if (cvs_readrepo(cf->cf_path, pbuf, sizeof(pbuf)) < 0) { + free(cdp); + return (NULL); + } + + cdp->cd_repo = strdup(pbuf); + if (cdp->cd_repo == NULL) { + free(cdp); + return (NULL); + } + + cdp->cd_root = cvsroot_get(cf->cf_path); + if (cdp->cd_root == NULL) { + cvs_file_freedir(cdp); + return (NULL); + } + + fd = open(cf->cf_path, O_RDONLY); + if (fd == -1) { + cvs_log(LP_ERRNO, "failed to open `%s'", cf->cf_path); + cvs_file_freedir(cdp); + return (NULL); + } + ret = getdirentries(fd, fbuf, sizeof(fbuf), &base); + if (ret == -1) { + cvs_log(LP_ERRNO, "failed to get directory entries"); + (void)close(fd); + cvs_file_freedir(cdp); + return (NULL); + } + + dp = fbuf; + ep = fbuf + (size_t)ret; + while (dp < ep) { + ent = (struct dirent *)dp; + dp += ent->d_reclen; + + if ((flags & CF_IGNORE) && cvs_file_isignored(ent->d_name)) + continue; + + snprintf(pbuf, sizeof(pbuf), "%s/%s", cf->cf_path, ent->d_name); + cfp = cvs_file_get(pbuf, flags); + + LIST_INSERT_HEAD(&(cdp->cd_files), cfp, cf_list); + } + + if (flags & CF_SORT) + cvs_file_sort(&(cdp->cd_files)); + + (void)close(fd); + + return (cdp); +} + + +/* + * cvs_file_free() + * + * Free a cvs_file structure and its contents. + */ + +void +cvs_file_free(struct cvs_file *cf) +{ + struct cvs_file *cfp; + struct cvs_dir *cd; + + if (cf->cf_path != NULL) + free(cf->cf_path); + if (cf->cf_stat != NULL) + free(cf->cf_stat); + if (cf->cf_ddat != NULL) + cvs_file_freedir(cf->cf_ddat); + free(cf); +} + + +/* + * cvs_file_freedir() + * + * Free a cvs_dir structure and its contents. + */ + +static void +cvs_file_freedir(struct cvs_dir *cd) +{ + struct cvs_file *cfp; + + if (cd->cd_root != NULL) + cvsroot_free(cd->cd_root); + if (cd->cd_repo != NULL) + free(cd->cd_repo); + + while (!LIST_EMPTY(&(cd->cd_files))) { + cfp = LIST_FIRST(&(cd->cd_files)); + LIST_REMOVE(cfp, cf_list); + cvs_file_free(cfp); + } +} + + +/* + * cvs_file_sort() + * + * Sort a list of cvs file structures according to their filename. + */ + +static int +cvs_file_sort(struct cvs_flist *flp) +{ + int i; + size_t nb; + struct cvs_file *cf, *cfvec[256]; + + i = 0; + LIST_FOREACH(cf, flp, cf_list) { + printf("adding `%s'\n", cf->cf_path); + cfvec[i++] = cf; + if (i == sizeof(cfvec)/sizeof(struct cvs_file *)) { + cvs_log(LP_WARN, "too many files to sort"); + return (-1); + } + + /* now unlink it from the list, + * we'll put it back in order later + */ + LIST_REMOVE(cf, cf_list); + } + + /* clear the list just in case */ + LIST_INIT(flp); + nb = (size_t)i; + + printf("Before: \n"); + for (i = 0; i < (int)nb; i++) + printf("[%d] = `%s'\n", i, cfvec[i]->cf_name); + heapsort(cfvec, nb, sizeof(cf), cvs_file_cmp); + printf("===================================\nAfter: \n"); + for (i = 0; i < (int)nb; i++) + printf("[%d] = `%s'\n", i, cfvec[i]->cf_name); + + /* rebuild the list from the bottom up */ + for (i = (int)nb - 1; i >= 0; i--) + LIST_INSERT_HEAD(flp, cfvec[i], cf_list); + + return (0); +} + + +static int +cvs_file_cmp(const void *f1, const void *f2) +{ + struct cvs_file *cf1, *cf2; + cf1 = *(struct cvs_file **)f1; + cf2 = *(struct cvs_file **)f2; + return strcmp(cf1->cf_name, cf2->cf_name); +} |