summaryrefslogtreecommitdiff
path: root/usr.bin/cvs
diff options
context:
space:
mode:
authorJean-Francois Brousseau <jfb@cvs.openbsd.org>2004-07-23 05:40:33 +0000
committerJean-Francois Brousseau <jfb@cvs.openbsd.org>2004-07-23 05:40:33 +0000
commit0818ee82726946bb94b983b7a7861d0daaf73ea7 (patch)
tree8c076d078b0224c9c30fa466a78315c7b55efd09 /usr.bin/cvs
parent240cc28967c76b7d64cbafbf5866fafe07f710d8 (diff)
Revamp the file interface to make life easier
Diffstat (limited to 'usr.bin/cvs')
-rw-r--r--usr.bin/cvs/cvs.h56
-rw-r--r--usr.bin/cvs/file.c262
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);
+}