summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Francois Brousseau <jfb@cvs.openbsd.org>2004-07-25 03:18:54 +0000
committerJean-Francois Brousseau <jfb@cvs.openbsd.org>2004-07-25 03:18:54 +0000
commit0bc2ac3e967cca4a3f1ebde45b18e9a73d3af118 (patch)
tree31b7d1aab4689c32bf80f0ba8b4b274b4da59cbe
parentef47280b946b382c1f6be8bea3f4f9aa17d5bc78 (diff)
* cleanup the file API with regards to flag handling and
general structure * implement cvs_ent_close() correctly, fix some memory leaks, and add cvs_ent_getent() to get a single entry easily
-rw-r--r--usr.bin/cvs/cvs.h24
-rw-r--r--usr.bin/cvs/entries.c86
-rw-r--r--usr.bin/cvs/file.c82
3 files changed, 152 insertions, 40 deletions
diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h
index a49688203a5..0233f7fe2c4 100644
--- a/usr.bin/cvs/cvs.h
+++ b/usr.bin/cvs/cvs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cvs.h,v 1.7 2004/07/23 05:40:32 jfb Exp $ */
+/* $OpenBSD: cvs.h,v 1.8 2004/07/25 03:18:53 jfb Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -28,7 +28,7 @@
#define CVS_H
#include <sys/param.h>
-
+#include <stdio.h>
#include "rcs.h"
#define CVS_VERSION "OpenCVS 0.1"
@@ -46,6 +46,7 @@
/* operations */
+#define CVS_OP_ANY 0 /* all operations */
#define CVS_OP_ADD 1
#define CVS_OP_ANNOTATE 2
#define CVS_OP_COMMIT 3
@@ -240,6 +241,7 @@ struct cvsroot {
#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 */
+#define CF_KNOWN 0x10 /* only recurse in directories known to CVS */
/*
@@ -249,18 +251,28 @@ struct cvsroot {
* points back to the parent node in the directory tree structure (it is
* NULL if the directory is at the wd of the command).
*
+ * The <cf_cvstat> field gives the file's status with regards to the CVS
+ * repository. The file can be in any one of the CVS_FST_* states.
* 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.).
*/
+#define CVS_FST_UNKNOWN 0
+#define CVS_FST_UPTODATE 1
+#define CVS_FST_MODIFIED 2
+#define CVS_FST_ADDED 3
+#define CVS_FST_REMOVED 4
+#define CVS_FST_CONFLICT 5
+
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 */
+ u_int16_t cf_cvstat; /* cvs status of the file */
+ u_int16_t cf_type; /* uses values from dirent.h */
+ struct stat *cf_stat; /* only available with CF_STAT flag */
+ struct cvs_dir *cf_ddat; /* only for directories */
LIST_ENTRY(cvs_file) cf_list;
};
@@ -401,6 +413,8 @@ int cvs_ent_addln (CVSENTRIES *, const char *);
int cvs_ent_remove (CVSENTRIES *, const char *);
struct cvs_ent* cvs_ent_parse (const char *);
void cvs_ent_close (CVSENTRIES *);
+void cvs_ent_free (struct cvs_ent *);
+struct cvs_ent* cvs_ent_getent (const char *);
/* history API */
CVSHIST* cvs_hist_open (const char *);
diff --git a/usr.bin/cvs/entries.c b/usr.bin/cvs/entries.c
index 967373eeb91..40f9db3bdd1 100644
--- a/usr.bin/cvs/entries.c
+++ b/usr.bin/cvs/entries.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: entries.c,v 1.4 2004/07/14 19:03:00 jfb Exp $ */
+/* $OpenBSD: entries.c,v 1.5 2004/07/25 03:18:53 jfb Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -90,6 +90,8 @@ cvs_ent_open(const char *dir, int flags)
(void)fclose(fp);
return (NULL);
}
+ memset(ep, 0, sizeof(*ep));
+
ep->cef_path = strdup(dir);
if (ep->cef_path == NULL) {
cvs_log(LP_ERRNO, "failed to copy Entries path");
@@ -125,12 +127,26 @@ cvs_ent_open(const char *dir, int flags)
/*
* cvs_ent_close()
*
- * Close the Entries file <ep>.
+ * Close the Entries file <ep> and free all data. Any reference to entries
+ * structure within that file become invalid.
*/
void
cvs_ent_close(CVSENTRIES *ep)
{
+ struct cvs_ent *ent;
+
+ if (ep->cef_file != NULL)
+ (void)fclose(ep);
+ if (ep->cef_path != NULL)
+ free(ep->cef_path);
+
+ while (!TAILQ_EMPTY(&(ep->cef_ent))) {
+ ent = TAILQ_FIRST(&(ep->cef_ent));
+ TAILQ_REMOVE(&(ep->cef_ent), ent, ce_list);
+ cvs_ent_free(ent);
+ }
+
free(ep);
}
@@ -228,12 +244,11 @@ cvs_ent_get(CVSENTRIES *ef, const char *file)
struct cvs_ent*
cvs_ent_next(CVSENTRIES *ef)
{
- if (ef->cef_cur == NULL) {
+ if (ef->cef_cur == NULL)
ef->cef_cur = TAILQ_FIRST(&(ef->cef_ent));
- return (ef->cef_cur);
- }
-
- return TAILQ_NEXT(ef->cef_cur, ce_list);
+ else
+ ef->cef_cur = TAILQ_NEXT(ef->cef_cur, ce_list);
+ return (ef->cef_cur);
}
@@ -256,6 +271,7 @@ cvs_ent_parse(const char *entry)
cvs_log(LP_ERRNO, "failed to allocate CVS entry");
return (NULL);
}
+ memset(entp, 0, sizeof(*entp));
entp->ce_rev = rcsnum_alloc();
if (entp->ce_rev == NULL) {
@@ -265,14 +281,13 @@ cvs_ent_parse(const char *entry)
entp->ce_line = strdup(entry);
if (entp->ce_line == NULL) {
- free(entp);
+ cvs_ent_free(entp);
return (NULL);
}
entp->ce_buf = strdup(entry);
if (entp->ce_buf == NULL) {
- free(entp->ce_line);
- free(entp);
+ cvs_ent_free(entp);
return (NULL);
}
sp = entp->ce_buf;
@@ -310,3 +325,54 @@ cvs_ent_parse(const char *entry)
return (entp);
}
+
+
+/*
+ * cvs_ent_free()
+ *
+ * Free a single CVS entries structure.
+ */
+
+void
+cvs_ent_free(struct cvs_ent *ent)
+{
+ if (ent->ce_rev != NULL)
+ rcsnum_free(ent->ce_rev);
+ if (ent->ce_line != NULL)
+ free(ent->ce_line);
+ if (ent->ce_buf != NULL)
+ free(ent->ce_buf);
+ free(ent);
+}
+
+
+/*
+ * cvs_ent_getent()
+ *
+ * Get a single entry from the CVS/Entries file of the basename portion of
+ * path <path> and return that entry. That entry must later be freed using
+ * cvs_ent_free().
+ */
+
+struct cvs_ent*
+cvs_ent_getent(const char *path)
+{
+ char base[MAXPATHLEN], file[MAXPATHLEN];
+ CVSENTRIES *entf;
+ struct cvs_ent *ep;
+
+ cvs_splitpath(path, base, sizeof(base), file, sizeof(file));
+
+ entf = cvs_ent_open(base, O_RDONLY);
+ if (entf == NULL)
+ return (NULL);
+
+ ep = cvs_ent_get(entf, file);
+ if (ep != NULL) {
+ /* take it out of the queue so it doesn't get freed */
+ TAILQ_REMOVE(&(entf->cef_ent), ep, ce_list);
+ }
+
+ cvs_ent_close(entf);
+ return (ep);
+}
diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c
index 07df1697b16..7ac68e4642a 100644
--- a/usr.bin/cvs/file.c
+++ b/usr.bin/cvs/file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.c,v 1.3 2004/07/23 05:40:32 jfb Exp $ */
+/* $OpenBSD: file.c,v 1.4 2004/07/25 03:18:52 jfb Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -87,6 +87,9 @@ static const char *cvs_ign_std[] = {
};
+static RCSNUM *cvs_addedrev;
+
+
TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats;
@@ -113,6 +116,9 @@ cvs_file_init(void)
TAILQ_INIT(&cvs_ign_pats);
+ cvs_addedrev = rcsnum_alloc();
+ rcsnum_aton("0", NULL, cvs_addedrev);
+
/* standard patterns to ignore */
for (i = 0; i < sizeof(cvs_ign_std)/sizeof(char *); i++)
cvs_file_ignore(cvs_ign_std[i]);
@@ -274,6 +280,15 @@ cvs_file_getv(const char *dir, int *nfiles, int recurse)
*
* Load a cvs_file structure with all the information pertaining to the file
* <path>.
+ * The <flags> parameter specifies various flags that alter the behaviour of
+ * the function. The CF_STAT flag is used to keep stat information of the
+ * file in the structure after it is used (it is lost otherwise). The
+ * CF_RECURSE flag causes the function to recursively load subdirectories
+ * when <path> is a directory. The CF_SORT flag causes the files to be
+ * sorted in alphabetical order upon loading.
+ * The special case of "." as a path specification generates recursion for
+ * a single level and is equivalent to calling cvs_file_get() on all files
+ * of that directory.
* Returns a pointer to the cvs file structure, which must later be freed
* with cvs_file_free().
*/
@@ -281,14 +296,21 @@ cvs_file_getv(const char *dir, int *nfiles, int recurse)
struct cvs_file*
cvs_file_get(const char *path, int flags)
{
+ int cwd;
size_t dlen;
struct stat st;
struct cvs_file *cfp;
+ struct cvs_ent *ent;
printf("cvs_file_get(%s)\n", path);
+ if (strcmp(path, ".") == 0)
+ cwd = 1;
+ else
+ cwd = 0;
+
if (stat(path, &st) == -1) {
- cvs_log(LP_ERRNO, "failed to stat file");
+ cvs_log(LP_ERRNO, "failed to stat %s", path);
return (NULL);
}
@@ -299,8 +321,22 @@ cvs_file_get(const char *path, int flags)
}
memset(cfp, 0, sizeof(*cfp));
+ ent = cvs_ent_getent(path);
+ if (ent == NULL)
+ cfp->cf_cvstat = (cwd == 1) ?
+ CVS_FST_UPTODATE : CVS_FST_UNKNOWN;
+ else {
+ if (rcsnum_cmp(ent->ce_rev, cvs_addedrev, 2) == 0)
+ cfp->cf_cvstat = CVS_FST_ADDED;
+ else
+ cfp->cf_cvstat = CVS_FST_UPTODATE;
+
+ cvs_ent_free(ent);
+ }
+
cfp->cf_path = strdup(path);
if (cfp->cf_path == NULL) {
+ cvs_log(LP_ERRNO, "failed to allocate file path");
free(cfp);
return (NULL);
}
@@ -313,11 +349,15 @@ cvs_file_get(const char *path, int flags)
/* 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 ((cfp->cf_type == DT_DIR) && ((flags & CF_RECURSE) || cwd)) {
+ if ((flags & CF_KNOWN) && (cfp->cf_cvstat == CVS_FST_UNKNOWN))
+ cfp->cf_ddat = NULL;
+ else {
+ cfp->cf_ddat = cvs_file_getdir(cfp, flags);
+ if (cfp->cf_ddat == NULL) {
+ cvs_file_free(cfp);
+ return (NULL);
+ }
}
}
@@ -361,15 +401,12 @@ cvs_file_getdir(struct cvs_file *cf, int flags)
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);
+ if (cvs_readrepo(cf->cf_path, pbuf, sizeof(pbuf)) == 0) {
+ cdp->cd_repo = strdup(pbuf);
+ if (cdp->cd_repo == NULL) {
+ free(cdp);
+ return (NULL);
+ }
}
cdp->cd_root = cvsroot_get(cf->cf_path);
@@ -403,8 +440,10 @@ cvs_file_getdir(struct cvs_file *cf, int flags)
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 (cfp != NULL) {
+ cfp->cf_parent = cf;
+ LIST_INSERT_HEAD(&(cdp->cd_files), cfp, cf_list);
+ }
}
if (flags & CF_SORT)
@@ -477,7 +516,6 @@ cvs_file_sort(struct cvs_flist *flp)
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");
@@ -494,13 +532,7 @@ cvs_file_sort(struct cvs_flist *flp)
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--)