summaryrefslogtreecommitdiff
path: root/usr.bin/cvs
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/cvs')
-rw-r--r--usr.bin/cvs/Makefile16
-rw-r--r--usr.bin/cvs/add.c347
-rw-r--r--usr.bin/cvs/admin.c379
-rw-r--r--usr.bin/cvs/annotate.c183
-rw-r--r--usr.bin/cvs/buf.c31
-rw-r--r--usr.bin/cvs/buf.h20
-rw-r--r--usr.bin/cvs/checkout.c390
-rw-r--r--usr.bin/cvs/cmd.c202
-rw-r--r--usr.bin/cvs/commit.c329
-rw-r--r--usr.bin/cvs/cvs.c175
-rw-r--r--usr.bin/cvs/cvs.h205
-rw-r--r--usr.bin/cvs/diff.c1792
-rw-r--r--usr.bin/cvs/diff.h8
-rw-r--r--usr.bin/cvs/diff3.c18
-rw-r--r--usr.bin/cvs/diff_internals.c1393
-rw-r--r--usr.bin/cvs/edit.c186
-rw-r--r--usr.bin/cvs/entries.c631
-rw-r--r--usr.bin/cvs/fatal.c5
-rw-r--r--usr.bin/cvs/file.c1616
-rw-r--r--usr.bin/cvs/file.h193
-rw-r--r--usr.bin/cvs/hist.c279
-rw-r--r--usr.bin/cvs/history.c226
-rw-r--r--usr.bin/cvs/import.c370
-rw-r--r--usr.bin/cvs/log.c193
-rw-r--r--usr.bin/cvs/log.h37
-rw-r--r--usr.bin/cvs/logmsg.c298
-rw-r--r--usr.bin/cvs/proto.c1033
-rw-r--r--usr.bin/cvs/proto.h40
-rw-r--r--usr.bin/cvs/rcs.c639
-rw-r--r--usr.bin/cvs/rcs.h17
-rw-r--r--usr.bin/cvs/rcsnum.c15
-rw-r--r--usr.bin/cvs/rcstime.c7
-rw-r--r--usr.bin/cvs/release.c196
-rw-r--r--usr.bin/cvs/remove.c239
-rw-r--r--usr.bin/cvs/repository.c130
-rw-r--r--usr.bin/cvs/repository.h31
-rw-r--r--usr.bin/cvs/req.c591
-rw-r--r--usr.bin/cvs/resp.c900
-rw-r--r--usr.bin/cvs/root.c9
-rw-r--r--usr.bin/cvs/server.c122
-rw-r--r--usr.bin/cvs/status.c315
-rw-r--r--usr.bin/cvs/tag.c307
-rw-r--r--usr.bin/cvs/update.c335
-rw-r--r--usr.bin/cvs/util.c504
-rw-r--r--usr.bin/cvs/util.h16
-rw-r--r--usr.bin/cvs/version.c66
-rw-r--r--usr.bin/cvs/watch.c255
-rw-r--r--usr.bin/cvs/worklist.h6
48 files changed, 3494 insertions, 11801 deletions
diff --git a/usr.bin/cvs/Makefile b/usr.bin/cvs/Makefile
index a73a94353bd..bf5a0cf28fe 100644
--- a/usr.bin/cvs/Makefile
+++ b/usr.bin/cvs/Makefile
@@ -1,15 +1,13 @@
-# $OpenBSD: Makefile,v 1.21 2006/04/02 02:42:33 ray Exp $
+# $OpenBSD: Makefile,v 1.22 2006/05/27 03:30:30 joris Exp $
-PROG= cvs
-MAN= cvs.1 cvsignore.5 cvsrc.5 cvswrappers.5 cvsintro.7
+PROG= opencvs
+MAN= cvs.1 cvsignore.5 cvsrc.5 cvswrappers.5 cvsintro.7
CPPFLAGS+=-I${.CURDIR}
-SRCS= cvs.c add.c admin.c annotate.c buf.c checkout.c cmd.c commit.c \
- compress.c date.y diff.c diff3.c edit.c entries.c fatal.c file.c \
- getlog.c history.c hist.c import.c init.c log.c logmsg.c proto.c \
- rcs.c rcsnum.c rcstime.c release.c remove.c req.c resp.c root.c \
- server.c status.c tag.c update.c util.c version.c watch.c \
- worklist.c xmalloc.c
+SRCS= cvs.c commit.c checkout.c buf.c cmd.c date.y diff.c diff3.c \
+ diff_internals.c entries.c fatal.c file.c log.c repository.c \
+ rcs.c rcsnum.c rcstime.c root.c status.c worklist.c util.c \
+ update.c xmalloc.c
CFLAGS+=-Wall
CFLAGS+=-Wstrict-prototypes -Wmissing-prototypes
diff --git a/usr.bin/cvs/add.c b/usr.bin/cvs/add.c
deleted file mode 100644
index 3dc59d5faa1..00000000000
--- a/usr.bin/cvs/add.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/* $OpenBSD: add.c,v 1.41 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * Copyright (c) 2005 Xavier Santolaria <xsa@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-extern char *__progname;
-
-
-static int cvs_add_remote(CVSFILE *, void *);
-static int cvs_add_local(CVSFILE *, void *);
-static int cvs_add_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_add_pre_exec(struct cvsroot *);
-static int cvs_add_directory(CVSFILE *);
-static int cvs_add_build_entry(CVSFILE *);
-
-struct cvs_cmd cvs_cmd_add = {
- CVS_OP_ADD, CVS_REQ_ADD, "add",
- { "ad", "new" },
- "Add a new file/directory to the repository",
- "[-k mode] [-m msg] file ...",
- "k:m:",
- NULL,
- 0,
- cvs_add_init,
- cvs_add_pre_exec,
- cvs_add_remote,
- cvs_add_local,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2
-};
-
-static int kflag = RCS_KWEXP_DEFAULT;
-static char *koptstr;
-static char kbuf[16];
-
-static int
-cvs_add_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- cvs_msg = NULL;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'k':
- koptstr = optarg;
- kflag = rcs_kflag_get(koptstr);
- if (RCS_KWEXP_INVAL(kflag)) {
- cvs_log(LP_ERR,
- "invalid RCS keyword expansion mode");
- rcs_kflag_usage();
- return (CVS_EX_USAGE);
- }
- break;
- case 'm':
- cvs_msg = xstrdup(optarg);
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- *arg = optind;
- return (0);
-}
-
-static int
-cvs_add_pre_exec(struct cvsroot *root)
-{
- kbuf[0] = '\0';
-
- if (kflag != RCS_KWEXP_DEFAULT) {
- strlcpy(kbuf, "-k", sizeof(kbuf));
- strlcat(kbuf, koptstr, sizeof(kbuf));
-
- if (root->cr_method != CVS_METHOD_LOCAL)
- cvs_sendarg(root, kbuf, 0);
- }
-
- return (0);
-}
-
-static int
-cvs_add_remote(CVSFILE *cf, void *arg)
-{
- struct cvsroot *root;
-
- root = CVS_DIR_ROOT(cf);
-
- if (cf->cf_type == DT_DIR) {
- cvs_senddir(root, cf);
- return (0);
- }
-
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_sendreq(root, CVS_REQ_ISMODIFIED, cf->cf_name);
-
- return (0);
-}
-
-static int
-cvs_add_local(CVSFILE *cf, void *arg)
-{
- int added, ret;
- char numbuf[64];
-
- added = 0;
-
- /* dont use `cvs add *' */
- if (strcmp(cf->cf_name, ".") == 0 ||
- strcmp(cf->cf_name, "..") == 0 ||
- strcmp(cf->cf_name, CVS_PATH_CVSDIR) == 0) {
- if (verbosity > 1)
- fatal("cannot add special file `%s'.", cf->cf_name);
- }
-
- if (cf->cf_type == DT_DIR)
- return cvs_add_directory(cf);
-
- if ((!(cf->cf_flags & CVS_FILE_ONDISK)) &&
- cf->cf_cvstat != CVS_FST_LOST &&
- cf->cf_cvstat != CVS_FST_REMOVED) {
- if (verbosity > 1)
- cvs_log(LP_WARN, "nothing known about `%s'",
- cf->cf_name);
- return (0);
- } else if (cf->cf_cvstat == CVS_FST_ADDED) {
- if (verbosity > 1)
- cvs_log(LP_WARN, "`%s' has already been entered",
- cf->cf_name);
- return (0);
- } else if (cf->cf_cvstat == CVS_FST_REMOVED) {
-
- /* XXX remove '-' from CVS/Entries */
-
- /* XXX check the file out */
-
- rcsnum_tostr(cf->cf_lrev, numbuf, sizeof(numbuf));
- cvs_log(LP_WARN, "%s, version %s, resurrected",
- cf->cf_name, numbuf);
-
- return (0);
- } else if (cf->cf_cvstat == CVS_FST_CONFLICT ||
- cf->cf_cvstat == CVS_FST_LOST ||
- cf->cf_cvstat == CVS_FST_MODIFIED ||
- cf->cf_cvstat == CVS_FST_UPTODATE) {
- if (verbosity > 1) {
- rcsnum_tostr(cf->cf_lrev, numbuf, sizeof(numbuf));
- cvs_log(LP_WARN,
- "%s already exists, with version number %s",
- cf->cf_name, numbuf);
- }
- return (0);
- }
-
- if ((ret = cvs_add_build_entry(cf)) != 0)
- return (ret);
- else {
- added++;
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "scheduling file `%s' for addition",
- cf->cf_name);
- }
-
- if (added != 0) {
- if (verbosity > 0)
- cvs_log(LP_NOTICE, "use '%s commit' to add %s "
- "permanently", __progname,
- (added == 1) ? "this file" : "these files");
- return (0);
- }
-
- return (0);
-}
-
-/*
- * cvs_add_directory()
- *
- * Add a directory to the repository.
- *
- * Returns 0 on success, -1 on failure.
- */
-static int
-cvs_add_directory(CVSFILE *cf)
-{
- int nb;
- char *date, *repo, *tag;
- char entry[CVS_ENT_MAXLINELEN], fpath[MAXPATHLEN], rcsdir[MAXPATHLEN];
- char msg[1024];
- CVSENTRIES *entf;
- struct cvsroot *root;
- struct stat st;
- struct cvs_ent *ent;
-
- entf = (CVSENTRIES *)cf->cf_entry;
-
- root = CVS_DIR_ROOT(cf);
- repo = CVS_DIR_REPO(cf);
-
- if (strlcpy(fpath, cf->cf_name, sizeof(fpath)) >= sizeof(fpath))
- fatal("cvs_add_directory: path truncation");
-
- if (strchr(fpath, '/') != NULL)
- fatal("directory %s not added; must be a direct sub-directory",
- fpath);
-
- /* Let's see if we have any per-directory tags first */
- cvs_parse_tagfile(&tag, &date, &nb);
-
- /* XXX check for <dir>/CVS */
-
- if (strlcpy(rcsdir, root->cr_dir, sizeof(rcsdir)) >= sizeof(rcsdir) ||
- strlcat(rcsdir, "/", sizeof(rcsdir)) >= sizeof(rcsdir) ||
- strlcat(rcsdir, repo, sizeof(rcsdir)) >= sizeof(rcsdir))
- fatal("cvs_add_directory: path truncation");
-
- if (stat(rcsdir, &st) == 0 && !(S_ISDIR(st.st_mode)))
- fatal("%s is not a directory; %s not added: %s", rcsdir, fpath,
- strerror(errno));
-
- snprintf(msg, sizeof(msg),
- "Directory %s added to the repository", rcsdir);
-
- if (tag != NULL) {
- strlcat(msg, "\n--> Using per-directory sticky tag ",
- sizeof(msg));
- strlcat(msg, tag, sizeof(msg));
- }
- if (date != NULL) {
- strlcat(msg, "\n--> Using per-directory sticky date ",
- sizeof(msg));
- strlcat(msg, date, sizeof(msg));
- }
- strlcat(msg, "\n", sizeof(msg));
-
- if (cvs_noexec == 0) {
- if (mkdir(rcsdir, 0777) == -1)
- fatal("cvs_add_directory: mkdir `%s': %s",
- rcsdir, strerror(errno));
- }
-
- /* create CVS/ admin files */
- if (cvs_noexec == 0)
- cvs_mkadmin(fpath, root->cr_str, repo, tag, date, nb);
-
- /* XXX Build the Entries line. */
- if (strlcpy(entry, "D/", sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, fpath, sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, "////", sizeof(entry)) >= sizeof(entry))
- fatal("cvs_add_directory: path truncation");
-
- if ((ent = cvs_ent_parse(entry)) == NULL)
- fatal("cvs_add_directory: cvs_ent_parse failed");
-
- if (cvs_ent_add(entf, ent) < 0)
- fatal("cvs_add_directory: cvs_ent_parse failed");
-
- cvs_printf("%s", msg);
-
- return (0);
-}
-
-static int
-cvs_add_build_entry(CVSFILE *cf)
-{
- char entry[CVS_ENT_MAXLINELEN], path[MAXPATHLEN];
- FILE *fp;
- CVSENTRIES *entf;
- struct cvs_ent *ent;
-
- entf = (CVSENTRIES *)cf->cf_entry;
-
- if (cvs_noexec == 1)
- return (0);
-
- /* Build the path to the <file>,t file. */
- if (strlcpy(path, CVS_PATH_CVSDIR, sizeof(path)) >= sizeof(path) ||
- strlcat(path, "/", sizeof(path)) >= sizeof(path) ||
- strlcat(path, cf->cf_name, sizeof(path)) >= sizeof(path) ||
- strlcat(path, CVS_DESCR_FILE_EXT, sizeof(path)) >= sizeof(path))
- fatal("cvs_add_build_entry: path truncation");
-
- if ((fp = fopen(path, "w+")) == NULL)
- fatal("cvs_add_build_entry: fopen `%s': %s", path,
- strerror(errno));
-
- if (cvs_msg != NULL) {
- if (fputs(cvs_msg, fp) == EOF)
- fatal("cvs_add_build_entry: fputs `%s': %s", path,
- strerror(errno));
- }
- (void)fclose(fp);
-
- /* XXX Build the Entries line. */
- if (strlcpy(entry, "/", sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, cf->cf_name, sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, "/0/Initial ", sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, cf->cf_name, sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, "/", sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, kbuf, sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, "/", sizeof(entry)) >= sizeof(entry)) {
- (void)cvs_unlink(path);
- fatal("cvs_add_build_entry: path truncation");
- }
-
- if ((ent = cvs_ent_parse(entry)) == NULL) {
- (void)cvs_unlink(path);
- fatal("cvs_add_build_entry: cvs_ent_parse failed");
- }
-
- if (cvs_ent_add(entf, ent) < 0) {
- (void)cvs_unlink(path);
- fatal("cvs_add_build_entry: cvs_ent_add failed");
- }
-
- return (0);
-}
diff --git a/usr.bin/cvs/admin.c b/usr.bin/cvs/admin.c
deleted file mode 100644
index 86272c17ca4..00000000000
--- a/usr.bin/cvs/admin.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/* $OpenBSD: admin.c,v 1.33 2006/04/10 08:08:00 xsa Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * Copyright (c) 2005 Joris Vink <joris@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-#define LOCK_SET 0x01
-#define LOCK_REMOVE 0x02
-
-#define FLAG_BRANCH 0x01
-#define FLAG_DELUSER 0x02
-#define FLAG_INTERACTIVE 0x04
-#define FLAG_QUIET 0x08
-
-static int cvs_admin_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_admin_pre_exec(struct cvsroot *);
-static int cvs_admin_remote(CVSFILE *, void *);
-static int cvs_admin_local(CVSFILE *, void *);
-
-struct cvs_cmd cvs_cmd_admin = {
- CVS_OP_ADMIN, CVS_REQ_ADMIN, "admin",
- { "adm", "rcs" },
- "Administrative front-end for RCS",
- "",
- "a:A:b::c:e::Ik:l::Lm:n:N:o:qs:t:u::U",
- NULL,
- CF_SORT | CF_IGNORE | CF_RECURSE,
- cvs_admin_init,
- cvs_admin_pre_exec,
- cvs_admin_remote,
- cvs_admin_local,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2
-};
-
-static char *q, *Ntag, *ntag, *comment, *replace_msg;
-static char *alist, *subst, *lockrev_arg, *unlockrev_arg;
-static char *state, *userfile, *branch_arg, *elist, *range;
-static int runflags, kflag, lockrev, lkmode;
-
-/* flag as invalid */
-static int kflag = RCS_KWEXP_ERR;
-static int lkmode = RCS_LOCK_INVAL;
-
-static int
-cvs_admin_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
- RCSNUM *rcs;
-
- runflags = lockrev = 0;
- Ntag = ntag = comment = replace_msg = NULL;
- state = alist = subst = elist = lockrev_arg = NULL;
- range = userfile = branch_arg = unlockrev_arg = NULL;
-
- /* option-o-rama ! */
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'a':
- alist = optarg;
- break;
- case 'A':
- userfile = optarg;
- break;
- case 'b':
- runflags |= FLAG_BRANCH;
- if (optarg)
- branch_arg = optarg;
- break;
- case 'c':
- comment = optarg;
- break;
- case 'e':
- runflags |= FLAG_DELUSER;
- if (optarg)
- elist = optarg;
- break;
- case 'I':
- runflags |= FLAG_INTERACTIVE;
- break;
- case 'k':
- subst = optarg;
- kflag = rcs_kflag_get(subst);
- if (RCS_KWEXP_INVAL(kflag)) {
- cvs_log(LP_ERR,
- "invalid RCS keyword expansion mode");
- rcs_kflag_usage();
- return (CVS_EX_USAGE);
- }
- break;
- case 'l':
- lockrev |= LOCK_SET;
- if (optarg)
- lockrev_arg = optarg;
- break;
- case 'L':
- lkmode = RCS_LOCK_STRICT;
- break;
- case 'm':
- replace_msg = optarg;
- break;
- case 'n':
- ntag = optarg;
- break;
- case 'N':
- Ntag = optarg;
- break;
- case 'o':
- range = optarg;
- break;
- case 'q':
- runflags |= FLAG_QUIET;
- break;
- case 's':
- state = optarg;
- break;
- case 't':
- break;
- case 'u':
- lockrev |= LOCK_REMOVE;
- if (optarg)
- unlockrev_arg = optarg;
- break;
- case 'U':
- if (lkmode != RCS_LOCK_INVAL) {
- cvs_log(LP_ERR, "-L and -U are incompatible");
- return (CVS_EX_USAGE);
- }
- lkmode = RCS_LOCK_LOOSE;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (lockrev_arg != NULL) {
- if ((rcs = rcsnum_parse(lockrev_arg)) == NULL) {
- cvs_log(LP_ERR, "%s is not a numeric branch",
- lockrev_arg);
- return (CVS_EX_USAGE);
- }
- rcsnum_free(rcs);
- }
-
- if (unlockrev_arg != NULL) {
- if ((rcs = rcsnum_parse(unlockrev_arg)) == NULL) {
- cvs_log(LP_ERR, "%s is not a numeric branch",
- unlockrev_arg);
- return (CVS_EX_USAGE);
- }
- rcsnum_free(rcs);
- }
-
- if (replace_msg != NULL) {
- if ((q = strchr(replace_msg, ':')) == NULL) {
- cvs_log(LP_ERR, "invalid option for -m");
- return (CVS_EX_USAGE);
- }
- *q = '\0';
- if ((rcs = rcsnum_parse(replace_msg)) == NULL) {
- cvs_log(LP_ERR, "%s is not a numeric revision",
- replace_msg);
- return (CVS_EX_USAGE);
- }
- rcsnum_free(rcs);
- *q = ':';
- }
-
- *arg = optind;
- return (0);
-}
-
-static int
-cvs_admin_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method == CVS_METHOD_LOCAL)
- return (0);
-
- if (alist != NULL) {
- cvs_sendarg(root, "-a", 0);
- cvs_sendarg(root, alist, 0);
- }
-
- if (userfile != NULL) {
- cvs_sendarg(root, "-A", 0);
- cvs_sendarg(root, userfile, 0);
- }
-
- if (runflags & FLAG_BRANCH) {
- cvs_sendarg(root, "-b", 0);
- if (branch_arg != NULL)
- cvs_sendarg(root, branch_arg, 0);
- }
-
- if (comment != NULL) {
- cvs_sendarg(root, "-c", 0);
- cvs_sendarg(root, comment, 0);
- }
-
- if (runflags & FLAG_DELUSER) {
- cvs_sendarg(root, "-e", 0);
- if (elist != NULL)
- cvs_sendarg(root, elist, 0);
- }
-
- if (runflags & FLAG_INTERACTIVE)
- cvs_sendarg(root, "-I", 0);
-
- if (subst != NULL) {
- cvs_sendarg(root, "-k", 0);
- cvs_sendarg(root, subst, 0);
- }
-
- if (lockrev & LOCK_SET) {
- cvs_sendarg(root, "-l", 0);
- if (lockrev_arg != NULL)
- cvs_sendarg(root, lockrev_arg, 0);
- }
-
- if (lkmode == RCS_LOCK_STRICT)
- cvs_sendarg(root, "-L", 0);
- else if (lkmode == RCS_LOCK_LOOSE)
- cvs_sendarg(root, "-U", 0);
-
- if (replace_msg != NULL) {
- cvs_sendarg(root, "-m", 0);
- cvs_sendarg(root, replace_msg, 0);
- }
-
- if (ntag != NULL) {
- cvs_sendarg(root, "-n", 0);
- cvs_sendarg(root, ntag, 0);
- }
-
- if (Ntag != NULL) {
- cvs_sendarg(root, "-N", 0);
- cvs_sendarg(root, Ntag, 0);
- }
-
- if (range != NULL) {
- cvs_sendarg(root, "-o", 0);
- cvs_sendarg(root, range, 0);
- }
-
- if (state != NULL) {
- cvs_sendarg(root, "-s", 0);
- cvs_sendarg(root, state, 0);
- }
-
- if (lockrev & LOCK_REMOVE) {
- cvs_sendarg(root, "-u", 0);
- if (unlockrev_arg != NULL)
- cvs_sendarg(root, unlockrev_arg, 0);
- }
-
- return (0);
-}
-
-/*
- * cvs_admin_remote()
- *
- * Perform admin commands on each file.
- */
-static int
-cvs_admin_remote(CVSFILE *cf, void *arg)
-{
- char fpath[MAXPATHLEN];
- struct cvsroot *root;
-
- root = CVS_DIR_ROOT(cf);
-
- if (cf->cf_type == DT_DIR) {
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- else
- cvs_senddir(root, cf);
- return (0);
- }
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
- cvs_sendentry(root, cf);
-
- switch (cf->cf_cvstat) {
- case CVS_FST_UNKNOWN:
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- break;
- case CVS_FST_UPTODATE:
- cvs_sendreq(root, CVS_REQ_UNCHANGED, cf->cf_name);
- break;
- case CVS_FST_MODIFIED:
- cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name);
- cvs_sendfile(root, fpath);
- break;
- default:
- break;
- }
-
- return (0);
-}
-
-/*
- * cvs_admin_local()
- *
- * Perform administrative operations on a local RCS file.
- */
-static int
-cvs_admin_local(CVSFILE *cf, void *arg)
-{
- char fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
- RCSFILE *rf;
-
- if (cf->cf_type == DT_DIR) {
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "Administrating %s", cf->cf_name);
- return (0);
- }
-
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- return (0);
- else if (cf->cf_cvstat == CVS_FST_ADDED) {
- cvs_log(LP_WARN, "cannot admin newly added file `%s'",
- cf->cf_name);
- return (0);
- }
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
- cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
-
- if ((rf = rcs_open(rcspath, RCS_RDWR)) == NULL)
- fatal("cvs_admin_local: rcs_open `%s': %s", rcspath,
- rcs_errstr(rcs_errno));
-
- if (!(runflags & FLAG_QUIET))
- cvs_printf("RCS file: %s\n", rcspath);
-
- rcs_kwexp_set(rf, kflag);
-
- if (lkmode != RCS_LOCK_INVAL)
- rcs_lock_setmode(rf, lkmode);
-
- rcs_close(rf);
-
- if (!(runflags & FLAG_QUIET))
- cvs_printf("done\n");
-
- return (0);
-}
diff --git a/usr.bin/cvs/annotate.c b/usr.bin/cvs/annotate.c
deleted file mode 100644
index 7f7b6855eca..00000000000
--- a/usr.bin/cvs/annotate.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/* $OpenBSD: annotate.c,v 1.29 2006/01/30 17:58:47 xsa Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-static int cvs_annotate_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_annotate_remote(CVSFILE *, void *);
-static int cvs_annotate_local(CVSFILE *, void *);
-static int cvs_annotate_pre_exec(struct cvsroot *);
-
-struct cvs_cmd cvs_cmd_annotate = {
- CVS_OP_ANNOTATE, CVS_REQ_ANNOTATE, "annotate",
- { "ann", "blame" },
- "Show last revision where each line was modified",
- "[-flR] [-D date | -r rev] ...",
- "D:flRr:",
- NULL,
- CF_SORT | CF_RECURSE | CF_IGNORE | CF_NOSYMS,
- cvs_annotate_init,
- cvs_annotate_pre_exec,
- cvs_annotate_remote,
- cvs_annotate_local,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2
-};
-
-static char *date, *rev;
-static int usehead;
-
-static int
-cvs_annotate_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- usehead = 0;
- date = NULL;
- rev = NULL;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'D':
- date = optarg;
- break;
- case 'f':
- usehead = 1;
- break;
- case 'l':
- cmd->file_flags &= ~CF_RECURSE;
- break;
- case 'R':
- cmd->file_flags |= CF_RECURSE;
- break;
- case 'r':
- rev = optarg;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- *arg = optind;
- return (0);
-}
-
-static int
-cvs_annotate_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method != CVS_METHOD_LOCAL) {
- if (usehead == 1)
- cvs_sendarg(root, "-f", 0);
-
- if (rev != NULL) {
- cvs_sendarg(root, "-r", 0);
- cvs_sendarg(root, rev, 0);
- }
-
- if (date != NULL) {
- cvs_sendarg(root, "-D", 0);
- cvs_sendarg(root, date, 0);
- }
- }
-
- return (0);
-}
-
-/*
- * cvs_annotate_remote()
- *
- * Annotate a single file.
- */
-static int
-cvs_annotate_remote(CVSFILE *cf, void *arg)
-{
- char fpath[MAXPATHLEN];
- struct cvsroot *root;
-
- root = CVS_DIR_ROOT(cf);
-
- if (cf->cf_type == DT_DIR) {
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- else
- cvs_senddir(root, cf);
- return (0);
- }
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
- cvs_sendentry(root, cf);
-
- switch (cf->cf_cvstat) {
- case CVS_FST_UNKNOWN:
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- break;
- case CVS_FST_UPTODATE:
- cvs_sendreq(root, CVS_REQ_UNCHANGED, cf->cf_name);
- break;
- case CVS_FST_ADDED:
- case CVS_FST_MODIFIED:
- cvs_sendreq(root, CVS_REQ_ISMODIFIED, cf->cf_name);
- break;
- default:
- break;
- }
-
- return (0);
-}
-
-
-static int
-cvs_annotate_local(CVSFILE *cf, void *arg)
-{
- char fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
- RCSFILE *rf;
-
- if (cf->cf_type == DT_DIR)
- return (0);
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- return (0);
-
- cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
-
- if ((rf = rcs_open(rcspath, RCS_READ)) == NULL)
- fatal("cvs_annotate_local: rcs_open `%s': %s", rcspath,
- rcs_errstr(rcs_errno));
-
- cvs_printf("Annotations for %s", cf->cf_name);
- cvs_printf("\n***************\n");
-
- rcs_close(rf);
-
- return (0);
-}
diff --git a/usr.bin/cvs/buf.c b/usr.bin/cvs/buf.c
index 43566991c7c..a4d0b2573b7 100644
--- a/usr.bin/cvs/buf.c
+++ b/usr.bin/cvs/buf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: buf.c,v 1.50 2006/04/14 02:49:43 deraadt Exp $ */
+/* $OpenBSD: buf.c,v 1.51 2006/05/27 03:30:30 joris Exp $ */
/*
* Copyright (c) 2003 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -26,6 +26,7 @@
#include "includes.h"
+#include "cvs.h"
#include "buf.h"
#include "log.h"
#include "xmalloc.h"
@@ -95,21 +96,20 @@ cvs_buf_load(const char *path, u_int flags)
BUF *buf;
if ((fd = open(path, O_RDONLY, 0600)) == -1) {
- cvs_log(LP_ERRNO, "%s", path);
+ cvs_log(LP_ERR, "%s", path);
return (NULL);
}
if (fstat(fd, &st) == -1)
fatal("cvs_buf_load: fstat: %s", strerror(errno));
- buf = cvs_buf_alloc((size_t)st.st_size, flags);
+ buf = cvs_buf_alloc(st.st_size, flags);
for (bp = buf->cb_cur; ; bp += (size_t)ret) {
len = SIZE_LEFT(buf);
ret = read(fd, bp, len);
- if (ret == -1) {
- cvs_buf_free(buf);
+ if (ret == -1)
fatal("cvs_buf_load: read: %s", strerror(errno));
- } else if (ret == 0)
+ else if (ret == 0)
break;
buf->cb_len += (size_t)ret;
@@ -356,7 +356,7 @@ cvs_buf_write(BUF *b, const char *path, mode_t mode)
}
if (fchmod(fd, mode) < 0)
- cvs_log(LP_ERRNO, "permissions not set on file %s", path);
+ cvs_log(LP_ERR, "permissions not set on file %s", path);
(void)close(fd);
@@ -371,27 +371,30 @@ cvs_buf_write(BUF *b, const char *path, mode_t mode)
* <template>, as per mkstemp
*/
void
-cvs_buf_write_stmp(BUF *b, char *template, mode_t mode)
+cvs_buf_write_stmp(BUF *b, char *template, mode_t mode, struct timeval *tv)
{
int fd;
if ((fd = mkstemp(template)) == -1)
fatal("mkstemp: `%s': %s", template, strerror(errno));
-#if defined(RCSPROG)
- cvs_worklist_add(template, &rcs_temp_files);
-#endif
-
if (cvs_buf_write_fd(b, fd) == -1) {
(void)unlink(template);
fatal("cvs_buf_write_stmp: cvs_buf_write_fd: `%s'", template);
}
if (fchmod(fd, mode) < 0)
- cvs_log(LP_ERRNO, "permissions not set on temporary file %s",
+ cvs_log(LP_ERR, "permissions not set on temporary file %s",
template);
+ if (tv != NULL) {
+ if (futimes(fd, tv) == -1)
+ fatal("cvs_buf_write_stmp: futimes failed");
+ }
+
(void)close(fd);
+
+ cvs_worklist_add(template, &temp_files);
}
/*
@@ -415,7 +418,6 @@ cvs_buf_grow(BUF *b, size_t len)
b->cb_cur = b->cb_buf + diff;
}
-#if !defined(RCSPROG)
/*
* cvs_buf_copy()
*
@@ -450,4 +452,3 @@ cvs_buf_peek(BUF *b, size_t off)
return (b->cb_buf + off);
}
-#endif /* RCSPROG */
diff --git a/usr.bin/cvs/buf.h b/usr.bin/cvs/buf.h
index f354e0864bd..ddb9d850d48 100644
--- a/usr.bin/cvs/buf.h
+++ b/usr.bin/cvs/buf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: buf.h,v 1.14 2006/04/06 16:48:34 xsa Exp $ */
+/* $OpenBSD: buf.h,v 1.15 2006/05/27 03:30:30 joris Exp $ */
/*
* Copyright (c) 2003 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -22,17 +22,6 @@
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Buffer management
- * -----------------
- *
- * This code provides an API to generic memory buffer management. All
- * operations are performed on a cvs_buf structure, which is kept opaque to the
- * API user in order to avoid corruption of the fields and make sure that only
- * the internals can modify the fields.
- *
- * The first step is to allocate a new buffer using the cvs_buf_create()
- * function, which returns a pointer to a new buffer.
*/
#ifndef BUF_H
@@ -41,10 +30,8 @@
/* flags */
#define BUF_AUTOEXT 1 /* autoextend on append */
-
typedef struct cvs_buf BUF;
-
BUF *cvs_buf_alloc(size_t, u_int);
BUF *cvs_buf_load(const char *, u_int);
void cvs_buf_free(BUF *);
@@ -59,11 +46,10 @@ void cvs_buf_putc(BUF *, int);
size_t cvs_buf_len(BUF *);
int cvs_buf_write_fd(BUF *, int);
int cvs_buf_write(BUF *, const char *, mode_t);
-void cvs_buf_write_stmp(BUF *, char *, mode_t);
-#if !defined(RCSPROG)
+void cvs_buf_write_stmp(BUF *, char *, mode_t, struct timeval *);
+
ssize_t cvs_buf_copy(BUF *, size_t, void *, size_t);
const void *cvs_buf_peek(BUF *, size_t);
-#endif /* RCSPROG */
#define cvs_buf_get(b) cvs_buf_peek(b, 0)
diff --git a/usr.bin/cvs/checkout.c b/usr.bin/cvs/checkout.c
index f792a6f8d26..6eccb8c5927 100644
--- a/usr.bin/cvs/checkout.c
+++ b/usr.bin/cvs/checkout.c
@@ -1,337 +1,179 @@
-/* $OpenBSD: checkout.c,v 1.52 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: checkout.c,v 1.53 2006/05/27 03:30:30 joris Exp $ */
/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include "cvs.h"
#include "log.h"
+#include "diff.h"
#include "proto.h"
-
-#define CVS_LISTMOD 1
-#define CVS_STATMOD 2
-
-static int cvs_checkout_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_checkout_pre_exec(struct cvsroot *);
-static int cvs_checkout_local(CVSFILE *cf, void *);
+int cvs_checkout(int, char **);
+static void checkout_repository(const char *, const char *);
struct cvs_cmd cvs_cmd_checkout = {
CVS_OP_CHECKOUT, CVS_REQ_CO, "checkout",
{ "co", "get" },
- "Checkout sources for editing",
+ "Checkout a working copy of a repository",
"[-AcflNnPpRs] [-D date | -r tag] [-d dir] [-j rev] [-k mode] "
"[-t id] module ...",
"AcD:d:fj:k:lNnPRr:st:",
NULL,
- 0,
- cvs_checkout_init,
- cvs_checkout_pre_exec,
- NULL,
- NULL,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
-};
-
-struct cvs_cmd cvs_cmd_export = {
- CVS_OP_EXPORT, CVS_REQ_EXPORT, "export",
- { "ex", "exp" },
- "Extract copy of a module without management directories",
- "[-flNnR] [-d dir] [-k mode] -D date | -r tag module ...",
- "D:d:fk:lNnRr:",
- NULL,
- 0,
- cvs_checkout_init,
- cvs_checkout_pre_exec,
- NULL,
- NULL,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
+ cvs_checkout
};
-static char *currepo = NULL;
-static DIR *dirp = NULL;
-static int cwdfd = -1;
-static char *date, *tag, *koptstr, *tgtdir, *rcsid;
-static int statmod = 0;
-static int shorten = 0;
-static int usehead = 0;
-static int kflag = RCS_KWEXP_DEFAULT;
-
-/* modules */
-static char **co_mods;
-static int co_nmod;
-
-/* XXX checkout has issues in remote mode, -N gets seen as module */
-
-static int
-cvs_checkout_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
+int
+cvs_checkout(int argc, char **argv)
{
- int ch;
-
- date = tag = koptstr = tgtdir = rcsid = NULL;
+ int i, ch, l;
+ struct stat st;
+ char repo[MAXPATHLEN];
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
+ while ((ch = getopt(argc, argv, cvs_cmd_checkout.cmd_opts)) != -1) {
switch (ch) {
- case 'A':
- break;
- case 'c':
- statmod = CVS_LISTMOD;
- break;
- case 'D':
- date = optarg;
- cmd->cmd_flags |= CVS_CMD_PRUNEDIRS;
- break;
- case 'd':
- tgtdir = optarg;
- shorten = 1;
- break;
- case 'f':
- usehead = 1;
- break;
- case 'j':
- break;
- case 'k':
- koptstr = optarg;
- kflag = rcs_kflag_get(koptstr);
- if (RCS_KWEXP_INVAL(kflag)) {
- cvs_log(LP_ERR,
- "invalid RCS keyword expansion mode");
- rcs_kflag_usage();
- return (CVS_EX_USAGE);
- }
- break;
- case 'P':
- cmd->cmd_flags |= CVS_CMD_PRUNEDIRS;
- break;
- case 'N':
- shorten = 0;
- break;
- case 'p':
- cvs_noexec = 1; /* no locks will be created */
- break;
- case 'r':
- tag = optarg;
- cmd->cmd_flags |= CVS_CMD_PRUNEDIRS;
- break;
- case 's':
- statmod = CVS_STATMOD;
- break;
- case 't':
- rcsid = optarg;
- break;
default:
- return (CVS_EX_USAGE);
+ fatal("%s", cvs_cmd_checkout.cmd_synopsis);
}
}
argc -= optind;
argv += optind;
- co_mods = argv;
- co_nmod = argc;
+ if (argc == 0)
+ fatal("%s", cvs_cmd_checkout.cmd_synopsis);
- if (statmod == 0 && argc == 0)
- fatal("must specify at least one module or directory");
+ for (i = 0; i < argc; i++) {
+ cvs_mkpath(argv[i]);
- if (statmod && (argc > 0))
- fatal("-c and -s must not get any arguments");
+ l = snprintf(repo, sizeof(repo), "%s/%s",
+ current_cvsroot->cr_dir, argv[i]);
+ if (l == -1 || l >= (int)sizeof(repo))
+ fatal("cvs_checkout: overflow");
- /* `export' command exceptions */
- if (cvs_cmdop == CVS_OP_EXPORT) {
- if (tag == NULL && date == NULL)
- fatal("must specify a tag or date");
+ if (stat(repo, &st) == -1) {
+ cvs_log(LP_ERR, "cannot find repository %s - ignored",
+ argv[i]);
+ continue;
+ }
- /* we don't want numerical revisions here */
- if (tag != NULL && rcsnum_parse(tag) != NULL)
- fatal("tag `%s' must be a symbolic tag", tag);
+ checkout_repository(repo, argv[i]);
}
- *arg = optind;
return (0);
}
-static int
-cvs_checkout_pre_exec(struct cvsroot *root)
+static void
+checkout_repository(const char *repobase, const char *wdbase)
{
- int i, ret;
- char *sp, repo[MAXPATHLEN];
-
- if ((dirp = opendir(".")) == NULL)
- fatal("cvs_checkout_pre_exec: opendir failed");
+ struct cvs_flisthead fl, dl;
+ struct cvs_recursion cr;
- cwdfd = dirfd(dirp);
+ TAILQ_INIT(&fl);
+ TAILQ_INIT(&dl);
- for (i = 0; i < co_nmod; i++) {
- if ((sp = strchr(co_mods[i], '/')) != NULL)
- *sp = '\0';
+ cr.enterdir = cvs_update_enterdir;
+ cr.leavedir = NULL;
+ cr.local = cvs_update_local;
+ cr.remote = NULL;
- if (mkdir(co_mods[i], 0755) == -1 && errno != EEXIST)
- fatal("cvs_checkout_pre_exec: mkdir `%s': %s",
- co_mods[i], strerror(errno));
+ cvs_repository_lock(repobase);
+ cvs_repository_getdir(repobase, wdbase, &fl, &dl);
- cvs_mkadmin(co_mods[i], root->cr_str, co_mods[i], NULL,
- NULL, 0);
+ cvs_file_walklist(&fl, &cr);
+ cvs_file_freelist(&fl);
- if (sp != NULL)
- *sp = '/';
- }
-
- if (root->cr_method == CVS_METHOD_LOCAL) {
- if ((dirp = opendir(".")) == NULL)
- fatal("cvs_checkout_pre_exec: opendir failed");
-
- cwdfd = dirfd(dirp);
-
- for (i = 0; i < co_nmod; i++) {
- if (strlcpy(repo, root->cr_dir, sizeof(repo)) >=
- sizeof(repo) ||
- strlcat(repo, "/", sizeof(repo)) >= sizeof(repo) ||
- strlcat(repo, co_mods[i], sizeof(repo)) >=
- sizeof(repo))
- fatal("cvs_checkout_pre_exec: path truncation");
-
- currepo = co_mods[i];
- ret = cvs_file_get(repo, CF_RECURSE | CF_REPO |
- CF_IGNORE, cvs_checkout_local, NULL, NULL);
- if (ret != CVS_EX_OK) {
- closedir(dirp);
- return (ret);
- }
- }
-
- closedir(dirp);
- } else {
- /*
- * These arguments are for the expand-modules
- * command that we send to the server before requesting
- * a checkout.
- */
- for (i = 0; i < co_nmod; i++)
- cvs_sendarg(root, co_mods[i], 0);
-
- cvs_sendreq(root, CVS_REQ_DIRECTORY, ".");
- cvs_sendln(root, root->cr_dir);
- cvs_sendreq(root, CVS_REQ_XPANDMOD, NULL);
-
- if (usehead == 1)
- cvs_sendarg(root, "-f", 0);
-
- if (tgtdir != NULL) {
- cvs_sendarg(root, "-d", 0);
- cvs_sendarg(root, tgtdir, 0);
- }
+ cvs_repository_unlock(repobase);
- if (shorten == 0)
- cvs_sendarg(root, "-N", 0);
+ cvs_file_walklist(&dl, &cr);
+ cvs_file_freelist(&dl);
+}
- if (cvs_cmd_checkout.cmd_flags & CVS_CMD_PRUNEDIRS);
- cvs_sendarg(root, "-P", 0);
+int
+cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, int flags)
+{
+ BUF *bp;
+ int l, oflags, exists;
+ time_t rcstime;
+ CVSENTRIES *ent;
+ struct timeval tv[2];
+ char *entry, rev[16], timebuf[32];
+
+ rcsnum_tostr(rnum, rev, sizeof(rev));
+
+ cvs_log(LP_TRACE, "cvs_checkout_file(%s, %s, %d)",
+ cf->file_path, rev, flags);
+
+ if ((bp = rcs_getrev(cf->file_rcs, rnum)) == NULL) {
+ cvs_log(LP_ERR, "%s: cannot find revision %s",
+ cf->file_path, rev);
+ return (0);
+ }
- for (i = 0; i < co_nmod; i++)
- cvs_sendarg(root, co_mods[i], 0);
+ oflags = O_WRONLY | O_TRUNC;
+ if (cf->fd != -1) {
+ exists = 1;
+ (void)close(cf->fd);
+ } else {
+ exists = 0;
+ oflags |= O_CREAT;
+ }
- if (statmod == CVS_LISTMOD)
- cvs_sendarg(root, "-c", 0);
- else if (statmod == CVS_STATMOD)
- cvs_sendarg(root, "-s", 0);
+ cf->fd = open(cf->file_path, oflags);
+ if (cf->fd == -1)
+ fatal("cvs_checkout_file: open: %s", strerror(errno));
- if (tag != NULL) {
- cvs_sendarg(root, "-r", 0);
- cvs_sendarg(root, tag, 0);
- }
+ if (cvs_buf_write_fd(bp, cf->fd) == -1)
+ fatal("cvs_checkout_file: %s", strerror(errno));
- if (date != NULL) {
- cvs_sendarg(root, "-D", 0);
- cvs_sendarg(root, date, 0);
- }
- }
+ cvs_buf_free(bp);
- return (0);
-}
+ if (fchmod(cf->fd, 0644) == -1)
+ fatal("cvs_checkout_file: fchmod: %s", strerror(errno));
-static int
-cvs_checkout_local(CVSFILE *cf, void *arg)
-{
- char rcspath[MAXPATHLEN], fpath[MAXPATHLEN];
- RCSFILE *rf;
- struct cvsroot *root;
- static int inattic = 0;
-
- /* we don't want these */
- if (cf->cf_type == DT_DIR && !strcmp(cf->cf_name, "Attic")) {
- inattic = 1;
- return (CVS_EX_OK);
+ if (exists == 0) {
+ rcstime = rcs_rev_getdate(cf->file_rcs, rnum);
+ if ((rcstime = cvs_hack_time(rcstime, 0)) == 0)
+ fatal("cvs_checkout_file: time conversion failed");
+ } else {
+ time(&rcstime);
}
- root = CVS_DIR_ROOT(cf);
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
- cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
-
- if (cf->cf_type == DT_DIR) {
- inattic = 0;
- if (verbosity > 1)
- cvs_log(LP_INFO, "Updating %s", fpath);
-
- if (cvs_cmdop != CVS_OP_SERVER) {
- /*
- * We pass an empty repository name to
- * cvs_create_dir(), because it will correctly
- * create the repository directory for us.
- */
- if (cvs_create_dir(fpath, 1, root->cr_dir, NULL) < 0)
- fatal("cvs_checkout_local: cvs_create_dir failed");
- if (fchdir(cwdfd) < 0)
- fatal("cvs_checkout_local: fchdir failed");
- } else {
- /*
- * TODO: send responses to client so it'll
- * create it's directories.
- */
- }
+ tv[0].tv_sec = rcstime;
+ tv[0].tv_usec = 0;
+ tv[1] = tv[0];
+ if (futimes(cf->fd, tv) == -1)
+ fatal("cvs_checkout_file: futimes: %s", strerror(errno));
- return (CVS_EX_OK);
- }
+ if ((rcstime = cvs_hack_time(rcstime, 1)) == 0)
+ fatal("cvs_checkout_file: to gmt failed");
- if (inattic == 1)
- return (CVS_EX_OK);
+ ctime_r(&rcstime, timebuf);
+ if (timebuf[strlen(timebuf) - 1] == '\n')
+ timebuf[strlen(timebuf) - 1] = '\0';
- if ((rf = rcs_open(rcspath, RCS_READ)) == NULL)
- fatal("cvs_checkout_local: rcs_open `%s': %s", rcspath,
- rcs_errstr(rcs_errno));
+ entry = xmalloc(CVS_ENT_MAXLINELEN);
+ l = snprintf(entry, CVS_ENT_MAXLINELEN, "/%s/%s/%s//", cf->file_name,
+ rev, timebuf);
- if (cvs_checkout_rev(rf, rf->rf_head, cf, fpath,
- (cvs_cmdop != CVS_OP_SERVER) ? 1 : 0,
- CHECKOUT_REV_CREATED) < 0)
- fatal("cvs_checkout_local: cvs_checkout_rev failed");
+ ent = cvs_ent_open(cf->file_wd);
+ cvs_ent_add(ent, entry);
+ cvs_ent_close(ent, ENT_SYNC);
- rcs_close(rf);
+ xfree(entry);
- cvs_printf("U %s\n", fpath);
- return (0);
+ return (1);
}
diff --git a/usr.bin/cvs/cmd.c b/usr.bin/cvs/cmd.c
index 74dfda1f82b..9d5df6ae04a 100644
--- a/usr.bin/cvs/cmd.c
+++ b/usr.bin/cvs/cmd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd.c,v 1.43 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: cmd.c,v 1.44 2006/05/27 03:30:30 joris Exp $ */
/*
* Copyright (c) 2005 Joris Vink <joris@openbsd.org>
* All rights reserved.
@@ -28,39 +28,26 @@
#include "cvs.h"
#include "log.h"
-#include "proto.h"
extern char *cvs_rootstr;
-/*
- * Command dispatch table
- * ----------------------
- *
- * The synopsis field should only contain the list of arguments that the
- * command supports, without the actual command's name.
- *
- * Command handlers are expected to return 0 if no error occurred, or one of
- * the CVS_EX_* error codes in case of an error. In case the error
- * returned is 1, the command's usage string is printed to standard
- * error before returning.
- */
struct cvs_cmd *cvs_cdt[] = {
+ &cvs_cmd_commit,
+ &cvs_cmd_checkout,
+ &cvs_cmd_diff,
+ &cvs_cmd_update,
+ &cvs_cmd_status,
+#if 0
&cvs_cmd_add,
&cvs_cmd_admin,
&cvs_cmd_annotate,
&cvs_cmd_checkout,
- &cvs_cmd_commit,
- &cvs_cmd_diff,
&cvs_cmd_edit,
&cvs_cmd_editors,
&cvs_cmd_export,
&cvs_cmd_history,
&cvs_cmd_import,
&cvs_cmd_init,
-#if defined(HAVE_KERBEROS)
- &cvs_cmd_kserver,
-#endif
- &cvs_cmd_log,
#if 0
&cvs_cmd_login,
&cvs_cmd_logout,
@@ -71,27 +58,16 @@ struct cvs_cmd *cvs_cdt[] = {
&cvs_cmd_rlog,
&cvs_cmd_rtag,
&cvs_cmd_server,
- &cvs_cmd_status,
&cvs_cmd_tag,
&cvs_cmd_unedit,
&cvs_cmd_update,
&cvs_cmd_version,
&cvs_cmd_watch,
&cvs_cmd_watchers,
+#endif
NULL
};
-#define MISSING_CVS_DIR 0x01
-#define MISSING_CVS_ENTRIES 0x02
-#define MISSING_CVS_REPO 0x04
-
-/*
- * cvs_findcmd()
- *
- * Find the entry in the command dispatch table whose name or one of its
- * aliases matches <cmd>.
- * Returns a pointer to the command entry on success, NULL on failure.
- */
struct cvs_cmd *
cvs_findcmd(const char *cmd)
{
@@ -132,165 +108,3 @@ cvs_findcmdbyreq(int reqid)
return (cmdp);
}
-
-
-/*
- * start the execution of a command.
- */
-int
-cvs_startcmd(struct cvs_cmd *cmd, int argc, char **argv)
-{
- int i, ret, error;
- struct cvsroot *root;
- int (*ex_hdlr)(CVSFILE *, void *);
- CVSFILE *cf;
- struct stat st;
-
- /* if the command requested is the server one, just call the
- * cvs_server() function to handle it, and return after it.
- */
- if (cmd->cmd_op == CVS_OP_SERVER)
- return cvs_server(argc, argv);
-
- if ((root = cvsroot_get(".")) == NULL)
- return (CVS_EX_BADROOT);
-
- i = 1;
- if (cmd->cmd_init != NULL) {
- if ((ret = (*cmd->cmd_init)(cmd, argc, argv, &i)) != 0)
- return (ret);
- }
-
- argc -= i;
- argv += i;
-
- /*
- * Check if we have the administrative files present, if we are
- * missing one, we will error out because we cannot continue.
- *
- * We are not checking for CVS/Root since we fetched the root
- * above via cvsroot_get().
- *
- * checkout, export, import, init and release do not depend on
- * these files.
- */
- error = 0;
- if (cmd->cmd_op != CVS_OP_CHECKOUT &&
- cmd->cmd_op != CVS_OP_EXPORT &&
- cmd->cmd_op != CVS_OP_IMPORT &&
- cmd->cmd_op != CVS_OP_INIT &&
- cmd->cmd_op != CVS_OP_RELEASE &&
- cmd->cmd_op != CVS_OP_VERSION) {
- /* check for the CVS directory */
- ret = stat(CVS_PATH_CVSDIR, &st);
- if ((ret == -1 && errno == ENOENT) ||
- (ret != -1 && !(S_ISDIR(st.st_mode))))
- error |= MISSING_CVS_DIR;
-
- /* check if the CVS/Entries file exists */
- ret = stat(CVS_PATH_ENTRIES, &st);
- if ((ret == -1 && errno == ENOENT) ||
- (ret != -1 && !(S_ISREG(st.st_mode))))
- error |= MISSING_CVS_ENTRIES;
-
- /* check if the CVS/Repository file exists */
- ret = stat(CVS_PATH_REPOSITORY, &st);
- if ((ret == -1 && errno == ENOENT) ||
- (ret != -1 && !(S_ISREG(st.st_mode))))
- error |= MISSING_CVS_REPO;
- }
-
- if (error > 0) {
- if (error & MISSING_CVS_DIR) {
- cvs_log(LP_ABORT, "missing '%s' directory",
- CVS_PATH_CVSDIR);
- return (CVS_EX_FILE);
- }
-
- if (error & MISSING_CVS_ENTRIES)
- cvs_log(LP_ABORT, "missing '%s' file",
- CVS_PATH_ENTRIES);
- if (error & MISSING_CVS_REPO)
- cvs_log(LP_ABORT, "missing '%s' file",
- CVS_PATH_REPOSITORY);
- return (CVS_EX_FILE);
- }
-
- if (!(cmd->cmd_flags & CVS_CMD_ALLOWSPEC) && (argc > 0))
- return (CVS_EX_USAGE);
-
- /*
- * This allows us to correctly fill in the repository
- * string for CVSFILE's fetched inside the repository itself.
- */
- if (cvs_cmdop == CVS_OP_SERVER)
- cvs_rootstr = xstrdup(root->cr_str);
-
- cvs_log(LP_TRACE, "cvs_startcmd() CVSROOT=%s", root->cr_str);
-
- if (root->cr_method != CVS_METHOD_LOCAL)
- cvs_connect(root);
-
- if (cmd->cmd_pre_exec != NULL) {
- if ((ret = cmd->cmd_pre_exec(root)) != 0)
- return (ret);
- }
-
- if (root->cr_method == CVS_METHOD_LOCAL)
- ex_hdlr = cmd->cmd_exec_local;
- else
- ex_hdlr = cmd->cmd_exec_remote;
-
- if (argc > 0) {
- ret = cvs_file_getspec(argv, argc, cmd->file_flags,
- ex_hdlr, NULL, NULL);
- } else {
- ret = cvs_file_get(".", cmd->file_flags,
- ex_hdlr, NULL, NULL);
- }
-
- if (ret != CVS_EX_OK)
- return (cvs_error);
-
- if (cmd->cmd_post_exec != NULL) {
- if ((ret = cmd->cmd_post_exec(root)) != 0)
- return (ret);
- }
-
- if (root->cr_method != CVS_METHOD_LOCAL) {
- /*
- * If we have to send the directory the command
- * has been issued in, obtain it.
- */
- if (cmd->cmd_flags & CVS_CMD_SENDDIR) {
- cf = cvs_file_loadinfo(".", CF_NOFILES, NULL, NULL, 1);
- if (cf == NULL)
- return (CVS_EX_DATA);
- cvs_senddir(root, cf);
- cvs_file_free(cf);
- }
-
- if (cmd->cmd_flags & CVS_CMD_SENDARGS2) {
- for (i = 0; i < argc; i++)
- cvs_sendarg(root, argv[i], 0);
- }
-
- if (cmd->cmd_req != CVS_REQ_NONE) {
- cvs_sendreq(root, cmd->cmd_req,
- (cmd->cmd_op == CVS_OP_INIT) ? root->cr_dir : NULL);
- }
- }
-
- if (cmd->cmd_cleanup != NULL)
- (*cmd->cmd_cleanup)();
-
-#if 0
- if (cvs_cmdop != CVS_OP_SERVER && cmd->cmd_flags & CVS_CMD_PRUNEDIRS)
- cvs_file_prune(fpath);
-#endif
-
- if (root->cr_method != CVS_METHOD_LOCAL)
- cvs_disconnect(root);
-
- return (0);
-}
diff --git a/usr.bin/cvs/commit.c b/usr.bin/cvs/commit.c
index 52553345a97..e92d6f52542 100644
--- a/usr.bin/cvs/commit.c
+++ b/usr.bin/cvs/commit.c
@@ -1,271 +1,204 @@
-/* $OpenBSD: commit.c,v 1.54 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: commit.c,v 1.55 2006/05/27 03:30:30 joris Exp $ */
/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
-#include "buf.h"
#include "cvs.h"
+#include "diff.h"
#include "log.h"
#include "proto.h"
+int cvs_commit(int, char **);
+void cvs_commit_local(struct cvs_file *);
+void cvs_commit_check_conflicts(struct cvs_file *);
+
+static char *commit_diff_file(struct cvs_file *);
-static int cvs_commit_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_commit_prepare(CVSFILE *, void *);
-static int cvs_commit_remote(CVSFILE *, void *);
-static int cvs_commit_local(CVSFILE *, void *);
-static int cvs_commit_pre_exec(struct cvsroot *);
+struct cvs_flisthead files_affected;
+int conflicts_found;
+char *logmsg;
struct cvs_cmd cvs_cmd_commit = {
CVS_OP_COMMIT, CVS_REQ_CI, "commit",
- { "ci", "com" },
+ { "ci", "com" },
"Check files into the repository",
"[-flR] [-F logfile | -m msg] [-r rev] ...",
"F:flm:Rr:",
NULL,
- CF_RECURSE | CF_IGNORE | CF_SORT,
- cvs_commit_init,
- cvs_commit_pre_exec,
- cvs_commit_remote,
- cvs_commit_local,
- NULL,
- NULL,
- CVS_CMD_SENDDIR | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDARGS2
+ cvs_commit
};
-static char *mfile = NULL;
-static char *rev = NULL;
-static char **commit_files = NULL;
-static int commit_fcount = 0;
-static int wantedstatus = 0;
-
-static int
-cvs_commit_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
+int
+cvs_commit(int argc, char **argv)
{
int ch;
+ char *arg = ".";
+ struct cvs_recursion cr;
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
+ while ((ch = getopt(argc, argv, cvs_cmd_commit.cmd_opts)) != -1) {
switch (ch) {
- case 'F':
- mfile = optarg;
- break;
case 'f':
- /* XXX half-implemented */
- cmd->file_flags &= ~CF_RECURSE;
+ break;
+ case 'F':
break;
case 'l':
- cmd->file_flags &= ~CF_RECURSE;
break;
case 'm':
- cvs_msg = xstrdup(optarg);
- break;
- case 'R':
- cmd->file_flags |= CF_RECURSE;
+ logmsg = xstrdup(optarg);
break;
case 'r':
- rev = optarg;
+ break;
+ case 'R':
break;
default:
- return (CVS_EX_USAGE);
+ fatal("%s", cvs_cmd_commit.cmd_synopsis);
}
}
- if (cvs_msg != NULL && mfile != NULL) {
- cvs_log(LP_ERR, "the -F and -m flags are mutually exclusive");
- return (CVS_EX_USAGE);
- }
+ argc -= optind;
+ argv += optind;
- if (mfile != NULL)
- cvs_msg = cvs_logmsg_open(mfile);
+ if (logmsg == NULL)
+ fatal("please use -m to specify a log message for now");
- *arg = optind;
+ TAILQ_INIT(&files_affected);
+ conflicts_found = 0;
- commit_files = (argv + optind);
- commit_fcount = (argc - optind);
+ cr.enterdir = NULL;
+ cr.leavedir = NULL;
+ cr.local = cvs_commit_check_conflicts;
+ cr.remote = NULL;
- return (0);
-}
-
-int
-cvs_commit_pre_exec(struct cvsroot *root)
-{
- CVSFILE *cfp;
- CVSFILE *tmp;
- int ret, i, flags = CF_RECURSE | CF_IGNORE | CF_SORT;
- struct cvs_flist added, modified, removed, *cl[3];
- int stattype[] = { CVS_FST_ADDED, CVS_FST_MODIFIED, CVS_FST_REMOVED };
+ if (argc > 0)
+ cvs_file_run(argc, argv, &cr);
+ else
+ cvs_file_run(1, &arg, &cr);
- SIMPLEQ_INIT(&added);
- SIMPLEQ_INIT(&modified);
- SIMPLEQ_INIT(&removed);
+ if (conflicts_found != 0)
+ fatal("%d conflicts found, please correct these first",
+ conflicts_found);
- cl[0] = &added;
- cl[1] = &modified;
- cl[2] = &removed;
+ cr.local = cvs_commit_local;
+ cvs_file_walklist(&files_affected, &cr);
+ cvs_file_freelist(&files_affected);
- if ((tmp = cvs_file_loadinfo(".", CF_NOFILES, NULL, NULL, 1)) == NULL)
- return (CVS_EX_DATA);
-
- /*
- * Obtain the file lists for the logmessage.
- */
- for (i = 0; i < 3; i++) {
- wantedstatus = stattype[i];
- if (commit_fcount != 0) {
- ret = cvs_file_getspec(commit_files, commit_fcount,
- flags, cvs_commit_prepare, cl[i], NULL);
- } else {
- ret = cvs_file_get(".", flags, cvs_commit_prepare,
- cl[i], NULL);
- }
+ return (0);
+}
- if (ret != CVS_EX_OK) {
- cvs_file_free(tmp);
- return (CVS_EX_DATA);
- }
- }
+void
+cvs_commit_check_conflicts(struct cvs_file *cf)
+{
+ cvs_log(LP_TRACE, "cvs_commit_check_conflicts(%s)", cf->file_path);
/*
- * If we didn't catch any file, don't call the editor.
+ * cvs_file_classify makes the noise for us
+ * XXX - we want that?
*/
- if (SIMPLEQ_EMPTY(&added) && SIMPLEQ_EMPTY(&modified) &&
- SIMPLEQ_EMPTY(&removed)) {
- cvs_file_free(tmp);
- return (0);
- }
+ cvs_file_classify(cf);
- /*
- * Fetch the log message for real, with all the files.
- */
- if (cvs_msg == NULL)
- cvs_msg = cvs_logmsg_get(tmp->cf_name, &added, &modified,
- &removed);
-
- cvs_file_free(tmp);
-
- /* free the file lists */
- for (i = 0; i < 3; i++) {
- while (!SIMPLEQ_EMPTY(cl[i])) {
- cfp = SIMPLEQ_FIRST(cl[i]);
- SIMPLEQ_REMOVE_HEAD(cl[i], cf_list);
- cvs_file_free(cfp);
- }
- }
+ if (cf->file_status == FILE_CONFLICT ||
+ cf->file_status == FILE_LOST ||
+ cf->file_status == FILE_UNLINK)
+ conflicts_found++;
- if (cvs_msg == NULL)
- return (CVS_EX_DATA);
+ if (cf->file_status == FILE_ADDED ||
+ cf->file_status == FILE_REMOVED ||
+ cf->file_status == FILE_MODIFIED)
+ cvs_file_get(cf->file_path, &files_affected);
+}
- if (root->cr_method != CVS_METHOD_LOCAL) {
- cvs_logmsg_send(root, cvs_msg);
+void
+cvs_commit_local(struct cvs_file *cf)
+{
+ BUF *b;
+ char *d, *f, rbuf[16];
- if (rev != NULL) {
- cvs_sendarg(root, "-r", 0);
- cvs_sendarg(root, rev, 0);
- }
- }
+ cvs_log(LP_TRACE, "cvs_commit_local(%s)", cf->file_path);
+ cvs_file_classify(cf);
- return (0);
-}
+ rcsnum_tostr(cf->file_rcs->rf_head, rbuf, sizeof(rbuf));
-/*
- * cvs_commit_prepare()
- *
- * Examine the file <cf> to see if it will be part of the commit, in which
- * case it gets added to the list passed as second argument.
- */
-int
-cvs_commit_prepare(CVSFILE *cf, void *arg)
-{
- CVSFILE *copy;
- struct cvs_flist *clp = (struct cvs_flist *)arg;
+ cvs_printf("Checking in %s:\n", cf->file_path);
+ cvs_printf("%s <- %s\n", cf->file_rpath, cf->file_path);
+ cvs_printf("old revision: %s; ", rbuf);
- if (cf->cf_type == DT_REG && cf->cf_cvstat == wantedstatus) {
- copy = cvs_file_copy(cf);
- if (copy == NULL)
- return (CVS_EX_DATA);
+ d = commit_diff_file(cf);
- SIMPLEQ_INSERT_TAIL(clp, copy, cf_list);
- }
+ if ((b = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL)
+ fatal("cvs_commit_local: failed to load file");
- return (0);
-}
+ cvs_buf_putc(b, '\0');
+ f = cvs_buf_release(b);
+ if (rcs_deltatext_set(cf->file_rcs, cf->file_rcs->rf_head, d) == -1)
+ fatal("cvs_commit_local: failed to set delta");
-/*
- * cvs_commit_remote()
- *
- * Commit a single file.
- */
-int
-cvs_commit_remote(CVSFILE *cf, void *arg)
-{
- char fpath[MAXPATHLEN];
- struct cvsroot *root;
+ if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, logmsg, -1, NULL) == -1)
+ fatal("cvs_commit_local: failed to add new revision");
- root = CVS_DIR_ROOT(cf);
+ if (rcs_deltatext_set(cf->file_rcs, cf->file_rcs->rf_head, f) == -1)
+ fatal("cvs_commit_local: failed to set new HEAD delta");
- if (cf->cf_type == DT_DIR) {
- if (cf->cf_cvstat != CVS_FST_UNKNOWN)
- cvs_senddir(root, cf);
- return (0);
- }
+ xfree(f);
+ xfree(d);
- cvs_file_getpath(cf, fpath, sizeof(fpath));
+ rcs_write(cf->file_rcs);
- if (cf->cf_cvstat == CVS_FST_ADDED ||
- cf->cf_cvstat == CVS_FST_MODIFIED ||
- cf->cf_cvstat == CVS_FST_REMOVED) {
- cvs_sendentry(root, cf);
+ rcsnum_tostr(cf->file_rcs->rf_head, rbuf, sizeof(rbuf));
+ cvs_printf("new revision: %s\n", rbuf);
- /* if it's removed, don't bother sending a
- * Modified request together with the file its
- * contents.
- */
- if (cf->cf_cvstat == CVS_FST_REMOVED)
- return (0);
+ (void)unlink(cf->file_path);
+ (void)close(cf->fd);
+ cf->fd = -1;
+ cvs_checkout_file(cf, cf->file_rcs->rf_head, 0);
- cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name);
- cvs_sendfile(root, fpath);
- }
+ cvs_printf("done\n");
- return (0);
}
-static int
-cvs_commit_local(CVSFILE *cf, void *arg)
+static char *
+commit_diff_file(struct cvs_file *cf)
{
- char fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
+ char*delta, *p1, *p2;
+ BUF *b1, *b2, *b3;
- if (cf->cf_type == DT_DIR) {
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "Examining %s", cf->cf_name);
- return (0);
- }
+ if ((b1 = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL)
+ fatal("commit_diff_file: failed to load '%s'", cf->file_path);
- cvs_file_getpath(cf, fpath, sizeof(fpath));
- cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
+ if ((b2 = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL)
+ fatal("commit_diff_file: failed to load HEAD for '%s'",
+ cf->file_path);
- return (0);
+ if ((b3 = cvs_buf_alloc(128, BUF_AUTOEXT)) == NULL)
+ fatal("commit_diff_file: failed to create diff buf");
+
+ (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
+ cvs_buf_write_stmp(b1, p1, 0600, NULL);
+ cvs_buf_free(b1);
+
+ (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
+ cvs_buf_write_stmp(b2, p2, 0600, NULL);
+ cvs_buf_free(b2);
+
+ diff_format = D_RCSDIFF;
+ if (cvs_diffreg(p1, p2, b3) == D_ERROR)
+ fatal("commit_diff_file: failed to get RCS patch");
+
+ cvs_buf_putc(b3, '\0');
+ delta = cvs_buf_release(b3);
+ return (delta);
}
diff --git a/usr.bin/cvs/cvs.c b/usr.bin/cvs/cvs.c
index a4df675a249..37229a523ee 100644
--- a/usr.bin/cvs/cvs.c
+++ b/usr.bin/cvs/cvs.c
@@ -1,5 +1,6 @@
-/* $OpenBSD: cvs.c,v 1.97 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: cvs.c,v 1.98 2006/05/27 03:30:30 joris Exp $ */
/*
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
*
@@ -30,48 +31,71 @@
#include "log.h"
#include "file.h"
-
extern char *__progname;
-
/* verbosity level: 0 = really quiet, 1 = quiet, 2 = verbose */
int verbosity = 2;
/* compression level used with zlib, 0 meaning no compression taking place */
-int cvs_compress = 0;
-int cvs_readrc = 1; /* read .cvsrc on startup */
-int cvs_trace = 0;
-int cvs_nolog = 0;
-int cvs_readonly = 0;
-int cvs_nocase = 0; /* set to 1 to disable filename case sensitivity */
-int cvs_noexec = 0; /* set to 1 to disable disk operations (-n option) */
-int cvs_error = -1; /* set to the correct error code on failure */
-char *cvs_defargs; /* default global arguments from .cvsrc */
-char *cvs_command; /* name of the command we are running */
-int cvs_cmdop;
-char *cvs_rootstr;
-char *cvs_rsh = CVS_RSH_DEFAULT;
-char *cvs_editor = CVS_EDITOR_DEFAULT;
-char *cvs_homedir = NULL;
-char *cvs_msg = NULL;
-char *cvs_repo_base = NULL;
-char *cvs_tmpdir = CVS_TMPDIR_DEFAULT;
-
-/* hierarchy of all the files affected by the command */
-CVSFILE *cvs_files;
+int cvs_compress = 0;
+int cvs_readrc = 1; /* read .cvsrc on startup */
+int cvs_trace = 0;
+int cvs_nolog = 0;
+int cvs_readonly = 0;
+int cvs_nocase = 0; /* set to 1 to disable filename case sensitivity */
+int cvs_noexec = 0; /* set to 1 to disable disk operations (-n option) */
+int cvs_error = -1; /* set to the correct error code on failure */
+int cvs_cmdop;
+
+char *cvs_defargs; /* default global arguments from .cvsrc */
+char *cvs_command; /* name of the command we are running */
+char *cvs_rootstr;
+char *cvs_rsh = CVS_RSH_DEFAULT;
+char *cvs_editor = CVS_EDITOR_DEFAULT;
+char *cvs_homedir = NULL;
+char *cvs_msg = NULL;
+char *cvs_repo_base = NULL;
+char *cvs_tmpdir = CVS_TMPDIR_DEFAULT;
+
+struct cvsroot *current_cvsroot = NULL;
static TAILQ_HEAD(, cvs_var) cvs_variables;
-
+int cvs_getopt(int, char **);
void usage(void);
static void cvs_read_rcfile(void);
-int cvs_getopt(int, char **);
-/*
- * usage()
- *
- * Display usage information.
- */
+struct cvs_wklhead temp_files;
+
+void sighandler(int);
+volatile sig_atomic_t cvs_quit = 0;
+volatile sig_atomic_t sig_received = 0;
+
+void
+sighandler(int sig)
+{
+ sig_received = sig;
+
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ cvs_quit = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+cvs_cleanup(void)
+{
+ cvs_log(LP_TRACE, "cvs_cleanup: removing locks");
+ cvs_worklist_run(&repo_locks, cvs_worklist_unlink);
+
+ cvs_log(LP_TRACE, "cvs_cleanup: removing temp files");
+ cvs_worklist_run(&temp_files, cvs_worklist_unlink);
+}
+
void
usage(void)
{
@@ -80,7 +104,6 @@ usage(void)
"[-T tmpdir] [-z level] command [...]\n", __progname);
}
-
int
main(int argc, char **argv)
{
@@ -93,15 +116,8 @@ main(int argc, char **argv)
tzset();
TAILQ_INIT(&cvs_variables);
-
- cvs_log_init(LD_STD, 0);
-
- /* by default, be very verbose */
- (void)cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
-
-#ifdef DEBUG
- (void)cvs_log_filter(LP_FILTER_UNSET, LP_DEBUG);
-#endif
+ SLIST_INIT(&repo_locks);
+ SLIST_INIT(&temp_files);
/* check environment so command-line options override it */
if ((envstr = getenv("CVS_RSH")) != NULL)
@@ -130,7 +146,7 @@ main(int argc, char **argv)
argv += ret;
if (argc == 0) {
usage();
- exit(CVS_EX_USAGE);
+ exit(1);
}
cvs_command = argv[0];
@@ -160,12 +176,12 @@ main(int argc, char **argv)
}
/* setup signal handlers */
- signal(SIGPIPE, SIG_IGN);
-
- if (cvs_file_init() < 0)
- fatal("failed to initialize file support");
-
- ret = -1;
+ signal(SIGTERM, sighandler);
+ signal(SIGINT, sighandler);
+ signal(SIGHUP, sighandler);
+ signal(SIGABRT, sighandler);
+ signal(SIGALRM, sighandler);
+ signal(SIGPIPE, sighandler);
cmdp = cvs_findcmd(cvs_command);
if (cmdp == NULL) {
@@ -174,7 +190,7 @@ main(int argc, char **argv)
for (i = 0; cvs_cdt[i] != NULL; i++)
fprintf(stderr, "\t%-16s%s\n",
cvs_cdt[i]->cmd_name, cvs_cdt[i]->cmd_descr);
- exit(CVS_EX_USAGE);
+ exit(1);
}
cvs_cmdop = cmdp->cmd_op;
@@ -192,46 +208,26 @@ main(int argc, char **argv)
cmd_argc += ret;
}
+
for (ret = 1; ret < argc; ret++)
cmd_argv[cmd_argc++] = argv[ret];
- ret = cvs_startcmd(cmdp, cmd_argc, cmd_argv);
- switch (ret) {
- case CVS_EX_USAGE:
- fprintf(stderr, "Usage: %s %s %s\n", __progname,
- cmdp->cmd_name, cmdp->cmd_synopsis);
- break;
- case CVS_EX_DATA:
- cvs_log(LP_ABORT, "internal data error");
- break;
- case CVS_EX_PROTO:
- cvs_log(LP_ABORT, "protocol error");
- break;
- case CVS_EX_FILE:
- cvs_log(LP_ABORT, "an operation on a file or directory failed");
- break;
- case CVS_EX_BADROOT:
- /* match GNU CVS output, thus the LP_ERR and LP_ABORT codes. */
+ cvs_file_init();
+
+ if ((current_cvsroot = cvsroot_get(".")) == NULL) {
cvs_log(LP_ERR,
- "No CVSROOT specified! Please use the `-d' option");
- cvs_log(LP_ABORT,
- "or set the CVSROOT enviroment variable.");
- break;
- case CVS_EX_ERR:
- cvs_log(LP_ABORT, "yeah, we failed, and we don't know why");
- break;
- default:
- break;
+ "No CVSROOT specified! Please use the '-d' option");
+ fatal("or set the CVSROOT enviroment variable.");
}
- if (cvs_files != NULL)
- cvs_file_free(cvs_files);
- if (cvs_msg != NULL)
- xfree(cvs_msg);
+ if (current_cvsroot->cr_method != CVS_METHOD_LOCAL)
+ fatal("remote setups are not supported yet");
- return (ret);
-}
+ cmdp->cmd(cmd_argc, cmd_argv);
+ cvs_cleanup();
+ return (0);
+}
int
cvs_getopt(int argc, char **argv)
@@ -279,17 +275,16 @@ cvs_getopt(int argc, char **argv)
ep = strchr(optarg, '=');
if (ep == NULL) {
cvs_log(LP_ERR, "no = in variable assignment");
- exit(CVS_EX_USAGE);
+ exit(1);
}
*(ep++) = '\0';
if (cvs_var_set(optarg, ep) < 0)
- exit(CVS_EX_USAGE);
+ exit(1);
break;
case 'T':
cvs_tmpdir = optarg;
break;
case 't':
- (void)cvs_log_filter(LP_FILTER_UNSET, LP_TRACE);
cvs_trace = 1;
break;
case 'v':
@@ -315,7 +310,7 @@ cvs_getopt(int argc, char **argv)
break;
default:
usage();
- exit(CVS_EX_USAGE);
+ exit(1);
}
}
@@ -326,7 +321,6 @@ cvs_getopt(int argc, char **argv)
return (ret);
}
-
/*
* cvs_read_rcfile()
*
@@ -347,7 +341,7 @@ cvs_read_rcfile(void)
strlcat(rcpath, "/", sizeof(rcpath)) >= sizeof(rcpath) ||
strlcat(rcpath, CVS_PATH_RC, sizeof(rcpath)) >= sizeof(rcpath)) {
errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", rcpath);
+ cvs_log(LP_ERR, "%s", rcpath);
return;
}
@@ -364,7 +358,7 @@ cvs_read_rcfile(void)
if ((len = strlen(linebuf)) == 0)
continue;
if (linebuf[len - 1] != '\n') {
- cvs_log(LP_WARN, "line too long in `%s:%d'", rcpath,
+ cvs_log(LP_ERR, "line too long in `%s:%d'", rcpath,
linenum);
break;
}
@@ -405,6 +399,7 @@ cvs_read_rcfile(void)
cmdp->cmd_defargs = xstrdup(lp);
}
}
+
if (ferror(fp)) {
cvs_log(LP_NOTICE, "failed to read line from `%s'", rcpath);
}
@@ -412,7 +407,6 @@ cvs_read_rcfile(void)
(void)fclose(fp);
}
-
/*
* cvs_var_set()
*
@@ -460,7 +454,6 @@ cvs_var_set(const char *var, const char *val)
return (0);
}
-
/*
* cvs_var_set()
*
@@ -482,10 +475,8 @@ cvs_var_unset(const char *var)
}
return (-1);
-
}
-
/*
* cvs_var_get()
*
diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h
index 057e0fd4100..290cc79b348 100644
--- a/usr.bin/cvs/cvs.h
+++ b/usr.bin/cvs/cvs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cvs.h,v 1.103 2006/04/01 20:11:25 joris Exp $ */
+/* $OpenBSD: cvs.h,v 1.104 2006/05/27 03:30:30 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -28,27 +28,25 @@
#define CVS_H
#include "rcs.h"
-#include "file.h"
-#include "util.h"
#include "xmalloc.h"
+#include "util.h"
+#include "file.h"
+#include "repository.h"
+#include "worklist.h"
-#define CVS_VERSION "OpenCVS 0.3"
+#define CVS_VERSION_MINOR "0"
+#define CVS_VERSION_MAJOR "1"
+#define CVS_VERSION_PORT
+
+#define CVS_VERSION \
+ "OpenCVS version " \
+ CVS_VERSION_MAJOR "." CVS_VERSION_MINOR CVS_VERSION_PORT
#define CVS_HIST_CACHE 128
#define CVS_HIST_NBFLD 6
-
#define CVS_CKSUM_LEN 33 /* length of a CVS checksum string */
-/* error codes */
-#define CVS_EX_ERR -1
-#define CVS_EX_OK 0
-#define CVS_EX_USAGE 1
-#define CVS_EX_DATA 2
-#define CVS_EX_PROTO 3
-#define CVS_EX_FILE 4
-#define CVS_EX_BADROOT 5
-
/* operations */
#define CVS_OP_UNKNOWN 0
#define CVS_OP_ADD 1
@@ -81,7 +79,6 @@
#define CVS_OP_ANY 64 /* all operations */
-
/* methods */
#define CVS_METHOD_NONE 0
#define CVS_METHOD_LOCAL 1 /* local access */
@@ -97,7 +94,6 @@
#define CVS_CMD_MAXDESCRLEN 64
#define CVS_CMD_MAXARG 128
-
/* defaults */
#define CVS_SERVER_DEFAULT "cvs"
#define CVS_RSH_DEFAULT "ssh"
@@ -123,7 +119,6 @@
#define CVS_PATH_TAGINFO CVS_PATH_ROOT "/taginfo"
#define CVS_PATH_VERIFYMSG CVS_PATH_ROOT "/verifymsg"
-
/* client-side paths */
#define CVS_PATH_RC ".cvsrc"
#define CVS_PATH_CVSDIR "CVS"
@@ -143,15 +138,6 @@
#define CVS_PATH_TEMPLATE CVS_PATH_CVSDIR "/Template"
#define CVS_PATH_UPDATEPROG CVS_PATH_CVSDIR "/Update.prog"
-
-/* flags for cmd_flags */
-#define CVS_CMD_ALLOWSPEC 0x01
-#define CVS_CMD_SENDARGS1 0x04
-#define CVS_CMD_SENDARGS2 0x08
-#define CVS_CMD_SENDDIR 0x10
-#define CVS_CMD_PRUNEDIRS 0x20
-
-
struct cvs_cmd {
u_int cmd_op;
u_int cmd_req;
@@ -161,23 +147,18 @@ struct cvs_cmd {
char *cmd_synopsis;
char *cmd_opts;
char *cmd_defargs;
- int file_flags;
-
- /* operations vector */
- int (*cmd_init)(struct cvs_cmd *, int, char **, int *);
- int (*cmd_pre_exec)(struct cvsroot *);
- int (*cmd_exec_remote)(CVSFILE *, void *);
- int (*cmd_exec_local)(CVSFILE *, void *);
- int (*cmd_post_exec)(struct cvsroot *);
- int (*cmd_cleanup)(void);
-
- /* flags for cvs_file_get() */
- int cmd_flags;
+
+ int (*cmd)(int, char **);
};
-struct cvs_file;
-struct cvs_dir;
-struct cvs_flist;
+struct cvsroot;
+
+struct cvs_recursion {
+ void (*enterdir)(struct cvs_file *);
+ void (*leavedir)(struct cvs_file *);
+ void (*local)(struct cvs_file *);
+ void (*remote)(struct cvs_file *, struct cvsroot *);
+};
struct cvs_var {
char *cv_name;
@@ -185,17 +166,6 @@ struct cvs_var {
TAILQ_ENTRY(cvs_var) cv_link;
};
-
-
-struct cvs_op {
- u_int co_op;
- uid_t co_uid; /* user performing the operation */
- char *co_tag; /* tag or branch, NULL if HEAD */
- char *co_msg; /* message string (on commit or add) */
- struct cvs_flist co_files;
-};
-
-
#define CVS_ROOT_CONNECTED 0x01
struct cvsroot {
@@ -225,7 +195,6 @@ struct cvsroot {
#define CVS_CLRVR(rt, rq) ((rt)->cr_vrmask[(rq) / 8] &= ~(1 << ((rq) % 8)))
#define CVS_RSTVR(rt) memset((rt)->cr_vrmask, 0, sizeof((rt)->cr_vrmask))
-
#define CVS_HIST_ADDED 'A'
#define CVS_HIST_EXPORT 'E'
#define CVS_HIST_RELEASE 'F'
@@ -234,7 +203,6 @@ struct cvsroot {
#define CVS_HIST_COMMIT 'R'
#define CVS_HIST_TAG 'T'
-
#define CVS_DATE_DUMMY "dummy timestamp"
#define CVS_DATE_DMSEC (time_t)-1
@@ -249,8 +217,8 @@ struct cvsroot {
#define CVS_ENT_MAXLINELEN 1024
-#define CVS_ENTF_SYNC 0x01 /* contents of disk and memory match */
-#define CVS_ENTF_WR 0x02 /* file is opened for writing too */
+#define ENT_NOSYNC 0
+#define ENT_SYNC 1
#define STRIP_SLASH(p) \
do { \
@@ -259,62 +227,36 @@ struct cvsroot {
while ((_slen > 0) && (p[_slen - 1] == '/')) \
p[--_slen] = '\0'; \
} while (0)
+
struct cvs_ent {
- char *ce_buf;
- u_int16_t ce_type;
- u_int16_t ce_status;
- char *ce_name;
- RCSNUM *ce_rev;
- time_t ce_mtime;
- char *ce_opts;
- char *ce_tag;
-
- /*
- * This variable is set to 1 if we have already processed this entry
- * in the cvs_file_getdir() function. This is to avoid files being
- * passed twice to the callbacks.
- */
- int processed;
- TAILQ_ENTRY(cvs_ent) ce_list;
+ char *ce_buf;
+ char *ce_name;
+ char *ce_opts;
+ char *ce_tag;
+ char *ce_conflict;
+ time_t ce_mtime;
+ u_int16_t ce_type;
+ u_int16_t ce_status;
+ RCSNUM *ce_rev;
+};
+
+struct cvs_ent_line {
+ char *buf;
+ TAILQ_ENTRY(cvs_ent_line) entries_list;
};
typedef struct cvs_entries {
char *cef_path;
char *cef_bpath;
- u_int cef_flags;
+ char *cef_lpath;
- TAILQ_HEAD(cvsentrieshead, cvs_ent) cef_ent;
- struct cvs_ent *cef_cur;
+ TAILQ_HEAD(, cvs_ent_line) cef_ent;
} CVSENTRIES;
-
-struct cvs_hent {
- char ch_event;
- time_t ch_date;
- uid_t ch_uid;
- char *ch_user;
- char *ch_curdir;
- char *ch_repo;
- RCSNUM *ch_rev;
- char *ch_arg;
-};
-
-
-typedef struct cvs_histfile {
- int chf_fd;
- char *chf_buf; /* read buffer */
- size_t chf_blen; /* buffer size */
- size_t chf_bused; /* bytes used in buffer */
-
- off_t chf_off; /* next read */
- u_int chf_sindex; /* history entry index of first in array */
- u_int chf_cindex; /* current index (for getnext()) */
- u_int chf_nbhent; /* number of valid entries in the array */
-
- struct cvs_hent chf_hent[CVS_HIST_CACHE];
-
-} CVSHIST;
-
+extern struct cvs_wklhead temp_files;
+extern volatile sig_atomic_t sig_received;
+extern volatile sig_atomic_t cvs_quit;
+extern struct cvsroot *current_cvsroot;
extern char *cvs_repo_base;
extern char *cvs_command;
extern char *cvs_editor;
@@ -332,7 +274,6 @@ extern int cvs_nocase;
extern int cvs_noexec;
extern int cvs_readonly;
extern int cvs_error;
-extern CVSFILE *cvs_files;
extern struct cvs_cmd *cvs_cdt[];
@@ -365,53 +306,37 @@ extern struct cvs_cmd cvs_cmd_unedit;
extern struct cvs_cmd cvs_cmd_watch;
extern struct cvs_cmd cvs_cmd_watchers;
-
+/* cmd.c */
struct cvs_cmd *cvs_findcmd(const char *);
struct cvs_cmd *cvs_findcmdbyreq(int);
-int cvs_startcmd(struct cvs_cmd *, int, char **);
-int cvs_server(int, char **);
+/* cvs.c */
int cvs_var_set(const char *, const char *);
int cvs_var_unset(const char *);
const char *cvs_var_get(const char *);
+void cvs_cleanup(void);
-
-/* root.c */
-struct cvsroot *cvsroot_parse(const char *);
-void cvsroot_remove(struct cvsroot *);
-struct cvsroot *cvsroot_get(const char *);
-
+/* date.y */
+time_t cvs_date_parse(const char *);
/* entries.c */
-CVSENTRIES *cvs_ent_open(const char *, int);
-struct cvs_ent *cvs_ent_get(CVSENTRIES *, const char *);
-struct cvs_ent *cvs_ent_next(CVSENTRIES *);
-int cvs_ent_add(CVSENTRIES *, struct cvs_ent *);
-int cvs_ent_addln(CVSENTRIES *, const char *);
-int cvs_ent_remove(CVSENTRIES *, const char *, int);
-int cvs_ent_write(CVSENTRIES *);
struct cvs_ent *cvs_ent_parse(const char *);
-void cvs_ent_close(CVSENTRIES *);
-void cvs_ent_free(struct cvs_ent *);
-
-/* history API */
-CVSHIST *cvs_hist_open(const char *);
-void cvs_hist_close(CVSHIST *);
-int cvs_hist_parse(CVSHIST *);
-struct cvs_hent *cvs_hist_getnext(CVSHIST *);
-int cvs_hist_append(CVSHIST *, struct cvs_hent *);
-
-/* logmsg.c */
-char *cvs_logmsg_open(const char *);
-char *cvs_logmsg_get(const char *, struct cvs_flist *,
- struct cvs_flist *, struct cvs_flist *);
-void cvs_logmsg_send(struct cvsroot *, const char *);
+struct cvs_ent *cvs_ent_get(CVSENTRIES *, const char *);
+CVSENTRIES *cvs_ent_open(const char *);
+void cvs_ent_add(CVSENTRIES *, const char *);
+void cvs_ent_remove(CVSENTRIES *, const char *);
+void cvs_ent_close(CVSENTRIES *, int);
+void cvs_ent_free(struct cvs_ent *);
+int cvs_ent_exists(CVSENTRIES *, const char *);
-/* date.y */
-time_t cvs_date_parse(const char *);
+/* root.c */
+struct cvsroot *cvsroot_parse(const char *);
+struct cvsroot *cvsroot_get(const char *);
+void cvsroot_remove(struct cvsroot *);
-/* XXX */
-int rcs_patch_lines(struct cvs_lines *, struct cvs_lines *);
-int cvs_checkout_rev(RCSFILE *, RCSNUM *, CVSFILE *, char *, int, int, ...);
+/* misc stuff */
+void cvs_update_local(struct cvs_file *);
+void cvs_update_enterdir(struct cvs_file *);
+int cvs_checkout_file(struct cvs_file *, RCSNUM *, int);
#endif
diff --git a/usr.bin/cvs/diff.c b/usr.bin/cvs/diff.c
index bf5aad4dd01..d3a4500bbee 100644
--- a/usr.bin/cvs/diff.c
+++ b/usr.bin/cvs/diff.c
@@ -1,305 +1,30 @@
-/* $OpenBSD: diff.c,v 1.90 2006/04/14 23:29:01 joris Exp $ */
+/* $OpenBSD: diff.c,v 1.91 2006/05/27 03:30:30 joris Exp $ */
/*
- * Copyright (C) Caldera International Inc. 2001-2002.
- * All rights reserved.
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code and documentation must retain the above
- * copyright notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed or owned by Caldera
- * International, Inc.
- * 4. Neither the name of Caldera International, Inc. nor the names of other
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
- * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
- * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- * Copyright (c) 2004 Jean-Francois Brousseau. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)diffreg.c 8.1 (Berkeley) 6/6/93
- */
-/*
- * Uses an algorithm due to Harold Stone, which finds
- * a pair of longest identical subsequences in the two
- * files.
- *
- * The major goal is to generate the match vector J.
- * J[i] is the index of the line in file1 corresponding
- * to line i file0. J[i] = 0 if there is no
- * such line in file1.
- *
- * Lines are hashed so as to work in core. All potential
- * matches are located by sorting the lines of each file
- * on the hash (called ``value''). In particular, this
- * collects the equivalence classes in file1 together.
- * Subroutine equiv replaces the value of each line in
- * file0 by the index of the first element of its
- * matching equivalence in (the reordered) file1.
- * To save space equiv squeezes file1 into a single
- * array member in which the equivalence classes
- * are simply concatenated, except that their first
- * members are flagged by changing sign.
- *
- * Next the indices that point into member are unsorted into
- * array class according to the original order of file0.
- *
- * The cleverness lies in routine stone. This marches
- * through the lines of file0, developing a vector klist
- * of "k-candidates". At step i a k-candidate is a matched
- * pair of lines x,y (x in file0 y in file1) such that
- * there is a common subsequence of length k
- * between the first i lines of file0 and the first y
- * lines of file1, but there is no such subsequence for
- * any smaller y. x is the earliest possible mate to y
- * that occurs in such a subsequence.
- *
- * Whenever any of the members of the equivalence class of
- * lines in file1 matable to a line in file0 has serial number
- * less than the y of some k-candidate, that k-candidate
- * with the smallest such y is replaced. The new
- * k-candidate is chained (via pred) to the current
- * k-1 candidate so that the actual subsequence can
- * be recovered. When a member has serial number greater
- * that the y of all k-candidates, the klist is extended.
- * At the end, the longest subsequence is pulled out
- * and placed in the array J by unravel
- *
- * With J in hand, the matches there recorded are
- * check'ed against reality to assure that no spurious
- * matches have crept in due to hashing. If they have,
- * they are broken, and "jackpot" is recorded--a harmless
- * matter except that a true match for a spuriously
- * mated line may now be unnecessarily reported as a change.
- *
- * Much of the complexity of the program comes simply
- * from trying to minimize core utilization and
- * maximize the range of doable problems by dynamically
- * allocating what is needed and reusing what is not.
- * The core requirements for problems larger than somewhat
- * are (in words) 2*length(file0) + length(file1) +
- * 3*(number of k-candidates installed), typically about
- * 6n words for files of length n.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
-#include "buf.h"
#include "cvs.h"
#include "diff.h"
#include "log.h"
#include "proto.h"
-#include "xmalloc.h"
-
-struct cand {
- int x;
- int y;
- int pred;
-} cand;
-
-struct line {
- int serial;
- int value;
-} *file[2];
-
-/*
- * The following struct is used to record change in formation when
- * doing a "context" or "unified" diff. (see routine "change" to
- * understand the highly mnemonic field names)
- */
-struct context_vec {
- int a; /* start line in old file */
- int b; /* end line in old file */
- int c; /* start line in new file */
- int d; /* end line in new file */
-};
-
-struct diff_arg {
- char *rev1;
- char *rev2;
- char *date1;
- char *date2;
-};
-
-#if !defined(RCSPROG)
-static int cvs_diff_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_diff_remote(CVSFILE *, void *);
-static int cvs_diff_local(CVSFILE *, void *);
-static int cvs_diff_pre_exec(struct cvsroot *);
-static int cvs_diff_cleanup(void);
-#endif
-
-static void output(FILE *, FILE *);
-static void check(FILE *, FILE *);
-static void range(int, int, char *);
-static void uni_range(int, int);
-static void dump_context_vec(FILE *, FILE *);
-static void dump_unified_vec(FILE *, FILE *);
-static int prepare(int, FILE *, off_t);
-static void prune(void);
-static void equiv(struct line *, int, struct line *, int, int *);
-static void unravel(int);
-static void unsort(struct line *, int, int *);
-static void change(FILE *, FILE *, int, int, int, int);
-static void sort(struct line *, int);
-static int ignoreline(char *);
-static int asciifile(FILE *);
-static void fetch(long *, int, int, FILE *, int, int);
-static int newcand(int, int, int);
-static int search(int *, int, int);
-static int skipline(FILE *);
-static int isqrt(int);
-static int stone(int *, int, int *, int *);
-static int readhash(FILE *);
-static int files_differ(FILE *, FILE *);
-static char *match_function(const long *, int, FILE *);
-static char *preadline(int, size_t, off_t);
+int cvs_diff(int, char **);
+void cvs_diff_local(struct cvs_file *);
-
-#if !defined(RCSPROG)
-static int Nflag;
-#endif
-static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag;
-static int context = 3;
-int diff_format = D_NORMAL;
-char *diff_file = NULL;
-RCSNUM *diff_rev1 = NULL;
-RCSNUM *diff_rev2 = NULL;
-char diffargs[128];
-static struct stat stb1, stb2;
-static char *ifdefname, *ignore_pats;
-regex_t ignore_re;
-
-static int *J; /* will be overlaid on class */
-static int *class; /* will be overlaid on file[0] */
-static int *klist; /* will be overlaid on file[0] after class */
-static int *member; /* will be overlaid on file[1] */
-static int clen;
-static int inifdef; /* whether or not we are in a #ifdef block */
-static int diff_len[2];
-static int pref, suff; /* length of prefix and suffix */
-static int slen[2];
-static int anychange;
-static long *ixnew; /* will be overlaid on file[1] */
-static long *ixold; /* will be overlaid on klist */
-static struct cand *clist; /* merely a free storage pot for candidates */
-static int clistlen; /* the length of clist */
-static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */
-static u_char *chrtran; /* translation table for case-folding */
-static struct context_vec *context_vec_start;
-static struct context_vec *context_vec_end;
-static struct context_vec *context_vec_ptr;
-
-#define FUNCTION_CONTEXT_SIZE 41
-static char lastbuf[FUNCTION_CONTEXT_SIZE];
-static int lastline;
-static int lastmatchline;
-BUF *diffbuf = NULL;
-
-/*
- * chrtran points to one of 2 translation tables: cup2low if folding upper to
- * lower case clow2low if not folding case
- */
-u_char clow2low[256] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
- 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
- 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
- 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
- 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41,
- 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
- 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
- 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
- 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
- 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
- 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
- 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
- 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
- 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
- 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
- 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
- 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
- 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
- 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
- 0xfd, 0xfe, 0xff
-};
-
-u_char cup2low[256] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
- 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
- 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
- 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
- 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61,
- 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
- 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62,
- 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
- 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
- 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
- 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
- 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
- 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
- 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
- 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
- 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
- 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
- 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
- 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
- 0xfd, 0xfe, 0xff
-};
-
-#if !defined(RCSPROG)
struct cvs_cmd cvs_cmd_diff = {
CVS_OP_DIFF, CVS_REQ_DIFF, "diff",
{ "di", "dif" },
@@ -308,1456 +33,173 @@ struct cvs_cmd cvs_cmd_diff = {
"[-k mode] [file ...]",
"cD:iklNnpr:Ru",
NULL,
- CF_RECURSE | CF_IGNORE | CF_SORT | CF_KNOWN,
- cvs_diff_init,
- cvs_diff_pre_exec,
- cvs_diff_remote,
- cvs_diff_local,
- NULL,
- cvs_diff_cleanup,
- CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
+ cvs_diff
};
-
-struct cvs_cmd cvs_cmd_rdiff = {
- CVS_OP_RDIFF, CVS_REQ_DIFF, "rdiff",
- { "pa", "patch" },
- "Create 'patch' format diffs between releases",
- "[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev "
- "[-D date2 | -rev2] module ...",
- "cD:flRr:stuV:",
- NULL,
- CF_RECURSE | CF_IGNORE | CF_SORT | CF_KNOWN,
- cvs_diff_init,
- cvs_diff_pre_exec,
- cvs_diff_remote,
- cvs_diff_local,
- NULL,
- cvs_diff_cleanup,
- CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
-};
-#endif
-
-#if !defined(RCSPROG)
-static struct diff_arg *dap = NULL;
-
-static int
-cvs_diff_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
+int
+cvs_diff(int argc, char **argv)
{
int ch;
+ char *arg = ".";
+ struct cvs_recursion cr;
- dap = xmalloc(sizeof(*dap));
- dap->date1 = dap->date2 = dap->rev1 = dap->rev2 = NULL;
strlcpy(diffargs, argv[0], sizeof(diffargs));
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
+ while ((ch = getopt(argc, argv, cvs_cmd_diff.cmd_opts)) != -1) {
switch (ch) {
case 'c':
strlcat(diffargs, " -c", sizeof(diffargs));
diff_format = D_CONTEXT;
break;
- case 'D':
- if (dap->date1 == NULL && dap->rev1 == NULL) {
- dap->date1 = optarg;
- } else if (dap->date2 == NULL && dap->rev2 == NULL) {
- dap->date2 = optarg;
- } else {
- cvs_log(LP_ERR,
- "no more than two revisions/dates can "
- "be specified");
- }
- break;
- case 'l':
- strlcat(diffargs, " -l", sizeof(diffargs));
- cvs_cmd_diff.file_flags &= ~CF_RECURSE;
- break;
- case 'i':
- strlcat(diffargs, " -i", sizeof(diffargs));
- iflag = 1;
- break;
- case 'N':
- strlcat(diffargs, " -N", sizeof(diffargs));
- Nflag = 1;
- break;
case 'n':
strlcat(diffargs, " -n", sizeof(diffargs));
diff_format = D_RCSDIFF;
break;
- case 'p':
- strlcat(diffargs, " -p", sizeof(diffargs));
- pflag = 1;
- break;
case 'r':
- if (dap->rev1 == NULL && dap->date1 == NULL) {
- dap->rev1 = optarg;
- } else if (dap->rev2 == NULL &&
- dap->date2 == NULL) {
- dap->rev2 = optarg;
+ if (diff_rev1 == NULL) {
+ diff_rev1 = rcsnum_parse(optarg);
+ if (diff_rev1 == NULL)
+ fatal("rcsnum_parse failed");
+ } else if (diff_rev2 == NULL) {
+ diff_rev2 = rcsnum_parse(optarg);
+ if (diff_rev2 == NULL)
+ fatal("rcsnum_parse failed");
} else {
- cvs_log(LP_ERR,
- "no more than two revisions/dates can "
- "be specified");
- return (CVS_EX_USAGE);
+ fatal("no more than 2 revisions/dates can"
+ " be specified");
}
break;
- case 'R':
- cvs_cmd_diff.file_flags |= CF_RECURSE;
- break;
case 'u':
strlcat(diffargs, " -u", sizeof(diffargs));
diff_format = D_UNIFIED;
break;
default:
- return (CVS_EX_USAGE);
- }
- }
-
- *arg = optind;
- return (0);
-}
-
-int
-cvs_diff_cleanup(void)
-{
- if (dap != NULL) {
- xfree(dap);
- dap = NULL;
- }
- return (0);
-}
-
-/*
- * cvs_diff_pre_exec()
- *
- */
-int
-cvs_diff_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method != CVS_METHOD_LOCAL) {
- /* send the flags */
- if (Nflag == 1)
- cvs_sendarg(root, "-N", 0);
- if (pflag == 1)
- cvs_sendarg(root, "-p", 0);
-
- if (diff_format == D_CONTEXT)
- cvs_sendarg(root, "-c", 0);
- else if (diff_format == D_UNIFIED)
- cvs_sendarg(root, "-u", 0);
-
- if (dap->rev1 != NULL) {
- cvs_sendarg(root, "-r", 0);
- cvs_sendarg(root, dap->rev1, 0);
- } else if (dap->date1 != NULL) {
- cvs_sendarg(root, "-D", 0);
- cvs_sendarg(root, dap->date1, 0);
- }
- if (dap->rev2 != NULL) {
- cvs_sendarg(root, "-r", 0);
- cvs_sendarg(root, dap->rev2, 0);
- } else if (dap->date2 != NULL) {
- cvs_sendarg(root, "-D", 0);
- cvs_sendarg(root, dap->date2, 0);
+ fatal("%s", cvs_cmd_diff.cmd_synopsis);
}
}
- return (0);
-}
-
-
-/*
- * cvs_diff_file()
- *
- * Diff a single file.
- */
-static int
-cvs_diff_remote(struct cvs_file *cfp, void *arg)
-{
- char fpath[MAXPATHLEN];
- struct cvsroot *root;
-
- if (cfp->cf_type == DT_DIR) {
- if (cfp->cf_cvstat == CVS_FST_UNKNOWN) {
- root = cfp->cf_parent->cf_root;
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
- } else {
- root = cfp->cf_root;
-#if 0
- if (cfp->cf_parent == NULL ||
- (root != cfp->cf_parent->cf_root)) {
- cvs_connect(root);
- cvs_diff_pre_exec(root);
- }
-#endif
+ argc -= optind;
+ argv += optind;
- cvs_senddir(root, cfp);
- }
+ cr.enterdir = NULL;
+ cr.leavedir = NULL;
+ cr.local = cvs_diff_local;
+ cr.remote = NULL;
- return (0);
- }
-
- if (cfp->cf_cvstat == CVS_FST_LOST) {
- cvs_log(LP_WARN, "cannot find file %s", cfp->cf_name);
- return (0);
- }
-
- diff_file = cvs_file_getpath(cfp, fpath, sizeof(fpath));
-
- if (cfp->cf_parent != NULL)
- root = cfp->cf_parent->cf_root;
+ if (argc > 0)
+ cvs_file_run(argc, argv, &cr);
else
- root = NULL;
-
- if (cfp->cf_cvstat == CVS_FST_UNKNOWN) {
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
- return (0);
- }
-
- cvs_sendentry(root, cfp);
-
- if (cfp->cf_cvstat == CVS_FST_UPTODATE) {
- cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
- return (0);
- }
-
- /* at this point, the file is modified */
- cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name);
- cvs_sendfile(root, diff_file);
+ cvs_file_run(1, &arg, &cr);
return (0);
}
-static int
-cvs_diff_local(CVSFILE *cf, void *arg)
+void
+cvs_diff_local(struct cvs_file *cf)
{
- char buf[64];
- char fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
- char path_tmp1[MAXPATHLEN], path_tmp2[MAXPATHLEN];
+ size_t len;
+ RCSNUM *r1;
BUF *b1, *b2;
- RCSNUM *r1, *r2;
- RCSFILE *rf;
+ struct stat st;
struct timeval tv[2], tv2[2];
+ char rbuf[16], p1[MAXPATHLEN], p2[MAXPATHLEN];
- memset(&tv, 0, sizeof(tv));
- memset(&tv2, 0, sizeof(tv2));
+ cvs_log(LP_TRACE, "cvs_diff_local(%s)", cf->file_path);
- rf = NULL;
- diff_file = cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- if (cf->cf_type == DT_DIR) {
+ if (cf->file_type == CVS_DIR) {
if (verbosity > 1)
- cvs_log(LP_NOTICE, "Diffing %s", fpath);
- return (0);
- }
-
- if (cf->cf_cvstat == CVS_FST_LOST) {
- cvs_log(LP_WARN, "cannot find file %s", cf->cf_name);
- return (0);
- }
-
- if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
- cvs_log(LP_WARN, "I know nothing about %s", diff_file);
- return (0);
- } else if (cf->cf_cvstat == CVS_FST_UPTODATE)
- return (0);
-
- /* at this point, the file is modified */
- cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
-
- if ((rf = rcs_open(rcspath, RCS_READ)) == NULL)
- fatal("cvs_diff_local: rcs_open `%s': %s", rcspath,
- rcs_errstr(rcs_errno));
-
- cvs_printf("Index: %s\n%s\nRCS file: %s\n", diff_file,
- RCS_DIFF_DIV, rcspath);
-
- if (dap->rev1 == NULL)
- r1 = cf->cf_lrev;
- else {
- if ((r1 = rcsnum_parse(dap->rev1)) == NULL)
- fatal("cvs_diff_local: rcsnum_parse failed");
- }
-
- cvs_printf("retrieving revision %s\n",
- rcsnum_tostr(r1, buf, sizeof(buf)));
- b1 = rcs_getrev(rf, r1);
-
- if (b1 == NULL) {
- cvs_log(LP_ERR, "failed to retrieve revision %s",
- rcsnum_tostr(r1, buf, sizeof(buf)));
- if (r1 != cf->cf_lrev)
- rcsnum_free(r1);
- rcs_close(rf);
- return (CVS_EX_DATA);
- }
- tv[0].tv_sec = (long)rcs_rev_getdate(rf, r1);
- tv[1].tv_sec = tv[0].tv_sec;
-
- if (r1 != cf->cf_lrev)
- rcsnum_free(r1);
-
- if (dap->rev2 != NULL) {
- cvs_printf("retrieving revision %s\n", dap->rev2);
- if ((r2 = rcsnum_parse(dap->rev2)) == NULL) {
- rcs_close(rf);
- return (CVS_EX_DATA);
- }
- b2 = rcs_getrev(rf, r2);
- tv2[0].tv_sec = (long)rcs_rev_getdate(rf, r2);
- tv2[1].tv_sec = tv2[0].tv_sec;
- rcsnum_free(r2);
- } else {
- struct stat st;
- if (stat(diff_file, &st) < 0) {
- cvs_log(LP_ERR, "failed to retrieve revision %s",
- dap->rev2);
- cvs_buf_free(b1);
- return (CVS_EX_DATA);
- }
- b2 = cvs_buf_load(diff_file, BUF_AUTOEXT);
- tv2[0].tv_sec = st.st_mtime;
- tv2[1].tv_sec = st.st_mtime;
- }
-
- rcs_close(rf);
-
- if (b2 == NULL) {
- cvs_log(LP_ERR, "failed to retrieve revision %s",
- dap->rev2);
- cvs_buf_free(b1);
- return (CVS_EX_DATA);
- }
-
- cvs_printf("%s", diffargs);
- cvs_printf(" -r%s", buf);
- if (dap->rev2 != NULL)
- cvs_printf(" -r%s", dap->rev2);
- cvs_printf(" %s\n", diff_file);
- strlcpy(path_tmp1, cvs_tmpdir, sizeof(path_tmp1));
- strlcat(path_tmp1, "/diff1.XXXXXXXXXX", sizeof(path_tmp1));
- cvs_buf_write_stmp(b1, path_tmp1, 0600);
- cvs_buf_free(b1);
- if (utimes(path_tmp1, (const struct timeval *)&tv) < 0)
- cvs_log(LP_ERRNO, "error setting utimes");
-
- strlcpy(path_tmp2, cvs_tmpdir, sizeof(path_tmp2));
- strlcat(path_tmp2, "/diff2.XXXXXXXXXX", sizeof(path_tmp2));
- cvs_buf_write_stmp(b2, path_tmp2, 0600);
- cvs_buf_free(b2);
- if (utimes(path_tmp2, (const struct timeval *)&tv2) < 0)
- cvs_log(LP_ERRNO, "error setting utimes");
-
- cvs_diffreg(path_tmp1, path_tmp2, NULL);
- (void)unlink(path_tmp1);
- (void)unlink(path_tmp2);
-
- return (0);
-}
-#endif
-
-
-int
-cvs_diffreg(const char *file1, const char *file2, BUF *out)
-{
- FILE *f1, *f2;
- int i, rval;
- void *tmp;
-
- f1 = f2 = NULL;
- rval = D_SAME;
- anychange = 0;
- lastline = 0;
- lastmatchline = 0;
- context_vec_ptr = context_vec_start - 1;
- chrtran = (iflag ? cup2low : clow2low);
- if (out != NULL)
- diffbuf = out;
-
- f1 = fopen(file1, "r");
- if (f1 == NULL) {
- cvs_log(LP_ERRNO, "%s", file1);
- goto closem;
- }
-
- f2 = fopen(file2, "r");
- if (f2 == NULL) {
- cvs_log(LP_ERRNO, "%s", file2);
- goto closem;
- }
-
- if (stat(file1, &stb1) < 0) {
- cvs_log(LP_ERRNO, "%s", file1);
- goto closem;
- }
- if (stat(file2, &stb2) < 0) {
- cvs_log(LP_ERRNO, "%s", file2);
- goto closem;
- }
- switch (files_differ(f1, f2)) {
- case 0:
- goto closem;
- case 1:
- break;
- default:
- /* error */
- goto closem;
- }
-
- if (!asciifile(f1) || !asciifile(f2)) {
- rval = D_BINARY;
- goto closem;
- }
- if (prepare(0, f1, stb1.st_size) < 0 ||
- prepare(1, f2, stb2.st_size) < 0) {
- goto closem;
- }
- prune();
- sort(sfile[0], slen[0]);
- sort(sfile[1], slen[1]);
-
- member = (int *)file[1];
- equiv(sfile[0], slen[0], sfile[1], slen[1], member);
- tmp = xrealloc(member, slen[1] + 2, sizeof(*member));
- member = tmp;
-
- class = (int *)file[0];
- unsort(sfile[0], slen[0], class);
- tmp = xrealloc(class, slen[0] + 2, sizeof(*class));
- class = tmp;
-
- klist = xcalloc(slen[0] + 2, sizeof(*klist));
- clen = 0;
- clistlen = 100;
- clist = xcalloc(clistlen, sizeof(*clist));
-
- if ((i = stone(class, slen[0], member, klist)) < 0)
- goto closem;
-
- xfree(member);
- xfree(class);
-
- tmp = xrealloc(J, diff_len[0] + 2, sizeof(*J));
- J = tmp;
- unravel(klist[i]);
- xfree(clist);
- xfree(klist);
-
- tmp = xrealloc(ixold, diff_len[0] + 2, sizeof(*ixold));
- ixold = tmp;
-
- tmp = xrealloc(ixnew, diff_len[1] + 2, sizeof(*ixnew));
- ixnew = tmp;
- check(f1, f2);
- output(f1, f2);
-
-closem:
- if (anychange == 1) {
- if (rval == D_SAME)
- rval = D_DIFFER;
- }
- if (f1 != NULL)
- fclose(f1);
- if (f2 != NULL)
- fclose(f2);
-
- return (rval);
-}
-
-/*
- * Check to see if the given files differ.
- * Returns 0 if they are the same, 1 if different, and -1 on error.
- * XXX - could use code from cmp(1) [faster]
- */
-static int
-files_differ(FILE *f1, FILE *f2)
-{
- char buf1[BUFSIZ], buf2[BUFSIZ];
- size_t i, j;
-
- if (stb1.st_size != stb2.st_size)
- return (1);
- for (;;) {
- i = fread(buf1, (size_t)1, sizeof(buf1), f1);
- j = fread(buf2, (size_t)1, sizeof(buf2), f2);
- if (i != j)
- return (1);
- if (i == 0 && j == 0) {
- if (ferror(f1) || ferror(f2))
- return (1);
- return (0);
- }
- if (memcmp(buf1, buf2, i) != 0)
- return (1);
- }
-}
-
-static int
-prepare(int i, FILE *fd, off_t filesize)
-{
- void *tmp;
- struct line *p;
- int j, h;
- size_t sz;
-
- rewind(fd);
-
- sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25;
- if (sz < 100)
- sz = 100;
-
- p = xcalloc(sz + 3, sizeof(*p));
- for (j = 0; (h = readhash(fd));) {
- if (j == (int)sz) {
- sz = sz * 3 / 2;
- tmp = xrealloc(p, sz + 3, sizeof(*p));
- p = tmp;
- }
- p[++j].value = h;
- }
- diff_len[i] = j;
- file[i] = p;
-
- return (0);
-}
-
-static void
-prune(void)
-{
- int i, j;
-
- for (pref = 0; pref < diff_len[0] && pref < diff_len[1] &&
- file[0][pref + 1].value == file[1][pref + 1].value;
- pref++)
- ;
- for (suff = 0;
- (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) &&
- (file[0][diff_len[0] - suff].value ==
- file[1][diff_len[1] - suff].value);
- suff++)
- ;
- for (j = 0; j < 2; j++) {
- sfile[j] = file[j] + pref;
- slen[j] = diff_len[j] - pref - suff;
- for (i = 0; i <= slen[j]; i++)
- sfile[j][i].serial = i;
- }
-}
-
-static void
-equiv(struct line *a, int n, struct line *b, int m, int *c)
-{
- int i, j;
-
- i = j = 1;
- while (i <= n && j <= m) {
- if (a[i].value < b[j].value)
- a[i++].value = 0;
- else if (a[i].value == b[j].value)
- a[i++].value = j;
- else
- j++;
- }
- while (i <= n)
- a[i++].value = 0;
- b[m + 1].value = 0;
- j = 0;
- while (++j <= m) {
- c[j] = -b[j].serial;
- while (b[j + 1].value == b[j].value) {
- j++;
- c[j] = b[j].serial;
- }
- }
- c[j] = -1;
-}
-
-/* Code taken from ping.c */
-static int
-isqrt(int n)
-{
- int y, x = 1;
-
- if (n == 0)
- return (0);
-
- do { /* newton was a stinker */
- y = x;
- x = n / x;
- x += y;
- x /= 2;
- } while (x - y > 1 || x - y < -1);
-
- return (x);
-}
-
-static int
-stone(int *a, int n, int *b, int *c)
-{
- int ret;
- int i, k, y, j, l;
- int oldc, tc, oldl;
- u_int numtries;
-
- /* XXX move the isqrt() out of the macro to avoid multiple calls */
- const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n));
-
- k = 0;
- if ((ret = newcand(0, 0, 0)) < 0)
- return (-1);
- c[0] = ret;
- for (i = 1; i <= n; i++) {
- j = a[i];
- if (j == 0)
- continue;
- y = -b[j];
- oldl = 0;
- oldc = c[0];
- numtries = 0;
- do {
- if (y <= clist[oldc].y)
- continue;
- l = search(c, k, y);
- if (l != oldl + 1)
- oldc = c[l - 1];
- if (l <= k) {
- if (clist[c[l]].y <= y)
- continue;
- tc = c[l];
- if ((ret = newcand(i, y, oldc)) < 0)
- return (-1);
- c[l] = ret;
- oldc = tc;
- oldl = l;
- numtries++;
- } else {
- if ((ret = newcand(i, y, oldc)) < 0)
- return (-1);
- c[l] = ret;
- k++;
- break;
- }
- } while ((y = b[++j]) > 0 && numtries < bound);
- }
- return (k);
-}
-
-static int
-newcand(int x, int y, int pred)
-{
- struct cand *q, *tmp;
- int newclistlen;
-
- if (clen == clistlen) {
- newclistlen = clistlen * 11 / 10;
- tmp = xrealloc(clist, newclistlen, sizeof(*clist));
- clist = tmp;
- clistlen = newclistlen;
- }
- q = clist + clen;
- q->x = x;
- q->y = y;
- q->pred = pred;
- return (clen++);
-}
-
-static int
-search(int *c, int k, int y)
-{
- int i, j, l, t;
-
- if (clist[c[k]].y < y) /* quick look for typical case */
- return (k + 1);
- i = 0;
- j = k + 1;
- for (;;) {
- l = (i + j) / 2;
- if (l <= i)
- break;
- t = clist[c[l]].y;
- if (t > y)
- j = l;
- else if (t < y)
- i = l;
- else
- return (l);
- }
- return (l + 1);
-}
-
-static void
-unravel(int p)
-{
- struct cand *q;
- int i;
-
- for (i = 0; i <= diff_len[0]; i++)
- J[i] = i <= pref ? i :
- i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0;
- for (q = clist + p; q->y != 0; q = clist + q->pred)
- J[q->x + pref] = q->y + pref;
-}
-
-/*
- * Check does double duty:
- * 1. ferret out any fortuitous correspondences due
- * to confounding by hashing (which result in "jackpot")
- * 2. collect random access indexes to the two files
- */
-static void
-check(FILE *f1, FILE *f2)
-{
- int i, j, jackpot, c, d;
- long ctold, ctnew;
-
- rewind(f1);
- rewind(f2);
- j = 1;
- ixold[0] = ixnew[0] = 0;
- jackpot = 0;
- ctold = ctnew = 0;
- for (i = 1; i <= diff_len[0]; i++) {
- if (J[i] == 0) {
- ixold[i] = ctold += skipline(f1);
- continue;
- }
- while (j < J[i]) {
- ixnew[j] = ctnew += skipline(f2);
- j++;
- }
- if (bflag == 1 || wflag == 1 || iflag == 1) {
- for (;;) {
- c = getc(f1);
- d = getc(f2);
- /*
- * GNU diff ignores a missing newline
- * in one file if bflag || wflag.
- */
- if ((bflag == 1 || wflag == 1) &&
- ((c == EOF && d == '\n') ||
- (c == '\n' && d == EOF))) {
- break;
- }
- ctold++;
- ctnew++;
- if (bflag == 1 && isspace(c) && isspace(d)) {
- do {
- if (c == '\n')
- break;
- ctold++;
- } while (isspace(c = getc(f1)));
- do {
- if (d == '\n')
- break;
- ctnew++;
- } while (isspace(d = getc(f2)));
- } else if (wflag == 1) {
- while (isspace(c) && c != '\n') {
- c = getc(f1);
- ctold++;
- }
- while (isspace(d) && d != '\n') {
- d = getc(f2);
- ctnew++;
- }
- }
- if (chrtran[c] != chrtran[d]) {
- jackpot++;
- J[i] = 0;
- if (c != '\n' && c != EOF)
- ctold += skipline(f1);
- if (d != '\n' && c != EOF)
- ctnew += skipline(f2);
- break;
- }
- if (c == '\n' || c == EOF)
- break;
- }
- } else {
- for (;;) {
- ctold++;
- ctnew++;
- if ((c = getc(f1)) != (d = getc(f2))) {
- /* jackpot++; */
- J[i] = 0;
- if (c != '\n' && c != EOF)
- ctold += skipline(f1);
- if (d != '\n' && c != EOF)
- ctnew += skipline(f2);
- break;
- }
- if (c == '\n' || c == EOF)
- break;
- }
- }
- ixold[i] = ctold;
- ixnew[j] = ctnew;
- j++;
- }
- for (; j <= diff_len[1]; j++)
- ixnew[j] = ctnew += skipline(f2);
- /*
- * if (jackpot != 0)
- * cvs_printf("jackpot\n");
- */
-}
-
-/* shellsort CACM #201 */
-static void
-sort(struct line *a, int n)
-{
- struct line *ai, *aim, w;
- int j, m = 0, k;
-
- if (n == 0)
+ cvs_log(LP_NOTICE, "Diffing inside %s", cf->file_path);
return;
- for (j = 1; j <= n; j *= 2)
- m = 2 * j - 1;
- for (m /= 2; m != 0; m /= 2) {
- k = n - m;
- for (j = 1; j <= k; j++) {
- for (ai = &a[j]; ai > a; ai -= m) {
- aim = &ai[m];
- if (aim < ai)
- break; /* wraparound */
- if (aim->value > ai[0].value ||
- (aim->value == ai[0].value &&
- aim->serial > ai[0].serial))
- break;
- w.value = ai[0].value;
- ai[0].value = aim->value;
- aim->value = w.value;
- w.serial = ai[0].serial;
- ai[0].serial = aim->serial;
- aim->serial = w.serial;
- }
- }
}
-}
-
-static void
-unsort(struct line *f, int l, int *b)
-{
- int *a, i;
-
- a = xcalloc(l + 1, sizeof(*a));
- for (i = 1; i <= l; i++)
- a[f[i].serial] = f[i].value;
- for (i = 1; i <= l; i++)
- b[i] = a[i];
- xfree(a);
-}
-
-static int
-skipline(FILE *f)
-{
- int i, c;
-
- for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++)
- continue;
- return (i);
-}
-
-static void
-output(FILE *f1, FILE *f2)
-{
- int m, i0, i1, j0, j1;
-
- rewind(f1);
- rewind(f2);
- m = diff_len[0];
- J[0] = 0;
- J[m + 1] = diff_len[1] + 1;
- for (i0 = 1; i0 <= m; i0 = i1 + 1) {
- while (i0 <= m && J[i0] == J[i0 - 1] + 1)
- i0++;
- j0 = J[i0 - 1] + 1;
- i1 = i0 - 1;
- while (i1 < m && J[i1 + 1] == 0)
- i1++;
- j1 = J[i1 + 1] - 1;
- J[i1] = j1;
- change(f1, f2, i0, i1, j0, j1);
- }
- if (m == 0)
- change(f1, f2, 1, 0, 1, diff_len[1]);
- if (diff_format == D_IFDEF) {
- for (;;) {
-#define c i0
- if ((c = getc(f1)) == EOF)
- return;
- diff_output("%c", c);
- }
-#undef c
- }
- if (anychange != 0) {
- if (diff_format == D_CONTEXT)
- dump_context_vec(f1, f2);
- else if (diff_format == D_UNIFIED)
- dump_unified_vec(f1, f2);
- }
-}
-
-static __inline void
-range(int a, int b, char *separator)
-{
- diff_output("%d", a > b ? b : a);
- if (a < b)
- diff_output("%s%d", separator, b);
-}
-
-static __inline void
-uni_range(int a, int b)
-{
- if (a < b)
- diff_output("%d,%d", a, b - a + 1);
- else if (a == b)
- diff_output("%d", b);
- else
- diff_output("%d,0", b);
-}
-
-static char *
-preadline(int fd, size_t rlen, off_t off)
-{
- char *line;
- ssize_t nr;
-
- line = xmalloc(rlen + 1);
- if ((nr = pread(fd, line, rlen, off)) < 0) {
- cvs_log(LP_ERRNO, "preadline failed");
- return (NULL);
- }
- line[nr] = '\0';
- return (line);
-}
-
-static int
-ignoreline(char *line)
-{
- int ret;
-
- ret = regexec(&ignore_re, line, (size_t)0, NULL, 0);
- xfree(line);
- return (ret == 0); /* if it matched, it should be ignored. */
-}
-
-/*
- * Indicate that there is a difference between lines a and b of the from file
- * to get to lines c to d of the to file. If a is greater then b then there
- * are no lines in the from file involved and this means that there were
- * lines appended (beginning at b). If c is greater than d then there are
- * lines missing from the to file.
- */
-static void
-change(FILE *f1, FILE *f2, int a, int b, int c, int d)
-{
- int i;
- static size_t max_context = 64;
- char buf[64];
- struct tm *t;
-
- if (diff_format != D_IFDEF && a > b && c > d)
- return;
- if (ignore_pats != NULL) {
- char *line;
- /*
- * All lines in the change, insert, or delete must
- * match an ignore pattern for the change to be
- * ignored.
- */
- if (a <= b) { /* Changes and deletes. */
- for (i = a; i <= b; i++) {
- line = preadline(fileno(f1),
- ixold[i] - ixold[i - 1], ixold[i - 1]);
- if (!ignoreline(line))
- goto proceed;
- }
- }
- if (a > b || c <= d) { /* Changes and inserts. */
- for (i = c; i <= d; i++) {
- line = preadline(fileno(f2),
- ixnew[i] - ixnew[i - 1], ixnew[i - 1]);
- if (!ignoreline(line))
- goto proceed;
- }
- }
- return;
- }
-proceed:
- if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) {
- /*
- * Allocate change records as needed.
- */
- if (context_vec_ptr == context_vec_end - 1) {
- struct context_vec *tmp;
- ptrdiff_t offset = context_vec_ptr - context_vec_start;
- max_context <<= 1;
- tmp = xrealloc(context_vec_start, max_context,
- sizeof(*context_vec_start));
- context_vec_start = tmp;
- context_vec_end = context_vec_start + max_context;
- context_vec_ptr = context_vec_start + offset;
- }
- if (anychange == 0) {
- /*
- * Print the context/unidiff header first time through.
- */
- t = localtime(&stb1.st_mtime);
- (void)strftime(buf, sizeof(buf),
- "%Y/%m/%d %H:%M:%S", t);
- diff_output("%s %s %s",
- diff_format == D_CONTEXT ? "***" : "---", diff_file,
- buf);
+ cvs_file_classify(cf);
- if (diff_rev1 != NULL) {
- rcsnum_tostr(diff_rev1, buf, sizeof(buf));
- diff_output("\t%s", buf);
- }
-
- printf("\n");
-
- t = localtime(&stb2.st_mtime);
- (void)strftime(buf, sizeof(buf),
- "%Y/%m/%d %H:%M:%S", t);
-
- diff_output("%s %s %s",
- diff_format == D_CONTEXT ? "---" : "+++", diff_file,
- buf);
-
- if (diff_rev2 != NULL) {
- rcsnum_tostr(diff_rev2, buf, sizeof(buf));
- diff_output("\t%s", buf);
- }
-
- printf("\n");
- anychange = 1;
- } else if (a > context_vec_ptr->b + (2 * context) + 1 &&
- c > context_vec_ptr->d + (2 * context) + 1) {
- /*
- * If this change is more than 'context' lines from the
- * previous change, dump the record and reset it.
- */
- if (diff_format == D_CONTEXT)
- dump_context_vec(f1, f2);
- else
- dump_unified_vec(f1, f2);
- }
- context_vec_ptr++;
- context_vec_ptr->a = a;
- context_vec_ptr->b = b;
- context_vec_ptr->c = c;
- context_vec_ptr->d = d;
+ if (cf->file_status == FILE_LOST) {
+ cvs_log(LP_ERR, "cannot find file %s", cf->file_path);
return;
- }
- if (anychange == 0)
- anychange = 1;
- switch (diff_format) {
- case D_BRIEF:
+ } else if (cf->file_status == FILE_UNKNOWN) {
+ cvs_log(LP_ERR, "I know nothing about %s", cf->file_path);
return;
- case D_NORMAL:
- range(a, b, ",");
- diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c');
- if (diff_format == D_NORMAL)
- range(c, d, ",");
- diff_output("\n");
- break;
- case D_RCSDIFF:
- if (a > b)
- diff_output("a%d %d\n", b, d - c + 1);
- else {
- diff_output("d%d %d\n", a, b - a + 1);
-
- if (!(c > d)) /* add changed lines */
- diff_output("a%d %d\n", b, d - c + 1);
- }
- break;
- }
- if (diff_format == D_NORMAL || diff_format == D_IFDEF) {
- fetch(ixold, a, b, f1, '<', 1);
- if (a <= b && c <= d && diff_format == D_NORMAL)
- diff_output("---\n");
- }
- fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0);
- if (inifdef) {
- diff_output("#endif /* %s */\n", ifdefname);
- inifdef = 0;
- }
-}
-
-static void
-fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile)
-{
- long j, nc;
- int i, c, col;
-
- /*
- * When doing #ifdef's, copy down to current line
- * if this is the first file, so that stuff makes it to output.
- */
- if (diff_format == D_IFDEF && oldfile) {
- long curpos = ftell(lb);
- /* print through if append (a>b), else to (nb: 0 vs 1 orig) */
- nc = f[a > b ? b : a - 1] - curpos;
- for (i = 0; i < nc; i++)
- diff_output("%c", getc(lb));
- }
- if (a > b)
+ } else if (cf->file_status == FILE_UPTODATE && diff_rev2 == NULL)
return;
- if (diff_format == D_IFDEF) {
- if (inifdef) {
- diff_output("#else /* %s%s */\n",
- oldfile == 1 ? "!" : "", ifdefname);
- } else {
- if (oldfile)
- diff_output("#ifndef %s\n", ifdefname);
- else
- diff_output("#ifdef %s\n", ifdefname);
- }
- inifdef = 1 + oldfile;
- }
- for (i = a; i <= b; i++) {
- fseek(lb, f[i - 1], SEEK_SET);
- nc = f[i] - f[i - 1];
- if (diff_format != D_IFDEF && ch != '\0') {
- diff_output("%c", ch);
- if (Tflag == 1 && (diff_format == D_NORMAL ||
- diff_format == D_CONTEXT ||
- diff_format == D_UNIFIED))
- diff_output("\t");
- else if (diff_format != D_UNIFIED)
- diff_output(" ");
- }
- col = 0;
- for (j = 0; j < nc; j++) {
- if ((c = getc(lb)) == EOF) {
- if (diff_format == D_RCSDIFF)
- cvs_log(LP_WARN,
- "No newline at end of file");
- else
- diff_output("\n\\ No newline at end of "
- "file");
- return;
- }
- if (c == '\t' && tflag == 1) {
- do {
- diff_output(" ");
- } while (++col & 7);
- } else {
- diff_output("%c", c);
- col++;
- }
- }
- }
-}
-/*
- * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578.
- */
-static int
-readhash(FILE *f)
-{
- int i, t, space;
- int sum;
+ diff_file = cf->file_path;
+ cvs_printf("Index: %s\n%s\nRCS file: %s\n", cf->file_path,
+ RCS_DIFF_DIV, cf->file_rpath);
- sum = 1;
- space = 0;
- if (bflag != 1 && wflag != 1) {
- if (iflag == 1)
- for (i = 0; (t = getc(f)) != '\n'; i++) {
- if (t == EOF) {
- if (i == 0)
- return (0);
- break;
- }
- sum = sum * 127 + chrtran[t];
- }
- else
- for (i = 0; (t = getc(f)) != '\n'; i++) {
- if (t == EOF) {
- if (i == 0)
- return (0);
- break;
- }
- sum = sum * 127 + t;
- }
+ if (diff_rev1 != NULL)
+ r1 = diff_rev1;
+ else
+ r1 = cf->file_ent->ce_rev;
+
+ diff_rev1 = r1;
+ rcsnum_tostr(r1, rbuf , sizeof(rbuf));
+ cvs_printf("retrieving revision %s\n", rbuf);
+ if ((b1 = rcs_getrev(cf->file_rcs, r1)) == NULL)
+ fatal("failed to retrieve revision %s", rbuf);
+
+ tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, r1);
+ tv[0].tv_usec = 0;
+ tv[1] = tv[0];
+
+ if (diff_rev2 != NULL) {
+ rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf));
+ cvs_printf("retrieving revision %s\n", rbuf);
+ if ((b2 = rcs_getrev(cf->file_rcs, diff_rev2)) == NULL)
+ fatal("failed to retrieve revision %s", rbuf);
+
+ tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2);
+ tv2[0].tv_usec = 0;
+ tv2[1] = tv2[0];
} else {
- for (i = 0;;) {
- switch (t = getc(f)) {
- case '\t':
- case ' ':
- space++;
- continue;
- default:
- if (space != 0 && wflag != 1) {
- i++;
- space = 0;
- }
- sum = sum * 127 + chrtran[t];
- i++;
- continue;
- case EOF:
- if (i == 0)
- return (0);
- /* FALLTHROUGH */
- case '\n':
- break;
- }
- break;
- }
- }
- /*
- * There is a remote possibility that we end up with a zero sum.
- * Zero is used as an EOF marker, so return 1 instead.
- */
- return (sum == 0 ? 1 : sum);
-}
-
-static int
-asciifile(FILE *f)
-{
- char buf[BUFSIZ];
- size_t i, cnt;
+ if (fstat(cf->fd, &st) == -1)
+ fatal("fstat failed %s", strerror(errno));
+ if ((b2 = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL)
+ fatal("failed to load %s", cf->file_path);
- if (aflag == 1 || f == NULL)
- return (1);
+ st.st_mtime = cvs_hack_time(st.st_mtime, 1);
+ if (st.st_mtime == 0)
+ fatal("cvs_diff_local: to gmt failed");
- rewind(f);
- cnt = fread(buf, (size_t)1, sizeof(buf), f);
- for (i = 0; i < cnt; i++)
- if (!isprint(buf[i]) && !isspace(buf[i]))
- return (0);
- return (1);
-}
-
-static char*
-match_function(const long *f, int pos, FILE *fp)
-{
- unsigned char buf[FUNCTION_CONTEXT_SIZE];
- size_t nc;
- int last = lastline;
- char *p;
-
- lastline = pos;
- while (pos > last) {
- fseek(fp, f[pos - 1], SEEK_SET);
- nc = f[pos] - f[pos - 1];
- if (nc >= sizeof(buf))
- nc = sizeof(buf) - 1;
- nc = fread(buf, (size_t)1, nc, fp);
- if (nc > 0) {
- buf[nc] = '\0';
- p = strchr((const char *)buf, '\n');
- if (p != NULL)
- *p = '\0';
- if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') {
- strlcpy(lastbuf, (const char *)buf,
- sizeof lastbuf);
- lastmatchline = pos;
- return lastbuf;
- }
- }
- pos--;
- }
- return (lastmatchline > 0) ? lastbuf : NULL;
-}
-
-
-/* dump accumulated "context" diff changes */
-static void
-dump_context_vec(FILE *f1, FILE *f2)
-{
- struct context_vec *cvp = context_vec_start;
- int lowa, upb, lowc, upd, do_output;
- int a, b, c, d;
- char ch, *f;
-
- if (context_vec_start > context_vec_ptr)
- return;
-
- b = d = 0; /* gcc */
- lowa = MAX(1, cvp->a - context);
- upb = MIN(diff_len[0], context_vec_ptr->b + context);
- lowc = MAX(1, cvp->c - context);
- upd = MIN(diff_len[1], context_vec_ptr->d + context);
-
- diff_output("***************");
- if (pflag == 1) {
- f = match_function(ixold, lowa - 1, f1);
- if (f != NULL) {
- diff_output(" ");
- diff_output("%s", f);
- }
+ tv2[0].tv_sec = st.st_mtime;
+ tv2[0].tv_usec = 0;
+ tv2[1] = tv2[0];
}
- diff_output("\n*** ");
- range(lowa, upb, ",");
- diff_output(" ****\n");
- /*
- * Output changes to the "old" file. The first loop suppresses
- * output if there were no changes to the "old" file (we'll see
- * the "old" lines as context in the "new" list).
- */
- do_output = 0;
- for (; cvp <= context_vec_ptr; cvp++)
- if (cvp->a <= cvp->b) {
- cvp = context_vec_start;
- do_output++;
- break;
- }
- if (do_output != 0) {
- while (cvp <= context_vec_ptr) {
- a = cvp->a;
- b = cvp->b;
- c = cvp->c;
- d = cvp->d;
+ cvs_printf("%s", diffargs);
- if (a <= b && c <= d)
- ch = 'c';
- else
- ch = (a <= b) ? 'd' : 'a';
+ rcsnum_tostr(r1, rbuf, sizeof(rbuf));
+ cvs_printf(" -r%s", rbuf);
- if (ch == 'a')
- fetch(ixold, lowa, b, f1, ' ', 0);
- else {
- fetch(ixold, lowa, a - 1, f1, ' ', 0);
- fetch(ixold, a, b, f1,
- ch == 'c' ? '!' : '-', 0);
- }
- lowa = b + 1;
- cvp++;
- }
- fetch(ixold, b + 1, upb, f1, ' ', 0);
+ if (diff_rev2 != NULL) {
+ rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf));
+ cvs_printf(" -r%s", rbuf);
}
- /* output changes to the "new" file */
- diff_output("--- ");
- range(lowc, upd, ",");
- diff_output(" ----\n");
- do_output = 0;
- for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++)
- if (cvp->c <= cvp->d) {
- cvp = context_vec_start;
- do_output++;
- break;
- }
- if (do_output != 0) {
- while (cvp <= context_vec_ptr) {
- a = cvp->a;
- b = cvp->b;
- c = cvp->c;
- d = cvp->d;
+ cvs_printf(" %s\n", cf->file_path);
- if (a <= b && c <= d)
- ch = 'c';
- else
- ch = (a <= b) ? 'd' : 'a';
+ len = strlcpy(p1, cvs_tmpdir, sizeof(p1));
+ if (len >= sizeof(p1))
+ fatal("cvs_diff_local: truncation");
- if (ch == 'd')
- fetch(ixnew, lowc, d, f2, ' ', 0);
- else {
- fetch(ixnew, lowc, c - 1, f2, ' ', 0);
- fetch(ixnew, c, d, f2,
- ch == 'c' ? '!' : '+', 0);
- }
- lowc = d + 1;
- cvp++;
- }
- fetch(ixnew, d + 1, upd, f2, ' ', 0);
- }
- context_vec_ptr = context_vec_start - 1;
-}
+ len = strlcat(p1, "/diff1.XXXXXXXXXX", sizeof(p1));
+ if (len >= sizeof(p1))
+ fatal("cvs_diff_local: truncation");
-/* dump accumulated "unified" diff changes */
-static void
-dump_unified_vec(FILE *f1, FILE *f2)
-{
- struct context_vec *cvp = context_vec_start;
- int lowa, upb, lowc, upd;
- int a, b, c, d;
- char ch, *f;
-
- if (context_vec_start > context_vec_ptr)
- return;
-
- b = d = 0; /* gcc */
- lowa = MAX(1, cvp->a - context);
- upb = MIN(diff_len[0], context_vec_ptr->b + context);
- lowc = MAX(1, cvp->c - context);
- upd = MIN(diff_len[1], context_vec_ptr->d + context);
-
- diff_output("@@ -");
- uni_range(lowa, upb);
- diff_output(" +");
- uni_range(lowc, upd);
- diff_output(" @@");
- if (pflag == 1) {
- f = match_function(ixold, lowa - 1, f1);
- if (f != NULL) {
- diff_output(" ");
- diff_output("%s", f);
- }
- }
- diff_output("\n");
-
- /*
- * Output changes in "unified" diff format--the old and new lines
- * are printed together.
- */
- for (; cvp <= context_vec_ptr; cvp++) {
- a = cvp->a;
- b = cvp->b;
- c = cvp->c;
- d = cvp->d;
-
- /*
- * c: both new and old changes
- * d: only changes in the old file
- * a: only changes in the new file
- */
- if (a <= b && c <= d)
- ch = 'c';
- else
- ch = (a <= b) ? 'd' : 'a';
+ cvs_buf_write_stmp(b1, p1, 0600, tv);
+ cvs_buf_free(b1);
- switch (ch) {
- case 'c':
- fetch(ixold, lowa, a - 1, f1, ' ', 0);
- fetch(ixold, a, b, f1, '-', 0);
- fetch(ixnew, c, d, f2, '+', 0);
- break;
- case 'd':
- fetch(ixold, lowa, a - 1, f1, ' ', 0);
- fetch(ixold, a, b, f1, '-', 0);
- break;
- case 'a':
- fetch(ixnew, lowc, c - 1, f2, ' ', 0);
- fetch(ixnew, c, d, f2, '+', 0);
- break;
- }
- lowa = b + 1;
- lowc = d + 1;
- }
- fetch(ixnew, d + 1, upd, f2, ' ', 0);
+ len = strlcpy(p2, cvs_tmpdir, sizeof(p2));
+ if (len >= sizeof(p2))
+ fatal("cvs_diff_local: truncation");
- context_vec_ptr = context_vec_start - 1;
-}
+ len = strlcat(p2, "/diff2.XXXXXXXXXX", sizeof(p2));
+ if (len >= sizeof(p2))
+ fatal("cvs_diff_local: truncation");
-void
-diff_output(const char *fmt, ...)
-{
- va_list vap;
- int i;
- char *str;
+ cvs_buf_write_stmp(b2, p2, 0600, tv2);
+ cvs_buf_free(b2);
- va_start(vap, fmt);
- i = vasprintf(&str, fmt, vap);
- va_end(vap);
- if (i == -1)
- fatal("diff_output: %s", strerror(errno));
- if (diffbuf != NULL)
- cvs_buf_append(diffbuf, str, strlen(str));
- else
- cvs_printf("%s", str);
- xfree(str);
+ cvs_diffreg(p1, p2, NULL);
+ cvs_worklist_run(&temp_files, cvs_worklist_unlink);
}
diff --git a/usr.bin/cvs/diff.h b/usr.bin/cvs/diff.h
index 0e3c56480ee..8ed8b8bc865 100644
--- a/usr.bin/cvs/diff.h
+++ b/usr.bin/cvs/diff.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: diff.h,v 1.10 2006/04/14 23:29:01 joris Exp $ */
+/* $OpenBSD: diff.h,v 1.11 2006/05/27 03:30:30 joris Exp $ */
/*
* Copyright (C) Caldera International Inc. 2001-2002.
* All rights reserved.
@@ -67,7 +67,6 @@
#define CVS_DIFF_H
#define CVS_DIFF_DEFCTX 3 /* default context length */
-
/*
* Output format options
*/
@@ -92,11 +91,6 @@
#define D_SKIPPED1 8 /* path1 was a special file */
#define D_SKIPPED2 9 /* path2 was a special file */
-
-#if defined(RCSPROG)
-struct cvs_lines;
-#endif
-
BUF *cvs_diff3(RCSFILE *, char *, RCSNUM *, RCSNUM *, int);
void diff_output(const char *, ...);
int cvs_diffreg(const char *, const char *, BUF *out);
diff --git a/usr.bin/cvs/diff3.c b/usr.bin/cvs/diff3.c
index 58f4195c266..16a7657fd7d 100644
--- a/usr.bin/cvs/diff3.c
+++ b/usr.bin/cvs/diff3.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diff3.c,v 1.23 2006/04/14 02:49:41 deraadt Exp $ */
+/* $OpenBSD: diff3.c,v 1.24 2006/05/27 03:30:30 joris Exp $ */
/*
* Copyright (C) Caldera International Inc. 2001-2002.
@@ -72,7 +72,7 @@ static const char copyright[] =
#ifndef lint
static const char rcsid[] =
- "$OpenBSD: diff3.c,v 1.23 2006/04/14 02:49:41 deraadt Exp $";
+ "$OpenBSD: diff3.c,v 1.24 2006/05/27 03:30:30 joris Exp $";
#endif /* not lint */
#include "includes.h"
@@ -187,13 +187,13 @@ cvs_diff3(RCSFILE *rf, char *workfile, RCSNUM *rev1, RCSNUM *rev2, int verbose)
diffb = cvs_buf_alloc((size_t)128, BUF_AUTOEXT);
strlcpy(path1, "/tmp/diff1.XXXXXXXXXX", sizeof(path1));
- cvs_buf_write_stmp(b1, path1, 0600);
+ cvs_buf_write_stmp(b1, path1, 0600, NULL);
strlcpy(path2, "/tmp/diff2.XXXXXXXXXX", sizeof(path2));
- cvs_buf_write_stmp(b2, path2, 0600);
+ cvs_buf_write_stmp(b2, path2, 0600, NULL);
strlcpy(path3, "/tmp/diff3.XXXXXXXXXX", sizeof(path3));
- cvs_buf_write_stmp(b3, path3, 0600);
+ cvs_buf_write_stmp(b3, path3, 0600, NULL);
cvs_buf_free(b2);
b2 = NULL;
@@ -202,13 +202,13 @@ cvs_diff3(RCSFILE *rf, char *workfile, RCSNUM *rev1, RCSNUM *rev2, int verbose)
cvs_diffreg(path2, path3, d2);
strlcpy(dp13, "/tmp/d13.XXXXXXXXXX", sizeof(dp13));
- cvs_buf_write_stmp(d1, dp13, 0600);
+ cvs_buf_write_stmp(d1, dp13, 0600, NULL);
cvs_buf_free(d1);
d1 = NULL;
strlcpy(dp23, "/tmp/d23.XXXXXXXXXX", sizeof(dp23));
- cvs_buf_write_stmp(d2, dp23, 0600);
+ cvs_buf_write_stmp(d2, dp23, 0600, NULL);
cvs_buf_free(d2);
d2 = NULL;
@@ -239,7 +239,7 @@ cvs_diff3(RCSFILE *rf, char *workfile, RCSNUM *rev1, RCSNUM *rev2, int verbose)
goto out;
if (verbose == 1 && diff3_conflicts != 0) {
- cvs_log(LP_WARN, "%d conflict%s found during merge, "
+ cvs_log(LP_ERR, "%d conflict%s found during merge, "
"please correct.", diff3_conflicts,
(diff3_conflicts > 1) ? "s" : "");
}
@@ -293,7 +293,7 @@ diff3_internal(int argc, char **argv, const char *fmark, const char *rmark)
for (i = 0; i <= 2; i++) {
if ((fp[i] = fopen(argv[i + 2], "r")) == NULL) {
- cvs_log(LP_ERRNO, "%s", argv[i + 2]);
+ cvs_log(LP_ERR, "%s", argv[i + 2]);
return (-1);
}
}
diff --git a/usr.bin/cvs/diff_internals.c b/usr.bin/cvs/diff_internals.c
new file mode 100644
index 00000000000..f5e8b95278b
--- /dev/null
+++ b/usr.bin/cvs/diff_internals.c
@@ -0,0 +1,1393 @@
+/* $OpenBSD: diff_internals.c,v 1.1 2006/05/27 03:30:30 joris Exp $ */
+/*
+ * Copyright (C) Caldera International Inc. 2001-2002.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * 4. Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
+ * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2004 Jean-Francois Brousseau. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)diffreg.c 8.1 (Berkeley) 6/6/93
+ */
+/*
+ * Uses an algorithm due to Harold Stone, which finds
+ * a pair of longest identical subsequences in the two
+ * files.
+ *
+ * The major goal is to generate the match vector J.
+ * J[i] is the index of the line in file1 corresponding
+ * to line i file0. J[i] = 0 if there is no
+ * such line in file1.
+ *
+ * Lines are hashed so as to work in core. All potential
+ * matches are located by sorting the lines of each file
+ * on the hash (called ``value''). In particular, this
+ * collects the equivalence classes in file1 together.
+ * Subroutine equiv replaces the value of each line in
+ * file0 by the index of the first element of its
+ * matching equivalence in (the reordered) file1.
+ * To save space equiv squeezes file1 into a single
+ * array member in which the equivalence classes
+ * are simply concatenated, except that their first
+ * members are flagged by changing sign.
+ *
+ * Next the indices that point into member are unsorted into
+ * array class according to the original order of file0.
+ *
+ * The cleverness lies in routine stone. This marches
+ * through the lines of file0, developing a vector klist
+ * of "k-candidates". At step i a k-candidate is a matched
+ * pair of lines x,y (x in file0 y in file1) such that
+ * there is a common subsequence of length k
+ * between the first i lines of file0 and the first y
+ * lines of file1, but there is no such subsequence for
+ * any smaller y. x is the earliest possible mate to y
+ * that occurs in such a subsequence.
+ *
+ * Whenever any of the members of the equivalence class of
+ * lines in file1 matable to a line in file0 has serial number
+ * less than the y of some k-candidate, that k-candidate
+ * with the smallest such y is replaced. The new
+ * k-candidate is chained (via pred) to the current
+ * k-1 candidate so that the actual subsequence can
+ * be recovered. When a member has serial number greater
+ * that the y of all k-candidates, the klist is extended.
+ * At the end, the longest subsequence is pulled out
+ * and placed in the array J by unravel
+ *
+ * With J in hand, the matches there recorded are
+ * check'ed against reality to assure that no spurious
+ * matches have crept in due to hashing. If they have,
+ * they are broken, and "jackpot" is recorded--a harmless
+ * matter except that a true match for a spuriously
+ * mated line may now be unnecessarily reported as a change.
+ *
+ * Much of the complexity of the program comes simply
+ * from trying to minimize core utilization and
+ * maximize the range of doable problems by dynamically
+ * allocating what is needed and reusing what is not.
+ * The core requirements for problems larger than somewhat
+ * are (in words) 2*length(file0) + length(file1) +
+ * 3*(number of k-candidates installed), typically about
+ * 6n words for files of length n.
+ */
+
+#include "includes.h"
+
+#include "buf.h"
+#include "cvs.h"
+#include "diff.h"
+#include "log.h"
+
+#include "xmalloc.h"
+
+struct cand {
+ int x;
+ int y;
+ int pred;
+} cand;
+
+struct line {
+ int serial;
+ int value;
+} *file[2];
+
+/*
+ * The following struct is used to record change in formation when
+ * doing a "context" or "unified" diff. (see routine "change" to
+ * understand the highly mnemonic field names)
+ */
+struct context_vec {
+ int a; /* start line in old file */
+ int b; /* end line in old file */
+ int c; /* start line in new file */
+ int d; /* end line in new file */
+};
+
+struct diff_arg {
+ char *rev1;
+ char *rev2;
+ char *date1;
+ char *date2;
+};
+
+static void output(FILE *, FILE *);
+static void check(FILE *, FILE *);
+static void range(int, int, char *);
+static void uni_range(int, int);
+static void dump_context_vec(FILE *, FILE *);
+static void dump_unified_vec(FILE *, FILE *);
+static int prepare(int, FILE *, off_t);
+static void prune(void);
+static void equiv(struct line *, int, struct line *, int, int *);
+static void unravel(int);
+static void unsort(struct line *, int, int *);
+static void change(FILE *, FILE *, int, int, int, int);
+static void sort(struct line *, int);
+static int ignoreline(char *);
+static int asciifile(FILE *);
+static void fetch(long *, int, int, FILE *, int, int);
+static int newcand(int, int, int);
+static int search(int *, int, int);
+static int skipline(FILE *);
+static int isqrt(int);
+static int stone(int *, int, int *, int *);
+static int readhash(FILE *);
+static int files_differ(FILE *, FILE *);
+static char *match_function(const long *, int, FILE *);
+static char *preadline(int, size_t, off_t);
+
+static int aflag, bflag, dflag, iflag, pflag, tflag, Tflag, wflag;
+static int context = 3;
+int diff_format = D_NORMAL;
+char *diff_file = NULL;
+RCSNUM *diff_rev1 = NULL;
+RCSNUM *diff_rev2 = NULL;
+char diffargs[128];
+static struct stat stb1, stb2;
+static char *ifdefname, *ignore_pats;
+regex_t ignore_re;
+
+static int *J; /* will be overlaid on class */
+static int *class; /* will be overlaid on file[0] */
+static int *klist; /* will be overlaid on file[0] after class */
+static int *member; /* will be overlaid on file[1] */
+static int clen;
+static int inifdef; /* whether or not we are in a #ifdef block */
+static int diff_len[2];
+static int pref, suff; /* length of prefix and suffix */
+static int slen[2];
+static int anychange;
+static long *ixnew; /* will be overlaid on file[1] */
+static long *ixold; /* will be overlaid on klist */
+static struct cand *clist; /* merely a free storage pot for candidates */
+static int clistlen; /* the length of clist */
+static struct line *sfile[2]; /* shortened by pruning common prefix/suffix */
+static u_char *chrtran; /* translation table for case-folding */
+static struct context_vec *context_vec_start;
+static struct context_vec *context_vec_end;
+static struct context_vec *context_vec_ptr;
+
+#define FUNCTION_CONTEXT_SIZE 41
+static char lastbuf[FUNCTION_CONTEXT_SIZE];
+static int lastline;
+static int lastmatchline;
+BUF *diffbuf = NULL;
+
+/*
+ * chrtran points to one of 2 translation tables: cup2low if folding upper to
+ * lower case clow2low if not folding case
+ */
+u_char clow2low[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41,
+ 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+ 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
+ 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
+ 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+ 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+ 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
+ 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+ 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
+ 0xfd, 0xfe, 0xff
+};
+
+u_char cup2low[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x60, 0x61,
+ 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x60, 0x61, 0x62,
+ 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
+ 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+ 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+ 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+ 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
+ 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+ 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1,
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc,
+ 0xfd, 0xfe, 0xff
+};
+
+int
+cvs_diffreg(const char *file1, const char *file2, BUF *out)
+{
+ FILE *f1, *f2;
+ int i, rval;
+ void *tmp;
+
+ f1 = f2 = NULL;
+ rval = D_SAME;
+ anychange = 0;
+ lastline = 0;
+ lastmatchline = 0;
+ context_vec_ptr = context_vec_start - 1;
+ chrtran = (iflag ? cup2low : clow2low);
+ if (out != NULL)
+ diffbuf = out;
+
+ f1 = fopen(file1, "r");
+ if (f1 == NULL) {
+ cvs_log(LP_ERR, "%s", file1);
+ goto closem;
+ }
+
+ f2 = fopen(file2, "r");
+ if (f2 == NULL) {
+ cvs_log(LP_ERR, "%s", file2);
+ goto closem;
+ }
+
+ if (stat(file1, &stb1) < 0) {
+ cvs_log(LP_ERR, "%s", file1);
+ goto closem;
+ }
+ if (stat(file2, &stb2) < 0) {
+ cvs_log(LP_ERR, "%s", file2);
+ goto closem;
+ }
+ switch (files_differ(f1, f2)) {
+ case 0:
+ goto closem;
+ case 1:
+ break;
+ default:
+ /* error */
+ goto closem;
+ }
+
+ if (!asciifile(f1) || !asciifile(f2)) {
+ rval = D_BINARY;
+ goto closem;
+ }
+ if (prepare(0, f1, stb1.st_size) < 0 ||
+ prepare(1, f2, stb2.st_size) < 0) {
+ goto closem;
+ }
+ prune();
+ sort(sfile[0], slen[0]);
+ sort(sfile[1], slen[1]);
+
+ member = (int *)file[1];
+ equiv(sfile[0], slen[0], sfile[1], slen[1], member);
+ tmp = xrealloc(member, slen[1] + 2, sizeof(*member));
+ member = tmp;
+
+ class = (int *)file[0];
+ unsort(sfile[0], slen[0], class);
+ tmp = xrealloc(class, slen[0] + 2, sizeof(*class));
+ class = tmp;
+
+ klist = xcalloc(slen[0] + 2, sizeof(*klist));
+ clen = 0;
+ clistlen = 100;
+ clist = xcalloc(clistlen, sizeof(*clist));
+
+ if ((i = stone(class, slen[0], member, klist)) < 0)
+ goto closem;
+
+ xfree(member);
+ xfree(class);
+
+ tmp = xrealloc(J, diff_len[0] + 2, sizeof(*J));
+ J = tmp;
+ unravel(klist[i]);
+ xfree(clist);
+ xfree(klist);
+
+ tmp = xrealloc(ixold, diff_len[0] + 2, sizeof(*ixold));
+ ixold = tmp;
+
+ tmp = xrealloc(ixnew, diff_len[1] + 2, sizeof(*ixnew));
+ ixnew = tmp;
+ check(f1, f2);
+ output(f1, f2);
+
+closem:
+ if (anychange == 1) {
+ if (rval == D_SAME)
+ rval = D_DIFFER;
+ }
+ if (f1 != NULL)
+ fclose(f1);
+ if (f2 != NULL)
+ fclose(f2);
+
+ return (rval);
+}
+
+/*
+ * Check to see if the given files differ.
+ * Returns 0 if they are the same, 1 if different, and -1 on error.
+ * XXX - could use code from cmp(1) [faster]
+ */
+static int
+files_differ(FILE *f1, FILE *f2)
+{
+ char buf1[BUFSIZ], buf2[BUFSIZ];
+ size_t i, j;
+
+ if (stb1.st_size != stb2.st_size)
+ return (1);
+ for (;;) {
+ i = fread(buf1, (size_t)1, sizeof(buf1), f1);
+ j = fread(buf2, (size_t)1, sizeof(buf2), f2);
+ if (i != j)
+ return (1);
+ if (i == 0 && j == 0) {
+ if (ferror(f1) || ferror(f2))
+ return (1);
+ return (0);
+ }
+ if (memcmp(buf1, buf2, i) != 0)
+ return (1);
+ }
+}
+
+static int
+prepare(int i, FILE *fd, off_t filesize)
+{
+ void *tmp;
+ struct line *p;
+ int j, h;
+ size_t sz;
+
+ rewind(fd);
+
+ sz = ((size_t)filesize <= SIZE_MAX ? (size_t)filesize : SIZE_MAX) / 25;
+ if (sz < 100)
+ sz = 100;
+
+ p = xcalloc(sz + 3, sizeof(*p));
+ for (j = 0; (h = readhash(fd));) {
+ if (j == (int)sz) {
+ sz = sz * 3 / 2;
+ tmp = xrealloc(p, sz + 3, sizeof(*p));
+ p = tmp;
+ }
+ p[++j].value = h;
+ }
+ diff_len[i] = j;
+ file[i] = p;
+
+ return (0);
+}
+
+static void
+prune(void)
+{
+ int i, j;
+
+ for (pref = 0; pref < diff_len[0] && pref < diff_len[1] &&
+ file[0][pref + 1].value == file[1][pref + 1].value;
+ pref++)
+ ;
+ for (suff = 0;
+ (suff < diff_len[0] - pref) && (suff < diff_len[1] - pref) &&
+ (file[0][diff_len[0] - suff].value ==
+ file[1][diff_len[1] - suff].value);
+ suff++)
+ ;
+ for (j = 0; j < 2; j++) {
+ sfile[j] = file[j] + pref;
+ slen[j] = diff_len[j] - pref - suff;
+ for (i = 0; i <= slen[j]; i++)
+ sfile[j][i].serial = i;
+ }
+}
+
+static void
+equiv(struct line *a, int n, struct line *b, int m, int *c)
+{
+ int i, j;
+
+ i = j = 1;
+ while (i <= n && j <= m) {
+ if (a[i].value < b[j].value)
+ a[i++].value = 0;
+ else if (a[i].value == b[j].value)
+ a[i++].value = j;
+ else
+ j++;
+ }
+ while (i <= n)
+ a[i++].value = 0;
+ b[m + 1].value = 0;
+ j = 0;
+ while (++j <= m) {
+ c[j] = -b[j].serial;
+ while (b[j + 1].value == b[j].value) {
+ j++;
+ c[j] = b[j].serial;
+ }
+ }
+ c[j] = -1;
+}
+
+/* Code taken from ping.c */
+static int
+isqrt(int n)
+{
+ int y, x = 1;
+
+ if (n == 0)
+ return (0);
+
+ do { /* newton was a stinker */
+ y = x;
+ x = n / x;
+ x += y;
+ x /= 2;
+ } while (x - y > 1 || x - y < -1);
+
+ return (x);
+}
+
+static int
+stone(int *a, int n, int *b, int *c)
+{
+ int ret;
+ int i, k, y, j, l;
+ int oldc, tc, oldl;
+ u_int numtries;
+
+ /* XXX move the isqrt() out of the macro to avoid multiple calls */
+ const u_int bound = dflag ? UINT_MAX : MAX(256, (u_int)isqrt(n));
+
+ k = 0;
+ if ((ret = newcand(0, 0, 0)) < 0)
+ return (-1);
+ c[0] = ret;
+ for (i = 1; i <= n; i++) {
+ j = a[i];
+ if (j == 0)
+ continue;
+ y = -b[j];
+ oldl = 0;
+ oldc = c[0];
+ numtries = 0;
+ do {
+ if (y <= clist[oldc].y)
+ continue;
+ l = search(c, k, y);
+ if (l != oldl + 1)
+ oldc = c[l - 1];
+ if (l <= k) {
+ if (clist[c[l]].y <= y)
+ continue;
+ tc = c[l];
+ if ((ret = newcand(i, y, oldc)) < 0)
+ return (-1);
+ c[l] = ret;
+ oldc = tc;
+ oldl = l;
+ numtries++;
+ } else {
+ if ((ret = newcand(i, y, oldc)) < 0)
+ return (-1);
+ c[l] = ret;
+ k++;
+ break;
+ }
+ } while ((y = b[++j]) > 0 && numtries < bound);
+ }
+ return (k);
+}
+
+static int
+newcand(int x, int y, int pred)
+{
+ struct cand *q, *tmp;
+ int newclistlen;
+
+ if (clen == clistlen) {
+ newclistlen = clistlen * 11 / 10;
+ tmp = xrealloc(clist, newclistlen, sizeof(*clist));
+ clist = tmp;
+ clistlen = newclistlen;
+ }
+ q = clist + clen;
+ q->x = x;
+ q->y = y;
+ q->pred = pred;
+ return (clen++);
+}
+
+static int
+search(int *c, int k, int y)
+{
+ int i, j, l, t;
+
+ if (clist[c[k]].y < y) /* quick look for typical case */
+ return (k + 1);
+ i = 0;
+ j = k + 1;
+ for (;;) {
+ l = (i + j) / 2;
+ if (l <= i)
+ break;
+ t = clist[c[l]].y;
+ if (t > y)
+ j = l;
+ else if (t < y)
+ i = l;
+ else
+ return (l);
+ }
+ return (l + 1);
+}
+
+static void
+unravel(int p)
+{
+ struct cand *q;
+ int i;
+
+ for (i = 0; i <= diff_len[0]; i++)
+ J[i] = i <= pref ? i :
+ i > diff_len[0] - suff ? i + diff_len[1] - diff_len[0] : 0;
+ for (q = clist + p; q->y != 0; q = clist + q->pred)
+ J[q->x + pref] = q->y + pref;
+}
+
+/*
+ * Check does double duty:
+ * 1. ferret out any fortuitous correspondences due
+ * to confounding by hashing (which result in "jackpot")
+ * 2. collect random access indexes to the two files
+ */
+static void
+check(FILE *f1, FILE *f2)
+{
+ int i, j, jackpot, c, d;
+ long ctold, ctnew;
+
+ rewind(f1);
+ rewind(f2);
+ j = 1;
+ ixold[0] = ixnew[0] = 0;
+ jackpot = 0;
+ ctold = ctnew = 0;
+ for (i = 1; i <= diff_len[0]; i++) {
+ if (J[i] == 0) {
+ ixold[i] = ctold += skipline(f1);
+ continue;
+ }
+ while (j < J[i]) {
+ ixnew[j] = ctnew += skipline(f2);
+ j++;
+ }
+ if (bflag == 1 || wflag == 1 || iflag == 1) {
+ for (;;) {
+ c = getc(f1);
+ d = getc(f2);
+ /*
+ * GNU diff ignores a missing newline
+ * in one file if bflag || wflag.
+ */
+ if ((bflag == 1 || wflag == 1) &&
+ ((c == EOF && d == '\n') ||
+ (c == '\n' && d == EOF))) {
+ break;
+ }
+ ctold++;
+ ctnew++;
+ if (bflag == 1 && isspace(c) && isspace(d)) {
+ do {
+ if (c == '\n')
+ break;
+ ctold++;
+ } while (isspace(c = getc(f1)));
+ do {
+ if (d == '\n')
+ break;
+ ctnew++;
+ } while (isspace(d = getc(f2)));
+ } else if (wflag == 1) {
+ while (isspace(c) && c != '\n') {
+ c = getc(f1);
+ ctold++;
+ }
+ while (isspace(d) && d != '\n') {
+ d = getc(f2);
+ ctnew++;
+ }
+ }
+ if (chrtran[c] != chrtran[d]) {
+ jackpot++;
+ J[i] = 0;
+ if (c != '\n' && c != EOF)
+ ctold += skipline(f1);
+ if (d != '\n' && c != EOF)
+ ctnew += skipline(f2);
+ break;
+ }
+ if (c == '\n' || c == EOF)
+ break;
+ }
+ } else {
+ for (;;) {
+ ctold++;
+ ctnew++;
+ if ((c = getc(f1)) != (d = getc(f2))) {
+ /* jackpot++; */
+ J[i] = 0;
+ if (c != '\n' && c != EOF)
+ ctold += skipline(f1);
+ if (d != '\n' && c != EOF)
+ ctnew += skipline(f2);
+ break;
+ }
+ if (c == '\n' || c == EOF)
+ break;
+ }
+ }
+ ixold[i] = ctold;
+ ixnew[j] = ctnew;
+ j++;
+ }
+ for (; j <= diff_len[1]; j++)
+ ixnew[j] = ctnew += skipline(f2);
+ /*
+ * if (jackpot != 0)
+ * cvs_printf("jackpot\n");
+ */
+}
+
+/* shellsort CACM #201 */
+static void
+sort(struct line *a, int n)
+{
+ struct line *ai, *aim, w;
+ int j, m = 0, k;
+
+ if (n == 0)
+ return;
+ for (j = 1; j <= n; j *= 2)
+ m = 2 * j - 1;
+ for (m /= 2; m != 0; m /= 2) {
+ k = n - m;
+ for (j = 1; j <= k; j++) {
+ for (ai = &a[j]; ai > a; ai -= m) {
+ aim = &ai[m];
+ if (aim < ai)
+ break; /* wraparound */
+ if (aim->value > ai[0].value ||
+ (aim->value == ai[0].value &&
+ aim->serial > ai[0].serial))
+ break;
+ w.value = ai[0].value;
+ ai[0].value = aim->value;
+ aim->value = w.value;
+ w.serial = ai[0].serial;
+ ai[0].serial = aim->serial;
+ aim->serial = w.serial;
+ }
+ }
+ }
+}
+
+static void
+unsort(struct line *f, int l, int *b)
+{
+ int *a, i;
+
+ a = xcalloc(l + 1, sizeof(*a));
+ for (i = 1; i <= l; i++)
+ a[f[i].serial] = f[i].value;
+ for (i = 1; i <= l; i++)
+ b[i] = a[i];
+ xfree(a);
+}
+
+static int
+skipline(FILE *f)
+{
+ int i, c;
+
+ for (i = 1; (c = getc(f)) != '\n' && c != EOF; i++)
+ continue;
+ return (i);
+}
+
+static void
+output(FILE *f1, FILE *f2)
+{
+ int m, i0, i1, j0, j1;
+
+ rewind(f1);
+ rewind(f2);
+ m = diff_len[0];
+ J[0] = 0;
+ J[m + 1] = diff_len[1] + 1;
+ for (i0 = 1; i0 <= m; i0 = i1 + 1) {
+ while (i0 <= m && J[i0] == J[i0 - 1] + 1)
+ i0++;
+ j0 = J[i0 - 1] + 1;
+ i1 = i0 - 1;
+ while (i1 < m && J[i1 + 1] == 0)
+ i1++;
+ j1 = J[i1 + 1] - 1;
+ J[i1] = j1;
+ change(f1, f2, i0, i1, j0, j1);
+ }
+ if (m == 0)
+ change(f1, f2, 1, 0, 1, diff_len[1]);
+ if (diff_format == D_IFDEF) {
+ for (;;) {
+#define c i0
+ if ((c = getc(f1)) == EOF)
+ return;
+ diff_output("%c", c);
+ }
+#undef c
+ }
+ if (anychange != 0) {
+ if (diff_format == D_CONTEXT)
+ dump_context_vec(f1, f2);
+ else if (diff_format == D_UNIFIED)
+ dump_unified_vec(f1, f2);
+ }
+}
+
+static __inline void
+range(int a, int b, char *separator)
+{
+ diff_output("%d", a > b ? b : a);
+ if (a < b)
+ diff_output("%s%d", separator, b);
+}
+
+static __inline void
+uni_range(int a, int b)
+{
+ if (a < b)
+ diff_output("%d,%d", a, b - a + 1);
+ else if (a == b)
+ diff_output("%d", b);
+ else
+ diff_output("%d,0", b);
+}
+
+static char *
+preadline(int fd, size_t rlen, off_t off)
+{
+ char *line;
+ ssize_t nr;
+
+ line = xmalloc(rlen + 1);
+ if ((nr = pread(fd, line, rlen, off)) < 0) {
+ cvs_log(LP_ERR, "preadline failed");
+ return (NULL);
+ }
+ line[nr] = '\0';
+ return (line);
+}
+
+static int
+ignoreline(char *line)
+{
+ int ret;
+
+ ret = regexec(&ignore_re, line, (size_t)0, NULL, 0);
+ xfree(line);
+ return (ret == 0); /* if it matched, it should be ignored. */
+}
+
+/*
+ * Indicate that there is a difference between lines a and b of the from file
+ * to get to lines c to d of the to file. If a is greater then b then there
+ * are no lines in the from file involved and this means that there were
+ * lines appended (beginning at b). If c is greater than d then there are
+ * lines missing from the to file.
+ */
+static void
+change(FILE *f1, FILE *f2, int a, int b, int c, int d)
+{
+ int i;
+ static size_t max_context = 64;
+ char buf[64];
+ struct tm *t;
+
+ if (diff_format != D_IFDEF && a > b && c > d)
+ return;
+ if (ignore_pats != NULL) {
+ char *line;
+ /*
+ * All lines in the change, insert, or delete must
+ * match an ignore pattern for the change to be
+ * ignored.
+ */
+ if (a <= b) { /* Changes and deletes. */
+ for (i = a; i <= b; i++) {
+ line = preadline(fileno(f1),
+ ixold[i] - ixold[i - 1], ixold[i - 1]);
+ if (!ignoreline(line))
+ goto proceed;
+ }
+ }
+ if (a > b || c <= d) { /* Changes and inserts. */
+ for (i = c; i <= d; i++) {
+ line = preadline(fileno(f2),
+ ixnew[i] - ixnew[i - 1], ixnew[i - 1]);
+ if (!ignoreline(line))
+ goto proceed;
+ }
+ }
+ return;
+ }
+proceed:
+ if (diff_format == D_CONTEXT || diff_format == D_UNIFIED) {
+ /*
+ * Allocate change records as needed.
+ */
+ if (context_vec_ptr == context_vec_end - 1) {
+ struct context_vec *tmp;
+ ptrdiff_t offset = context_vec_ptr - context_vec_start;
+ max_context <<= 1;
+ tmp = xrealloc(context_vec_start, max_context,
+ sizeof(*context_vec_start));
+ context_vec_start = tmp;
+ context_vec_end = context_vec_start + max_context;
+ context_vec_ptr = context_vec_start + offset;
+ }
+ if (anychange == 0) {
+ /*
+ * Print the context/unidiff header first time through.
+ */
+ t = localtime(&stb1.st_mtime);
+ (void)strftime(buf, sizeof(buf),
+ "%d %b %G %H:%M:%S", t);
+
+ diff_output("%s %s %s",
+ diff_format == D_CONTEXT ? "***" : "---", diff_file,
+ buf);
+
+ if (diff_rev1 != NULL) {
+ rcsnum_tostr(diff_rev1, buf, sizeof(buf));
+ diff_output("\t%s", buf);
+ }
+
+ printf("\n");
+
+ t = localtime(&stb2.st_mtime);
+ (void)strftime(buf, sizeof(buf),
+ "%d %b %G %H:%M:%S", t);
+
+ diff_output("%s %s %s",
+ diff_format == D_CONTEXT ? "---" : "+++", diff_file,
+ buf);
+
+ if (diff_rev2 != NULL) {
+ rcsnum_tostr(diff_rev2, buf, sizeof(buf));
+ diff_output("\t%s", buf);
+ }
+
+ printf("\n");
+ anychange = 1;
+ } else if (a > context_vec_ptr->b + (2 * context) + 1 &&
+ c > context_vec_ptr->d + (2 * context) + 1) {
+ /*
+ * If this change is more than 'context' lines from the
+ * previous change, dump the record and reset it.
+ */
+ if (diff_format == D_CONTEXT)
+ dump_context_vec(f1, f2);
+ else
+ dump_unified_vec(f1, f2);
+ }
+ context_vec_ptr++;
+ context_vec_ptr->a = a;
+ context_vec_ptr->b = b;
+ context_vec_ptr->c = c;
+ context_vec_ptr->d = d;
+ return;
+ }
+ if (anychange == 0)
+ anychange = 1;
+ switch (diff_format) {
+ case D_BRIEF:
+ return;
+ case D_NORMAL:
+ range(a, b, ",");
+ diff_output("%c", a > b ? 'a' : c > d ? 'd' : 'c');
+ if (diff_format == D_NORMAL)
+ range(c, d, ",");
+ diff_output("\n");
+ break;
+ case D_RCSDIFF:
+ if (a > b)
+ diff_output("a%d %d\n", b, d - c + 1);
+ else {
+ diff_output("d%d %d\n", a, b - a + 1);
+
+ if (!(c > d)) /* add changed lines */
+ diff_output("a%d %d\n", b, d - c + 1);
+ }
+ break;
+ }
+ if (diff_format == D_NORMAL || diff_format == D_IFDEF) {
+ fetch(ixold, a, b, f1, '<', 1);
+ if (a <= b && c <= d && diff_format == D_NORMAL)
+ diff_output("---\n");
+ }
+ fetch(ixnew, c, d, f2, diff_format == D_NORMAL ? '>' : '\0', 0);
+ if (inifdef) {
+ diff_output("#endif /* %s */\n", ifdefname);
+ inifdef = 0;
+ }
+}
+
+static void
+fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile)
+{
+ long j, nc;
+ int i, c, col;
+
+ /*
+ * When doing #ifdef's, copy down to current line
+ * if this is the first file, so that stuff makes it to output.
+ */
+ if (diff_format == D_IFDEF && oldfile) {
+ long curpos = ftell(lb);
+ /* print through if append (a>b), else to (nb: 0 vs 1 orig) */
+ nc = f[a > b ? b : a - 1] - curpos;
+ for (i = 0; i < nc; i++)
+ diff_output("%c", getc(lb));
+ }
+ if (a > b)
+ return;
+ if (diff_format == D_IFDEF) {
+ if (inifdef) {
+ diff_output("#else /* %s%s */\n",
+ oldfile == 1 ? "!" : "", ifdefname);
+ } else {
+ if (oldfile)
+ diff_output("#ifndef %s\n", ifdefname);
+ else
+ diff_output("#ifdef %s\n", ifdefname);
+ }
+ inifdef = 1 + oldfile;
+ }
+ for (i = a; i <= b; i++) {
+ fseek(lb, f[i - 1], SEEK_SET);
+ nc = f[i] - f[i - 1];
+ if (diff_format != D_IFDEF && ch != '\0') {
+ diff_output("%c", ch);
+ if (Tflag == 1 && (diff_format == D_NORMAL ||
+ diff_format == D_CONTEXT ||
+ diff_format == D_UNIFIED))
+ diff_output("\t");
+ else if (diff_format != D_UNIFIED)
+ diff_output(" ");
+ }
+ col = 0;
+ for (j = 0; j < nc; j++) {
+ if ((c = getc(lb)) == EOF) {
+ if (diff_format == D_RCSDIFF)
+ cvs_log(LP_ERR,
+ "No newline at end of file");
+ else
+ diff_output("\n\\ No newline at end of "
+ "file");
+ return;
+ }
+ if (c == '\t' && tflag == 1) {
+ do {
+ diff_output(" ");
+ } while (++col & 7);
+ } else {
+ diff_output("%c", c);
+ col++;
+ }
+ }
+ }
+}
+
+/*
+ * Hash function taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578.
+ */
+static int
+readhash(FILE *f)
+{
+ int i, t, space;
+ int sum;
+
+ sum = 1;
+ space = 0;
+ if (bflag != 1 && wflag != 1) {
+ if (iflag == 1)
+ for (i = 0; (t = getc(f)) != '\n'; i++) {
+ if (t == EOF) {
+ if (i == 0)
+ return (0);
+ break;
+ }
+ sum = sum * 127 + chrtran[t];
+ }
+ else
+ for (i = 0; (t = getc(f)) != '\n'; i++) {
+ if (t == EOF) {
+ if (i == 0)
+ return (0);
+ break;
+ }
+ sum = sum * 127 + t;
+ }
+ } else {
+ for (i = 0;;) {
+ switch (t = getc(f)) {
+ case '\t':
+ case ' ':
+ space++;
+ continue;
+ default:
+ if (space != 0 && wflag != 1) {
+ i++;
+ space = 0;
+ }
+ sum = sum * 127 + chrtran[t];
+ i++;
+ continue;
+ case EOF:
+ if (i == 0)
+ return (0);
+ /* FALLTHROUGH */
+ case '\n':
+ break;
+ }
+ break;
+ }
+ }
+ /*
+ * There is a remote possibility that we end up with a zero sum.
+ * Zero is used as an EOF marker, so return 1 instead.
+ */
+ return (sum == 0 ? 1 : sum);
+}
+
+static int
+asciifile(FILE *f)
+{
+ char buf[BUFSIZ];
+ size_t i, cnt;
+
+ if (aflag == 1 || f == NULL)
+ return (1);
+
+ rewind(f);
+ cnt = fread(buf, (size_t)1, sizeof(buf), f);
+ for (i = 0; i < cnt; i++)
+ if (!isprint(buf[i]) && !isspace(buf[i]))
+ return (0);
+ return (1);
+}
+
+static char*
+match_function(const long *f, int pos, FILE *fp)
+{
+ unsigned char buf[FUNCTION_CONTEXT_SIZE];
+ size_t nc;
+ int last = lastline;
+ char *p;
+
+ lastline = pos;
+ while (pos > last) {
+ fseek(fp, f[pos - 1], SEEK_SET);
+ nc = f[pos] - f[pos - 1];
+ if (nc >= sizeof(buf))
+ nc = sizeof(buf) - 1;
+ nc = fread(buf, (size_t)1, nc, fp);
+ if (nc > 0) {
+ buf[nc] = '\0';
+ p = strchr((const char *)buf, '\n');
+ if (p != NULL)
+ *p = '\0';
+ if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') {
+ strlcpy(lastbuf, (const char *)buf,
+ sizeof lastbuf);
+ lastmatchline = pos;
+ return lastbuf;
+ }
+ }
+ pos--;
+ }
+ return (lastmatchline > 0) ? lastbuf : NULL;
+}
+
+
+/* dump accumulated "context" diff changes */
+static void
+dump_context_vec(FILE *f1, FILE *f2)
+{
+ struct context_vec *cvp = context_vec_start;
+ int lowa, upb, lowc, upd, do_output;
+ int a, b, c, d;
+ char ch, *f;
+
+ if (context_vec_start > context_vec_ptr)
+ return;
+
+ b = d = 0; /* gcc */
+ lowa = MAX(1, cvp->a - context);
+ upb = MIN(diff_len[0], context_vec_ptr->b + context);
+ lowc = MAX(1, cvp->c - context);
+ upd = MIN(diff_len[1], context_vec_ptr->d + context);
+
+ diff_output("***************");
+ if (pflag == 1) {
+ f = match_function(ixold, lowa - 1, f1);
+ if (f != NULL) {
+ diff_output(" ");
+ diff_output("%s", f);
+ }
+ }
+ diff_output("\n*** ");
+ range(lowa, upb, ",");
+ diff_output(" ****\n");
+
+ /*
+ * Output changes to the "old" file. The first loop suppresses
+ * output if there were no changes to the "old" file (we'll see
+ * the "old" lines as context in the "new" list).
+ */
+ do_output = 0;
+ for (; cvp <= context_vec_ptr; cvp++)
+ if (cvp->a <= cvp->b) {
+ cvp = context_vec_start;
+ do_output++;
+ break;
+ }
+ if (do_output != 0) {
+ while (cvp <= context_vec_ptr) {
+ a = cvp->a;
+ b = cvp->b;
+ c = cvp->c;
+ d = cvp->d;
+
+ if (a <= b && c <= d)
+ ch = 'c';
+ else
+ ch = (a <= b) ? 'd' : 'a';
+
+ if (ch == 'a')
+ fetch(ixold, lowa, b, f1, ' ', 0);
+ else {
+ fetch(ixold, lowa, a - 1, f1, ' ', 0);
+ fetch(ixold, a, b, f1,
+ ch == 'c' ? '!' : '-', 0);
+ }
+ lowa = b + 1;
+ cvp++;
+ }
+ fetch(ixold, b + 1, upb, f1, ' ', 0);
+ }
+ /* output changes to the "new" file */
+ diff_output("--- ");
+ range(lowc, upd, ",");
+ diff_output(" ----\n");
+
+ do_output = 0;
+ for (cvp = context_vec_start; cvp <= context_vec_ptr; cvp++)
+ if (cvp->c <= cvp->d) {
+ cvp = context_vec_start;
+ do_output++;
+ break;
+ }
+ if (do_output != 0) {
+ while (cvp <= context_vec_ptr) {
+ a = cvp->a;
+ b = cvp->b;
+ c = cvp->c;
+ d = cvp->d;
+
+ if (a <= b && c <= d)
+ ch = 'c';
+ else
+ ch = (a <= b) ? 'd' : 'a';
+
+ if (ch == 'd')
+ fetch(ixnew, lowc, d, f2, ' ', 0);
+ else {
+ fetch(ixnew, lowc, c - 1, f2, ' ', 0);
+ fetch(ixnew, c, d, f2,
+ ch == 'c' ? '!' : '+', 0);
+ }
+ lowc = d + 1;
+ cvp++;
+ }
+ fetch(ixnew, d + 1, upd, f2, ' ', 0);
+ }
+ context_vec_ptr = context_vec_start - 1;
+}
+
+/* dump accumulated "unified" diff changes */
+static void
+dump_unified_vec(FILE *f1, FILE *f2)
+{
+ struct context_vec *cvp = context_vec_start;
+ int lowa, upb, lowc, upd;
+ int a, b, c, d;
+ char ch, *f;
+
+ if (context_vec_start > context_vec_ptr)
+ return;
+
+ b = d = 0; /* gcc */
+ lowa = MAX(1, cvp->a - context);
+ upb = MIN(diff_len[0], context_vec_ptr->b + context);
+ lowc = MAX(1, cvp->c - context);
+ upd = MIN(diff_len[1], context_vec_ptr->d + context);
+
+ diff_output("@@ -");
+ uni_range(lowa, upb);
+ diff_output(" +");
+ uni_range(lowc, upd);
+ diff_output(" @@");
+ if (pflag == 1) {
+ f = match_function(ixold, lowa - 1, f1);
+ if (f != NULL) {
+ diff_output(" ");
+ diff_output("%s", f);
+ }
+ }
+ diff_output("\n");
+
+ /*
+ * Output changes in "unified" diff format--the old and new lines
+ * are printed together.
+ */
+ for (; cvp <= context_vec_ptr; cvp++) {
+ a = cvp->a;
+ b = cvp->b;
+ c = cvp->c;
+ d = cvp->d;
+
+ /*
+ * c: both new and old changes
+ * d: only changes in the old file
+ * a: only changes in the new file
+ */
+ if (a <= b && c <= d)
+ ch = 'c';
+ else
+ ch = (a <= b) ? 'd' : 'a';
+
+ switch (ch) {
+ case 'c':
+ fetch(ixold, lowa, a - 1, f1, ' ', 0);
+ fetch(ixold, a, b, f1, '-', 0);
+ fetch(ixnew, c, d, f2, '+', 0);
+ break;
+ case 'd':
+ fetch(ixold, lowa, a - 1, f1, ' ', 0);
+ fetch(ixold, a, b, f1, '-', 0);
+ break;
+ case 'a':
+ fetch(ixnew, lowc, c - 1, f2, ' ', 0);
+ fetch(ixnew, c, d, f2, '+', 0);
+ break;
+ }
+ lowa = b + 1;
+ lowc = d + 1;
+ }
+ fetch(ixnew, d + 1, upd, f2, ' ', 0);
+
+ context_vec_ptr = context_vec_start - 1;
+}
+
+void
+diff_output(const char *fmt, ...)
+{
+ va_list vap;
+ int i;
+ char *str;
+
+ va_start(vap, fmt);
+ i = vasprintf(&str, fmt, vap);
+ va_end(vap);
+ if (i == -1)
+ fatal("diff_output: %s", strerror(errno));
+ if (diffbuf != NULL)
+ cvs_buf_append(diffbuf, str, strlen(str));
+ else
+ cvs_printf("%s", str);
+ xfree(str);
+}
diff --git a/usr.bin/cvs/edit.c b/usr.bin/cvs/edit.c
deleted file mode 100644
index 23d78757e7d..00000000000
--- a/usr.bin/cvs/edit.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/* $OpenBSD: edit.c,v 1.12 2006/03/16 09:06:19 xsa Exp $ */
-/*
- * Copyright (c) 2005 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-
-static int cvs_edit_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_edit_remote(CVSFILE *, void *);
-static int cvs_edit_local(CVSFILE *, void *);
-
-static int cvs_editors_remote(CVSFILE *, void *);
-
-
-struct cvs_cmd cvs_cmd_edit = {
- CVS_OP_EDIT, CVS_REQ_NOOP, "edit",
- { },
- "Mark a file as being edited",
- "[-lR] [-a action] [file ...]",
- "a:lR",
- NULL,
- CF_SORT | CF_RECURSE,
- cvs_edit_init,
- NULL,
- cvs_edit_remote,
- cvs_edit_local,
- NULL,
- NULL,
- 0
-};
-
-struct cvs_cmd cvs_cmd_editors = {
- CVS_OP_EDITORS, CVS_REQ_EDITORS, "editors",
- { },
- "List editors on a file",
- "[-lR] [file ...]",
- "lR",
- NULL,
- CF_SORT | CF_RECURSE,
- cvs_edit_init,
- NULL,
- cvs_editors_remote,
- NULL,
- NULL,
- NULL,
- CVS_CMD_SENDDIR | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDARGS2
-};
-
-
-struct cvs_cmd cvs_cmd_unedit = {
- CVS_OP_UNEDIT, CVS_REQ_NOOP, "unedit",
- { },
- "Undo an edit command",
- "[-lR] [file ...]",
- "lR",
- NULL,
- CF_SORT | CF_RECURSE,
- cvs_edit_init,
- NULL,
- cvs_edit_remote,
- cvs_edit_local,
- NULL,
- NULL,
- 0
-};
-
-
-
-static int
-cvs_edit_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'a':
- /*
- * The `editors' and `unedit' commands do not have
- * the -a option. Check which command has been issued.
- */
- if (cvs_cmdop != CVS_OP_EDIT)
- return (CVS_EX_USAGE);
- break;
- case 'l':
- cmd->file_flags &= ~CF_RECURSE;
- break;
- case 'R':
- cmd->file_flags |= CF_RECURSE;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- *arg = optind;
- return (CVS_EX_OK);
-}
-
-
-/*
- * cvs_edit_remote()
- *
- */
-static int
-cvs_edit_remote(CVSFILE *cf, void *arg)
-{
- return (CVS_EX_OK);
-}
-
-
-/*
- * cvs_edit_local()
- *
- */
-static int
-cvs_edit_local(CVSFILE *cf, void *arg)
-{
- return (CVS_EX_OK);
-}
-
-
-/*
- * cvs_editors_remote()
- *
- */
-static int
-cvs_editors_remote(CVSFILE *cf, void *arg)
-{
- struct cvsroot *root;
-
- root = CVS_DIR_ROOT(cf);
-
- if (cf->cf_type == DT_DIR) {
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- else
- cvs_senddir(root, cf);
- return (0);
- }
-
- cvs_sendentry(root, cf);
-
- switch (cf->cf_cvstat) {
- case CVS_FST_UNKNOWN:
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- break;
- case CVS_FST_UPTODATE:
- cvs_sendreq(root, CVS_REQ_UNCHANGED, cf->cf_name);
- break;
- case CVS_FST_ADDED:
- case CVS_FST_MODIFIED:
- cvs_sendreq(root, CVS_REQ_ISMODIFIED, cf->cf_name);
- break;
- default:
- break;
- }
-
- return (0);
-}
diff --git a/usr.bin/cvs/entries.c b/usr.bin/cvs/entries.c
index d3dfe84e5cb..8db8457b787 100644
--- a/usr.bin/cvs/entries.c
+++ b/usr.bin/cvs/entries.c
@@ -1,27 +1,18 @@
-/* $OpenBSD: entries.c,v 1.56 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: entries.c,v 1.57 2006/05/27 03:30:30 joris Exp $ */
/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
@@ -29,486 +20,314 @@
#include "cvs.h"
#include "log.h"
-
#define CVS_ENTRIES_NFIELDS 6
#define CVS_ENTRIES_DELIM '/'
+static struct cvs_ent_line *ent_get_line(CVSENTRIES *, const char *);
-/*
- * cvs_ent_open()
- *
- * Open the CVS Entries file for the directory <dir>.
- * Returns a pointer to the CVSENTRIES file structure on success, or NULL
- * on failure.
- */
CVSENTRIES *
-cvs_ent_open(const char *dir, int flags)
+cvs_ent_open(const char *dir)
{
- size_t len;
- int exists, nodir;
- char bpath[MAXPATHLEN], *p;
- char cdpath[MAXPATHLEN], ebuf[CVS_ENT_MAXLINELEN], entpath[MAXPATHLEN];
- char mode[4];
FILE *fp;
- struct stat st;
- struct cvs_ent *ent;
+ size_t len;
CVSENTRIES *ep;
+ char *p, buf[MAXPATHLEN];
+ struct cvs_ent *ent;
+ struct cvs_ent_line *line;
- exists = 0;
- nodir = 1;
- memset(mode, 0, sizeof(mode));
-
- /*
- * Check if the CVS/ dir does exist. If it does,
- * maybe the Entries file was deleted by accident,
- * display error message. Else we might be doing a fresh
- * update or checkout of a module.
- */
- len = cvs_path_cat(dir, CVS_PATH_CVSDIR, cdpath, sizeof(cdpath));
- if (len >= sizeof(cdpath))
- return (NULL);
-
- if (stat(cdpath, &st) == 0 && S_ISDIR(st.st_mode))
- nodir = 0; /* the CVS/ directory does exist */
-
- len = cvs_path_cat(dir, CVS_PATH_BACKUPENTRIES, bpath, sizeof(bpath));
- if (len >= sizeof(entpath))
- return (NULL);
-
- len = cvs_path_cat(dir, CVS_PATH_ENTRIES, entpath, sizeof(entpath));
- if (len >= sizeof(entpath))
- return (NULL);
+ ep = (CVSENTRIES *)xmalloc(sizeof(*ep));
+ memset(ep, 0, sizeof(*ep));
- switch (flags & O_ACCMODE) {
- case O_WRONLY:
- case O_RDWR:
- /* we have to use append otherwise the file gets truncated */
- mode[0] = 'w';
- mode[1] = '+';
- break;
- case O_RDONLY:
- mode[0] = 'r';
- break;
- }
+ cvs_path_cat(dir, CVS_PATH_ENTRIES, buf, sizeof(buf));
+ ep->cef_path = xstrdup(buf);
- /* we can use 'r' if the file already exists */
- if (stat(entpath, &st) == 0) {
- exists = 1;
- mode[0] = 'r';
- }
-
- fp = fopen(entpath, mode);
- if (fp == NULL) {
- if (nodir == 0)
- cvs_log(LP_ERRNO, "cannot open %s for %s", entpath,
- mode[1] == '+' ? "writing" : "reading");
- return (NULL);
- }
+ cvs_path_cat(dir, CVS_PATH_BACKUPENTRIES, buf, sizeof(buf));
+ ep->cef_bpath = xstrdup(buf);
- ep = xcalloc(1, sizeof(*ep));
+ cvs_path_cat(dir, CVS_PATH_LOGENTRIES, buf, sizeof(buf));
+ ep->cef_lpath = xstrdup(buf);
- ep->cef_path = xstrdup(entpath);
- ep->cef_bpath = xstrdup(bpath);
- ep->cef_cur = NULL;
TAILQ_INIT(&(ep->cef_ent));
- while (fgets(ebuf, (int)sizeof(ebuf), fp) != NULL) {
- len = strlen(ebuf);
- if (len > 0 && ebuf[len - 1] == '\n')
- ebuf[--len] = '\0';
- if (ebuf[0] == 'D' && ebuf[1] == '\0')
- break;
- ent = cvs_ent_parse(ebuf);
- if (ent == NULL)
- continue;
-
- TAILQ_INSERT_TAIL(&(ep->cef_ent), ent, ce_list);
- }
-
- if (ferror(fp)) {
- cvs_log(LP_ERRNO, "read error on %s", entpath);
- (void)fclose(fp);
- cvs_ent_close(ep);
- return (NULL);
- }
+ if ((fp = fopen(ep->cef_path, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fp)) {
+ len = strlen(buf);
+ if (len > 0 && buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
- /* only keep a pointer to the open file if we're in writing mode */
- if ((flags & O_WRONLY) || (flags & O_RDWR))
- ep->cef_flags |= CVS_ENTF_WR;
+ if (buf[0] == 'D' && buf[1] == '\0')
+ break;
- (void)fclose(fp);
+ line = (struct cvs_ent_line *)xmalloc(sizeof(*line));
+ line->buf = xstrdup(buf);
+ TAILQ_INSERT_TAIL(&(ep->cef_ent), line, entries_list);
+ }
- /*
- * look for Entries.Log and add merge it together with our
- * list of things.
- */
- len = cvs_path_cat(dir, CVS_PATH_LOGENTRIES, entpath, sizeof(entpath));
- if (len >= sizeof(entpath)) {
- cvs_ent_close(ep);
- return (NULL);
+ (void)fclose(fp);
}
- fp = fopen(entpath, "r");
- if (fp != NULL) {
- while (fgets(ebuf, (int)sizeof(ebuf), fp) != NULL) {
- len = strlen(ebuf);
- if (len > 0 && ebuf[len - 1] == '\n')
- ebuf[--len] = '\0';
-
- p = &ebuf[2];
- ent = cvs_ent_parse(p);
- if (ent == NULL)
- continue;
-
- if (ebuf[0] == 'A')
- cvs_ent_add(ep, ent);
- else if (ebuf[0] == 'R')
- cvs_ent_remove(ep, ent->ce_name, 0);
+ if ((fp = fopen(ep->cef_lpath, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf), fp)) {
+ len = strlen(buf);
+ if (len > 0 && buf[strlen(buf) - 1] == '\n')
+ buf[strlen(buf) - 1] = '\0';
+
+ p = &buf[1];
+
+ if (buf[0] == 'A') {
+ line = xmalloc(sizeof(*line));
+ line->buf = xstrdup(p);
+ TAILQ_INSERT_TAIL(&(ep->cef_ent), line,
+ entries_list);
+ } else if (buf[0] == 'R') {
+ ent = cvs_ent_parse(p);
+ line = ent_get_line(ep, ent->ce_name);
+ if (line != NULL)
+ TAILQ_REMOVE(&(ep->cef_ent), line,
+ entries_list);
+ cvs_ent_free(ent);
+ }
}
- (void)fclose(fp);
- /* always un-synced here, because we
- * just added or removed entries.
- */
- ep->cef_flags &= ~CVS_ENTF_SYNC;
- } else {
- if (exists == 1)
- ep->cef_flags |= CVS_ENTF_SYNC;
+ (void)fclose(fp);
}
return (ep);
}
-
-/*
- * cvs_ent_close()
- *
- * 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 *
+cvs_ent_parse(const char *entry)
{
+ int i;
struct cvs_ent *ent;
+ char *fields[CVS_ENTRIES_NFIELDS], *buf, *sp, *dp;
- if (cvs_noexec == 0 && (ep->cef_flags & CVS_ENTF_WR) &&
- !(ep->cef_flags & CVS_ENTF_SYNC)) {
- /* implicit sync with disk */
- (void)cvs_ent_write(ep);
- }
+ buf = xstrdup(entry);
+ sp = buf;
+ i = 0;
+ do {
+ dp = strchr(sp, CVS_ENTRIES_DELIM);
+ if (dp != NULL)
+ *(dp++) = '\0';
+ fields[i++] = sp;
+ sp = dp;
+ } while (dp != NULL && i < CVS_ENTRIES_NFIELDS);
- if (ep->cef_path != NULL)
- xfree(ep->cef_path);
+ if (i < CVS_ENTRIES_NFIELDS)
+ fatal("missing fields in entry line '%s'", entry);
- if (ep->cef_bpath != NULL)
- xfree(ep->cef_bpath);
+ ent = (struct cvs_ent *)xmalloc(sizeof(*ent));
+ ent->ce_buf = buf;
- while (!TAILQ_EMPTY(&(ep->cef_ent))) {
- ent = TAILQ_FIRST(&(ep->cef_ent));
- TAILQ_REMOVE(&(ep->cef_ent), ent, ce_list);
- cvs_ent_free(ent);
- }
+ if (*fields[0] == '\0')
+ ent->ce_type = CVS_ENT_FILE;
+ else if (*fields[0] == 'D')
+ ent->ce_type = CVS_ENT_DIR;
+ else
+ ent->ce_type = CVS_ENT_NONE;
- xfree(ep);
-}
+ ent->ce_status = CVS_ENT_REG;
+ ent->ce_name = fields[1];
+ ent->ce_rev = NULL;
+ if (ent->ce_type == CVS_ENT_FILE) {
+ if (*fields[2] == '-') {
+ ent->ce_status = CVS_ENT_REMOVED;
+ sp = fields[2] + 1;
+ } else {
+ sp = fields[2];
+ if (fields[2][0] == '0' && fields[2][1] == '\0')
+ ent->ce_status = CVS_ENT_ADDED;
+ }
-/*
- * cvs_ent_add()
- *
- * Add the entry <ent> to the Entries file <ef>. The disk contents are not
- * modified until a call to cvs_ent_write() is performed. This is done
- * implicitly on a call to cvs_ent_close() on an Entries file that has been
- * opened for writing.
- * Returns 0 on success, or -1 on failure.
- */
-int
-cvs_ent_add(CVSENTRIES *ef, struct cvs_ent *ent)
-{
- if (!(ef->cef_flags & CVS_ENTF_WR)) {
- cvs_log(LP_ERR, "Entries file is opened in read-only mode");
- return (-1);
- }
+ if ((ent->ce_rev = rcsnum_parse(sp)) == NULL)
+ fatal("failed to parse entry revision '%s'", entry);
- if (cvs_ent_get(ef, ent->ce_name) != NULL) {
- cvs_log(LP_ERR, "attempt to add duplicate entry for `%s'",
- ent->ce_name);
- return (-1);
+ if (strcmp(fields[3], CVS_DATE_DUMMY) == 0 ||
+ strncmp(fields[3], "Initial ", 8) == 0 ||
+ strncmp(fields[3], "Result of merge", 15) == 0)
+ ent->ce_mtime = CVS_DATE_DMSEC;
+ else
+ ent->ce_mtime = cvs_date_parse(fields[3]);
}
- TAILQ_INSERT_TAIL(&(ef->cef_ent), ent, ce_list);
+ ent->ce_conflict = fields[3];
+ if ((dp = strchr(ent->ce_conflict, '+')) != NULL)
+ *dp = '\0';
+ else
+ ent->ce_conflict = NULL;
- ef->cef_flags &= ~CVS_ENTF_SYNC;
+ if (strcmp(fields[4], ""))
+ ent->ce_opts = fields[4];
+ else
+ ent->ce_opts = NULL;
- return (0);
-}
+ if (strcmp(fields[5], ""))
+ ent->ce_tag = fields[5];
+ else
+ ent->ce_tag = NULL;
+ return (ent);
+}
-/*
- * cvs_ent_addln()
- *
- * Add a line to the Entries file.
- */
-int
-cvs_ent_addln(CVSENTRIES *ef, const char *line)
+struct cvs_ent *
+cvs_ent_get(CVSENTRIES *ep, const char *name)
{
struct cvs_ent *ent;
+ struct cvs_ent_line *l;
- if (!(ef->cef_flags & CVS_ENTF_WR)) {
- cvs_log(LP_ERR, "Entries file is opened in read-only mode");
- return (-1);
- }
+ l = ent_get_line(ep, name);
+ if (l == NULL)
+ return (NULL);
- ent = cvs_ent_parse(line);
- if (ent == NULL)
- return (-1);
+ ent = cvs_ent_parse(l->buf);
+ return (ent);
+}
- if (cvs_ent_get(ef, ent->ce_name) != NULL)
- return (-1);
+int
+cvs_ent_exists(CVSENTRIES *ep, const char *name)
+{
+ struct cvs_ent_line *l;
- TAILQ_INSERT_TAIL(&(ef->cef_ent), ent, ce_list);
- ef->cef_flags &= ~CVS_ENTF_SYNC;
+ l = ent_get_line(ep, name);
+ if (l == NULL)
+ return (0);
- return (0);
+ return (1);
}
-
-/*
- * cvs_ent_remove()
- *
- * Remove an entry from the Entries file <ef>. The entry's name is given
- * by <name>.
- */
-int
-cvs_ent_remove(CVSENTRIES *ef, const char *name, int useprev)
+void
+cvs_ent_close(CVSENTRIES *ep, int writefile)
{
- struct cvs_ent *ent;
-
- cvs_log(LP_TRACE, "cvs_ent_remove(%s)", name);
+ FILE *fp;
+ struct cvs_ent_line *l;
- ent = cvs_ent_get(ef, name);
- if (ent == NULL)
- return (-1);
+ if (writefile) {
+ if ((fp = fopen(ep->cef_bpath, "w")) == NULL)
+ fatal("cvs_ent_close: failed to write %s",
+ ep->cef_path);
+ }
- if (ef->cef_cur == ent) {
- /* if this element was the last one retrieved through a
- * call to cvs_ent_next(), point to the next element to avoid
- * keeping an invalid reference.
- */
- if (useprev) {
- ef->cef_cur = TAILQ_PREV(ef->cef_cur,
- cvsentrieshead, ce_list);
- } else {
- ef->cef_cur = TAILQ_NEXT(ef->cef_cur, ce_list);
+ while ((l = TAILQ_FIRST(&(ep->cef_ent))) != NULL) {
+ if (writefile) {
+ fputs(l->buf, fp);
+ fputc('\n', fp);
}
+
+ TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
+ xfree(l->buf);
+ xfree(l);
}
- TAILQ_REMOVE(&(ef->cef_ent), ent, ce_list);
- cvs_ent_free(ent);
- ef->cef_flags &= ~CVS_ENTF_SYNC;
+ if (writefile) {
+ fputc('D', fp);
+ (void)fclose(fp);
- return (0);
-}
+ if (rename(ep->cef_bpath, ep->cef_path) == -1)
+ fatal("cvs_ent_close: %s: %s", ep->cef_path,
+ strerror(errno));
+ (void)unlink(ep->cef_lpath);
+ }
-/*
- * cvs_ent_get()
- *
- * Get the CVS entry from the Entries file <ef> whose 'name' portion matches
- * <file>.
- * Returns a pointer to the cvs entry structure on success, or NULL on failure.
- */
-struct cvs_ent *
-cvs_ent_get(CVSENTRIES *ef, const char *file)
+ xfree(ep->cef_path);
+ xfree(ep->cef_bpath);
+ xfree(ep->cef_lpath);
+ xfree(ep);
+}
+
+void
+cvs_ent_add(CVSENTRIES *ep, const char *line)
{
+ FILE *fp;
+ struct cvs_ent_line *l;
struct cvs_ent *ent;
- TAILQ_FOREACH(ent, &(ef->cef_ent), ce_list)
- if (strcmp(ent->ce_name, file) == 0)
- return (ent);
+ if ((ent = cvs_ent_parse(line)) == NULL)
+ fatal("cvs_ent_add: parsing failed '%s'", line);
- return (NULL);
-}
+ l = ent_get_line(ep, ent->ce_name);
+ if (l != NULL)
+ cvs_ent_remove(ep, ent->ce_name);
+ cvs_ent_free(ent);
-/*
- * cvs_ent_next()
- *
- * This function is used to iterate over the entries in an Entries file. The
- * first call will return the first entry of the file and each subsequent call
- * will return the entry following the last one returned.
- * Returns a pointer to the cvs entry structure on success, or NULL on failure.
- */
-struct cvs_ent *
-cvs_ent_next(CVSENTRIES *ef)
-{
- if (ef->cef_cur == NULL)
- ef->cef_cur = TAILQ_FIRST(&(ef->cef_ent));
- else
- ef->cef_cur = TAILQ_NEXT(ef->cef_cur, ce_list);
- return (ef->cef_cur);
-}
+ cvs_log(LP_TRACE, "cvs_ent_add(%s, %s)", ep->cef_path, line);
+ if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
+ fatal("cvs_ent_add: failed to open '%s'", ep->cef_lpath);
-/*
- * cvs_ent_parse()
- *
- * Parse a single line from a CVS/Entries file and return a cvs_ent structure
- * containing all the parsed information.
- */
-struct cvs_ent*
-cvs_ent_parse(const char *entry)
-{
- int i;
- char *fields[CVS_ENTRIES_NFIELDS], *buf, *sp, *dp;
- struct cvs_ent *ent;
+ fputc('A', fp);
+ fputs(line, fp);
+ fputc('\n', fp);
- buf = xstrdup(entry);
- sp = buf;
- i = 0;
- do {
- dp = strchr(sp, CVS_ENTRIES_DELIM);
- if (dp != NULL)
- *(dp++) = '\0';
- fields[i++] = sp;
- sp = dp;
- } while (dp != NULL && i < CVS_ENTRIES_NFIELDS);
+ (void)fclose(fp);
- if (i < CVS_ENTRIES_NFIELDS) {
- cvs_log(LP_ERR, "missing fields in entry line `%s'", entry);
- return (NULL);
- }
+ l = (struct cvs_ent_line *)xmalloc(sizeof(*l));
+ l->buf = xstrdup(line);
+ TAILQ_INSERT_TAIL(&(ep->cef_ent), l, entries_list);
+}
- ent = xcalloc(1, sizeof(*ent));
- ent->ce_buf = buf;
+void
+cvs_ent_remove(CVSENTRIES *ep, const char *name)
+{
+ FILE *fp;
+ struct cvs_ent_line *l;
- if (*fields[0] == '\0')
- ent->ce_type = CVS_ENT_FILE;
- else if (*fields[0] == 'D')
- ent->ce_type = CVS_ENT_DIR;
- else
- ent->ce_type = CVS_ENT_NONE;
+ cvs_log(LP_TRACE, "cvs_ent_remove(%s, %s)", ep->cef_path, name);
- ent->ce_status = CVS_ENT_REG;
- ent->ce_name = fields[1];
- ent->processed = 0;
+ l = ent_get_line(ep, name);
+ if (l == NULL)
+ return;
- if (ent->ce_type == CVS_ENT_FILE) {
- if (*fields[2] == '-') {
- ent->ce_status = CVS_ENT_REMOVED;
- sp = fields[2] + 1;
- } else {
- sp = fields[2];
- if (fields[2][0] == '0' && fields[2][1] == '\0')
- ent->ce_status = CVS_ENT_ADDED;
- }
+ if ((fp = fopen(ep->cef_lpath, "a")) == NULL)
+ fatal("cvs_ent_remove: failed to open '%s'",
+ ep->cef_lpath);
- if ((ent->ce_rev = rcsnum_parse(sp)) == NULL) {
- cvs_ent_free(ent);
- return (NULL);
- }
+ fputc('R', fp);
+ fputs(l->buf, fp);
+ fputc('\n', fp);
- if (cvs_cmdop == CVS_OP_SERVER) {
- if (!strcmp(fields[3], "up to date"))
- ent->ce_status = CVS_ENT_UPTODATE;
- } else {
- if (strcmp(fields[3], CVS_DATE_DUMMY) == 0 ||
- strncmp(fields[3], "Initial ", 8) == 0)
- ent->ce_mtime = CVS_DATE_DMSEC;
- else
- ent->ce_mtime = cvs_date_parse(fields[3]);
- }
- }
+ (void)fclose(fp);
- ent->ce_opts = fields[4];
- ent->ce_tag = fields[5];
- return (ent);
+ TAILQ_REMOVE(&(ep->cef_ent), l, entries_list);
+ xfree(l->buf);
+ xfree(l);
}
-/*
- * 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_buf != NULL)
- xfree(ent->ce_buf);
+ xfree(ent->ce_buf);
xfree(ent);
}
-/*
- * cvs_ent_write()
- *
- * Explicitly write the contents of the Entries file <ef> to disk.
- * Returns 0 on success, or -1 on failure.
- */
-int
-cvs_ent_write(CVSENTRIES *ef)
+static struct cvs_ent_line *
+ent_get_line(CVSENTRIES *ep, const char *name)
{
- size_t len;
- char revbuf[64], timebuf[32];
- struct cvs_ent *ent;
- FILE *fp;
+ char *p, *s;
+ struct cvs_ent_line *l;
- if (ef->cef_flags & CVS_ENTF_SYNC)
- return (0);
+ TAILQ_FOREACH(l, &(ep->cef_ent), entries_list) {
+ if (l->buf[0] == 'D')
+ p = &(l->buf[2]);
+ else
+ p = &(l->buf[1]);
- if ((fp = fopen(ef->cef_bpath, "w")) == NULL) {
- cvs_log(LP_ERRNO, "failed to open Entries `%s'", ef->cef_bpath);
- return (-1);
- }
+ if ((s = strchr(p, '/')) == NULL)
+ fatal("ent_get_line: bad entry line '%s'", l->buf);
- TAILQ_FOREACH(ent, &(ef->cef_ent), ce_list) {
- if (ent->ce_type == CVS_ENT_DIR) {
- putc('D', fp);
- timebuf[0] = '\0';
- revbuf[0] = '\0';
- } else {
- rcsnum_tostr(ent->ce_rev, revbuf, sizeof(revbuf));
- if (ent->ce_mtime == CVS_DATE_DMSEC &&
- ent->ce_status != CVS_ENT_ADDED)
- strlcpy(timebuf, CVS_DATE_DUMMY,
- sizeof(timebuf));
- else if (ent->ce_status == CVS_ENT_ADDED) {
- strlcpy(timebuf, "Initial ", sizeof(timebuf));
- strlcat(timebuf, ent->ce_name, sizeof(timebuf));
- } else {
- ctime_r(&(ent->ce_mtime), timebuf);
- len = strlen(timebuf);
- if (len > 0 && timebuf[len - 1] == '\n')
- timebuf[--len] = '\0';
- }
- }
+ *s = '\0';
- if (cvs_cmdop == CVS_OP_SERVER) {
- if (ent->ce_status == CVS_ENT_UPTODATE)
- strlcpy(timebuf, "up to date", sizeof(timebuf));
- else
- timebuf[0] = '\0';
+ if (!strcmp(p, name)) {
+ *s = '/';
+ return (l);
}
- fprintf(fp, "/%s/%s%s/%s/%s/%s\n", ent->ce_name,
- (ent->ce_status == CVS_ENT_REMOVED) ? "-" : "", revbuf,
- timebuf, (ent->ce_opts != NULL) ? ent->ce_opts : "",
- (ent->ce_tag != NULL) ? ent->ce_tag : "");
+ *s = '/';
}
- /* terminating line */
- putc('D', fp);
- putc('\n', fp);
-
- ef->cef_flags |= CVS_ENTF_SYNC;
- fclose(fp);
-
- /* rename Entries.Backup to Entries */
- cvs_rename(ef->cef_bpath, ef->cef_path);
-
- /* remove Entries.Log */
- cvs_unlink(CVS_PATH_LOGENTRIES);
-
- return (0);
+ return (NULL);
}
diff --git a/usr.bin/cvs/fatal.c b/usr.bin/cvs/fatal.c
index 7eb37d25c1c..8bf10f68cf4 100644
--- a/usr.bin/cvs/fatal.c
+++ b/usr.bin/cvs/fatal.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fatal.c,v 1.6 2006/01/30 15:49:18 niallo Exp $ */
+/* $OpenBSD: fatal.c,v 1.7 2006/05/27 03:30:30 joris Exp $ */
/*
* Copyright (c) 2002 Markus Friedl. All rights reserved.
*
@@ -38,5 +38,8 @@ fatal(const char *fmt,...)
va_start(args, fmt);
cvs_vlog(LP_ABORT, fmt, args);
va_end(args);
+
+ cvs_cleanup();
+
exit(1);
}
diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c
index f5b2de74053..1f46f3b21d1 100644
--- a/usr.bin/cvs/file.c
+++ b/usr.bin/cvs/file.c
@@ -1,5 +1,6 @@
-/* $OpenBSD: file.c,v 1.137 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: file.c,v 1.138 2006/05/27 03:30:30 joris Exp $ */
/*
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
*
@@ -34,13 +35,6 @@
#define CVS_CHAR_ISMETA(c) ((c == '*') || (c == '?') || (c == '['))
-/* ignore pattern */
-struct cvs_ignpat {
- char ip_pat[MAXNAMLEN];
- int ip_flags;
- TAILQ_ENTRY(cvs_ignpat) ip_list;
-};
-
/*
* Standard patterns to ignore.
*/
@@ -48,7 +42,6 @@ static const char *cvs_ign_std[] = {
".",
"..",
"*.o",
- "*.so",
"*.a",
"*.bak",
"*.orig",
@@ -68,65 +61,35 @@ static const char *cvs_ign_std[] = {
"*~",
"_$*",
"*$",
-#ifdef OLD_SMELLY_CRUFT
- "RCSLOG",
- "tags",
- "TAGS",
- "RCS",
- "SCCS",
- "cvslog.*", /* to ignore CVS_CLIENT_LOG output */
- "#*",
- ",*",
-#endif
};
-/*
- * Entries in the CVS/Entries file with a revision of '0' have only been
- * added. Compare against this revision to see if this is the case
- */
-static RCSNUM *cvs_addedrev;
-
-TAILQ_HEAD(, cvs_ignpat) cvs_ign_pats;
-
-static int cvs_file_getdir(CVSFILE *, int, int (*)(CVSFILE *, void *),
- void *, int);
+struct ignore_head cvs_ign_pats;
+struct ignore_head dir_ign_pats;
-static int cvs_load_dirinfo(CVSFILE *, int);
-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 *);
-static CVSFILE *cvs_file_alloc(const char *, u_int);
-static CVSFILE *cvs_file_lget(const char *, int, CVSFILE *, CVSENTRIES *,
- struct cvs_ent *);
+static int cvs_file_cmpname(const char *, const char *);
-/*
- * cvs_file_init()
- *
- */
-int
+void
cvs_file_init(void)
{
int i, l;
- size_t len;
- char path[MAXPATHLEN], buf[MAXNAMLEN];
FILE *ifp;
+ size_t len;
+ char *path, *buf;
- TAILQ_INIT(&cvs_ign_pats);
+ path = xmalloc(MAXPATHLEN);
+ buf = xmalloc(MAXNAMLEN);
- if ((cvs_addedrev = rcsnum_parse("0")) == NULL)
- return (-1);
+ TAILQ_INIT(&cvs_ign_pats);
+ TAILQ_INIT(&dir_ign_pats);
/* standard patterns to ignore */
for (i = 0; i < (int)(sizeof(cvs_ign_std)/sizeof(char *)); i++)
- cvs_file_ignore(cvs_ign_std[i]);
+ cvs_file_ignore(cvs_ign_std[i], &cvs_ign_pats);
/* read the cvsignore file in the user's home directory, if any */
- l = snprintf(path, sizeof(path), "%s/.cvsignore", cvs_homedir);
- if (l == -1 || l >= (int)sizeof(path)) {
- errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", path);
- return (-1);
- }
+ l = snprintf(path, MAXPATHLEN, "%s/.cvsignore", cvs_homedir);
+ if (l == -1 || l >= MAXPATHLEN)
+ fatal("overflow in cvs_file_init");
ifp = fopen(path, "r");
if (ifp == NULL) {
@@ -134,36 +97,36 @@ cvs_file_init(void)
cvs_log(LP_ERRNO,
"failed to open user's cvsignore file `%s'", path);
} else {
- while (fgets(buf, (int)sizeof(buf), ifp) != NULL) {
+ while (fgets(buf, MAXNAMLEN, ifp) != NULL) {
len = strlen(buf);
if (len == 0)
continue;
- if (buf[len - 1] != '\n') {
+
+ if (buf[len - 1] != '\n')
cvs_log(LP_ERR, "line too long in `%s'", path);
- }
+
buf[--len] = '\0';
- cvs_file_ignore(buf);
+ cvs_file_ignore(buf, &cvs_ign_pats);
}
+
(void)fclose(ifp);
}
- return (0);
+ xfree(path);
+ xfree(buf);
}
-/*
- * cvs_file_ignore()
- *
- * Add the pattern <pat> to the list of patterns for files to ignore.
- * Returns 0 on success, or -1 on failure.
- */
-int
-cvs_file_ignore(const char *pat)
+void
+cvs_file_ignore(const char *pat, struct ignore_head *list)
{
char *cp;
+ size_t len;
struct cvs_ignpat *ip;
ip = xmalloc(sizeof(*ip));
- strlcpy(ip->ip_pat, pat, sizeof(ip->ip_pat));
+ len = strlcpy(ip->ip_pat, pat, sizeof(ip->ip_pat));
+ if (len >= sizeof(ip->ip_pat))
+ fatal("cvs_file_ignore: truncation of pattern '%s'", pat);
/* check if we will need globbing for that pattern */
ip->ip_flags = CVS_IGN_STATIC;
@@ -174,17 +137,9 @@ cvs_file_ignore(const char *pat)
}
}
- TAILQ_INSERT_TAIL(&cvs_ign_pats, ip, ip_list);
-
- return (0);
+ TAILQ_INSERT_TAIL(list, ip, ip_list);
}
-/*
- * cvs_file_chkign()
- *
- * Returns 1 if the filename <file> is matched by one of the ignore
- * patterns, or 0 otherwise.
- */
int
cvs_file_chkign(const char *file)
{
@@ -203,1093 +158,596 @@ cvs_file_chkign(const char *file)
return (1);
}
+ TAILQ_FOREACH(ip, &dir_ign_pats, ip_list) {
+ if (ip->ip_flags & CVS_IGN_STATIC) {
+ if (cvs_file_cmpname(file, ip->ip_pat) == 0)
+ return (1);
+ } else if (fnmatch(ip->ip_pat, file, flags) == 0)
+ return (1);
+ }
+
return (0);
}
-/*
- * cvs_file_create()
- *
- * Create a new file whose path is specified in <path> and of type <type>.
- * If the type is DT_DIR, the CVS administrative repository and files will be
- * created.
- * Returns the created file on success, or NULL on failure.
- */
-CVSFILE *
-cvs_file_create(CVSFILE *parent, const char *path, u_int type, mode_t mode)
+void
+cvs_file_run(int argc, char **argv, struct cvs_recursion *cr)
{
- int fd, l;
- char fp[MAXPATHLEN], repo[MAXPATHLEN];
- CVSFILE *cfp;
-
- cfp = cvs_file_alloc(path, type);
- if (cfp == NULL)
- return (NULL);
-
- l = 0;
- cfp->cf_mode = mode;
- cfp->cf_parent = parent;
-
- if (type == DT_DIR) {
- cfp->cf_root = cvsroot_get(path);
- if (cfp->cf_root == NULL) {
- cvs_file_free(cfp);
- return (NULL);
- }
-
- if (cvs_repo_base != NULL) {
- cvs_file_getpath(cfp, fp, sizeof(fp));
- l = snprintf(repo, sizeof(repo), "%s/%s", cvs_repo_base,
- fp);
- } else {
- cvs_file_getpath(cfp, repo, sizeof(repo));
- l = 0;
- }
+ int i;
+ struct cvs_flisthead fl;
- if (l == -1 || l >= (int)sizeof(repo)) {
- errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", repo);
- cvs_file_free(cfp);
- return (NULL);
- }
+ TAILQ_INIT(&fl);
- cfp->cf_repo = xstrdup(repo);
- if ((mkdir(path, mode) == -1 && errno != EEXIST) ||
- cvs_mkadmin(path, cfp->cf_root->cr_str, cfp->cf_repo,
- NULL, NULL, 0) < 0) {
- cvs_file_free(cfp);
- return (NULL);
- }
- } else {
- fd = open(path, O_WRONLY|O_CREAT|O_EXCL, mode);
- if (fd == -1) {
- cvs_file_free(cfp);
- return (NULL);
- }
- (void)close(fd);
- }
+ for (i = 0; i < argc; i++)
+ cvs_file_get(argv[i], &fl);
- return (cfp);
+ cvs_file_walklist(&fl, cr);
+ cvs_file_freelist(&fl);
}
-
-/*
- * cvs_file_copy()
- *
- * Allocate space to create a copy of the file <orig>. The copy inherits all
- * of the original's attributes, but does not inherit its children if the
- * original file is a directory. Note that files copied using this mechanism
- * are linked to their parent, but the parent has no link to the file. This
- * is so cvs_file_getpath() works.
- * Returns the copied file on success, or NULL on failure. The returned
- * structure should be freed using cvs_file_free().
- */
-CVSFILE *
-cvs_file_copy(CVSFILE *orig)
+struct cvs_filelist *
+cvs_file_get(const char *name, struct cvs_flisthead *fl)
{
- char path[MAXPATHLEN];
- CVSFILE *cfp;
-
- cvs_file_getpath(orig, path, sizeof(path));
-
- cfp = cvs_file_alloc(path, orig->cf_type);
- if (cfp == NULL)
- return (NULL);
+ const char *p;
+ struct cvs_filelist *l;
- cfp->cf_parent = orig->cf_parent;
- cfp->cf_mode = orig->cf_mode;
- cfp->cf_cvstat = orig->cf_cvstat;
+ for (p = name; p[0] == '.' && p[1] == '/';)
+ p += 2;
- if (orig->cf_type == DT_REG) {
- cfp->cf_etime = orig->cf_etime;
- cfp->cf_mtime = orig->cf_mtime;
- } else if (orig->cf_type == DT_DIR) {
- /* XXX copy CVS directory attributes */
- }
-
- return (cfp);
-}
-
-
-/*
- * cvs_file_get()
- *
- * 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_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().
- */
+ TAILQ_FOREACH(l, fl, flist)
+ if (!strcmp(l->file_path, p))
+ return (l);
-int
-cvs_file_get(const char *path, int flags, int (*cb)(CVSFILE *, void *),
- void *arg, struct cvs_flist *list)
-{
- char *files[1];
+ l = (struct cvs_filelist *)xmalloc(sizeof(*l));
+ l->file_path = xstrdup(p);
- *(const char **)files = path;
- return cvs_file_getspec(files, 1, flags, cb, arg, list);
+ TAILQ_INSERT_TAIL(fl, l, flist);
+ return (l);
}
-
-/*
- * cvs_file_getspec()
- *
- * Obtain the info about the supplied files or directories.
- */
-int
-cvs_file_getspec(char **fspec, int fsn, int flags, int (*cb)(CVSFILE *, void *),
- void *arg, struct cvs_flist *list)
+struct cvs_file *
+cvs_file_get_cf(const char *d, const char *f, int fd, int type)
{
- int i, freecf;
- char pcopy[MAXPATHLEN];
- CVSFILE *cf;
- extern char *cvs_rootstr;
-
- freecf = (list == NULL);
- cvs_error = CVS_EX_DATA;
+ int l;
+ struct cvs_file *cf;
+ char *p, *rpath;
- /* init the list */
- if (list != NULL)
- SIMPLEQ_INIT(list);
+ rpath = xmalloc(MAXPATHLEN);
- /*
- * Fetch the needed information about ".", so we can setup a few
- * things to get ourselfs going.
- */
- cf = cvs_file_lget(".", 0, NULL, NULL, NULL);
- if (cf == NULL) {
- cvs_log(LP_ERR, "failed to obtain '.' information");
- return (-1);
- }
+ l = snprintf(rpath, MAXPATHLEN, "%s/%s", d, f);
+ if (l == -1 || l >= MAXPATHLEN)
+ fatal("cvs_file_get_cf: overflow");
- /*
- * save the base repository path so we can use it to create
- * the correct full repopath later on.
- */
- if (cf->cf_repo != NULL) {
- if (cvs_repo_base != NULL)
- xfree(cvs_repo_base);
- cvs_repo_base = xstrdup(cf->cf_repo);
- }
+ for (p = rpath; p[0] == '.' && p[1] == '/';)
+ p += 2;
- /*
- * This will go away when we have support for multiple Roots.
- */
- if (cvs_rootstr == NULL && cf->cf_root != NULL) {
- cvs_rootstr = xstrdup(cf->cf_root->cr_str);
- }
+ cf = (struct cvs_file *)xmalloc(sizeof(*cf));
+ memset(cf, 0, sizeof(*cf));
- cvs_error = CVS_EX_OK;
+ cf->file_name = xstrdup(f);
+ cf->file_wd = xstrdup(d);
+ cf->file_path = xstrdup(p);
+ cf->fd = fd;
+ cf->repo_fd = -1;
+ cf->file_type = type;
+ cf->file_status = cf->file_flags = 0;
+ cf->file_ent = NULL;
- /*
- * Since some commands don't require any files to operate
- * we can stop right here for those.
- */
- if (cf->cf_root != NULL) {
- if (cf->cf_root->cr_method != CVS_METHOD_LOCAL &&
- cvs_cmdop == CVS_OP_CHECKOUT) {
- cvs_file_free(cf);
- return (0);
- }
- }
+ xfree(rpath);
+ return (cf);
+}
- cvs_file_free(cf);
+void
+cvs_file_walklist(struct cvs_flisthead *fl, struct cvs_recursion *cr)
+{
+ int len, fd, type;
+ struct stat st;
+ struct cvs_file *cf;
+ struct cvs_filelist *l, *nxt;
+ char *d, *f, *repo, *fpath;
+
+ fpath = xmalloc(MAXPATHLEN);
+ repo = xmalloc(MAXPATHLEN);
+
+ for (l = TAILQ_FIRST(fl); l != NULL; l = nxt) {
+ if (cvs_quit)
+ fatal("received signal %d", sig_received);
+
+ cvs_log(LP_TRACE, "cvs_file_walklist: element '%s'",
+ l->file_path);
+
+ if ((f = basename(l->file_path)) == NULL)
+ fatal("cvs_file_walklist: basename failed");
+ if ((d = dirname(l->file_path)) == NULL)
+ fatal("cvs_file_walklist: dirname failed");
+
+ if ((fd = open(l->file_path, O_RDONLY)) != -1) {
+ if (fstat(fd, &st) == -1) {
+ cvs_log(LP_ERRNO, "%s", l->file_path);
+ (void)close(fd);
+ goto next;
+ }
- if (cvs_cmdop == CVS_OP_VERSION)
- return (0);
+ if (S_ISDIR(st.st_mode))
+ type = CVS_DIR;
+ else if (S_ISREG(st.st_mode))
+ type = CVS_FILE;
+ else {
+ cvs_log(LP_ERR,
+ "ignoring bad file type for %s",
+ l->file_path);
+ (void)close(fd);
+ goto next;
+ }
+ } else {
+ if (stat(d, &st) == -1) {
+ cvs_log(LP_ERRNO, "%s", d);
+ goto next;
+ }
- for (i = 0; i < fsn; i++) {
- strlcpy(pcopy, fspec[i], sizeof(pcopy));
+ cvs_get_repo(d, repo, MAXPATHLEN);
+ len = snprintf(fpath, MAXPATHLEN, "%s/%s",
+ repo, f);
+ if (len == -1 || len >= MAXPATHLEN)
+ fatal("cvs_file_walklist: overflow");
- /*
- * get rid of any trailing slashes.
- */
- STRIP_SLASH(pcopy);
+ if ((fd = open(fpath, O_RDONLY)) == -1) {
+ strlcat(fpath, RCS_FILE_EXT, MAXPATHLEN);
+ fd = open(fpath, O_RDONLY);
+ }
- /*
- * Load the information.
- */
- cf = cvs_file_loadinfo(pcopy, flags, cb, arg, freecf);
- if (cf == NULL) {
- if (cvs_error != CVS_EX_OK)
- return (-1);
- continue;
+ if (fd != -1) {
+ if (fstat(fd, &st) == -1)
+ fatal("cvs_file_walklist: %s: %s",
+ fpath, strerror(errno));
+
+ if (S_ISDIR(st.st_mode))
+ type = CVS_DIR;
+ else if (S_ISREG(st.st_mode))
+ type = CVS_FILE;
+ else {
+ cvs_log(LP_ERR,
+ "ignoring bad file type for %s",
+ l->file_path);
+ (void)close(fd);
+ goto next;
+ }
+
+ /* this file is not in our working copy yet */
+ (void)close(fd);
+ fd = -1;
+ }
}
- /*
- * If extra actions are needed, do them now.
- */
- if (cf->cf_type == DT_DIR) {
- /* do possible extra actions .. */
+ cf = cvs_file_get_cf(d, f, fd, type);
+ if (cf->file_type == CVS_DIR) {
+ cvs_file_walkdir(cf, cr);
} else {
- /* do possible extra actions .. */
+ if (cr->local != NULL)
+ cr->local(cf);
}
- /*
- * Attach it to a list if requested, otherwise
- * just free it again.
- */
- if (list != NULL)
- SIMPLEQ_INSERT_TAIL(list, cf, cf_list);
- else
- cvs_file_free(cf);
+ cvs_file_free(cf);
+
+next:
+ nxt = TAILQ_NEXT(l, flist);
+ TAILQ_REMOVE(fl, l, flist);
+
+ xfree(l->file_path);
+ xfree(l);
}
- return (0);
+ xfree(fpath);
+ xfree(repo);
}
-/*
- * Load the neccesary information about file or directory <path>.
- * Returns a pointer to the loaded information on success, or NULL
- * on failure.
- *
- * If cb is not NULL, the requested path will be passed to that callback
- * with <arg> as an argument.
- *
- * the <freecf> argument is passed to cvs_file_getdir, if this is 1
- * CVSFILE * structs will be free'd once we are done with them.
- */
-CVSFILE *
-cvs_file_loadinfo(char *path, int flags, int (*cb)(CVSFILE *, void *),
- void *arg, int freecf)
+void
+cvs_file_walkdir(struct cvs_file *cf, struct cvs_recursion *cr)
{
- CVSFILE *cf, *base;
- CVSENTRIES *entf;
- struct cvs_ent *ent;
- char *p;
- char parent[MAXPATHLEN], item[MAXPATHLEN];
- int type, callit;
+ int l;
+ FILE *fp;
+ int nbytes;
+ size_t len;
+ long base;
+ size_t bufsize;
struct stat st;
- struct cvsroot *root;
+ struct dirent *dp;
+ struct cvs_ent *ent;
+ struct cvs_ignpat *ip;
+ struct cvs_ent_line *line;
+ struct cvs_flisthead fl, dl;
+ CVSENTRIES *entlist;
+ char *buf, *ebuf, *cp, *repo, *fpath;
- type = 0;
- base = cf = NULL;
- entf = NULL;
- ent = NULL;
+ cvs_log(LP_TRACE, "cvs_file_walkdir(%s)", cf->file_path);
- /*
- * We first have to find out what type of item we are
- * dealing with. A file or a directory.
- *
- * We can do this by stat(2)'ing the item, but since it
- * might be gone we also check the Entries file in the
- * parent directory.
- */
+ if (cr->enterdir != NULL)
+ cr->enterdir(cf);
- /* get parent directory */
- if ((p = strrchr(path, '/')) != NULL) {
- *p++ = '\0';
- strlcpy(parent, path, sizeof(parent));
- strlcpy(item, p, sizeof(item));
- *--p = '/';
- } else {
- strlcpy(parent, ".", sizeof(parent));
- strlcpy(item, path, sizeof(item));
- }
-
- /*
- * There might not be an Entries file, so do not fail if there
- * is none available to get the info from.
- */
- entf = cvs_ent_open(parent, O_RDWR);
+ if (cr->local != NULL)
+ cr->local(cf);
- /*
- * Load the Entry if we successfully opened the Entries file.
- */
- if (entf != NULL)
- ent = cvs_ent_get(entf, item);
+ repo = xmalloc(MAXPATHLEN);
+ fpath = xmalloc(MAXPATHLEN);
/*
- * No Entry available? fall back to stat(2)'ing the item, if
- * that fails, assume a normal file.
+ * If we do not have a admin directory inside here, dont bother.
*/
- if (ent == NULL) {
- if (stat(path, &st) == -1)
- type = DT_REG;
- else
- type = IFTODT(st.st_mode);
- } else {
- if (ent->ce_type == CVS_ENT_DIR)
- type = DT_DIR;
- else
- type = DT_REG;
- }
+ l = snprintf(fpath, MAXPATHLEN, "%s/%s", cf->file_path,
+ CVS_PATH_CVSDIR);
+ if (l == -1 || l >= MAXPATHLEN)
+ fatal("cvs_file_walkdir: overflow");
- /*
- * Get the base, which is <parent> for a normal file or
- * <path> for a directory.
- */
- if (type == DT_DIR)
- base = cvs_file_lget(path, flags, NULL, entf, ent);
- else
- base = cvs_file_lget(parent, flags, NULL, entf, NULL);
-
- if (base == NULL) {
- cvs_log(LP_ERR, "failed to obtain directory info for '%s'",
- parent);
- cvs_error = CVS_EX_FILE;
- goto fail;
+ if (stat(fpath, &st) == -1) {
+ xfree(repo);
+ xfree(fpath);
+ return;
}
/*
- * Sanity.
+ * check for a local .cvsignore file
*/
- if (base->cf_type != DT_DIR) {
- cvs_log(LP_ERR, "base directory isn't a directory at all");
- goto fail;
- }
+ l = snprintf(fpath, MAXPATHLEN, "%s/.cvsignore", cf->file_path);
+ if (l == -1 || l >= MAXPATHLEN)
+ fatal("cvs_file_walkdir: overflow");
- root = CVS_DIR_ROOT(base);
- if (root == NULL) {
- cvs_error = CVS_EX_BADROOT;
- goto fail;
- }
+ if ((fp = fopen(fpath, "r")) != NULL) {
+ while (fgets(fpath, MAXPATHLEN, fp)) {
+ len = strlen(fpath);
+ if (fpath[len - 1] == '\n')
+ fpath[len - 1] = '\0';
- /*
- * If we have a normal file, get the info and link it
- * to the base.
- */
- if (type != DT_DIR) {
- cf = cvs_file_lget(path, flags, base, entf, ent);
- if (cf == NULL) {
- cvs_error = CVS_EX_DATA;
- goto fail;
+ cvs_file_ignore(fpath, &dir_ign_pats);
}
- cvs_file_attach(base, cf);
+ (void)fclose(fp);
}
- /*
- * Always pass the base directory, unless:
- * - we are running in server or local mode and the path is not "."
- * - the directory does not exist on disk.
- * - the callback is NULL.
- */
- callit = 1;
- if (cb == NULL)
- callit = 0;
-
- if (cvs_cmdop == CVS_OP_SERVER && type != DT_DIR)
- callit = 0;
-
- if (root->cr_method == CVS_METHOD_LOCAL && type != DT_DIR)
- callit = 0;
-
- if (!(base->cf_flags & CVS_FILE_ONDISK))
- callit = 0;
-
- if (callit != 0) {
- if ((cvs_error = cb(base,arg)) != CVS_EX_OK)
- goto fail;
- }
+ if (fstat(cf->fd, &st) == -1)
+ fatal("cvs_file_walkdir: %s %s", cf->file_path,
+ strerror(errno));
- /*
- * If we have a normal file, pass it as well.
- */
- if (type != DT_DIR) {
- if (cb != NULL && (cvs_error = cb(cf, arg)) != CVS_EX_OK)
- goto fail;
- } else {
- /*
- * If the directory exists, recurse through it.
- */
- if ((base->cf_flags & CVS_FILE_ONDISK) &&
- cvs_file_getdir(base, flags, cb, arg, freecf) < 0) {
- cvs_error = CVS_EX_FILE;
- goto fail;
- }
- }
+ bufsize = st.st_size;
+ if (bufsize < st.st_blksize)
+ bufsize = st.st_blksize;
- if (entf != NULL) {
- cvs_ent_close(entf);
- entf = NULL;
- }
+ buf = xmalloc(bufsize);
+ TAILQ_INIT(&fl);
+ TAILQ_INIT(&dl);
- return (base);
+ while ((nbytes = getdirentries(cf->fd, buf, bufsize, &base)) > 0) {
+ ebuf = buf + nbytes;
+ cp = buf;
-fail:
- if (entf != NULL)
- cvs_ent_close(entf);
- if (base != NULL)
- cvs_file_free(base);
- return (NULL);
-}
-
-/*
- * cvs_file_find()
- *
- * Find the pointer to a CVS file entry within the file hierarchy <hier>.
- * The file's pathname <path> must be relative to the base of <hier>.
- * Returns the entry on success, or NULL on failure.
- */
-CVSFILE *
-cvs_file_find(CVSFILE *hier, const char *path)
-{
- char *pp, *sp, pbuf[MAXPATHLEN];
- CVSFILE *sf, *cf;
-
- strlcpy(pbuf, path, sizeof(pbuf));
-
- cf = hier;
- pp = pbuf;
- do {
- sp = strchr(pp, '/');
- if (sp != NULL)
- *(sp++) = '\0';
-
- /* special case */
- if (*pp == '.') {
- if (*(pp + 1) == '.' && *(pp + 2) == '\0') {
- /* request to go back to parent */
- if (cf->cf_parent == NULL) {
- cvs_log(LP_NOTICE,
- "path %s goes back too far", path);
- return (NULL);
- }
- cf = cf->cf_parent;
- continue;
- } else if (*(pp + 1) == '\0')
+ while (cp < ebuf) {
+ dp = (struct dirent *)cp;
+ if (!strcmp(dp->d_name, ".") ||
+ !strcmp(dp->d_name, "..") ||
+ !strcmp(dp->d_name, CVS_PATH_CVSDIR) ||
+ dp->d_reclen == 0) {
+ cp += dp->d_reclen;
continue;
- }
-
- SIMPLEQ_FOREACH(sf, &(cf->cf_files), cf_list)
- if (cvs_file_cmpname(pp, sf->cf_name) == 0)
- break;
- if (sf == NULL)
- return (NULL);
-
- cf = sf;
- pp = sp;
- } while (sp != NULL);
-
- return (cf);
-}
-
-
-/*
- * cvs_file_getpath()
- *
- * Get the full path of the file <file> and store it in <buf>, which is of
- * size <len>. For portability, it is recommended that <buf> always be
- * at least MAXPATHLEN bytes long.
- * Returns a pointer to the start of the path.
- */
-char *
-cvs_file_getpath(CVSFILE *file, char *buf, size_t len)
-{
- memset(buf, '\0', len);
- if (file->cf_dir != NULL) {
- strlcat(buf, file->cf_dir, len);
- strlcat(buf, "/", len);
- }
-
- strlcat(buf, file->cf_name, len);
- return (buf);
-}
-
-/*
- * cvs_file_attach()
- *
- * Attach the file <file> as one of the children of parent <parent>, which
- * has to be a file of type DT_DIR.
- * Returns 0 on success, or -1 on failure.
- */
-int
-cvs_file_attach(CVSFILE *parent, CVSFILE *file)
-{
- if (parent->cf_type != DT_DIR)
- return (-1);
-
- SIMPLEQ_INSERT_TAIL(&(parent->cf_files), file, cf_list);
- file->cf_parent = parent;
-
- return (0);
-}
-
-
-/*
- * Load directory information
- */
-static int
-cvs_load_dirinfo(CVSFILE *cf, int flags)
-{
- char fpath[MAXPATHLEN];
- char pbuf[MAXPATHLEN];
- struct stat st;
- int l;
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
+ }
- /*
- * Try to obtain the Root for this given directory, if we cannot
- * get it, fail, unless we are dealing with a directory that is
- * unknown or not on disk.
- */
- cf->cf_root = cvsroot_get(fpath);
- if (cf->cf_root == NULL) {
- if (cf->cf_cvstat == CVS_FST_UNKNOWN ||
- !(cf->cf_flags & CVS_FILE_ONDISK))
- return (0);
- return (-1);
- }
+ if (cvs_file_chkign(dp->d_name)) {
+ cp += dp->d_reclen;
+ continue;
+ }
- /* 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)) {
- errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", pbuf);
- return (-1);
+ l = snprintf(fpath, MAXPATHLEN, "%s/%s",
+ cf->file_path, dp->d_name);
+ if (l == -1 || l >= MAXPATHLEN)
+ fatal("cvs_file_walkdir: overflow");
+
+ /*
+ * Anticipate the file type to sort them,
+ * note that we do not determine the final
+ * type until we actually have the fd floating
+ * around.
+ */
+ if (dp->d_type == DT_DIR)
+ cvs_file_get(fpath, &dl);
+ else if (dp->d_type == DT_REG)
+ cvs_file_get(fpath, &fl);
+
+ cp += dp->d_reclen;
+ }
}
- if (stat(pbuf, &st) == 0 && S_ISDIR(st.st_mode)) {
- if (cvs_readrepo(fpath, pbuf, sizeof(pbuf)) == 0)
- cf->cf_repo = xstrdup(pbuf);
- } else {
- /*
- * Fill in the repo path ourselfs.
- */
- if (cvs_repo_base != NULL) {
- l = snprintf(pbuf, sizeof(pbuf), "%s/%s",
- cvs_repo_base, fpath);
- if (l == -1 || l >= (int)sizeof(pbuf))
- return (-1);
-
- cf->cf_repo = xstrdup(pbuf);
- } else
- cf->cf_repo = NULL;
- }
+ if (nbytes == -1)
+ fatal("cvs_file_walkdir: %s %s", cf->file_path,
+ strerror(errno));
- return (0);
-}
+ xfree(buf);
-/*
- * 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, int (*cb)(CVSFILE *, void *),
- void *arg, int freecf)
-{
- int ret;
- size_t len;
- DIR *dp;
- struct dirent *de;
- char fpath[MAXPATHLEN], pbuf[MAXPATHLEN];
- CVSENTRIES *entf;
- CVSFILE *cfp;
- struct cvs_ent *ent;
- struct cvs_flist dirs;
- int nfiles, ndirs;
-
- if ((flags & CF_KNOWN) && cf->cf_cvstat == CVS_FST_UNKNOWN)
- return (0);
-
- /*
- * if we are working with a repository, fiddle with
- * the pathname again.
- */
- if (flags & CF_REPO) {
- ret = snprintf(fpath, sizeof(fpath), "%s%s%s",
- cf->cf_root->cr_dir,
- (cf->cf_dir != NULL) ? "/" : "",
- (cf->cf_dir != NULL) ? cf->cf_dir : "");
- if (ret == -1 || ret >= (int)sizeof(fpath))
- return (-1);
-
- if (cf->cf_dir != NULL)
- xfree(cf->cf_dir);
- cf->cf_dir = xstrdup(fpath);
+ while ((ip = TAILQ_FIRST(&dir_ign_pats)) != NULL) {
+ TAILQ_REMOVE(&dir_ign_pats, ip, ip_list);
+ xfree(ip);
}
- nfiles = ndirs = 0;
- SIMPLEQ_INIT(&dirs);
- cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- if ((dp = opendir(fpath)) == NULL) {
- cvs_log(LP_ERRNO, "failed to open directory '%s'", fpath);
- return (-1);
- }
-
- ret = -1;
- entf = cvs_ent_open(fpath, O_RDWR);
- while ((de = readdir(dp)) != NULL) {
- if (!strcmp(de->d_name, ".") ||
- !strcmp(de->d_name, ".."))
- continue;
-
- len = cvs_path_cat(fpath, de->d_name, pbuf, sizeof(pbuf));
- if (len >= sizeof(pbuf))
- goto done;
-
- if (entf != NULL)
- ent = cvs_ent_get(entf, de->d_name);
- else
- ent = NULL;
-
- /*
- * Do some filtering on the current directory item.
- */
- if ((flags & CF_IGNORE) && cvs_file_chkign(de->d_name))
- continue;
-
- if (!(flags & CF_RECURSE) && (de->d_type == DT_DIR)) {
- if (ent != NULL)
- ent->processed = 1;
- continue;
- }
-
- if (de->d_type != DT_DIR && (flags & CF_NOFILES))
- continue;
+ entlist = cvs_ent_open(cf->file_path);
+ TAILQ_FOREACH(line, &(entlist->cef_ent), entries_list) {
+ ent = cvs_ent_parse(line->buf);
- cfp = cvs_file_lget(pbuf, flags, cf, entf, ent);
- if (cfp == NULL) {
- cvs_log(LP_ERR, "failed to get '%s'", pbuf);
- goto done;
- }
-
- /*
- * A file is linked to the parent <cf>, a directory
- * is added to the dirs SIMPLEQ list for later use.
- */
- if (cfp->cf_type != DT_DIR && !freecf) {
- SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
- nfiles++;
- } else if (cfp->cf_type == DT_DIR) {
- SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list);
- ndirs++;
- }
+ l = snprintf(fpath, MAXPATHLEN, "%s/%s", cf->file_path,
+ ent->ce_name);
+ if (l == -1 || l >= MAXPATHLEN)
+ fatal("cvs_file_walkdir: overflow");
- /*
- * Now, for a file, pass it to the callback if it was
- * supplied to us.
- */
- if (cfp->cf_type != DT_DIR && cb != NULL) {
- if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
- goto done;
- }
-
- /*
- * Mark the entry as processed.
- */
- if (ent != NULL)
- ent->processed = 1;
-
- /*
- * If we don't want to keep it, free it
- */
- if (cfp->cf_type != DT_DIR && freecf)
- cvs_file_free(cfp);
- }
-
- closedir(dp);
- dp = NULL;
-
- /*
- * Pass over all of the entries now, so we pickup any files
- * that might have been lost, or are for some reason not on disk.
- *
- * (Follows the same procedure as above ... can we merge them?)
- */
- while (entf != NULL && (ent = cvs_ent_next(entf)) != NULL) {
- if (ent->processed == 1)
- continue;
- if (!(flags & CF_RECURSE) && ent->ce_type == CVS_ENT_DIR)
- continue;
- if ((flags & CF_NOFILES) && ent->ce_type != CVS_ENT_DIR)
- continue;
-
- len = cvs_path_cat(fpath, ent->ce_name, pbuf, sizeof(pbuf));
- if (len >= sizeof(pbuf))
- goto done;
-
- cfp = cvs_file_lget(pbuf, flags, cf, entf, ent);
- if (cfp == NULL) {
- cvs_log(LP_ERR, "failed to fetch '%s'", pbuf);
- goto done;
- }
-
- if (cfp->cf_type != DT_DIR && !freecf) {
- SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
- nfiles++;
- } else if (cfp->cf_type == DT_DIR) {
- SIMPLEQ_INSERT_TAIL(&dirs, cfp, cf_list);
- ndirs++;
- }
-
- if (cfp->cf_type != DT_DIR && cb != NULL) {
- if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
- goto done;
- }
-
- if (cfp->cf_type != DT_DIR && freecf)
- cvs_file_free(cfp);
- }
+ if (ent->ce_type == CVS_ENT_DIR)
+ cvs_file_get(fpath, &dl);
+ else if (ent->ce_type == CVS_ENT_FILE)
+ cvs_file_get(fpath, &fl);
- /*
- * Sort files and dirs if requested.
- */
- if (flags & CF_SORT) {
- if (nfiles > 0)
- cvs_file_sort(&(cf->cf_files), nfiles);
- if (ndirs > 0)
- cvs_file_sort(&dirs, ndirs);
+ cvs_ent_free(ent);
}
- /*
- * Finally, run over the directories we have encountered.
- * Before calling cvs_file_getdir() on them, we pass them
- * to the callback first.
- */
- while (!SIMPLEQ_EMPTY(&dirs)) {
- cfp = SIMPLEQ_FIRST(&dirs);
- SIMPLEQ_REMOVE_HEAD(&dirs, cf_list);
-
- if (!freecf)
- SIMPLEQ_INSERT_TAIL(&(cf->cf_files), cfp, cf_list);
-
- if (cb != NULL) {
- if ((cvs_error = cb(cfp, arg)) != CVS_EX_OK)
- goto done;
- }
+ cvs_ent_close(entlist, ENT_NOSYNC);
- if ((cfp->cf_flags & CVS_FILE_ONDISK) &&
- cvs_file_getdir(cfp, flags, cb, arg, freecf) < 0)
- goto done;
+ cvs_get_repo(cf->file_path, repo, MAXPATHLEN);
+ cvs_repository_lock(repo);
- if (freecf)
- cvs_file_free(cfp);
- }
+ cvs_repository_getdir(repo, cf->file_path, &fl, &dl);
- ret = 0;
- cfp = NULL;
-done:
- if (cfp != NULL && freecf)
- cvs_file_free(cfp);
+ cvs_file_walklist(&fl, cr);
+ cvs_file_freelist(&fl);
- while (!SIMPLEQ_EMPTY(&dirs)) {
- cfp = SIMPLEQ_FIRST(&dirs);
- SIMPLEQ_REMOVE_HEAD(&dirs, cf_list);
+ cvs_repository_unlock(repo);
- cvs_file_free(cfp);
- }
+ cvs_file_walklist(&dl, cr);
+ cvs_file_freelist(&dl);
- if (entf != NULL)
- cvs_ent_close(entf);
- if (dp != NULL)
- closedir(dp);
+ xfree(repo);
+ xfree(fpath);
- return (ret);
+ if (cr->leavedir != NULL)
+ cr->leavedir(cf);
}
-
-/*
- * cvs_file_free()
- *
- * Free a cvs_file structure and its contents.
- */
void
-cvs_file_free(CVSFILE *cf)
+cvs_file_freelist(struct cvs_flisthead *fl)
{
- CVSFILE *child;
-
- if (cf->cf_name != NULL)
- xfree(cf->cf_name);
-
- if (cf->cf_dir != NULL)
- xfree(cf->cf_dir);
-
- if (cf->cf_type == DT_DIR) {
- if (cf->cf_root != NULL)
- cvsroot_remove(cf->cf_root);
- if (cf->cf_repo != NULL)
- xfree(cf->cf_repo);
- while (!SIMPLEQ_EMPTY(&(cf->cf_files))) {
- child = SIMPLEQ_FIRST(&(cf->cf_files));
- SIMPLEQ_REMOVE_HEAD(&(cf->cf_files), cf_list);
- cvs_file_free(child);
- }
- } else {
- if (cf->cf_tag != NULL)
- xfree(cf->cf_tag);
- if (cf->cf_opts != NULL)
- xfree(cf->cf_opts);
- }
+ struct cvs_filelist *f;
- xfree(cf);
+ while ((f = TAILQ_FIRST(fl)) != NULL) {
+ TAILQ_REMOVE(fl, f, flist);
+ xfree(f->file_path);
+ xfree(f);
+ }
}
-
-/*
- * cvs_file_sort()
- *
- * Sort a list of cvs file structures according to their filename. The list
- * <flp> is modified according to the sorting algorithm. The number of files
- * in the list must be given by <nfiles>.
- * Returns 0 on success, or -1 on failure.
- */
-static int
-cvs_file_sort(struct cvs_flist *flp, u_int nfiles)
+void
+cvs_file_classify(struct cvs_file *cf)
{
- int i;
- size_t nb;
- CVSFILE *cf, **cfvec;
-
- cfvec = xcalloc((size_t)nfiles, sizeof(*cfvec));
-
- i = 0;
- SIMPLEQ_FOREACH(cf, flp, cf_list) {
- if (i == (int)nfiles) {
- cvs_log(LP_WARN, "too many files to sort");
- /* rebuild the list and abort sorting */
- while (--i >= 0)
- SIMPLEQ_INSERT_HEAD(flp, cfvec[i], cf_list);
- xfree(cfvec);
- return (-1);
- }
- cfvec[i++] = cf;
+ size_t len;
+ time_t mtime;
+ struct stat st;
+ int rflags, l, ismodified, rcsdead;
+ CVSENTRIES *entlist = NULL;
+ const char *state;
+ char *repo, *rcsfile, r1[16], r2[16];
+
+ cvs_log(LP_TRACE, "cvs_file_classify(%s)", cf->file_path);
- /* now unlink it from the list,
- * we'll put it back in order later
- */
- SIMPLEQ_REMOVE_HEAD(flp, cf_list);
+ if (!strcmp(cf->file_path, ".")) {
+ cf->file_status = FILE_UPTODATE;
+ return;
}
- /* clear the list just in case */
- SIMPLEQ_INIT(flp);
- nb = (size_t)i;
+ entlist = cvs_ent_open(cf->file_wd);
- heapsort(cfvec, nb, sizeof(cf), cvs_file_cmp);
+ repo = xmalloc(MAXPATHLEN);
+ rcsfile = xmalloc(MAXPATHLEN);
- /* rebuild the list from the bottom up */
- for (i = (int)nb - 1; i >= 0; i--)
- SIMPLEQ_INSERT_HEAD(flp, cfvec[i], cf_list);
+ cvs_get_repo(cf->file_wd, repo, MAXPATHLEN);
+ l = snprintf(rcsfile, MAXPATHLEN, "%s/%s",
+ repo, cf->file_name);
+ if (l == -1 || l >= MAXPATHLEN)
+ fatal("cvs_file_classify: overflow");
- xfree(cfvec);
- return (0);
-}
+ if (cf->file_type == CVS_FILE) {
+ len = strlcat(rcsfile, RCS_FILE_EXT, MAXPATHLEN);
+ if (len >= MAXPATHLEN)
+ fatal("cvs_file_classify: truncation");
+ }
+ cf->file_rpath = xstrdup(rcsfile);
+ cf->file_ent = cvs_ent_get(entlist, cf->file_name);
-static int
-cvs_file_cmp(const void *f1, const void *f2)
-{
- const CVSFILE *cf1, *cf2;
- cf1 = *(CVSFILE * const *)f1;
- cf2 = *(CVSFILE * const *)f2;
- return cvs_file_cmpname(cf1->cf_name, cf2->cf_name);
-}
+ if (cf->file_type == CVS_DIR) {
+ if (cf->fd == -1 && stat(rcsfile, &st) != -1)
+ cf->file_status = DIR_CREATE;
+ else if (cf->file_ent != NULL)
+ cf->file_status = FILE_UPTODATE;
+ xfree(repo);
+ xfree(rcsfile);
+ cvs_ent_close(entlist, ENT_NOSYNC);
+ return;
+ }
+ rflags = 0;
+ cf->repo_fd = open(cf->file_rpath, O_RDONLY);
+ if (cf->repo_fd != -1) {
+ cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, rflags);
+ if (cf->file_rcs == NULL)
+ fatal("cvs_file_classify: rcs_open failed while it "
+ "shouldn't");
+ } else {
+ cf->file_rcs = NULL;
+ }
-/*
- * cvs_file_alloc()
- *
- * Allocate a CVSFILE structure and initialize its internals.
- */
-CVSFILE *
-cvs_file_alloc(const char *path, u_int type)
-{
- CVSFILE *cfp;
- char *p;
+ if (cf->file_ent != NULL)
+ rcsnum_tostr(cf->file_ent->ce_rev, r1, sizeof(r1));
+ if (cf->file_rcs != NULL)
+ rcsnum_tostr(cf->file_rcs->rf_head, r2, sizeof(r2));
- cfp = xcalloc(1, sizeof(*cfp));
+ ismodified = rcsdead = 0;
+ if (cf->fd != -1 && cf->file_ent != NULL) {
+ if (fstat(cf->fd, &st) == -1)
+ fatal("cvs_file_classify: %s", strerror(errno));
- cfp->cf_type = type;
- cfp->cf_cvstat = CVS_FST_UNKNOWN;
+ mtime = cvs_hack_time(st.st_mtime, 1);
+ if (mtime == 0)
+ fatal("to gmt failed");
- if (type == DT_DIR) {
- SIMPLEQ_INIT(&(cfp->cf_files));
+ if (mtime != cf->file_ent->ce_mtime)
+ ismodified = 1;
}
- cfp->cf_name = xstrdup(basename(path));
- if ((p = strrchr(path, '/')) != NULL) {
- *p = '\0';
- if (strcmp(path, "."))
- cfp->cf_dir = xstrdup(path);
- else
- cfp->cf_dir = NULL;
- *p = '/';
- } else
- cfp->cf_dir = NULL;
-
- return (cfp);
-}
-
-
-/*
- * cvs_file_lget()
- *
- * Get the file and link it with the parent right away.
- * Returns a pointer to the created file structure on success, or NULL on
- * failure.
- */
-static CVSFILE *
-cvs_file_lget(const char *path, int flags, CVSFILE *parent, CVSENTRIES *pent,
- struct cvs_ent *ent)
-{
- char *c;
- int ret;
- u_int type;
- struct stat st;
- CVSFILE *cfp;
- struct cvsroot *root;
-
- type = DT_UNKNOWN;
- ret = stat(path, &st);
- if (ret == 0)
- type = IFTODT(st.st_mode);
-
- if ((flags & CF_REPO) && type != DT_DIR) {
- if ((c = strrchr(path, ',')) == NULL)
- return (NULL);
- *c = '\0';
+ if (cf->file_rcs != NULL) {
+ state = rcs_state_get(cf->file_rcs, cf->file_rcs->rf_head);
+ if (state == NULL)
+ fatal("failed to get state for HEAD for %s",
+ cf->file_path);
+ if (!strcmp(state, "dead"))
+ rcsdead = 1;
}
- if ((cfp = cvs_file_alloc(path, type)) == NULL)
- return (NULL);
- cfp->cf_parent = parent;
- cfp->cf_entry = pent;
-
- if (cfp->cf_type == DT_DIR && cfp->cf_parent == NULL)
- cfp->cf_flags |= CVS_DIRF_BASE;
-
- if (ret == 0) {
- cfp->cf_mode = st.st_mode & ACCESSPERMS;
- if (cfp->cf_type == DT_REG)
- cfp->cf_mtime = st.st_mtime;
- cfp->cf_flags |= CVS_FILE_ONDISK;
-
- if (ent == NULL)
- if (cfp->cf_flags & CVS_DIRF_BASE)
- cfp->cf_cvstat = CVS_FST_UPTODATE;
- else
- cfp->cf_cvstat = CVS_FST_UNKNOWN;
- else {
- /* always show directories as up-to-date */
- if (ent->ce_type == CVS_ENT_DIR)
- cfp->cf_cvstat = CVS_FST_UPTODATE;
- else if (rcsnum_cmp(ent->ce_rev, cvs_addedrev, 2) == 0)
- cfp->cf_cvstat = CVS_FST_ADDED;
- else {
- /*
- * correct st.st_mtime first
- */
- if ((st.st_mtime =
- cvs_hack_time(st.st_mtime, 1)) == 0) {
- cvs_file_free(cfp);
- return (NULL);
- }
-
- /* check last modified time */
- if (ent->ce_mtime == (time_t)st.st_mtime) {
- cfp->cf_cvstat = CVS_FST_UPTODATE;
- } else {
- cfp->cf_cvstat = CVS_FST_MODIFIED;
- }
+ /*
+ * 10 Sin
+ * 20 Goto hell
+ * (I welcome you if-else hell)
+ */
+ if (cf->file_ent == NULL) {
+ if (cf->file_rcs == NULL) {
+ if (cf->fd == -1) {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "nothing known about '%s'",
+ cf->file_path);
+ } else {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "use add to create an entry for %s",
+ cf->file_path);
}
- cfp->cf_etime = ent->ce_mtime;
- }
- } else {
- if (ent == NULL) {
- /* assume it is a file and unknown */
- cfp->cf_cvstat = CVS_FST_UNKNOWN;
- cfp->cf_type = DT_REG;
+ cf->file_status = FILE_UNKNOWN;
+ } else if (rcsdead == 1) {
+ if (cf->fd == -1) {
+ cf->file_status = FILE_UPTODATE;
+ } else {
+ cvs_log(LP_NOTICE,
+ "use add to create an entry for %s",
+ cf->file_path);
+ cf->file_status = FILE_UNKNOWN;
+ }
} else {
- if (ent->ce_type == CVS_ENT_FILE)
- cfp->cf_type = DT_REG;
- else if (ent->ce_type == CVS_ENT_DIR)
- cfp->cf_type = DT_DIR;
- else
- cvs_log(LP_WARN, "unknown ce_type %d",
- ent->ce_type);
-
- if (ent->ce_status == CVS_ENT_REMOVED)
- cfp->cf_cvstat = CVS_FST_REMOVED;
- else if (ent->ce_status == CVS_ENT_UPTODATE)
- cfp->cf_cvstat = CVS_FST_UPTODATE;
- else if (ent->ce_status == CVS_ENT_ADDED)
- cfp->cf_cvstat = CVS_FST_ADDED;
- else
- cfp->cf_cvstat = CVS_FST_LOST;
+ cf->file_status = FILE_CHECKOUT;
}
-
- /* XXX assume 0644 ? */
- cfp->cf_mode = 0644;
- }
-
- if (ent != NULL) {
- /* steal the RCSNUM */
- cfp->cf_lrev = ent->ce_rev;
-
- if (ent->ce_type == CVS_ENT_FILE) {
- if (ent->ce_tag[0] != '\0')
- cfp->cf_tag = xstrdup(ent->ce_tag);
-
- if (ent->ce_opts[0] != '\0')
- cfp->cf_opts = xstrdup(ent->ce_opts);
+ } else if (cf->file_ent->ce_status == CVS_ENT_ADDED) {
+ if (cf->fd == -1) {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "warning: new-born %s has dissapeared",
+ cf->file_path);
+ cf->file_status = FILE_REMOVE_ENTRY;
+ } else if (cf->file_rcs == NULL || rcsdead == 1) {
+ cf->file_status = FILE_ADDED;
+ } else {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "conflict: %s already created by others",
+ cf->file_path);
+ cf->file_status = FILE_CONFLICT;
}
- }
-
- if (cfp->cf_type == DT_DIR) {
- if (cvs_load_dirinfo(cfp, flags) < 0) {
- cvs_file_free(cfp);
- return (NULL);
+ } else if (cf->file_ent->ce_status == CVS_ENT_REMOVED) {
+ if (cf->fd != -1) {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "%s should be removed but is still there",
+ cf->file_path);
+ cf->file_status = FILE_REMOVED;
+ } else if (cf->file_rcs == NULL || rcsdead == 1) {
+ cf->file_status = FILE_REMOVE_ENTRY;
+ } else {
+ if (strcmp(r1, r2)) {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "conflict: removed %s was modified"
+ " by a second party",
+ cf->file_path);
+ cf->file_status = FILE_CONFLICT;
+ } else {
+ cf->file_status = FILE_REMOVED;
+ }
}
- }
-
- if (flags & CF_REPO) {
- root = CVS_DIR_ROOT(cfp);
-
- cfp->cf_mode = 0644;
- cfp->cf_cvstat = CVS_FST_LOST;
-
- c = xstrdup(cfp->cf_dir);
- xfree(cfp->cf_dir);
+ } else if (cf->file_ent->ce_status == CVS_ENT_REG) {
+ if (cf->file_rcs == NULL || rcsdead == 1) {
+ if (cf->fd == -1) {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "warning: %s's entry exists but"
+ " there is no longer a file"
+ " in the repository,"
+ " removing entry",
+ cf->file_path);
+ cf->file_status = FILE_REMOVE_ENTRY;
+ } else {
+ if (ismodified) {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "conflict: %s is no longer "
+ "in the repository but is "
+ "locally modified",
+ cf->file_path);
+ cf->file_status = FILE_CONFLICT;
+ } else {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "%s is no longer in the "
+ "repository",
+ cf->file_path);
- if (strcmp(c, root->cr_dir)) {
- c += strlen(root->cr_dir) + 1;
- cfp->cf_dir = xstrdup(c);
- c -= strlen(root->cr_dir) + 1;
+ cf->file_status = FILE_UNLINK;
+ }
+ }
} else {
- cfp->cf_dir = NULL;
+ if (cf->fd == -1) {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE,
+ "warning: %s was lost",
+ cf->file_path);
+ cf->file_status = FILE_LOST;
+ } else {
+ if (ismodified == 1)
+ cf->file_status = FILE_MODIFIED;
+ else
+ cf->file_status = FILE_UPTODATE;
+
+ if (strcmp(r1, r2)) {
+ if (cf->file_status == FILE_MODIFIED)
+ cf->file_status = FILE_MERGE;
+ else
+ cf->file_status = FILE_PATCH;
+ }
+ }
}
-
- xfree(c);
- }
-
- if (cfp->cf_repo != NULL && cfp->cf_type == DT_DIR &&
- !strcmp(cfp->cf_repo, path))
- cfp->cf_cvstat = CVS_FST_UPTODATE;
-
- /*
- * In server mode, we do a few extra checks.
- */
- if (cvs_cmdop == CVS_OP_SERVER) {
- /*
- * If for some reason a file was added,
- * but does not exist anymore, start complaining.
- */
- if (!(cfp->cf_flags & CVS_FILE_ONDISK) &&
- (cfp->cf_cvstat == CVS_FST_ADDED) &&
- (cfp->cf_type != DT_DIR))
- cvs_log(LP_WARN, "new-born %s has disappeared", path);
-
- /*
- * Any other needed checks?
- */
}
- return (cfp);
+ xfree(repo);
+ xfree(rcsfile);
+ cvs_ent_close(entlist, ENT_NOSYNC);
}
+void
+cvs_file_free(struct cvs_file *cf)
+{
+ xfree(cf->file_name);
+ xfree(cf->file_wd);
+ xfree(cf->file_path);
+
+ if (cf->file_rpath != NULL)
+ xfree(cf->file_rpath);
+ if (cf->file_ent != NULL)
+ cvs_ent_free(cf->file_ent);
+ if (cf->file_rcs != NULL)
+ rcs_close(cf->file_rcs);
+ if (cf->fd != -1)
+ (void)close(cf->fd);
+ if (cf->repo_fd != -1)
+ (void)close(cf->repo_fd);
+ xfree(cf);
+}
static int
cvs_file_cmpname(const char *name1, const char *name2)
@@ -1297,75 +755,3 @@ cvs_file_cmpname(const char *name1, const char *name2)
return (cvs_nocase == 0) ? (strcmp(name1, name2)) :
(strcasecmp(name1, name2));
}
-
-/*
- * remove any empty directories.
- */
-int
-cvs_file_prune(char *path)
-{
- DIR *dirp;
- int l, pwd, empty;
- struct dirent *dp;
- char fpath[MAXPATHLEN];
- CVSENTRIES *entf;
- CVSFILE *cfp;
-
- pwd = (!strcmp(path, "."));
-
- if ((dirp = opendir(path)) == NULL) {
- cvs_log(LP_ERRNO, "failed to open `%s'", fpath);
- return (-1);
- }
-
- empty = 0;
- entf = cvs_ent_open(path, O_RDWR);
-
- while ((dp = readdir(dirp)) != NULL) {
- if (!strcmp(dp->d_name, ".") ||
- !strcmp(dp->d_name, "..") ||
- !strcmp(dp->d_name, CVS_PATH_CVSDIR))
- continue;
-
- empty++;
- if (dp->d_type == DT_DIR) {
- l = snprintf(fpath, sizeof(fpath), "%s%s%s",
- (pwd) ? "" : path, (pwd) ? "" : "/", dp->d_name);
- if (l == -1 || l >= (int)sizeof(fpath)) {
- errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", fpath);
- continue;
- }
-
- cfp = cvs_file_find(cvs_files, fpath);
- if (cfp == NULL)
- continue;
-
- /* ignore unknown directories */
- if (cfp->cf_cvstat == CVS_FST_UNKNOWN)
- continue;
-
- if (cvs_file_prune(fpath)) {
- empty--;
- if (entf)
- cvs_ent_remove(entf, fpath, 0);
- } else {
- empty++;
- }
- }
- }
-
- closedir(dirp);
- if (entf)
- cvs_ent_close(entf);
-
- empty = (empty == 0);
- if (empty) {
- if (cvs_rmdir(path) < 0) {
- cvs_log(LP_ERR, "failed to prune `%s'", path);
- empty = 0;
- }
- }
-
- return (empty);
-}
diff --git a/usr.bin/cvs/file.h b/usr.bin/cvs/file.h
index 2d688b32130..59b82304761 100644
--- a/usr.bin/cvs/file.h
+++ b/usr.bin/cvs/file.h
@@ -1,5 +1,6 @@
-/* $OpenBSD: file.h,v 1.33 2006/01/02 09:42:20 xsa Exp $ */
+/* $OpenBSD: file.h,v 1.34 2006/05/27 03:30:30 joris Exp $ */
/*
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
*
@@ -29,123 +30,77 @@
#include "rcs.h"
-struct cvs_file;
-struct cvs_entries;
-
-#define CF_STAT 0x01 /* obsolete */
-#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 */
-#define CF_CREATE 0x20 /* create if file does not exist */
-#define CF_NOSYMS 0x40 /* ignore symbolic links */
-#define CF_NOFILES 0x80 /* don't load any files inside a directory */
-#define CF_REPO 0x100 /* we are loading a repository with ,v files */
-
-/*
- * 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).
- *
- * 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.
- */
-#define CVS_FST_UNKNOWN 0 /* Unknown */
-#define CVS_FST_UPTODATE 1 /* Up-to-date */
-#define CVS_FST_MODIFIED 2 /* Locally Modified */
-#define CVS_FST_ADDED 3 /* Locally Added */
-#define CVS_FST_REMOVED 4 /* Locally Removed */
-#define CVS_FST_CONFLICT 5 /* Unresolved Conflict */
-#define CVS_FST_PATCHED 6
-#define CVS_FST_LOST 7 /* Needs Checkout */
-
-SIMPLEQ_HEAD(cvs_flist, cvs_file);
-
-typedef struct cvs_file {
- struct cvs_file *cf_parent; /* parent directory (NULL if none) */
-
- /*
- * cf_name contains the basename of the fullpath
- * cf_dir contains the parent directory the file or dir is in.
- * if cf_dir is NULL the file is in the parent directory.
- */
- char *cf_name;
- char *cf_dir;
-
- /* pointer to the parent directory's entry file */
- void *cf_entry;
-
- mode_t cf_mode;
- u_int8_t cf_cvstat; /* cvs status of the file */
- u_int8_t cf_type; /* uses values from dirent.h */
- u_int16_t cf_flags;
-
- union {
- struct {
- RCSNUM *cd_lrev; /* local revision */
- time_t cd_etime; /* time in Entries file */
- time_t cd_mtime;
- char *cd_tag;
- char *cd_opts;
- } cf_reg;
- struct {
- char *cd_repo;
- struct cvsroot *cd_root;
- struct cvs_flist cd_files;
- } cf_dir;
- } cf_td;
-
- SIMPLEQ_ENTRY(cvs_file) cf_list;
-} CVSFILE;
-
-/* only valid for regular files */
-#define cf_etime cf_td.cf_reg.cd_etime
-#define cf_mtime cf_td.cf_reg.cd_mtime
-#define cf_lrev cf_td.cf_reg.cd_lrev
-#define cf_tag cf_td.cf_reg.cd_tag
-#define cf_opts cf_td.cf_reg.cd_opts
-
-/* only valid for directories */
-#define cf_files cf_td.cf_dir.cd_files
-#define cf_repo cf_td.cf_dir.cd_repo
-#define cf_root cf_td.cf_dir.cd_root
-
-#define CVS_DIRF_STATIC 0x01
-#define CVS_DIRF_STICKY 0x02
-#define CVS_DIRF_BASE 0x04
-#define CVS_FILE_ONDISK 0x08
-
-#define CVS_DIR_ROOT(f) ((((f)->cf_type == DT_DIR) && \
- ((f)->cf_root != NULL)) ? (f)->cf_root : \
- (((f)->cf_parent == NULL) ? NULL : (f)->cf_parent->cf_root))
-
-#define CVS_DIR_REPO(f) (((f)->cf_type == DT_DIR) ? \
- (f)->cf_repo : (((f)->cf_parent == NULL) ? \
- NULL : (f)->cf_parent->cf_repo))
-
-int cvs_file_init(void);
-int cvs_file_ignore(const char *);
-int cvs_file_chkign(const char *);
-int cvs_file_get(const char *, int, int (*)(CVSFILE *, void *),
- void *, struct cvs_flist *);
-int cvs_file_getspec(char **, int, int, int (*)(CVSFILE *, void *),
- void *, struct cvs_flist *);
-CVSFILE *cvs_file_loadinfo(char *, int, int (*)(CVSFILE *, void *), void *,
- int);
-
-CVSFILE *cvs_file_create(CVSFILE *, const char *, u_int, mode_t);
-CVSFILE *cvs_file_copy(CVSFILE *);
-int cvs_file_attach(CVSFILE *, CVSFILE *);
-
-int cvs_file_init(void);
-int cvs_file_ignore(const char *);
-int cvs_file_chkign(const char *);
-CVSFILE *cvs_file_load(const char *, int);
-CVSFILE *cvs_file_find(CVSFILE *, const char *);
-char *cvs_file_getpath(CVSFILE *, char *, size_t);
-void cvs_file_free(CVSFILE *);
-int cvs_file_prune(char *);
+struct cvs_file {
+ char *file_name;
+ char *file_wd;
+ char *file_path;
+ char *file_rpath;
+
+ int fd;
+ int repo_fd;
+ int file_type;
+ int file_status;
+ int file_flags;
+
+ RCSFILE *file_rcs;
+ struct cvs_ent *file_ent;
+};
+
+#define FILE_UNKNOWN 0
+#define FILE_ADDED 1
+#define FILE_REMOVED 2
+#define FILE_MODIFIED 3
+#define FILE_UPTODATE 4
+#define FILE_LOST 5
+#define FILE_CHECKOUT 6
+#define FILE_MERGE 7
+#define FILE_PATCH 8
+#define FILE_REMOVE_ENTRY 9
+#define FILE_CONFLICT 10
+#define FILE_UNLINK 11
+
+#define DIR_CREATE 12
+
+struct cvs_filelist {
+ char *file_path;
+ TAILQ_ENTRY(cvs_filelist) flist;
+};
+
+TAILQ_HEAD(cvs_flisthead, cvs_filelist);
+
+struct cvs_recursion;
+
+#define CVS_DIR 1
+#define CVS_FILE 2
+
+#define CVS_ISDIR(cf) \
+ ((cf)->file_type == CVS_DIR)
+
+#define CVS_ISFILE(cf) \
+ ((cf)->file_type == CVS_FILE)
+
+TAILQ_HEAD(cvs_flist, cvs_file);
+
+struct cvs_ignpat {
+ char ip_pat[MAXNAMLEN];
+ int ip_flags;
+ TAILQ_ENTRY(cvs_ignpat) ip_list;
+};
+
+TAILQ_HEAD(ignore_head, cvs_ignpat);
+
+void cvs_file_init(void);
+void cvs_file_ignore(const char *, struct ignore_head *);
+void cvs_file_classify(struct cvs_file *);
+void cvs_file_free(struct cvs_file *);
+void cvs_file_run(int, char **, struct cvs_recursion *);
+void cvs_file_walklist(struct cvs_flisthead *, struct cvs_recursion *);
+void cvs_file_walkdir(struct cvs_file *, struct cvs_recursion *);
+void cvs_file_freelist(struct cvs_flisthead *);
+struct cvs_filelist *cvs_file_get(const char *, struct cvs_flisthead *);
+
+int cvs_file_chkign(const char *);
+
+struct cvs_file *cvs_file_get_cf(const char *, const char *, int, int);
#endif /* FILE_H */
diff --git a/usr.bin/cvs/hist.c b/usr.bin/cvs/hist.c
deleted file mode 100644
index 93dbf1fe5be..00000000000
--- a/usr.bin/cvs/hist.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/* $OpenBSD: hist.c,v 1.14 2006/04/05 01:38:55 ray Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-
-#define CVS_HIST_BUFSIZE 8192
-
-
-
-static int cvs_hist_fillbuf(CVSHIST *);
-static int cvs_hist_fmt(const struct cvs_hent *, char *, size_t);
-
-
-/*
- * cvs_hist_open()
- *
- * Open a CVS history file.
- * Returns the number of entries in the file on success, or -1 on error.
- */
-CVSHIST *
-cvs_hist_open(const char *path)
-{
- CVSHIST *histp;
-
- histp = xcalloc(1, sizeof(*histp));
-
- histp->chf_buf = xmalloc((size_t)CVS_HIST_BUFSIZE);
- histp->chf_blen = CVS_HIST_BUFSIZE;
- histp->chf_off = 0;
-
- histp->chf_sindex = 0;
- histp->chf_cindex = 0;
- histp->chf_nbhent = 0;
-
- cvs_log(LP_TRACE, "cvs_hist_open(%s)", path);
-
- histp->chf_fd = open(path, O_RDONLY, 0);
- if (histp->chf_fd == -1) {
- cvs_log(LP_ERRNO,
- "failed to open CVS history file `%s'", path);
- cvs_nolog = 1;
- xfree(histp->chf_buf);
- xfree(histp);
- return (NULL);
- }
-
- cvs_hist_fillbuf(histp);
-
- return (histp);
-}
-
-
-/*
- * cvs_hist_close()
- *
- * Close the CVS history file previously opened by a call to cvs_hist_open()
- */
-void
-cvs_hist_close(CVSHIST *histp)
-{
- if (histp->chf_fd >= 0)
- (void)close(histp->chf_fd);
- xfree(histp->chf_buf);
- xfree(histp);
-}
-
-
-/*
- * cvs_hist_getnext()
- *
- * Get the next entry from the history file <histp>. Whenever using this
- * function, it should be assumed that the return value of the previous call
- * to cvs_hist_getnext() is now invalid.
- * Returns the next entry from the file on success, or NULL on failure or if
- * no entries are left.
- */
-struct cvs_hent *
-cvs_hist_getnext(CVSHIST *histp)
-{
- if (histp->chf_cindex == histp->chf_nbhent) {
- /* no more cached entries, refill buf and parse */
- cvs_hist_fillbuf(histp);
- cvs_hist_parse(histp);
- }
- return (&(histp->chf_hent[histp->chf_cindex++]));
-}
-
-
-/*
- * cvs_hist_append()
- *
- * Append a history entry to the history file <histp>. The file offset is
- * first set to the end of the file.
- * Returns 0 on success, or -1 on failure.
- */
-int
-cvs_hist_append(CVSHIST *histp, struct cvs_hent *hentp)
-{
- char hbuf[128];
-
- if (cvs_nolog == 1)
- return (0);
-
- if (cvs_hist_fmt(hentp, hbuf, sizeof(hbuf)) < 0) {
- cvs_log(LP_ERR, "failed to append CVS history entry");
- return (-1);
- }
-
- /* position ourself at the end */
- if (lseek(histp->chf_fd, (off_t)0, SEEK_END) == -1) {
- cvs_log(LP_ERRNO, "failed to seek to end of CVS history file");
- return (-1);
- }
-
- if (write(histp->chf_fd, hbuf, strlen(hbuf)) == -1) {
- cvs_log(LP_ERR, "failed to write CVS history entry to file");
- return (-1);
- }
-
- return (0);
-}
-
-
-
-/*
- * cvs_hist_fillbuf()
- *
- * Fill the history file's internal buffer for future parsing.
- */
-static int
-cvs_hist_fillbuf(CVSHIST *histp)
-{
- ssize_t ret;
-
- /* reposition ourself in case we're missing the start of a record */
- if (lseek(histp->chf_fd, histp->chf_off, SEEK_SET) == -1) {
- cvs_log(LP_ERRNO, "failed to seek in CVS history file");
- return (-1);
- }
- ret = read(histp->chf_fd, histp->chf_buf, histp->chf_blen);
- if (ret == -1) {
- cvs_log(LP_ERRNO, "failed to buffer CVS history file");
- return (-1);
- } else {
- histp->chf_bused = (size_t)ret;
- }
-
- return (ret);
-}
-
-
-/*
- * cvs_hist_parse()
- *
- * Parse the current contents of the internal buffer of <histp> and regenerate
- * the buffered history entries.
- * Returns the number of entries parsed on success, or -1 on failure.
- */
-int
-cvs_hist_parse(CVSHIST *histp)
-{
- u_int i, fld;
- char *fields[CVS_HIST_NBFLD], *sp, *bep, *ep, *errp;
-
- sp = histp->chf_buf;
- bep = histp->chf_buf + histp->chf_bused - 1;
-
- for (i = 0; i < CVS_HIST_CACHE; i++) {
- ep = memchr(sp, '\n', bep - sp);
- if (ep == NULL) {
- /*
- * No record or incomplete record left to parse,
- * so adjust the next read offset in consequence.
- */
- histp->chf_off += (off_t)(sp - histp->chf_buf);
- break;
- } else if (ep == bep) {
- histp->chf_off += (off_t)histp->chf_bused;
- }
- *(ep++) = '\0';
-
- printf("hist(%s)\n", sp);
-
- histp->chf_hent[i].ch_event = *sp++;
-
- /* split the record in fields */
- fields[0] = sp;
-
- fld = 1;
- while (sp < ep) {
- if (*sp == '|') {
- *sp = '\0';
- fields[fld++] = sp + 1;
- }
- if (fld == CVS_HIST_NBFLD)
- break;
- sp++;
- }
-#if 0
- for (fld = 0; fld < CVS_HIST_NBFLD; fld++)
- printf("fields[%u] = `%s'\n", fld, fields[fld]);
-#endif
-
- histp->chf_hent[i].ch_date = (time_t)strtol(fields[0],
- &errp, 16);
- if (*errp != '\0') {
- cvs_log(LP_ERR,
- "parse error in date field of CVS history entry");
- continue;
- }
-
- histp->chf_hent[i].ch_user = fields[1];
- histp->chf_hent[i].ch_curdir = fields[2];
- histp->chf_hent[i].ch_repo = fields[3];
- histp->chf_hent[i].ch_rev = rcsnum_alloc();
- rcsnum_aton(fields[4], NULL, histp->chf_hent[i].ch_rev);
- histp->chf_hent[i].ch_arg = fields[5];
- sp = ep;
- }
-
- /* update indexes */
- histp->chf_sindex += histp->chf_nbhent;
- histp->chf_nbhent = i;
- histp->chf_cindex = 0;
-
-
- return (i);
-}
-
-
-/*
- * cvs_hist_fmt()
- *
- * Format the contents of the CVS history entry <ent> into the format used in
- * the CVS `history' file, and store the resulting string in <buf>, which is
- * of size <blen>.
- */
-static int
-cvs_hist_fmt(const struct cvs_hent *ent, char *buf, size_t blen)
-{
- char numbuf[64];
- int len;
-
- if (rcsnum_tostr(ent->ch_rev, numbuf, sizeof(numbuf)) == NULL)
- return (-1);
-
- len = snprintf(buf, blen, "%c%8x|%s|%s|%s|%s|%s",
- ent->ch_event, ent->ch_date, ent->ch_user, ent->ch_curdir,
- ent->ch_repo, numbuf, ent->ch_arg);
- if (len >= (int)blen || len == -1)
- return (-1);
- return (len);
-}
diff --git a/usr.bin/cvs/history.c b/usr.bin/cvs/history.c
deleted file mode 100644
index ab2de4ce7e4..00000000000
--- a/usr.bin/cvs/history.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/* $OpenBSD: history.c,v 1.26 2006/01/23 14:02:42 xsa Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-#define CVS_HISTORY_MAXMOD 16
-
-/* history flags */
-#define CVS_HF_A 0x01
-#define CVS_HF_C 0x02
-#define CVS_HF_E 0x04
-#define CVS_HF_L 0x08
-#define CVS_HF_M 0x10
-#define CVS_HF_O 0x20
-#define CVS_HF_T 0x40
-#define CVS_HF_W 0x80
-
-#define CVS_HF_EXCL (CVS_HF_C|CVS_HF_E|CVS_HF_M|CVS_HF_O|CVS_HF_T|CVS_HF_X)
-
-static int cvs_history_init(struct cvs_cmd *, int, char **, int *);
-#if 0
-static void cvs_history_print(struct cvs_hent *);
-#endif
-static int cvs_history_pre_exec(struct cvsroot *);
-
-extern char *__progname;
-
-struct cvs_cmd cvs_cmd_history = {
- CVS_OP_HISTORY, CVS_REQ_HISTORY, "history",
- { "hi", "his" },
- "Show repository access history",
- "[-aceloTw] [-b str] [-D date] [-f file] [-m module]\n"
- " [-n module] [-p path] [-r rev] [-t tag]\n"
- " [-u user] [-x ACEFGMORTUW] [-z tz] [file ...]",
- "ab:cD:ef:lm:n:op:r:Tt:u:wx:z:",
- NULL,
- 0,
- cvs_history_init,
- cvs_history_pre_exec,
- NULL,
- NULL,
- NULL,
- NULL,
- CVS_CMD_SENDDIR
-};
-
-static int flags = 0;
-static char *date, *rev, *user, *tag;
-static char *zone = "+0000";
-static u_int nbmod = 0;
-static u_int rep = 0;
-static char *modules[CVS_HISTORY_MAXMOD];
-
-static int
-cvs_history_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- date = rev = user = tag = NULL;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'a':
- flags |= CVS_HF_A;
- break;
- case 'b':
- break;
- case 'c':
- rep++;
- flags |= CVS_HF_C;
- break;
- case 'D':
- break;
- case 'e':
- rep++;
- flags |= CVS_HF_E;
- break;
- case 'f':
- break;
- case 'l':
- flags |= CVS_HF_L;
- break;
- case 'm':
- rep++;
- flags |= CVS_HF_M;
- if (nbmod == CVS_HISTORY_MAXMOD) {
- cvs_log(LP_ERR, "too many `-m' options");
- return (CVS_EX_USAGE);
- }
- modules[nbmod++] = optarg;
- break;
- case 'n':
- break;
- case 'o':
- rep++;
- flags |= CVS_HF_O;
- break;
- case 'r':
- rev = optarg;
- break;
- case 'T':
- rep++;
- flags |= CVS_HF_T;
- break;
- case 't':
- tag = optarg;
- break;
- case 'u':
- user = optarg;
- break;
- case 'w':
- flags |= CVS_HF_W;
- break;
- case 'x':
- rep++;
- break;
- case 'z':
- zone = optarg;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- if (rep > 1) {
- cvs_log(LP_ERR,
- "Only one report type allowed from: \"-Tcomxe\"");
- return (CVS_EX_USAGE);
- } else if (rep == 0)
- flags |= CVS_HF_O; /* use -o as default */
-
- *arg = optind;
- return (0);
-}
-
-static int
-cvs_history_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method != CVS_METHOD_LOCAL) {
- if (flags & CVS_HF_A)
- cvs_sendarg(root, "-a", 0);
-
- if (flags & CVS_HF_C)
- cvs_sendarg(root, "-c", 0);
-
- if (flags & CVS_HF_O)
- cvs_sendarg(root, "-o", 0);
-
- if (date != NULL) {
- cvs_sendarg(root, "-D", 0);
- cvs_sendarg(root, date, 0);
- }
-
- if (rev != NULL) {
- cvs_sendarg(root, "-r", 0);
- cvs_sendarg(root, rev, 0);
- }
-
- if (tag != NULL) {
- cvs_sendarg(root, "-t", 0);
- cvs_sendarg(root, tag, 0);
- }
-
- /* if no user is specified, get login name of command issuer */
- if (!(flags & CVS_HF_A) && (user == NULL)) {
- if ((user = getlogin()) == NULL)
- fatal("cannot get login name");
- }
-
- if (!(flags & CVS_HF_A)) {
- cvs_sendarg(root, "-u", 0);
- cvs_sendarg(root, user, 0);
- }
-
- cvs_sendarg(root, "-z", 0);
- cvs_sendarg(root, zone, 0);
- }
-
- return (0);
-}
-
-
-#if 0
-static void
-cvs_history_print(struct cvs_hent *hent)
-{
- struct tm etime;
-
- if (localtime_r(&(hent->ch_date), &etime) == NULL) {
- cvs_log(LP_ERR, "failed to convert timestamp to structure");
- return;
- }
-
- printf("%c %4d-%02d-%02d %02d:%02d +%04d %-16s %-16s\n",
- hent->ch_event, etime.tm_year + 1900, etime.tm_mon + 1,
- etime.tm_mday, etime.tm_hour, etime.tm_min,
- 0, hent->ch_user, hent->ch_repo);
-}
-#endif
diff --git a/usr.bin/cvs/import.c b/usr.bin/cvs/import.c
deleted file mode 100644
index 5aa7acbf41e..00000000000
--- a/usr.bin/cvs/import.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/* $OpenBSD: import.c,v 1.43 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Joris Vink <joris@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-#define CVS_IMPORT_DEFBRANCH "1.1.1"
-
-
-static int cvs_import_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_import_pre_exec(struct cvsroot *);
-static int cvs_import_pre_exec(struct cvsroot *);
-static int cvs_import_post_exec(struct cvsroot *);
-static int cvs_import_remote(CVSFILE *, void *);
-static int cvs_import_local(CVSFILE *, void *);
-static int cvs_import_cleanup(void);
-
-static int dflag = 0;
-static int conflicts = 0;
-static RCSNUM *imp_brnum;
-
-static char *module, *vendor, *release;
-
-struct cvs_cmd cvs_cmd_import = {
- CVS_OP_IMPORT, CVS_REQ_IMPORT, "import",
- { "im", "imp" },
- "Import sources into CVS, using vendor branches",
- "[-d] [-b branch] [-I ign] [-k mode] [-m msg] [-W spec] module "
- "vendortag releasetag ...",
- "b:dI:k:m:W:",
- NULL,
- CF_RECURSE | CF_IGNORE | CF_NOSYMS,
- cvs_import_init,
- cvs_import_pre_exec,
- cvs_import_remote,
- cvs_import_local,
- cvs_import_post_exec,
- cvs_import_cleanup,
- CVS_CMD_SENDDIR
-};
-
-static int
-cvs_import_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'b':
- if ((imp_brnum = rcsnum_parse(optarg)) == NULL) {
- cvs_log(LP_ERR, "%s is not a numeric branch",
- optarg);
- return (CVS_EX_USAGE);
- }
- break;
- case 'd':
- dflag = 1;
- break;
- case 'I':
- if (cvs_file_ignore(optarg) < 0) {
- cvs_log(LP_ERR, "failed to add `%s' to list "
- "of ignore patterns", optarg);
- return (CVS_EX_USAGE);
- }
- break;
- case 'k':
- break;
- case 'm':
- cvs_msg = xstrdup(optarg);
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- argc -= optind;
- argv += optind;
- if (argc != 3)
- return (CVS_EX_USAGE);
-
- if (imp_brnum == NULL &&
- (imp_brnum = rcsnum_parse(CVS_IMPORT_DEFBRANCH)) == NULL)
- fatal("cvs_import_init: rcsnum_parse failed");
-
- module = argv[0];
- vendor = argv[1];
- release = argv[2];
-
- *arg = optind + 3;
-
- if (cvs_msg == NULL)
- cvs_msg = cvs_logmsg_get(NULL, NULL, NULL, NULL);
-
- return (0);
-}
-
-static int
-cvs_import_pre_exec(struct cvsroot *root)
-{
- char numbuf[64], repodir[MAXPATHLEN];
-
- if (root->cr_method == CVS_METHOD_LOCAL) {
- if (cvs_path_cat(root->cr_dir, module, repodir,
- sizeof(repodir)) >= sizeof(repodir))
- fatal("cvs_import_pre_exec: cvs_path_cat overflow");
-
- if (mkdir(repodir, 0775) == -1)
- fatal("cvs_import_pre_exec: mkdir `%s': %s",
- repodir, strerror(errno));
- } else {
- rcsnum_tostr(imp_brnum, numbuf, sizeof(numbuf));
-
- cvs_sendarg(root, "-b", 0);
- cvs_sendarg(root, numbuf, 0);
- cvs_logmsg_send(root, cvs_msg);
- cvs_sendarg(root, module, 0);
- cvs_sendarg(root, vendor, 0);
- cvs_sendarg(root, release, 0);
- }
-
- return (0);
-}
-
-static int
-cvs_import_post_exec(struct cvsroot *root)
-{
- char buf[8];
-
- if (root->cr_method == CVS_METHOD_LOCAL) {
- if (conflicts > 0)
- snprintf(buf, sizeof(buf), "%d", conflicts);
-
- if (verbosity > 0)
- cvs_printf("\n%s conflicts created by this import\n\n",
- conflicts == 0 ? "No" : buf);
- }
-
- return (CVS_EX_OK);
-}
-
-/*
- * cvs_import_remote()
- *
- * Perform the import of a single file or directory.
- */
-static int
-cvs_import_remote(CVSFILE *cf, void *arg)
-{
- size_t sz;
- struct cvsroot *root;
- char fpath[MAXPATHLEN], repodir[MAXPATHLEN];
- char repo[MAXPATHLEN], date[32];
-
- root = CVS_DIR_ROOT(cf);
-
- if (cvs_path_cat(root->cr_dir, module, repo, sizeof(repo)) >=
- sizeof(repo))
- fatal("cvs_import_remove: cvs_path_cat overflow");
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- if (cf->cf_type == DT_DIR) {
- if (!strcmp(cf->cf_name, "."))
- strlcpy(repodir, repo, sizeof(repodir));
- else {
- if(cvs_path_cat(repo, fpath, repodir,
- sizeof(repodir)) >= sizeof(repodir))
- fatal("cvs_import_remove: cvs_path_cat overflow");
- }
-
- cvs_sendreq(root, CVS_REQ_DIRECTORY, fpath);
- cvs_sendln(root, repodir);
- return (0);
- }
-
- if (dflag == 1) {
- ctime_r(&(cf->cf_mtime), date);
- sz = strlen(date);
- if (sz > 0 && date[sz - 1] == '\n')
- date[--sz] = '\0';
- cvs_sendreq(root, CVS_REQ_CHECKINTIME, date);
- }
-
- cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name);
- cvs_sendfile(root, fpath);
-
- return (0);
-}
-
-static int
-cvs_import_local(CVSFILE *cf, void *arg)
-{
- time_t stamp;
- char *fcont;
- char fpath[MAXPATHLEN], rpath[MAXPATHLEN], repo[MAXPATHLEN];
- const char *comment;
- struct stat fst;
- struct timeval ts[2];
- struct cvsroot *root;
- struct rcs_delta *rdp;
- struct rcs_branch *brp;
- RCSFILE *rf;
- RCSNUM *rev, *brev;
- BUF *bp;
-
- root = CVS_DIR_ROOT(cf);
-
- if (cvs_path_cat(root->cr_dir, module, repo, sizeof(repo)) >=
- sizeof(repo))
- fatal("cvs_import_local: cvs_path_cat overflow");
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- if (cf->cf_type == DT_DIR) {
- if (!strcmp(cf->cf_name, "."))
- strlcpy(rpath, repo, sizeof(rpath));
- else {
- if (cvs_path_cat(repo, fpath, rpath,
- sizeof(rpath)) >= sizeof(rpath))
- fatal("cvs_import_local: cvs_path_cat overflow");
-
- cvs_printf("Importing %s\n", rpath);
- if (mkdir(rpath, 0755) == -1) {
- cvs_log(LP_ERRNO, "failed to create %s",
- rpath);
- }
- }
-
- return (0);
- }
-
- /*
- * If -d was given, use the file's last modification time as the
- * timestamps for the initial revisions.
- */
- if (dflag == 1) {
- if (stat(fpath, &fst) == -1)
- fatal("cvs_import_local: stat failed on `%s': %s",
- fpath, strerror(errno));
-
- stamp = (time_t)fst.st_mtime;
-
- ts[0].tv_sec = stamp;
- ts[0].tv_usec = 0;
- ts[1].tv_sec = stamp;
- ts[1].tv_usec = 0;
- } else
- stamp = -1;
-
- if (strlcpy(rpath, repo, sizeof(rpath)) >= sizeof(rpath) ||
- strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath) ||
- strlcat(rpath, fpath, sizeof(rpath)) >= sizeof(rpath) ||
- strlcat(rpath, RCS_FILE_EXT, sizeof(rpath)) >= sizeof(rpath))
- fatal("cvs_import_local: path truncation");
-
- cvs_printf("N %s\n", fpath);
-
- if ((rf = rcs_open(rpath, RCS_RDWR|RCS_CREATE, 0444)) == NULL)
- fatal("cvs_import_local: rcs_open: `%s': %s", rpath,
- rcs_errstr(rcs_errno));
-
- comment = rcs_comment_lookup(cf->cf_name);
- if (comment != NULL)
- rcs_comment_set(rf, comment);
-
- brev = rcsnum_brtorev(imp_brnum);
- if (rcs_rev_add(rf, brev, cvs_msg, stamp, NULL) < 0) {
- (void)unlink(rpath);
- fatal("cvs_import_local: rcs_rev_add failed: %s",
- rcs_errstr(rcs_errno));
- }
-
- if (rcs_sym_add(rf, release, brev) < 0) {
- (void)unlink(rpath);
- fatal("cvs_import_local: rcs_sym_add failed: %s",
- rcs_errstr(rcs_errno));
- }
-
- rev = rcsnum_alloc();
- rcsnum_cpy(imp_brnum, rev, 2);
- if (rcs_rev_add(rf, rev, cvs_msg, stamp, NULL) < 0) {
- (void)unlink(rpath);
- fatal("cvs_import_local: rcs_rev_add failed: %s",
- rcs_errstr(rcs_errno));
- }
-
- if (rcs_head_set(rf, rev) < 0) {
- (void)unlink(rpath);
- fatal("cvs_import_local: rcs_head_set failed: %s",
- rcs_errstr(rcs_errno));
- }
-
- if (rcs_branch_set(rf, imp_brnum) < 0) {
- (void)unlink(rpath);
- fatal("cvs_import_local: rcs_branch_set failed: %s",
- rcs_errstr(rcs_errno));
- }
-
- if (rcs_sym_add(rf, vendor, imp_brnum) < 0) {
- (void)unlink(rpath);
- fatal("cvs_import_local: rcs_sym_add failed: %s",
- rcs_errstr(rcs_errno));
- }
-
- /*
- * Put the branch revision on the branches list for the first revision.
- */
- rdp = rcs_findrev(rf, rev);
- brp = xmalloc(sizeof(*brp));
- brp->rb_num = rcsnum_alloc();
- rcsnum_cpy(brev, brp->rb_num, 0);
- TAILQ_INSERT_TAIL(&(rdp->rd_branches), brp, rb_list);
-
- if ((bp = cvs_buf_load(fpath, BUF_AUTOEXT)) == NULL) {
- (void)unlink(rpath);
- fatal("cvs_import_local: cvs_buf_load failed");
- }
-
- cvs_buf_putc(bp, '\0');
-
- fcont = cvs_buf_release(bp);
-
- if (rcs_deltatext_set(rf, rev, fcont) < 0) {
- (void)unlink(rpath);
- fatal("cvs_import_local: rcs_deltatext_set failed");
- }
-
- /* add the vendor tag and release tag as symbols */
- rcs_close(rf);
-
- if (dflag ==1 && utimes(rpath, ts) == -1)
- cvs_log(LP_ERRNO, "failed to timestamp RCS file");
-
- return (0);
-}
-
-static int
-cvs_import_cleanup(void)
-{
- if (imp_brnum != NULL)
- rcsnum_free(imp_brnum);
- return (0);
-}
diff --git a/usr.bin/cvs/log.c b/usr.bin/cvs/log.c
index 94b02d0305c..22064ec3548 100644
--- a/usr.bin/cvs/log.c
+++ b/usr.bin/cvs/log.c
@@ -1,5 +1,6 @@
-/* $OpenBSD: log.c,v 1.34 2006/04/20 12:13:19 xsa Exp $ */
+/* $OpenBSD: log.c,v 1.35 2006/05/27 03:30:30 joris Exp $ */
/*
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
*
@@ -31,138 +32,7 @@
extern char *__progname;
-
-#ifdef unused
-static char *cvs_log_levels[LP_MAX + 1] = {
- "debug",
- "info",
- "notice",
- "warning",
- "error",
- "alert",
- "error",
- "abort",
- "trace",
-};
-#endif
-
-static int cvs_slpriomap[LP_MAX + 1] = {
- LOG_DEBUG,
- LOG_INFO,
- LOG_NOTICE,
- LOG_WARNING,
- LOG_ERR,
- LOG_ALERT,
- LOG_ERR,
- LOG_ERR,
- LOG_DEBUG,
-};
-
-#if !defined(RCSPROG)
static int send_m = 1;
-#endif
-static u_int cvs_log_dest = LD_STD;
-static u_int cvs_log_flags = 0;
-
-static struct syslog_data cvs_sl = SYSLOG_DATA_INIT;
-
-/* filter manipulation macros */
-#define CVS_LOG_FLTRRST() (cvs_log_filters = 0)
-#define CVS_LOG_FLTRSET(l) (cvs_log_filters |= (1 << l))
-#define CVS_LOG_FLTRGET(l) (cvs_log_filters & (1 << l))
-#define CVS_LOG_FLTRCLR(l) (cvs_log_filters &= ~(1 << l))
-
-static u_int cvs_log_filters;
-
-
-/*
- * cvs_log_init()
- *
- * Initialize the logging facility of the server.
- */
-void
-cvs_log_init(u_int dest, u_int flags)
-{
- int slopt;
-
- cvs_log_dest = dest;
- cvs_log_flags = flags;
-
- /* by default, filter only LP_DEBUG and LP_INFO levels */
- CVS_LOG_FLTRRST();
- CVS_LOG_FLTRSET(LP_DEBUG);
- CVS_LOG_FLTRSET(LP_INFO);
-
- /* traces are enabled with the -t command-line option */
- CVS_LOG_FLTRSET(LP_TRACE);
-
- if (dest & LD_SYSLOG) {
- slopt = 0;
-
- if (dest & LD_CONS)
- slopt |= LOG_CONS;
- if (flags & LF_PID)
- slopt |= LOG_PID;
-
- openlog_r(__progname, slopt, LOG_DAEMON, &cvs_sl);
- }
-}
-
-
-/*
- * cvs_log_cleanup()
- *
- * Cleanup the logging facility.
- */
-void
-cvs_log_cleanup(void)
-{
-
- closelog_r(&cvs_sl);
-}
-
-
-/*
- * cvs_log_filter()
- *
- * Apply or remove filters on the logging facility. The exact operation is
- * specified by the <how> and <level> arguments. The <how> arguments tells
- * how the filters will be affected, and <level> gives the log levels that
- * will be affected by the change.
- * Returns 0 on success, or -1 on failure.
- */
-
-int
-cvs_log_filter(u_int how, u_int level)
-{
- u_int i;
-
- if (level > LP_MAX && level != LP_ALL) {
- cvs_log(LP_ERR, "invalid log level for filter");
- return (-1);
- }
-
- switch (how) {
- case LP_FILTER_SET:
- if (level == LP_ALL)
- for (i = 0; i <= LP_MAX; i++)
- CVS_LOG_FLTRSET(i);
- else
- CVS_LOG_FLTRSET(level);
- break;
- case LP_FILTER_UNSET:
- if (level == LP_ALL)
- CVS_LOG_FLTRRST();
- else
- CVS_LOG_FLTRCLR(level);
- break;
- default:
- return (-1);
- }
-
- return (0);
-}
-
/*
* cvs_log()
@@ -181,7 +51,6 @@ cvs_log(u_int level, const char *fmt, ...)
va_end(vap);
}
-
/*
* cvs_vlog()
*
@@ -194,16 +63,10 @@ cvs_vlog(u_int level, const char *fmt, va_list vap)
int ecp;
char prefix[64], buf[1024], ebuf[255];
FILE *out;
-#if !defined(RCSPROG)
char *cmdname;
struct cvs_cmd *cmdp;
-#endif
- if (level > LP_MAX)
- fatal("cvs_vlog failed");
-
- /* apply any filters */
- if (CVS_LOG_FLTRGET(level))
+ if (cvs_trace != 1 && level == LP_TRACE)
return;
if (level == LP_ERRNO)
@@ -212,7 +75,6 @@ cvs_vlog(u_int level, const char *fmt, va_list vap)
ecp = 0;
/* always use the command name in error messages, not aliases */
-#if !defined(RCSPROG)
if (cvs_command == NULL)
cmdname = " ";
else {
@@ -233,54 +95,41 @@ cvs_vlog(u_int level, const char *fmt, va_list vap)
snprintf(prefix, sizeof(prefix), "%s %s", __progname,
cmdname);
} else /* just use the standard strlcpy */
-#endif
strlcpy(prefix, __progname, sizeof(prefix));
- if ((cvs_log_flags & LF_PID) && level != LP_TRACE) {
- snprintf(buf, sizeof(buf), "[%d]", (int)getpid());
- strlcat(prefix, buf, sizeof(prefix));
- }
-
vsnprintf(buf, sizeof(buf), fmt, vap);
if (level == LP_ERRNO) {
snprintf(ebuf, sizeof(ebuf), ": %s", strerror(errno));
strlcat(buf, ebuf, sizeof(buf));
}
- if (cvs_log_dest & LD_STD) {
- if (level < LP_NOTICE)
- out = stdout;
- else
- out = stderr;
+ if (level == LP_NOTICE)
+ out = stdout;
+ else
+ out = stderr;
-#if !defined(RCSPROG)
- if (cvs_cmdop == CVS_OP_SERVER) {
- if (out == stdout)
- putc('M', out);
- else {
- out = stdout;
- putc('E', out);
- }
- putc(' ', out);
+ if (cvs_cmdop == CVS_OP_SERVER) {
+ if (out == stdout)
+ putc('M', out);
+ else {
+ out = stdout;
+ putc('E', out);
}
-#endif
- fputs(prefix, out);
- if (level != LP_TRACE)
- fputs(": ", out);
- fputs(buf, out);
- fputc('\n', out);
+ putc(' ', out);
}
- if (cvs_log_dest & LD_SYSLOG)
- syslog_r(cvs_slpriomap[level], &cvs_sl, "%s", buf);
+ fputs(prefix, out);
+ if (level != LP_TRACE)
+ fputs(": ", out);
+ fputs(buf, out);
+ fputc('\n', out);
/* preserve it just in case we changed it? */
if (level == LP_ERRNO)
errno = ecp;
}
-
/*
* cvs_printf()
*
@@ -291,14 +140,11 @@ int
cvs_printf(const char *fmt, ...)
{
int ret;
-#if !defined(RCSPROG)
char *nstr, *dp, *sp;
-#endif
va_list vap;
va_start(vap, fmt);
-#if !defined(RCSPROG)
if (cvs_cmdop == CVS_OP_SERVER) {
ret = vasprintf(&nstr, fmt, vap);
if (ret == -1)
@@ -326,7 +172,6 @@ cvs_printf(const char *fmt, ...)
}
xfree(nstr);
} else
-#endif
ret = vprintf(fmt, vap);
va_end(vap);
diff --git a/usr.bin/cvs/log.h b/usr.bin/cvs/log.h
index a5490d12b1f..2eef696f164 100644
--- a/usr.bin/cvs/log.h
+++ b/usr.bin/cvs/log.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.h,v 1.18 2006/04/20 12:13:19 xsa Exp $ */
+/* $OpenBSD: log.h,v 1.19 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -27,38 +27,13 @@
#ifndef LOG_H
#define LOG_H
-/* log destinations */
-#define LD_STD 0x01
-#define LD_SYSLOG 0x02
-#define LD_CONS 0x04
-
-#define LD_ALL (LD_STD|LD_SYSLOG|LD_CONS)
-
-/* log flags */
-#define LF_PID 0x01 /* include PID in messages */
-
-
/* log priority levels */
-#define LP_DEBUG 0
-#define LP_INFO 1
-#define LP_NOTICE 2
-#define LP_WARN 3
-#define LP_ERR 4
-#define LP_ALERT 5
-#define LP_ERRNO 6
-#define LP_ABORT 7
-#define LP_TRACE 8
-
-#define LP_MAX 8
-#define LP_ALL 255
-
-/* filtering methods */
-#define LP_FILTER_SET 0 /* set a filter */
-#define LP_FILTER_UNSET 1 /* remove a filter */
+#define LP_NOTICE 0
+#define LP_ERR 1
+#define LP_ERRNO 2
+#define LP_ABORT 3
+#define LP_TRACE 4
-void cvs_log_init(u_int, u_int);
-void cvs_log_cleanup(void);
-int cvs_log_filter(u_int, u_int);
void cvs_log(u_int, const char *, ...) __attribute__((format(printf, 2, 3)));
void cvs_vlog(u_int, const char *, va_list);
int cvs_printf(const char *, ...) __attribute__((format(printf, 1, 2)));
diff --git a/usr.bin/cvs/logmsg.c b/usr.bin/cvs/logmsg.c
deleted file mode 100644
index 933ccf9e0c7..00000000000
--- a/usr.bin/cvs/logmsg.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/* $OpenBSD: logmsg.c,v 1.28 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "buf.h"
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-#define CVS_LOGMSG_BIGMSG 32000
-#define CVS_LOGMSG_PREFIX "CVS:"
-#define CVS_LOGMSG_LINE \
-"----------------------------------------------------------------------"
-
-
-static const char *cvs_logmsg_ops[3] = {
- "Added", "Modified", "Removed",
-};
-
-
-/*
- * cvs_logmsg_open()
- *
- * Open the file specified by <path> and allocate a buffer large enough to
- * hold all of the file's contents. Lines starting with the log prefix
- * are not included in the result.
- * The returned value must later be free()d.
- * Returns a pointer to the allocated buffer on success, or NULL on failure.
- */
-char *
-cvs_logmsg_open(const char *path)
-{
- int lcont;
- size_t len;
- char lbuf[256], *msg;
- struct stat st;
- FILE *fp;
- BUF *bp;
-
- if (stat(path, &st) == -1)
- fatal("cvs_logmsg_open: stat: `%s': %s", path, strerror(errno));
-
- if (!S_ISREG(st.st_mode))
- fatal("cvs_logmsg_open: message file must be a regular file");
-
- if (st.st_size > CVS_LOGMSG_BIGMSG) {
- do {
- fprintf(stderr,
- "The specified message file seems big. "
- "Proceed anyways? (y/n) ");
- if (fgets(lbuf, (int)sizeof(lbuf), stdin) == NULL)
- fatal("cvs_logmsg_open: fgets failed");
-
- len = strlen(lbuf);
- if (len == 0 || len > 2 ||
- (lbuf[0] != 'y' && lbuf[0] != 'n')) {
- fprintf(stderr, "invalid input\n");
- continue;
- } else if (lbuf[0] == 'y')
- break;
- else if (lbuf[0] == 'n')
- fatal("aborted by user");
-
- } while (1);
- }
-
- if ((fp = fopen(path, "r")) == NULL)
- fatal("cvs_logmsg_open: fopen: `%s': %s",
- path, strerror(errno));
-
- bp = cvs_buf_alloc((size_t)128, BUF_AUTOEXT);
-
- /* lcont is used to tell if a buffer returned by fgets is a start
- * of line or just line continuation because the buffer isn't
- * large enough to hold the entire line.
- */
- lcont = 0;
-
- while (fgets(lbuf, (int)sizeof(lbuf), fp) != NULL) {
- len = strlen(lbuf);
- if (len == 0)
- continue;
- else if (lcont == 0 &&
- strncmp(lbuf, CVS_LOGMSG_PREFIX, strlen(CVS_LOGMSG_PREFIX)) == 0)
- /* skip lines starting with the prefix */
- continue;
-
- cvs_buf_append(bp, lbuf, strlen(lbuf));
-
- lcont = (lbuf[len - 1] == '\n') ? 0 : 1;
- }
- (void)fclose(fp);
-
- cvs_buf_putc(bp, '\0');
-
- msg = (char *)cvs_buf_release(bp);
-
- return (msg);
-}
-
-
-/*
- * cvs_logmsg_get()
- *
- * Get a log message by forking and executing the user's editor. The <dir>
- * argument is a relative path to the directory for which the log message
- * applies, and the 3 tail queue arguments contains all the files for which the
- * log message will apply. Any of these arguments can be set to NULL in the
- * case where there is no information to display.
- * Returns the message in a dynamically allocated string on success, NULL on
- * failure.
- */
-char *
-cvs_logmsg_get(const char *dir, struct cvs_flist *added,
- struct cvs_flist *modified, struct cvs_flist *removed)
-{
- int i, fd, argc, fds[3], nl;
- size_t len, tlen;
- char *argv[4], buf[16], path[MAXPATHLEN], fpath[MAXPATHLEN], *msg;
- FILE *fp;
- CVSFILE *cvsfp;
- struct stat st1, st2;
- struct cvs_flist *files[3];
-
- files[0] = added;
- files[1] = modified;
- files[2] = removed;
-
- msg = NULL;
- fds[0] = -1;
- fds[1] = -1;
- fds[2] = -1;
- strlcpy(path, cvs_tmpdir, sizeof(path));
- strlcat(path, "/cvsXXXXXXXXXX", sizeof(path));
- argc = 0;
- argv[argc++] = cvs_editor;
- argv[argc++] = path;
- argv[argc] = NULL;
- tlen = 0;
-
- if ((fd = mkstemp(path)) == -1)
- fatal("cvs_logmsg_get: mkstemp: `%s': %s",
- path, strerror(errno));
-
- if ((fp = fdopen(fd, "w")) == NULL) {
- if (unlink(path) == -1)
- cvs_log(LP_ERRNO, "failed to unlink temporary file");
- fatal("cvs_logmsg_get: fdopen failed");
- }
-
- fprintf(fp, "\n%s %s\n%s Enter Log. Lines beginning with `%s' are "
- "removed automatically\n%s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE,
- CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX, CVS_LOGMSG_PREFIX);
-
- if (dir != NULL)
- fprintf(fp, "%s Commiting in %s\n%s\n", CVS_LOGMSG_PREFIX, dir,
- CVS_LOGMSG_PREFIX);
-
- for (i = 0; i < 3; i++) {
- if (files[i] == NULL)
- continue;
-
- if (SIMPLEQ_EMPTY(files[i]))
- continue;
-
- fprintf(fp, "%s %s Files:", CVS_LOGMSG_PREFIX,
- cvs_logmsg_ops[i]);
- nl = 1;
- SIMPLEQ_FOREACH(cvsfp, files[i], cf_list) {
- /* take the space into account */
- cvs_file_getpath(cvsfp, fpath, sizeof(fpath));
- len = strlen(fpath) + 1;
- if (tlen + len >= 72)
- nl = 1;
-
- if (nl) {
- fprintf(fp, "\n%s\t", CVS_LOGMSG_PREFIX);
- tlen = 8;
- nl = 0;
- }
-
- fprintf(fp, " %s", fpath);
- tlen += len;
- }
- fputc('\n', fp);
-
- }
- fprintf(fp, "%s %s\n", CVS_LOGMSG_PREFIX, CVS_LOGMSG_LINE);
- (void)fflush(fp);
-
- if (fstat(fd, &st1) == -1) {
- if (unlink(path) == -1)
- cvs_log(LP_ERRNO, "failed to unlink log file %s", path);
- fatal("cvs_logmsg_get: fstat failed");
- }
-
- for (;;) {
- if (cvs_exec(argc, argv, fds) < 0)
- break;
-
- if (fstat(fd, &st2) == -1) {
- cvs_log(LP_ERRNO, "failed to stat log message file");
- break;
- }
-
- if (st2.st_mtime != st1.st_mtime) {
- msg = cvs_logmsg_open(path);
- break;
- }
-
- /* nothing was entered */
- fprintf(stderr,
- "\nLog message unchanged or not specified\na)bort, "
- "c)ontinue, e)dit, !)reuse this message unchanged "
- "for remaining dirs\nAction: (continue) ");
-
- if (fgets(buf, (int)sizeof(buf), stdin) == NULL) {
- cvs_log(LP_ERRNO, "failed to read from standard input");
- break;
- }
-
- len = strlen(buf);
- if (len == 0 || len > 2) {
- fprintf(stderr, "invalid input\n");
- continue;
- } else if (buf[0] == 'a') {
- cvs_log(LP_ABORT, "aborted by user");
- break;
- } else if (buf[0] == '\n' || buf[0] == 'c') {
- /* empty message */
- msg = xstrdup("");
- break;
- } else if (buf[0] == 'e')
- continue;
- else if (buf[0] == '!') {
- /* XXX do something */
- }
- }
-
- (void)fclose(fp);
- (void)close(fd);
-
- if (unlink(path) == -1)
- cvs_log(LP_ERRNO, "failed to unlink log file %s", path);
-
- return (msg);
-}
-
-
-/*
- * cvs_logmsg_send()
- *
- */
-void
-cvs_logmsg_send(struct cvsroot *root, const char *msg)
-{
- const char *mp;
- char *np, buf[256];
-
- cvs_sendarg(root, "-m", 0);
-
- for (mp = msg; mp != NULL; mp = strchr(mp, '\n')) {
- if (*mp == '\n')
- mp++;
-
- /* XXX ghetto */
- strlcpy(buf, mp, sizeof(buf));
- np = strchr(buf, '\n');
- if (np != NULL)
- *np = '\0';
- cvs_sendarg(root, buf, (mp == msg) ? 0 : 1);
- }
-}
diff --git a/usr.bin/cvs/proto.c b/usr.bin/cvs/proto.c
deleted file mode 100644
index e0b2010bb0a..00000000000
--- a/usr.bin/cvs/proto.c
+++ /dev/null
@@ -1,1033 +0,0 @@
-/* $OpenBSD: proto.c,v 1.97 2006/04/14 02:49:43 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- * CVS client/server protocol
- * ==========================
- *
- * The following code implements the CVS client/server protocol, which is
- * documented at the following URL:
- * http://www.iam.unibe.ch/~til/documentation/cvs/cvsclient_toc.html
- * http://www.elegosoft.com/cvs/cvsclient_toc.html
- *
- * The protocol is split up into two parts; the first part is the client side
- * of things and is composed of all the response handlers, which are all named
- * with a prefix of "cvs_resp_". The second part is the set of request
- * handlers used by the server. These handlers process the request and
- * generate the appropriate response to send back. The prefix for request
- * handlers is "cvs_req_".
- *
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-/* request flags */
-#define CVS_REQF_RESP 0x01
-
-
-static void cvs_initlog(void);
-
-struct cvs_req cvs_requests[] = {
- { CVS_REQ_DIRECTORY, "Directory", 0 },
- { CVS_REQ_MAXDOTDOT, "Max-dotdot", 0 },
- { CVS_REQ_STATICDIR, "Static-directory", 0 },
- { CVS_REQ_STICKY, "Sticky", 0 },
- { CVS_REQ_ENTRY, "Entry", 0 },
- { CVS_REQ_ENTRYEXTRA, "EntryExtra", 0 },
- { CVS_REQ_CHECKINTIME, "Checkin-time", 0 },
- { CVS_REQ_MODIFIED, "Modified", 0 },
- { CVS_REQ_ISMODIFIED, "Is-modified", 0 },
- { CVS_REQ_UNCHANGED, "Unchanged", 0 },
- { CVS_REQ_USEUNCHANGED, "UseUnchanged", 0 },
- { CVS_REQ_NOTIFY, "Notify", 0 },
- { CVS_REQ_NOTIFYUSER, "NotifyUser", 0 },
- { CVS_REQ_QUESTIONABLE, "Questionable", 0 },
- { CVS_REQ_CASE, "Case", 0 },
- { CVS_REQ_UTF8, "Utf8", 0 },
- { CVS_REQ_ARGUMENT, "Argument", 0 },
- { CVS_REQ_ARGUMENTX, "Argumentx", 0 },
- { CVS_REQ_GLOBALOPT, "Global_option", 0 },
- { CVS_REQ_GZIPSTREAM, "Gzip-stream", 0 },
- { CVS_REQ_READCVSRC2, "read-cvsrc2", 0 },
- { CVS_REQ_READWRAP, "read-cvswrappers", 0 },
- { CVS_REQ_READIGNORE, "read-cvsignore", 0 },
- { CVS_REQ_ERRIFREADER, "Error-If-Reader", 0 },
- { CVS_REQ_VALIDRCSOPT, "Valid-RcsOptions", 0 },
- { CVS_REQ_SET, "Set", 0 },
- { CVS_REQ_XPANDMOD, "expand-modules", CVS_REQF_RESP },
- { CVS_REQ_LOG, "log", CVS_REQF_RESP },
- { CVS_REQ_CO, "co", CVS_REQF_RESP },
- { CVS_REQ_EXPORT, "export", CVS_REQF_RESP },
- { CVS_REQ_ANNOTATE, "annotate", CVS_REQF_RESP },
- { CVS_REQ_RDIFF, "rdiff", CVS_REQF_RESP },
- { CVS_REQ_RTAG, "rtag", CVS_REQF_RESP },
- { CVS_REQ_INIT, "init", CVS_REQF_RESP },
- { CVS_REQ_STATUS, "status", CVS_REQF_RESP },
- { CVS_REQ_UPDATE, "update", CVS_REQF_RESP },
- { CVS_REQ_HISTORY, "history", CVS_REQF_RESP },
- { CVS_REQ_IMPORT, "import", CVS_REQF_RESP },
- { CVS_REQ_ADD, "add", CVS_REQF_RESP },
- { CVS_REQ_REMOVE, "remove", CVS_REQF_RESP },
- { CVS_REQ_RELEASE, "release", CVS_REQF_RESP },
- { CVS_REQ_ROOT, "Root", 0 },
- { CVS_REQ_VALIDRESP, "Valid-responses", 0 },
- { CVS_REQ_VALIDREQ, "valid-requests", CVS_REQF_RESP },
- { CVS_REQ_VERSION, "version", CVS_REQF_RESP },
- { CVS_REQ_NOOP, "noop", CVS_REQF_RESP },
- { CVS_REQ_DIFF, "diff", CVS_REQF_RESP },
- { CVS_REQ_CI, "ci", CVS_REQF_RESP },
- { CVS_REQ_TAG, "tag", CVS_REQF_RESP },
- { CVS_REQ_ADMIN, "admin", CVS_REQF_RESP },
- { CVS_REQ_WATCHERS, "watchers", CVS_REQF_RESP },
- { CVS_REQ_WATCH_ON, "watch-on", CVS_REQF_RESP },
- { CVS_REQ_WATCH_OFF, "watch-off", CVS_REQF_RESP },
- { CVS_REQ_WATCH_ADD, "watch-add", CVS_REQF_RESP },
- { CVS_REQ_WATCH_REMOVE, "watch-remove", CVS_REQF_RESP },
- { CVS_REQ_EDITORS, "editors", CVS_REQF_RESP },
-};
-
-struct cvs_resp cvs_responses[] = {
- { CVS_RESP_OK, "ok" },
- { CVS_RESP_ERROR, "error" },
- { CVS_RESP_VALIDREQ, "Valid-requests" },
- { CVS_RESP_M, "M" },
- { CVS_RESP_MBINARY, "Mbinary" },
- { CVS_RESP_MT, "MT" },
- { CVS_RESP_E, "E" },
- { CVS_RESP_F, "F" },
- { CVS_RESP_CREATED, "Created" },
- { CVS_RESP_UPDATED, "Updated" },
- { CVS_RESP_UPDEXIST, "Update-existing" },
- { CVS_RESP_MERGED, "Merged" },
- { CVS_RESP_REMOVED, "Removed" },
- { CVS_RESP_RMENTRY, "Remove-entry" },
- { CVS_RESP_CKSUM, "Checksum" },
- { CVS_RESP_CLRSTATDIR, "Clear-static-directory" },
- { CVS_RESP_SETSTATDIR, "Set-static-directory" },
- { CVS_RESP_NEWENTRY, "New-entry" },
- { CVS_RESP_CHECKEDIN, "Checked-in" },
- { CVS_RESP_MODE, "Mode" },
- { CVS_RESP_MODTIME, "Mod-time" },
- { CVS_RESP_MODXPAND, "Module-expansion" },
- { CVS_RESP_SETSTICKY, "Set-sticky" },
- { CVS_RESP_CLRSTICKY, "Clear-sticky" },
- { CVS_RESP_RCSDIFF, "Rcs-diff" },
- { CVS_RESP_TEMPLATE, "Template" },
- { CVS_RESP_COPYFILE, "Copy-file" },
-};
-
-#define CVS_NBREQ (sizeof(cvs_requests)/sizeof(cvs_requests[0]))
-#define CVS_NBRESP (sizeof(cvs_responses)/sizeof(cvs_responses[0]))
-
-/* hack to receive the remote version without outputting it */
-u_int cvs_version_sent = 0;
-
-static char cvs_proto_buf[4096];
-
-/*
- * Output files for protocol logging when the CVS_CLIENT_LOG environment
- * variable is set.
- */
-static int cvs_server_logon = 0;
-static FILE *cvs_server_inlog = NULL;
-static FILE *cvs_server_outlog = NULL;
-
-static pid_t cvs_subproc_pid;
-
-/* last directory sent with cvs_senddir() */
-static char cvs_lastdir[MAXPATHLEN] = "";
-
-
-/*
- * cvs_connect()
- *
- * Open a client connection to the cvs server whose address is given in
- * the <root> variable. The method used to connect depends on the
- * setting of the CVS_RSH variable.
- * Once the connection has been established, we first send the list of
- * responses we support and request the list of supported requests from the
- * server. Then, a version request is sent and various global flags are sent.
- */
-void
-cvs_connect(struct cvsroot *root)
-{
- size_t len;
- int argc, infd[2], outfd[2], errfd[2];
- char *argv[16], *cvs_server_cmd, tmsg[1024], *vresp;
-
- if (root->cr_method == CVS_METHOD_PSERVER)
- fatal("no pserver support due to security issues");
- else if (root->cr_method == CVS_METHOD_KSERVER ||
- root->cr_method == CVS_METHOD_GSERVER ||
- root->cr_method == CVS_METHOD_EXT ||
- root->cr_method == CVS_METHOD_FORK)
- fatal("connection method not supported yet");
-
- if (root->cr_flags & CVS_ROOT_CONNECTED) {
- cvs_log(LP_NOTICE, "already connected to CVSROOT");
- return;
- }
-
- if (pipe(infd) == -1)
- fatal("failed to create input pipe for client connection");
-
- if (pipe(outfd) == -1)
- fatal("failed to create output pipe for client connection");
-
- if (pipe(errfd) == -1)
- fatal("failed to create error pipe for client connection");
-
- cvs_subproc_pid = fork();
- if (cvs_subproc_pid == -1) {
- fatal("failed to fork for cvs server connection");
- } else if (cvs_subproc_pid == 0) {
- if (dup2(infd[0], STDIN_FILENO) == -1 ||
- dup2(outfd[1], STDOUT_FILENO) == -1)
- fatal("failed to setup standard streams "
- "for cvs server");
-
- (void)close(infd[1]);
- (void)close(outfd[0]);
- (void)close(errfd[0]);
-
- argc = 0;
- argv[argc++] = cvs_rsh;
-
- if (root->cr_user != NULL) {
- argv[argc++] = "-l";
- argv[argc++] = root->cr_user;
- }
-
- cvs_server_cmd = getenv("CVS_SERVER");
- if (cvs_server_cmd == NULL)
- cvs_server_cmd = CVS_SERVER_DEFAULT;
-
- argv[argc++] = root->cr_host;
- argv[argc++] = cvs_server_cmd;
- argv[argc++] = "server";
- argv[argc] = NULL;
-
- if (cvs_trace == 1) {
- tmsg[0] = '\0';
- for (argc = 0; argv[argc] != NULL; argc++) {
- len = strlcat(tmsg, argv[argc], sizeof(tmsg));
- if (len >= sizeof(tmsg))
- fatal("truncation in cvs_connect");
-
- len = strlcat(tmsg, " ", sizeof(tmsg));
- if (len >= sizeof(tmsg))
- fatal("truncation in cvs_connect");
- }
- }
-
- cvs_log(LP_TRACE, "Starting server: %s", tmsg);
-
- execvp(argv[0], argv);
- fatal("failed to execute cvs server");
- }
-
- /* we are the parent */
- (void)close(infd[0]);
- (void)close(outfd[1]);
- (void)close(errfd[1]);
-
- root->cr_srvin = fdopen(infd[1], "w");
- if (root->cr_srvin == NULL)
- fatal("failed to create pipe stream");
-
- root->cr_srvout = fdopen(outfd[0], "r");
- if (root->cr_srvout == NULL)
- fatal("failed to create pipe stream");
-
- /* make the streams line-buffered */
- (void)setvbuf(root->cr_srvin, NULL, _IOLBF, (size_t)0);
- (void)setvbuf(root->cr_srvout, NULL, _IOLBF, (size_t)0);
-
- cvs_initlog();
-
- /*
- * Send the server the list of valid responses, then ask for valid
- * requests.
- */
-
- vresp = cvs_resp_getvalid();
- cvs_sendreq(root, CVS_REQ_VALIDRESP, vresp);
- xfree(vresp);
-
- cvs_sendreq(root, CVS_REQ_VALIDREQ, NULL);
-
- /* send the CVSROOT to the server */
- cvs_sendreq(root, CVS_REQ_ROOT, root->cr_dir);
-
- /* don't fail if this request doesn't work */
- cvs_sendreq(root, CVS_REQ_VERSION, NULL);
-
- /* now share our global options with the server */
- if (verbosity <= 1)
- cvs_sendreq(root, CVS_REQ_GLOBALOPT, "-q");
- if (verbosity == 0)
- cvs_sendreq(root, CVS_REQ_GLOBALOPT, "-Q");
-
- if (cvs_noexec == 1)
- cvs_sendreq(root, CVS_REQ_GLOBALOPT, "-n");
-
- if (cvs_nolog == 1)
- cvs_sendreq(root, CVS_REQ_GLOBALOPT, "-l");
-
- if (cvs_readonly == 1)
- cvs_sendreq(root, CVS_REQ_GLOBALOPT, "-r");
-
- if (cvs_trace == 1)
- cvs_sendreq(root, CVS_REQ_GLOBALOPT, "-t");
-
- /* not sure why, but we have to send this */
- cvs_sendreq(root, CVS_REQ_USEUNCHANGED, NULL);
-
- cvs_log(LP_DEBUG, "connected to %s", root->cr_host);
-
- root->cr_flags |= CVS_ROOT_CONNECTED;
-}
-
-
-/*
- * cvs_disconnect()
- *
- * Disconnect from the cvs server.
- */
-void
-cvs_disconnect(struct cvsroot *root)
-{
- if (!(root->cr_flags & CVS_ROOT_CONNECTED))
- return;
-
- cvs_log(LP_DEBUG, "closing connection to %s", root->cr_host);
-
- if (root->cr_srvin != NULL) {
- (void)fclose(root->cr_srvin);
- root->cr_srvin = NULL;
- }
- if (root->cr_srvout != NULL) {
- (void)fclose(root->cr_srvout);
- root->cr_srvout = NULL;
- }
-
- root->cr_flags &= ~CVS_ROOT_CONNECTED;
-}
-
-
-/*
- * cvs_req_getbyid()
- *
- */
-struct cvs_req*
-cvs_req_getbyid(int reqid)
-{
- u_int i;
-
- for (i = 0; i < CVS_NBREQ; i++)
- if (cvs_requests[i].req_id == reqid)
- return &(cvs_requests[i]);
-
- return (NULL);
-}
-
-
-/*
- * cvs_req_getbyname()
- */
-struct cvs_req*
-cvs_req_getbyname(const char *rname)
-{
- u_int i;
-
- for (i = 0; i < CVS_NBREQ; i++)
- if (strcmp(cvs_requests[i].req_str, rname) == 0)
- return &(cvs_requests[i]);
-
- return (NULL);
-}
-
-
-/*
- * cvs_req_getvalid()
- *
- * Build a space-separated list of all the requests that this protocol
- * implementation supports.
- */
-char *
-cvs_req_getvalid(void)
-{
- u_int i;
- size_t len;
- char *vrstr;
- BUF *buf;
-
- buf = cvs_buf_alloc((size_t)512, BUF_AUTOEXT);
-
- cvs_buf_set(buf, cvs_requests[0].req_str,
- strlen(cvs_requests[0].req_str), (size_t)0);
-
- for (i = 1; i < CVS_NBREQ; i++) {
- cvs_buf_putc(buf, ' ');
- cvs_buf_append(buf, cvs_requests[i].req_str,
- strlen(cvs_requests[i].req_str));
- }
-
- /* NUL-terminate */
- cvs_buf_putc(buf, '\0');
-
- len = cvs_buf_len(buf);
- vrstr = xmalloc(len);
- cvs_buf_copy(buf, (size_t)0, vrstr, len);
- cvs_buf_free(buf);
-
- return (vrstr);
-}
-
-
-/*
- * cvs_resp_getbyid()
- *
- */
-struct cvs_resp*
-cvs_resp_getbyid(int respid)
-{
- u_int i;
-
- for (i = 0; i < CVS_NBRESP; i++)
- if (cvs_responses[i].resp_id == (u_int)respid)
- return &(cvs_responses[i]);
-
- return (NULL);
-}
-
-
-/*
- * cvs_resp_getbyname()
- */
-struct cvs_resp *
-cvs_resp_getbyname(const char *rname)
-{
- u_int i;
-
- for (i = 0; i < CVS_NBRESP; i++)
- if (strcmp(cvs_responses[i].resp_str, rname) == 0)
- return &(cvs_responses[i]);
-
- return (NULL);
-}
-
-
-/*
- * cvs_resp_getvalid()
- *
- * Build a space-separated list of all the responses that this protocol
- * implementation supports.
- */
-char *
-cvs_resp_getvalid(void)
-{
- u_int i;
- size_t len;
- char *vrstr;
- BUF *buf;
-
- buf = cvs_buf_alloc((size_t)512, BUF_AUTOEXT);
-
- cvs_buf_set(buf, cvs_responses[0].resp_str,
- strlen(cvs_responses[0].resp_str), (size_t)0);
-
- for (i = 1; i < CVS_NBRESP; i++) {
- cvs_buf_putc(buf, ' ');
- cvs_buf_append(buf, cvs_responses[i].resp_str,
- strlen(cvs_responses[i].resp_str));
- }
-
- /* NUL-terminate */
- cvs_buf_putc(buf, '\0');
-
- len = cvs_buf_len(buf);
- vrstr = xmalloc(len);
- cvs_buf_copy(buf, (size_t)0, vrstr, len);
- cvs_buf_free(buf);
-
- return (vrstr);
-}
-
-
-/*
- * cvs_sendfile()
- *
- * Send the mode and size of a file followed by the file's contents.
- * Returns 0 on success, or -1 on failure.
- */
-void
-cvs_sendfile(struct cvsroot *root, const char *path)
-{
- int fd, l;
- ssize_t ret;
- char buf[4096];
- struct stat st;
-
- cvs_log(LP_TRACE, "Sending file `%s' to server", basename(path));
-
- if (stat(path, &st) == -1) {
- fatal("cvs_sendfile(): stat failed on '%s': %s",
- path, strerror(errno));
- }
-
- cvs_modetostr(st.st_mode, buf, sizeof(buf));
-
- fd = open(path, O_RDONLY, 0);
- if (fd == -1) {
- fatal("cvs_sendfile(): failed to open '%s': %s",
- path, strerror(errno));
- }
-
- cvs_sendln(root, buf);
-
- l = snprintf(buf, sizeof(buf), "%lld\n", st.st_size);
- if (l == -1 || l >= (int)sizeof(buf))
- fatal("overflow in cvs_sendfile");
-
- cvs_sendln(root, buf);
-
- while ((ret = read(fd, buf, sizeof(buf))) != 0) {
- if (ret == -1)
- fatal("cvs_sendfile: read error on '%s'", path);
-
- cvs_sendraw(root, buf, (size_t)ret);
- }
-
- (void)close(fd);
-}
-
-
-/*
- * cvs_recvfile()
- *
- * Receive the mode and size of a file followed the file's contents and
- * create or update the file whose path is <path> with the received
- * information.
- */
-BUF*
-cvs_recvfile(struct cvsroot *root, mode_t *mode)
-{
- size_t len;
- ssize_t ret;
- off_t fsz, cnt;
- char buf[4096], *ep;
- BUF *fbuf;
-
- fbuf = cvs_buf_alloc(sizeof(buf), BUF_AUTOEXT);
-
- cvs_getln(root, buf, sizeof(buf));
- cvs_strtomode(buf, mode);
-
- cvs_getln(root, buf, sizeof(buf));
-
- fsz = (off_t)strtol(buf, &ep, 10);
- if (*ep != '\0')
- fatal("parse error in file size transmission");
-
- cnt = 0;
- do {
- len = MIN(sizeof(buf), (size_t)(fsz - cnt));
- if (len == 0)
- break;
- ret = cvs_recvraw(root, buf, len);
- cvs_buf_append(fbuf, buf, (size_t)ret);
- cnt += (off_t)ret;
- } while (cnt < fsz);
-
- return (fbuf);
-}
-
-/*
- * cvs_sendreq()
- *
- * Send a request to the server of type <rid>, with optional arguments
- * contained in <arg>, which should not be terminated by a newline.
- * Returns 0 on success, or -1 on failure.
- */
-void
-cvs_sendreq(struct cvsroot *root, u_int rid, const char *arg)
-{
- int ret;
- struct cvs_req *req;
-
- if (root->cr_srvin == NULL)
- fatal("cannot send request %u: Not connected", rid);
-
- req = cvs_req_getbyid(rid);
- if (req == NULL)
- fatal("unsupported request type %u", rid);
-
- /* is this request supported by the server? */
- if (!CVS_GETVR(root, req->req_id)) {
- if (rid == CVS_REQ_VERSION) {
- cvs_sendreq(root, CVS_REQ_NOOP, arg);
- } else {
- cvs_log(LP_WARN,
- "remote end does not support request `%s'",
- req->req_str);
- }
-
- return;
- }
-
- if (strlcpy(cvs_proto_buf, req->req_str, sizeof(cvs_proto_buf)) >=
- sizeof(cvs_proto_buf) ||
- strlcat(cvs_proto_buf, (arg == NULL) ? "" : " ",
- sizeof(cvs_proto_buf)) >= sizeof(cvs_proto_buf) ||
- strlcat(cvs_proto_buf, (arg == NULL) ? "" : arg,
- sizeof(cvs_proto_buf)) >= sizeof(cvs_proto_buf) ||
- strlcat(cvs_proto_buf, "\n",
- sizeof(cvs_proto_buf)) >= sizeof(cvs_proto_buf))
- fatal("cvs_sendreq: overflow when creating proto buffer");
-
- if (cvs_server_inlog != NULL)
- fputs(cvs_proto_buf, cvs_server_inlog);
-
- ret = fputs(cvs_proto_buf, root->cr_srvin);
- if (ret == EOF)
- fatal("failed to send request to server");
-
- if (rid == CVS_REQ_VERSION)
- cvs_version_sent = 1;
-
- if (req->req_flags & CVS_REQF_RESP)
- cvs_getresp(root);
-}
-
-
-/*
- * cvs_getresp()
- *
- * Get a response from the server. This call will actually read and handle
- * responses from the server until one of the response handlers returns
- * non-zero (either an error occurred or the end of the response was reached).
- * Returns the number of handled commands on success, or -1 on failure.
- */
-void
-cvs_getresp(struct cvsroot *root)
-{
- int ret;
- size_t len;
-
- do {
- /* wait for incoming data */
- if (fgets(cvs_proto_buf, (int)sizeof(cvs_proto_buf),
- root->cr_srvout) == NULL) {
- if (feof(root->cr_srvout))
- return;
- fatal("failed to read response from server");
- }
-
- if (cvs_server_outlog != NULL)
- fputs(cvs_proto_buf, cvs_server_outlog);
-
- if ((len = strlen(cvs_proto_buf)) != 0) {
- /* if len - 1 != '\n' the line is truncated */
- if (cvs_proto_buf[len - 1] == '\n')
- cvs_proto_buf[--len] = '\0';
- }
-
- ret = cvs_resp_handle(root, cvs_proto_buf);
- } while (ret == 0);
-}
-
-
-/*
- * cvs_getln()
- *
- * Get a line from the remote end and store it in <lbuf>. The terminating
- * newline character is stripped from the result.
- */
-void
-cvs_getln(struct cvsroot *root, char *lbuf, size_t len)
-{
- size_t rlen;
- FILE *in;
-
- if (cvs_cmdop == CVS_OP_SERVER)
- in = stdin;
- else
- in = root->cr_srvout;
-
- if (fgets(lbuf, (int)len, in) == NULL) {
- if (ferror(in)) {
- fatal("cvs_getln: error reading server: %s",
- strerror(errno));
- }
-
- if (feof(in))
- *lbuf = '\0';
- }
-
- if (cvs_server_outlog != NULL)
- fputs(lbuf, cvs_server_outlog);
-
- rlen = strlen(lbuf);
- if (rlen > 0 && lbuf[rlen - 1] == '\n')
- lbuf[--rlen] = '\0';
-}
-
-
-/*
- * cvs_sendresp()
- *
- * Send a response of type <rid> to the client, with optional arguments
- * contained in <arg>, which should not be terminated by a newline.
- */
-void
-cvs_sendresp(u_int rid, const char *arg)
-{
- int ret;
- struct cvs_resp *resp;
-
- if ((resp = cvs_resp_getbyid(rid)) == NULL)
- fatal("unsupported response type %u", rid);
-
- ret = fputs(resp->resp_str, stdout);
- if (ret == EOF) {
- cvs_log(LP_ERRNO, "failed to send response to client");
- } else {
- if (arg != NULL) {
- putc(' ', stdout);
- fputs(arg, stdout);
- }
- putc('\n', stdout);
- }
-}
-
-
-/*
- * cvs_sendln()
- *
- * Send a single line <line> string to the remote end. The line is sent as is,
- * without any modifications.
- */
-void
-cvs_sendln(struct cvsroot *root, const char *line)
-{
- int nl;
- size_t len;
- FILE *out;
-
- if (cvs_cmdop == CVS_OP_SERVER)
- out = stdout;
- else
- out = root->cr_srvin;
-
- nl = 0;
- len = strlen(line);
-
- if (len > 0 && line[len - 1] != '\n')
- nl = 1;
-
- if (cvs_server_inlog != NULL) {
- fputs(line, cvs_server_inlog);
- if (nl)
- putc('\n', cvs_server_inlog);
- }
- fputs(line, out);
- if (nl)
- putc('\n', out);
-}
-
-
-/*
- * cvs_sendraw()
- *
- * Send the first <len> bytes from the buffer <src> to the server.
- */
-void
-cvs_sendraw(struct cvsroot *root, const void *src, size_t len)
-{
- FILE *out;
-
- if (cvs_cmdop == CVS_OP_SERVER)
- out = stdout;
- else
- out = root->cr_srvin;
-
- if (cvs_server_inlog != NULL)
- fwrite(src, sizeof(char), len, cvs_server_inlog);
- if (fwrite(src, sizeof(char), len, out) < len)
- fatal("failed to send data");
-}
-
-
-/*
- * cvs_recvraw()
- *
- * Receive the first <len> bytes from the buffer <src> to the server.
- */
-size_t
-cvs_recvraw(struct cvsroot *root, void *dst, size_t len)
-{
- size_t ret;
- FILE *in;
-
- if (cvs_cmdop == CVS_OP_SERVER)
- in = stdin;
- else
- in = root->cr_srvout;
-
- ret = fread(dst, sizeof(char), len, in);
- if (ret == 0) {
- if (ferror(in)) {
- fatal("cvs_recvraw: error reading from server: %s",
- strerror(errno));
- }
- } else {
- if (cvs_server_outlog != NULL)
- fwrite(dst, sizeof(char), len, cvs_server_outlog);
- }
-
- return (ret);
-}
-
-
-/*
- * cvs_senddir()
- *
- * Send a `Directory' request along with the 2 paths that follow it. If
- * the directory info to be sent is the same as the last info sent, the
- * call does nothing and simply returns without an error.
- */
-void
-cvs_senddir(struct cvsroot *root, CVSFILE *dir)
-{
- size_t len;
- char lbuf[MAXPATHLEN], rbuf[MAXPATHLEN];
-
- if (dir->cf_type != DT_DIR)
- fatal("cvs_senddir(): cf_type != DT_DIR: %d", dir->cf_type);
-
- cvs_file_getpath(dir, lbuf, sizeof(lbuf));
- if (strcmp(lbuf, cvs_lastdir) == 0 && cvs_cmdop != CVS_OP_CHECKOUT)
- return;
-
- if (dir->cf_repo == NULL) {
- len = strlcpy(rbuf, root->cr_dir, sizeof(rbuf));
- if (len >= sizeof(rbuf))
- fatal("cvs_senddir: path truncation");
- } else {
- len = cvs_path_cat(root->cr_dir, dir->cf_repo, rbuf,
- sizeof(rbuf));
- if (len >= sizeof(rbuf))
- fatal("cvs_senddir: path truncation");
- }
-
- cvs_sendreq(root, CVS_REQ_DIRECTORY, lbuf);
- cvs_sendln(root, rbuf);
-
- len = strlcpy(cvs_lastdir, lbuf, sizeof(cvs_lastdir));
- if (len >= sizeof(lbuf))
- fatal("path truncation in cvs_senddir");
-}
-
-
-/*
- * cvs_sendarg()
- *
- * Send the argument <arg> to the server. The argument <append> is used to
- * determine if the argument should be simply appended to the last argument
- * sent or if it should be created as a new argument (0).
- */
-void
-cvs_sendarg(struct cvsroot *root, const char *arg, int append)
-{
- cvs_sendreq(root, append == 0 ? CVS_REQ_ARGUMENT :
- CVS_REQ_ARGUMENTX, arg);
-}
-
-
-/*
- * cvs_sendentry()
- *
- * Send an `Entry' request to the server along with the mandatory fields from
- * the CVS entry <ent> (which are the name and revision).
- */
-void
-cvs_sendentry(struct cvsroot *root, const CVSFILE *file)
-{
- char ebuf[CVS_ENT_MAXLINELEN], numbuf[64];
-
- if (file->cf_type != DT_REG)
- fatal("cvs_sendentry: cf_type != DT_REG: %d", file->cf_type);
-
- /* don't send Entry for unknown files */
- if (file->cf_cvstat == CVS_FST_UNKNOWN)
- return;
-
- if (strlcpy(ebuf, "/", sizeof(ebuf)) >= sizeof(ebuf) ||
- strlcat(ebuf, file->cf_name, sizeof(ebuf)) >= sizeof(ebuf) ||
- strlcat(ebuf, "/", sizeof(ebuf)) >= sizeof(ebuf) ||
- strlcat(ebuf, (file->cf_cvstat == CVS_FST_REMOVED) ? "-" : "",
- sizeof(ebuf)) >= sizeof(ebuf) ||
- strlcat(ebuf, rcsnum_tostr(file->cf_lrev, numbuf, sizeof(numbuf)),
- sizeof(ebuf)) >= sizeof(ebuf) ||
- strlcat(ebuf, "///", sizeof(ebuf)) >= sizeof(ebuf))
- fatal("cvs_sendentry: overflow when creating entry buffer");
-
- cvs_sendreq(root, CVS_REQ_ENTRY, ebuf);
-}
-
-
-/*
- * cvs_initlog()
- *
- * Initialize protocol logging if the CVS_CLIENT_LOG environment variable is
- * set. In this case, the variable's value is used as a path to which the
- * appropriate suffix is added (".in" for server input and ".out" for server
- * output.
- * Returns 0 on success, or -1 on failure.
- */
-static void
-cvs_initlog(void)
-{
- int l;
- u_int i;
- char *env, *envdup, buf[MAXPATHLEN], fpath[MAXPATHLEN];
- char rpath[MAXPATHLEN], *s;
- struct stat st;
- time_t now;
- struct passwd *pwd;
-
- /* avoid doing it more than once */
- if (cvs_server_logon)
- return;
-
- env = getenv("CVS_CLIENT_LOG");
- if (env == NULL)
- return;
-
- envdup = xstrdup(env);
- if ((s = strchr(envdup, '%')) != NULL)
- *s = '\0';
-
- if (strlcpy(buf, env, sizeof(buf)) >= sizeof(buf))
- fatal("string truncation in cvs_initlog");
-
- if (strlcpy(rpath, envdup, sizeof(rpath)) >= sizeof(rpath))
- fatal("string truncation in cvs_initlog");
-
- xfree(envdup);
-
- s = buf;
- while ((s = strchr(s, '%')) != NULL) {
- s++;
- switch (*s) {
- case 'c':
- if (strlcpy(fpath, cvs_command, sizeof(fpath)) >=
- sizeof(fpath))
- fatal("string truncation in cvs_initlog");
- break;
- case 'd':
- time(&now);
- if (strlcpy(fpath, ctime(&now), sizeof(fpath)) >=
- sizeof(fpath))
- fatal("string truncation in cvs_initlog");
- break;
- case 'p':
- snprintf(fpath, sizeof(fpath), "%d", getpid());
- break;
- case 'u':
- if ((pwd = getpwuid(getuid())) != NULL) {
- if (strlcpy(fpath, pwd->pw_name,
- sizeof(fpath)) >= sizeof(fpath))
- fatal("truncation in cvs_initlog");
- } else {
- fpath[0] = '\0';
- }
- endpwent();
- break;
- default:
- fpath[0] = '\0';
- break;
- }
-
- if (fpath[0] != '\0') {
- if (strlcat(rpath, "-", sizeof(rpath)) >= sizeof(rpath))
- fatal("string truncation cvs_initlog");
-
- if (strlcat(rpath, fpath, sizeof(rpath))
- >= sizeof(rpath))
- fatal("string truncation in cvs_initlog");
- }
- }
-
- for (i = 0; i < UINT_MAX; i++) {
- l = snprintf(fpath, sizeof(fpath), "%s-%d.in", rpath, i);
- if (l == -1 || l >= (int)sizeof(fpath))
- fatal("overflow in cvs_initlog()");
-
- if (stat(fpath, &st) != -1)
- continue;
-
- if (errno != ENOENT)
- fatal("cvs_initlog() stat failed '%s'",
- strerror(errno));
-
- break;
- }
-
- cvs_server_inlog = fopen(fpath, "w");
- if (cvs_server_inlog == NULL)
- fatal("failed to open server input log `%s'", fpath);
-
- for (i = 0; i < UINT_MAX; i++) {
- l = snprintf(fpath, sizeof(fpath), "%s-%d.out", rpath, i);
- if (l == -1 || l >= (int)sizeof(fpath))
- fatal("overflow in cvs_initlog()");
-
- if (stat(fpath, &st) != -1)
- continue;
-
- if (errno != ENOENT)
- fatal("cvs_initlog() stat failed '%s'",
- strerror(errno));
-
- break;
- }
-
- cvs_server_outlog = fopen(fpath, "w");
- if (cvs_server_outlog == NULL)
- fatal("failed to open server output log `%s'", fpath);
-
- /* make the streams line-buffered */
- setvbuf(cvs_server_inlog, NULL, _IOLBF, (size_t)0);
- setvbuf(cvs_server_outlog, NULL, _IOLBF, (size_t)0);
-
- cvs_server_logon = 1;
-}
diff --git a/usr.bin/cvs/proto.h b/usr.bin/cvs/proto.h
index 1ab98dadcbc..a0ca441009c 100644
--- a/usr.bin/cvs/proto.h
+++ b/usr.bin/cvs/proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proto.h,v 1.12 2006/01/04 14:58:12 xsa Exp $ */
+/* $OpenBSD: proto.h,v 1.13 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -28,14 +28,10 @@
#define PROTO_H
#include "buf.h"
-#include "file.h"
-
#define CVS_PROTO_MAXARG 256
-
#define CVS_REQ_TIMEOUT 300
-
/* client/server protocol requests */
#define CVS_REQ_NONE 0
#define CVS_REQ_ROOT 1
@@ -110,11 +106,8 @@
#define CVS_REQ_WATCH_OFF 71
#define CVS_REQ_WATCH_ADD 72
#define CVS_REQ_WATCH_REMOVE 73
-
-
#define CVS_REQ_MAX 73
-
/* responses */
#define CVS_RESP_NONE 0
#define CVS_RESP_OK 1
@@ -149,8 +142,7 @@
#define CVS_RESP_E 30
#define CVS_RESP_F 31
#define CVS_RESP_MT 32
-
-#define CVS_RESP_MAX 32
+#define CVS_RESP_MAX 32
struct cvs_req {
int req_id;
@@ -163,32 +155,4 @@ struct cvs_resp {
char resp_str[32];
};
-
-BUF *cvs_recvfile(struct cvsroot *, mode_t *);
-void cvs_sendfile(struct cvsroot *, const char *);
-void cvs_connect(struct cvsroot *);
-void cvs_disconnect(struct cvsroot *);
-
-int cvs_req_handle(char *);
-struct cvs_req *cvs_req_getbyid(int);
-struct cvs_req *cvs_req_getbyname(const char *);
-char *cvs_req_getvalid(void);
-
-int cvs_resp_handle(struct cvsroot *, char *);
-struct cvs_resp* cvs_resp_getbyid(int);
-struct cvs_resp* cvs_resp_getbyname(const char *);
-char* cvs_resp_getvalid(void);
-
-void cvs_sendreq(struct cvsroot *, u_int, const char *);
-void cvs_getresp(struct cvsroot *);
-void cvs_sendresp(u_int, const char *);
-void cvs_getln(struct cvsroot *, char *, size_t);
-void cvs_senddir(struct cvsroot *, CVSFILE *);
-void cvs_sendarg(struct cvsroot *, const char *, int);
-void cvs_sendln(struct cvsroot *, const char *);
-void cvs_sendentry(struct cvsroot *, const CVSFILE *);
-void cvs_sendraw(struct cvsroot *, const void *, size_t);
-size_t cvs_recvraw(struct cvsroot *, void *, size_t);
-
-
#endif /* PROTO_H */
diff --git a/usr.bin/cvs/rcs.c b/usr.bin/cvs/rcs.c
index 036424a27a8..7105e2918ab 100644
--- a/usr.bin/cvs/rcs.c
+++ b/usr.bin/cvs/rcs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcs.c,v 1.171 2006/05/01 18:17:39 niallo Exp $ */
+/* $OpenBSD: rcs.c,v 1.172 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -26,16 +26,18 @@
#include "includes.h"
+#include "buf.h"
#include "cvs.h"
+#include "diff.h"
#include "log.h"
#include "rcs.h"
-#include "diff.h"
+#include "util.h"
+#include "xmalloc.h"
#define RCS_BUFSIZE 16384
#define RCS_BUFEXTSIZE 8192
#define RCS_KWEXP_SIZE 1024
-
/* RCS token types */
#define RCS_TOK_ERR -1
#define RCS_TOK_EOF 0
@@ -45,7 +47,6 @@
#define RCS_TOK_SCOLON 4
#define RCS_TOK_COLON 5
-
#define RCS_TOK_HEAD 8
#define RCS_TOK_BRANCH 9
#define RCS_TOK_ACCESS 10
@@ -65,11 +66,9 @@
#define RCS_ISKEY(t) (((t) >= RCS_TOK_HEAD) && ((t) <= RCS_TOK_BRANCHES))
-
#define RCS_NOSCOL 0x01 /* no terminating semi-colon */
#define RCS_VOPT 0x02 /* value is optional */
-
/* opaque parse data */
struct rcs_pdata {
u_int rp_lines;
@@ -86,15 +85,12 @@ struct rcs_pdata {
FILE *rp_file;
};
-
#define RCS_TOKSTR(rfp) ((struct rcs_pdata *)rfp->rf_pdata)->rp_buf
#define RCS_TOKLEN(rfp) ((struct rcs_pdata *)rfp->rf_pdata)->rp_tlen
-
/* invalid characters in RCS symbol names */
static const char rcs_sym_invch[] = RCS_SYM_INVALCHAR;
-
/* comment leaders, depending on the file's suffix */
static const struct rcs_comment {
const char *rc_suffix;
@@ -179,19 +175,6 @@ struct rcs_kw rcs_expkw[] = {
#define NB_COMTYPES (sizeof(rcs_comments)/sizeof(rcs_comments[0]))
-#ifdef notyet
-static struct rcs_kfl {
- char rk_char;
- int rk_val;
-} rcs_kflags[] = {
- { 'k', RCS_KWEXP_NAME },
- { 'v', RCS_KWEXP_VAL },
- { 'l', RCS_KWEXP_LKR },
- { 'o', RCS_KWEXP_OLD },
- { 'b', RCS_KWEXP_NONE },
-};
-#endif
-
static struct rcs_key {
char rk_str[16];
int rk_id;
@@ -218,7 +201,6 @@ static struct rcs_key {
#define RCS_NKEYS (sizeof(rcs_keys)/sizeof(rcs_keys[0]))
-
static const char *rcs_errstrs[] = {
"No error",
"No such entry",
@@ -230,10 +212,10 @@ static const char *rcs_errstrs[] = {
#define RCS_NERR (sizeof(rcs_errstrs)/sizeof(rcs_errstrs[0]))
-
int rcs_errno = RCS_ERR_NOERR;
-char *timezone_flag = NULL;
+int rcs_patch_lines(struct cvs_lines *, struct cvs_lines *);
+static int rcs_movefile(char *, char *, mode_t, u_int);
static void rcs_parse_init(RCSFILE *);
static int rcs_parse_admin(RCSFILE *);
static int rcs_parse_delta(RCSFILE *);
@@ -256,25 +238,12 @@ static void rcs_strprint(const u_char *, size_t, FILE *);
static char* rcs_expand_keywords(char *, struct rcs_delta *, char *,
size_t, int);
-/*
- * rcs_open()
- *
- * Open a file containing RCS-formatted information. The file's path is
- * given in <path>, and the opening flags are given in <flags>, which is either
- * RCS_READ, RCS_WRITE, or RCS_RDWR. If the open requests write access and
- * the file does not exist, the RCS_CREATE flag must also be given, in which
- * case it will be created with the mode specified in a third argument of
- * type mode_t. If the file exists and RCS_CREATE is passed, the open will
- * fail.
- * Returns a handle to the opened file on success, or NULL on failure.
- */
RCSFILE *
-rcs_open(const char *path, int flags, ...)
+rcs_open(const char *path, int fd, int flags, ...)
{
- int ret, mode;
+ int mode;
mode_t fmode;
RCSFILE *rfp;
- struct stat st;
va_list vap;
struct rcs_delta *rdp;
struct rcs_lock *lkr;
@@ -282,23 +251,11 @@ rcs_open(const char *path, int flags, ...)
fmode = S_IRUSR|S_IRGRP|S_IROTH;
flags &= 0xffff; /* ditch any internal flags */
- if (((ret = stat(path, &st)) == -1) && errno == ENOENT) {
- if (flags & RCS_CREATE) {
- va_start(vap, flags);
- mode = va_arg(vap, int);
- va_end(vap);
- fmode = (mode_t)mode;
- } else {
- /* XXX, make this command dependant? */
-#if 0
- cvs_log(LP_ERR, "RCS file `%s' does not exist", path);
-#endif
- rcs_errno = RCS_ERR_NOENT;
- return (NULL);
- }
- } else if (ret == 0 && (flags & RCS_CREATE)) {
- cvs_log(LP_ERR, "RCS file `%s' exists", path);
- return (NULL);
+ if (flags & RCS_CREATE) {
+ va_start(vap, flags);
+ mode = va_arg(vap, int);
+ va_end(vap);
+ fmode = (mode_t)mode;
}
rfp = xcalloc(1, sizeof(*rfp));
@@ -306,6 +263,7 @@ rcs_open(const char *path, int flags, ...)
rfp->rf_path = xstrdup(path);
rfp->rf_flags = flags | RCS_SLOCK | RCS_SYNCED;
rfp->rf_mode = fmode;
+ rfp->fd = fd;
TAILQ_INIT(&(rfp->rf_delta));
TAILQ_INIT(&(rfp->rf_access));
@@ -396,39 +354,40 @@ rcs_close(RCSFILE *rfp)
*
* Write the contents of the RCS file handle <rfp> to disk in the file whose
* path is in <rf_path>.
- * Returns 0 on success, or -1 on failure.
*/
-int
+void
rcs_write(RCSFILE *rfp)
{
FILE *fp;
- char buf[1024], numbuf[64], fn[19] = "";
- void *bp;
+ char buf[1024], numbuf[64], *fn;
struct rcs_access *ap;
struct rcs_sym *symp;
struct rcs_branch *brp;
struct rcs_delta *rdp;
struct rcs_lock *lkp;
- ssize_t nread, nwritten;
size_t len;
int fd, from_fd, to_fd;
from_fd = to_fd = fd = -1;
if (rfp->rf_flags & RCS_SYNCED)
- return (0);
+ return;
/* Write operations need the whole file parsed */
rcs_parse_deltatexts(rfp, NULL);
- strlcpy(fn, "/tmp/rcs.XXXXXXXXXX", sizeof(fn));
+ (void)xasprintf(&fn, "%s/rcs.XXXXXXXXXX", cvs_tmpdir);
+
if ((fd = mkstemp(fn)) == -1)
- fatal("mkstemp: `%s': %s", fn, strerror(errno));
+ fatal("%s", fn);
if ((fp = fdopen(fd, "w+")) == NULL) {
- fd = errno;
- unlink(fn);
- fatal("fdopen: %s", strerror(fd));
+ int saved_errno;
+
+ saved_errno = errno;
+ (void)unlink(fn);
+ errno = saved_errno;
+ fatal("%s", fn);
}
if (rfp->rf_head != NULL)
@@ -452,9 +411,10 @@ rcs_write(RCSFILE *rfp)
fprintf(fp, "symbols");
TAILQ_FOREACH(symp, &(rfp->rf_symbols), rs_list) {
rcsnum_tostr(symp->rs_num, numbuf, sizeof(numbuf));
- strlcpy(buf, symp->rs_name, sizeof(buf));
- strlcat(buf, ":", sizeof(buf));
- strlcat(buf, numbuf, sizeof(buf));
+ if (strlcpy(buf, symp->rs_name, sizeof(buf)) >= sizeof(buf) ||
+ strlcat(buf, ":", sizeof(buf)) >= sizeof(buf) ||
+ strlcat(buf, numbuf, sizeof(buf)) >= sizeof(buf))
+ fatal("rcs_write: string overflow");
fprintf(fp, "\n\t%s", buf);
}
fprintf(fp, ";\n");
@@ -537,81 +497,91 @@ rcs_write(RCSFILE *rfp)
}
fputs("@\n", fp);
}
- fclose(fp);
-
- /*
- * We try to use rename() to atomically put the new file in place.
- * If that fails, we try a copy.
- */
- if (rename(fn, rfp->rf_path) == -1) {
- if (errno == EXDEV) {
- /* rename() not supported so we have to copy. */
- if (chmod(rfp->rf_path, S_IWUSR) == -1 &&
- !(rfp->rf_flags & RCS_CREATE)) {
- fatal("chmod(%s, 0%o) failed",
- rfp->rf_path, S_IWUSR);
- }
+ (void)fclose(fp);
- if ((from_fd = open(fn, O_RDONLY)) == -1) {
- cvs_log(LP_ERRNO, "failed to open `%s'",
- rfp->rf_path);
- return (-1);
- }
+ if (rcs_movefile(fn, rfp->rf_path, rfp->rf_mode, rfp->rf_flags) == -1) {
+ (void)unlink(fn);
+ fatal("rcs_movefile failed");
+ }
- if ((to_fd = open(rfp->rf_path,
- O_WRONLY|O_TRUNC|O_CREAT)) == -1) {
- cvs_log(LP_ERRNO, "failed to open `%s'", fn);
- close(from_fd);
- return (-1);
- }
+ rfp->rf_flags |= RCS_SYNCED;
- bp = xmalloc(MAXBSIZE);
- for (;;) {
- if ((nread = read(from_fd, bp, MAXBSIZE)) == 0)
- break;
- if (nread == -1)
- goto err;
- nwritten = write(to_fd, bp, (size_t)nread);
- if (nwritten == -1 || nwritten != nread)
- goto err;
- }
+ if (fn != NULL)
+ xfree(fn);
+}
- if (nread < 0) {
-err: if (unlink(rfp->rf_path) == -1)
- cvs_log(LP_ERRNO,
- "failed to unlink `%s'",
- rfp->rf_path);
- close(from_fd);
- close(to_fd);
- xfree(bp);
- return (-1);
- }
+/*
+ * rcs_movefile()
+ *
+ * Move a file using rename(2) if possible and copying if not.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+rcs_movefile(char *from, char *to, mode_t perm, u_int to_flags)
+{
+ FILE *src, *dst;
+ size_t nread, nwritten;
+ char *buf;
+ int ret;
- close(from_fd);
- close(to_fd);
- xfree(bp);
+ ret = -1;
- if (unlink(fn) == -1) {
- cvs_log(LP_ERRNO,
- "failed to unlink `%s'", fn);
- return (-1);
- }
- } else {
- cvs_log(LP_ERRNO,
- "failed to access temp RCS output file");
+ if (rename(from, to) == 0) {
+ if (chmod(to, perm) == -1) {
+ cvs_log(LP_ERRNO, "%s", to);
return (-1);
}
+ return (0);
+ } else if (errno != EXDEV) {
+ cvs_log(LP_NOTICE, "failed to access temp RCS output file");
+ return (-1);
}
- if (chmod(rfp->rf_path, rfp->rf_mode) == -1) {
- cvs_log(LP_ERRNO, "failed to chmod `%s'",
- rfp->rf_path);
+ if ((chmod(to, S_IWUSR) == -1) && !(to_flags & RCS_CREATE)) {
+ cvs_log(LP_ERR, "chmod(%s, 0%o) failed", to, S_IWUSR);
return (-1);
}
- rfp->rf_flags |= RCS_SYNCED;
+ /* different filesystem, have to copy the file */
+ if ((src = fopen(from, "r")) == NULL) {
+ cvs_log(LP_ERRNO, "%s", from);
+ return (-1);
+ }
+ if ((dst = fopen(to, "w")) == NULL) {
+ cvs_log(LP_ERRNO, "%s", to);
+ return (-1);
+ }
+ if (fchmod(fileno(dst), perm)) {
+ cvs_log(LP_ERR, "%s", to);
+ (void)unlink(to);
+ return (-1);
+ }
- return (0);
+ buf = xmalloc(MAXBSIZE);
+ while ((nread = fread(buf, sizeof(char), MAXBSIZE, src)) != 0) {
+ if (ferror(src)) {
+ cvs_log(LP_ERRNO, "failed to read `%s'", from);
+ (void)unlink(to);
+ goto out;
+ }
+ nwritten = fwrite(buf, sizeof(char), nread, dst);
+ if (nwritten != nread) {
+ cvs_log(LP_ERRNO, "failed to write `%s'", to);
+ (void)unlink(to);
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+ (void)fclose(src);
+ (void)fclose(dst);
+ (void)unlink(from);
+
+out:
+ xfree(buf);
+
+ return (ret);
}
/*
@@ -1383,18 +1353,10 @@ rcs_rev_add(RCSFILE *rf, RCSNUM *rev, const char *msg, time_t date,
int
rcs_rev_remove(RCSFILE *rf, RCSNUM *rev)
{
- size_t len;
- char *tmpdir;
- char *newdeltatext, path_tmp1[MAXPATHLEN], path_tmp2[MAXPATHLEN];
+ char *newdeltatext, *path_tmp1, *path_tmp2;
struct rcs_delta *rdp, *prevrdp, *nextrdp;
BUF *nextbuf, *prevbuf, *newdiff;
-#if defined(RCSPROG)
- tmpdir = rcs_tmpdir;
-#else
- tmpdir = cvs_tmpdir;
-#endif
-
if (rev == RCS_HEAD_REV)
rev = rf->rf_head;
@@ -1429,32 +1391,17 @@ rcs_rev_remove(RCSFILE *rf, RCSNUM *rev)
newdiff = cvs_buf_alloc(64, BUF_AUTOEXT);
/* calculate new diff */
- len = strlcpy(path_tmp1, tmpdir, sizeof(path_tmp1));
- if (len >= sizeof(path_tmp1))
- fatal("path truncation in rcs_rev_remove");
-
- len = strlcat(path_tmp1, "/diff1.XXXXXXXXXX",
- sizeof(path_tmp1));
- if (len >= sizeof(path_tmp1))
- fatal("path truncation in rcs_rev_remove");
-
- cvs_buf_write_stmp(nextbuf, path_tmp1, 0600);
+ (void)xasprintf(&path_tmp1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
+ cvs_buf_write_stmp(nextbuf, path_tmp1, 0600, NULL);
cvs_buf_free(nextbuf);
- len = strlcpy(path_tmp2, tmpdir, sizeof(path_tmp2));
- if (len >= sizeof(path_tmp2))
- fatal("path truncation in rcs_rev_remove");
-
- len = strlcat(path_tmp2, "/diff2.XXXXXXXXXX",
- sizeof(path_tmp2));
- if (len >= sizeof(path_tmp2))
- fatal("path truncation in rcs_rev_remove");
-
- cvs_buf_write_stmp(prevbuf, path_tmp2, 0600);
+ (void)xasprintf(&path_tmp2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
+ cvs_buf_write_stmp(prevbuf, path_tmp2, 0600, NULL);
cvs_buf_free(prevbuf);
diff_format = D_RCSDIFF;
- cvs_diffreg(path_tmp1, path_tmp2, newdiff);
+ if (cvs_diffreg(path_tmp1, path_tmp2, newdiff) == D_ERROR)
+ fatal("rcs_diffreg failed");
newdeltatext = cvs_buf_release(newdiff);
} else if (nextrdp == NULL && prevrdp != NULL) {
@@ -1490,6 +1437,11 @@ rcs_rev_remove(RCSFILE *rf, RCSNUM *rev)
if (newdeltatext != NULL)
xfree(newdeltatext);
+ if (path_tmp1 != NULL)
+ xfree(path_tmp1);
+ if (path_tmp2 != NULL)
+ xfree(path_tmp2);
+
return (0);
}
@@ -1768,8 +1720,8 @@ rcs_parse_init(RCSFILE *rfp)
pdp->rp_lines = 0;
pdp->rp_pttype = RCS_TOK_ERR;
- if ((pdp->rp_file = fopen(rfp->rf_path, "r")) == NULL)
- fatal("fopen: `%s': %s", rfp->rf_path, strerror(errno));
+ if ((pdp->rp_file = fdopen(rfp->fd, "r")) == NULL)
+ fatal("fopen: `%s'", rfp->rf_path);
pdp->rp_buf = xmalloc((size_t)RCS_BUFSIZE);
pdp->rp_blen = RCS_BUFSIZE;
@@ -2057,8 +2009,7 @@ rcs_parse_delta(RCSFILE *rfp)
break;
default:
rcs_errno = RCS_ERR_PARSE;
- cvs_log(LP_ERR,
- "unexpected token `%s' in RCS delta",
+ cvs_log(LP_ERR, "unexpected token `%s' in RCS delta",
RCS_TOKSTR(rfp));
rcs_freedelta(rdp);
return (-1);
@@ -2149,7 +2100,9 @@ rcs_parse_deltatext(RCSFILE *rfp)
}
rdp->rd_text = xmalloc(RCS_TOKLEN(rfp) + 1);
- strlcpy(rdp->rd_text, RCS_TOKSTR(rfp), (RCS_TOKLEN(rfp) + 1));
+ if (strlcpy(rdp->rd_text, RCS_TOKSTR(rfp), (RCS_TOKLEN(rfp) + 1)) >=
+ RCS_TOKLEN(rfp) + 1)
+ fatal("rcs_parse_deltatext: strlcpy");
rdp->rd_tlen = RCS_TOKLEN(rfp);
return (1);
@@ -2436,7 +2389,9 @@ rcs_gettok(RCSFILE *rfp)
if (pdp->rp_pttype != RCS_TOK_ERR) {
type = pdp->rp_pttype;
- strlcpy(pdp->rp_buf, pdp->rp_ptok, pdp->rp_blen);
+ if (strlcpy(pdp->rp_buf, pdp->rp_ptok, pdp->rp_blen) >=
+ pdp->rp_blen)
+ fatal("rcs_gettok: strlcpy");
pdp->rp_pttype = RCS_TOK_ERR;
return (type);
}
@@ -2550,7 +2505,9 @@ rcs_pushtok(RCSFILE *rfp, const char *tok, int type)
return (-1);
pdp->rp_pttype = type;
- strlcpy(pdp->rp_ptok, tok, sizeof(pdp->rp_ptok));
+ if (strlcpy(pdp->rp_ptok, tok, sizeof(pdp->rp_ptok)) >=
+ sizeof(pdp->rp_ptok))
+ fatal("rcs_pushtok: strlcpy");
return (0);
}
@@ -2628,13 +2585,6 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, char *data,
i = 0;
/*
- * -z support for RCS
- */
- tb = rdp->rd_date;
- if (timezone_flag != NULL)
- rcs_set_tz(timezone_flag, rdp, &tb);
-
- /*
* Keyword formats:
* $Keyword$
* $Keyword: value$
@@ -2700,10 +2650,15 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, char *data,
expbuf[0] = '\0';
if (mode & RCS_KWEXP_NAME) {
- strlcat(expbuf, "$", sizeof(expbuf));
- strlcat(expbuf, kwstr, sizeof(expbuf));
- if (mode & RCS_KWEXP_VAL)
- strlcat(expbuf, ": ", sizeof(expbuf));
+ if (strlcat(expbuf, "$", sizeof(expbuf))
+ >= sizeof(expbuf) ||
+ strlcat(expbuf, kwstr, sizeof(expbuf))
+ >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: truncated");
+ if ((mode & RCS_KWEXP_VAL) &&
+ strlcat(expbuf, ": ", sizeof(expbuf))
+ >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: truncated");
}
/*
@@ -2713,64 +2668,89 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, char *data,
if (mode & RCS_KWEXP_VAL) {
if (kwtype & RCS_KW_RCSFILE) {
if (!(kwtype & RCS_KW_FULLPATH))
- strlcat(expbuf,
+ (void)strlcat(expbuf,
basename(rcsfile),
sizeof(expbuf));
else
- strlcat(expbuf, rcsfile,
- sizeof(expbuf));
- strlcat(expbuf, " ", sizeof(expbuf));
+ (void)strlcat(expbuf,
+ rcsfile, sizeof(expbuf));
+ if (strlcat(expbuf, " ",
+ sizeof(expbuf)) >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: "
+ "truncated");
}
if (kwtype & RCS_KW_REVISION) {
rcsnum_tostr(rdp->rd_num, buf,
sizeof(buf));
- strlcat(buf, " ", sizeof(buf));
- strlcat(expbuf, buf, sizeof(expbuf));
+ if (strlcat(buf, " ", sizeof(buf))
+ >= sizeof(buf) ||
+ strlcat(expbuf, buf,
+ sizeof(expbuf)) >= sizeof(buf))
+ fatal("rcs_expand_keywords: "
+ "truncated");
}
if (kwtype & RCS_KW_DATE) {
- if (timezone_flag != NULL)
- fmt = "%Y/%m/%d %H:%M:%S%z ";
- else
- fmt = "%Y/%m/%d %H:%M:%S ";
+ fmt = "%Y/%m/%d %H:%M:%S ";
strftime(buf, sizeof(buf), fmt, &tb);
- strlcat(expbuf, buf, sizeof(expbuf));
+ if (strlcat(expbuf, buf,
+ sizeof(expbuf)) >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: "
+ "string truncated");
}
if (kwtype & RCS_KW_AUTHOR) {
- strlcat(expbuf, rdp->rd_author,
- sizeof(expbuf));
- strlcat(expbuf, " ", sizeof(expbuf));
+ if (strlcat(expbuf, rdp->rd_author,
+ sizeof(expbuf)) >= sizeof(expbuf) ||
+ strlcat(expbuf, " ",
+ sizeof(expbuf)) >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: "
+ "string truncated");
}
if (kwtype & RCS_KW_STATE) {
- strlcat(expbuf, rdp->rd_state,
- sizeof(expbuf));
- strlcat(expbuf, " ", sizeof(expbuf));
+ if (strlcat(expbuf, rdp->rd_state,
+ sizeof(expbuf)) >= sizeof(expbuf) ||
+ strlcat(expbuf, " ",
+ sizeof(expbuf)) >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: "
+ "string truncated");
}
/* order does not matter anymore below */
if (kwtype & RCS_KW_LOG)
- strlcat(expbuf, " ", sizeof(expbuf));
+ if (strlcat(expbuf, " ",
+ sizeof(expbuf)) >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: "
+ "string truncated");
if (kwtype & RCS_KW_SOURCE) {
- strlcat(expbuf, rcsfile,
- sizeof(expbuf));
- strlcat(expbuf, " ", sizeof(expbuf));
+ if (strlcat(expbuf, rcsfile,
+ sizeof(expbuf)) >= sizeof(expbuf) ||
+ strlcat(expbuf, " ",
+ sizeof(expbuf)) >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: "
+ "string truncated");
}
if (kwtype & RCS_KW_NAME)
- strlcat(expbuf, " ", sizeof(expbuf));
+ if (strlcat(expbuf, " ",
+ sizeof(expbuf)) >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: "
+ "string truncated");
}
/* end the expansion */
if (mode & RCS_KWEXP_NAME)
- strlcat(expbuf, "$", sizeof(expbuf));
+ if (strlcat(expbuf, "$",
+ sizeof(expbuf)) >= sizeof(expbuf))
+ fatal("rcs_expand_keywords: truncated");
sizdiff = strlen(expbuf) - (end - start);
tbuf = xstrdup(end);
+
/* only realloc if we have to */
if (sizdiff > 0) {
char *newdata;
@@ -2778,6 +2758,7 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, char *data,
len += sizdiff;
newdata = xrealloc(data, 1, len);
data = newdata;
+
/*
* ensure string pointers are not invalidated
* after realloc()
@@ -2785,8 +2766,9 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, char *data,
start = data + start_offset;
c = data + c_offset;
}
- strlcpy(start, expbuf, len);
- strlcat(data, tbuf, len);
+ if (strlcpy(start, expbuf, len) >= len ||
+ strlcat(data, tbuf, len) >= len)
+ fatal("rcs_expand_keywords: string truncated");
xfree(tbuf);
i += strlen(expbuf);
}
@@ -2954,7 +2936,7 @@ rcs_kwexp_buf(BUF *bp, RCSFILE *rf, RCSNUM *rev)
if (!(expmode & RCS_KWEXP_NONE)) {
if ((rdp = rcs_findrev(rf, rev)) == NULL)
- fatal("could not fetch revision");
+ fatal("could not fetch revision");
cvs_buf_putc(bp, '\0');
len = cvs_buf_len(bp);
tbuf = cvs_buf_release(bp);
@@ -2966,248 +2948,3 @@ rcs_kwexp_buf(BUF *bp, RCSFILE *rf, RCSNUM *rev)
}
return (bp);
}
-
-#if !defined(RCSPROG)
-
-static char *month_tab[] = {
- "Jan",
- "Feb",
- "Mar",
- "Apr",
- "May",
- "Jun",
- "Jul",
- "Aug",
- "Sep",
- "Oct",
- "Nov",
- "Dec"
-};
-
-void
-rcs_kflag_usage(void)
-{
- (void)fprintf(stderr, "Valid expansion modes include:\n"
- "\t-kkv\tGenerate keywords using the default form.\n"
- "\t-kkvl\tLike -kkv, except locker's name inserted.\n"
- "\t-kk\tGenerate only keyword names in keyword strings.\n"
- "\t-kv\tGenerate only keyword values in keyword strings.\n"
- "\t-ko\tGenerate old keyword string "
- "(no changes from checked in file).\n"
- "\t-kb\tGenerate binary file unmodified (merges not allowed).\n");
-}
-
-/*
- * Checkout a certain revision <rev> of RCS file <rf> to either standard
- * output when running in server mode, or to <fpath> when running in local mode.
- *
- * If type is CHECKOUT_REV_MERGED we have an extra argument, which
- * is the buffer containing the merged file.
- *
- * If type is CHECKOUT_REV_REMOVED, the file has been removed and we
- * need to do the same thing.
- */
-int
-cvs_checkout_rev(RCSFILE *rf, RCSNUM *rev, CVSFILE *cf, char *fpath,
- int local, int type, ...)
-{
- BUF *bp;
- int l, ret, fsize;
- char timebuf[32], entry[MAXPATHLEN], copyfile[MAXPATHLEN];
- char *content, *repo, buf[MAXPATHLEN], modestr[16];
- struct cvsroot *root;
- struct cvs_ent *ent;
- va_list ap;
- time_t rcstime;
- struct timeval tv[2];
- struct tm *tp;
- RCSNUM *oldrev;
-
- bp = NULL;
- ret = -1;
- content = NULL;
- oldrev = NULL;
-
- if (type != CHECKOUT_REV_MERGED && type != CHECKOUT_REV_REMOVED) {
- /* fetch the contents of the revision */
- if ((bp = rcs_getrev(rf, rev)) == NULL) {
- cvs_log(LP_ERR, "revision '%s' not found in file '%s'",
- rcsnum_tostr(rev, buf, sizeof(buf)), fpath);
- goto out;
- }
- bp = rcs_kwexp_buf(bp, rf, rev);
- } else if (type != CHECKOUT_REV_REMOVED) {
- va_start(ap, type);
- bp = va_arg(ap, BUF *);
- va_end(ap);
- }
-
- if (type == CHECKOUT_REV_CREATED)
- rcstime = rcs_rev_getdate(rf, rev);
- else if (type == CHECKOUT_REV_MERGED ||
- type == CHECKOUT_REV_UPDATED) {
- time(&rcstime);
- if ((rcstime = cvs_hack_time(rcstime, 1)) < 0)
- goto out;
- }
-
- if (type == CHECKOUT_REV_CREATED ||
- type == CHECKOUT_REV_MERGED ||
- type == CHECKOUT_REV_UPDATED) {
- ctime_r(&rcstime, timebuf);
- l = strlen(timebuf);
- if (l > 0 && timebuf[l - 1] == '\n')
- timebuf[--l] = '\0';
-
- l = snprintf(entry, sizeof(entry), "/%s/%s/%s/%s/", cf->cf_name,
- rcsnum_tostr(rev, buf, sizeof(buf)),
- (local == 1) ? timebuf : "",
- (type == CHECKOUT_REV_MERGED) ? "+=" : "");
- if (l == -1 || l >= (int)sizeof(buf))
- goto out;
- }
-
- if (type == CHECKOUT_REV_MERGED) {
- oldrev = rcsnum_alloc();
- rcsnum_cpy(rev, oldrev, 0);
-
- if (oldrev->rn_id[oldrev->rn_len - 1] <= 0)
- goto out;
- oldrev = rcsnum_dec(oldrev);
-
- l = snprintf(copyfile, sizeof(copyfile), ".#%s.%s",
- cf->cf_name, rcsnum_tostr(oldrev, buf, sizeof(buf)));
- if (l == -1 || l >= (int)sizeof(copyfile))
- goto out;
- }
-
- root = CVS_DIR_ROOT(cf);
- repo = CVS_DIR_REPO(cf);
-
- /*
- * In local mode, just copy the entire contents to fpath.
- * In server mode, we need to send it to the client together with
- * some responses.
- */
- if (local) {
- l = 0;
- if (cf->cf_entry == NULL) {
- l = 1;
- cf->cf_entry = cvs_ent_open(cf->cf_dir, O_RDWR);
- if (cf->cf_entry == NULL) {
- cvs_log(LP_ERR, "failed to open Entry "
- "file '%s'", cf->cf_dir);
- goto out;
- }
- }
-
- cvs_ent_remove(cf->cf_entry, cf->cf_name, 1);
- if (type != CHECKOUT_REV_REMOVED) {
- cvs_ent_addln(cf->cf_entry, entry);
- ent = cvs_ent_get(cf->cf_entry, cf->cf_name);
- ent->processed = 1;
- }
-
- if (l == 1)
- cvs_ent_close(cf->cf_entry);
-
- switch (type) {
- case CHECKOUT_REV_REMOVED:
- if (cvs_unlink(fpath) < 0)
- goto out;
- break;
- case CHECKOUT_REV_MERGED:
- /* XXX move the old file when merging */
- case CHECKOUT_REV_UPDATED:
- case CHECKOUT_REV_CREATED:
- cvs_buf_write(bp, fpath, cf->cf_mode);
- /*
- * correct the time first
- */
- if ((rcstime = cvs_hack_time(rcstime, 0)) == 0)
- goto out;
-
- tv[0].tv_sec = rcstime;
- tv[0].tv_usec = 0;
- tv[1] = tv[0];
- if (utimes(fpath, tv) == -1)
- cvs_log(LP_ERRNO, "failed to set timestamps");
- break;
- }
- } else {
- /* sanity */
- if (cf->cf_type != DT_REG) {
- cvs_log(LP_ERR, "cvs_checkout_rev: none DT_REG file");
- goto out;
- }
-
- /*
- * if we are removing a file, we don't need this stuff.
- */
- if (type != CHECKOUT_REV_REMOVED) {
- if ((rcstime = cvs_hack_time(rcstime, 0)) == 0)
- goto out;
-
- tp = gmtime(&rcstime);
- l = snprintf(timebuf, sizeof(timebuf),
- "%02d %s %d %02d:%02d:%02d -0000",
- tp->tm_mday, month_tab[tp->tm_mon],
- tp->tm_year + 1900, tp->tm_hour,
- tp->tm_min, tp->tm_sec);
- if (l == -1 || l >= (int)sizeof(timebuf))
- goto out;
-
- fsize = cvs_buf_len(bp);
- cvs_modetostr(cf->cf_mode, modestr, sizeof(modestr));
- cvs_buf_putc(bp, '\0');
- content = cvs_buf_release(bp);
- bp = NULL;
- }
-
- if (type == CHECKOUT_REV_MERGED) {
- printf("Copy-file %s/\n", (cf->cf_dir != NULL) ?
- cf->cf_dir : ".");
- printf("%s/%s/%s\n", root->cr_dir, repo, cf->cf_name);
- printf("%s\n", copyfile);
- }
-
- switch (type) {
- case CHECKOUT_REV_MERGED:
- printf("Merged");
- break;
- case CHECKOUT_REV_REMOVED:
- printf("Removed");
- break;
- case CHECKOUT_REV_CREATED:
- printf("Mod-time %s\n", timebuf);
- printf("Created");
- break;
- default:
- cvs_log(LP_ERR, "cvs_checkout_rev: bad type %d",
- type);
- goto out;
- }
-
- printf(" %s/\n", (cf->cf_dir != NULL) ? cf->cf_dir : ".");
- printf("%s/%s\n", repo, cf->cf_name);
-
- if (type != CHECKOUT_REV_REMOVED) {
- printf("%s\n", entry);
- printf("%s\n%d\n%s", modestr, fsize, content);
- }
- }
-
- ret = 0;
-
-out:
- if (oldrev != NULL)
- rcsnum_free(oldrev);
- if (bp != NULL)
- cvs_buf_free(bp);
- if (content != NULL)
- xfree(content);
-
- return (ret);
-}
-
-#endif /* !RCSPROG */
diff --git a/usr.bin/cvs/rcs.h b/usr.bin/cvs/rcs.h
index 03c07ee88bd..5024ed29485 100644
--- a/usr.bin/cvs/rcs.h
+++ b/usr.bin/cvs/rcs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcs.h,v 1.61 2006/04/14 22:33:15 niallo Exp $ */
+/* $OpenBSD: rcs.h,v 1.62 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -133,7 +133,7 @@ struct rcs_kw {
#define RCS_ERR_PARSE 5
#define RCS_ERR_ERRNO 255
-/* used for cvs_checkout_rev */
+/* used for rcs_checkout_rev */
#define CHECKOUT_REV_CREATED 1
#define CHECKOUT_REV_MERGED 2
#define CHECKOUT_REV_REMOVED 3
@@ -190,6 +190,7 @@ struct rcs_delta {
typedef struct rcs_file {
+ int fd;
char *rf_path;
mode_t rf_mode;
u_int rf_flags;
@@ -209,11 +210,9 @@ typedef struct rcs_file {
void *rf_pdata;
} RCSFILE;
-
extern int rcs_errno;
-
-RCSFILE *rcs_open(const char *, int, ...);
+RCSFILE *rcs_open(const char *, int, int, ...);
void rcs_close(RCSFILE *);
const RCSNUM *rcs_head_get(RCSFILE *);
int rcs_head_set(RCSFILE *, RCSNUM *);
@@ -251,8 +250,7 @@ const char *rcs_state_get(RCSFILE *, RCSNUM *);
int rcs_state_check(const char *);
RCSNUM *rcs_tag_resolve(RCSFILE *, const char *);
const char *rcs_errstr(int);
-int rcs_write(RCSFILE *);
-
+void rcs_write(RCSFILE *);
int rcs_kflag_get(const char *);
void rcs_kflag_usage(void);
@@ -272,12 +270,7 @@ int rcsnum_cmp(const RCSNUM *, const RCSNUM *, u_int);
/* rcstime.c */
void rcs_set_tz(char *, struct rcs_delta *, struct tm *);
-
extern char *timezone_flag;
-
-#if defined(RCSPROG)
-extern char *rcs_tmpdir;
-#endif
extern int rcsnum_flags;
#endif /* RCS_H */
diff --git a/usr.bin/cvs/rcsnum.c b/usr.bin/cvs/rcsnum.c
index 1063601a8d5..c6185704025 100644
--- a/usr.bin/cvs/rcsnum.c
+++ b/usr.bin/cvs/rcsnum.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcsnum.c,v 1.36 2006/04/14 22:33:15 niallo Exp $ */
+/* $OpenBSD: rcsnum.c,v 1.37 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -30,7 +30,6 @@
#include "log.h"
#include "rcs.h"
-
static void rcsnum_setsize(RCSNUM *, u_int);
static char *rcsnum_itoa(u_int16_t, char *, size_t);
@@ -102,6 +101,7 @@ rcsnum_tostr(const RCSNUM *nump, char *buf, size_t blen)
{
u_int i;
char tmp[8];
+ size_t len;
if (nump == NULL || nump->rn_len == 0) {
buf[0] = '\0';
@@ -110,9 +110,14 @@ rcsnum_tostr(const RCSNUM *nump, char *buf, size_t blen)
strlcpy(buf, rcsnum_itoa(nump->rn_id[0], buf, blen), blen);
for (i = 1; i < nump->rn_len; i++) {
- strlcat(buf, ".", blen);
- strlcat(buf, rcsnum_itoa(nump->rn_id[i], tmp, sizeof(tmp)),
- blen);
+ len = strlcat(buf, ".", blen);
+ if (len >= blen)
+ fatal("rcsnum_tostr: overflow 1");
+
+ len = strlcat(buf,
+ rcsnum_itoa(nump->rn_id[i], tmp, sizeof(tmp)), blen);
+ if (len >= blen)
+ fatal("rcsnum_tostr: overflow 2");
}
return (buf);
diff --git a/usr.bin/cvs/rcstime.c b/usr.bin/cvs/rcstime.c
index eda07bc0606..267d704b690 100644
--- a/usr.bin/cvs/rcstime.c
+++ b/usr.bin/cvs/rcstime.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcstime.c,v 1.5 2006/04/17 06:33:22 ray Exp $ */
+/* $OpenBSD: rcstime.c,v 1.6 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
* All rights reserved.
@@ -33,7 +33,7 @@ void
rcs_set_tz(char *tz, struct rcs_delta *rdp, struct tm *tb)
{
int tzone;
- int pos;
+ int neg, pos;
char *h, *m;
struct tm *ltb;
time_t now;
@@ -44,9 +44,10 @@ rcs_set_tz(char *tz, struct rcs_delta *rdp, struct tm *tb)
ltb->tm_hour += ((int)ltb->tm_gmtoff/3600);
memcpy(tb, ltb, sizeof(struct tm));
} else {
- pos = 0;
+ neg = pos = 0;
switch (*tz) {
case '-':
+ neg = 1;
break;
case '+':
pos = 1;
diff --git a/usr.bin/cvs/release.c b/usr.bin/cvs/release.c
deleted file mode 100644
index 58a2ae4fcbf..00000000000
--- a/usr.bin/cvs/release.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* $OpenBSD: release.c,v 1.32 2006/03/15 19:59:36 niallo Exp $ */
-/*
- * Copyright (c) 2005 Xavier Santolaria <xsa@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-#define UPDCMD_FLAGS "-n -q -d"
-
-extern char *__progname;
-
-static int cvs_release_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_release_pre_exec(struct cvsroot *);
-static int cvs_release_dir(CVSFILE *, void *);
-
-struct cvs_cmd cvs_cmd_release = {
- CVS_OP_RELEASE, CVS_REQ_RELEASE, "release",
- { "re", "rel" },
- "Release",
- "[-d]",
- "d",
- NULL,
- CF_NOFILES,
- cvs_release_init,
- cvs_release_pre_exec,
- cvs_release_dir,
- cvs_release_dir,
- NULL,
- NULL,
- CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC
-};
-
-static int dflag; /* -d option */
-
-static int
-cvs_release_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'd':
- dflag = 1;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- argc -= optind;
- argv += optind;
- *arg = optind;
-
- if (argc == 0)
- return (CVS_EX_USAGE);
-
- return (0);
-}
-
-static int
-cvs_release_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method != CVS_METHOD_LOCAL) {
- if (dflag == 1)
- cvs_sendarg(root, "-d", 0);
- }
- return (0);
-}
-
-/*
- * cvs_release_dir()
- *
- * Release specified directorie(s).
- * Returns 0 on success, or -1 on failure.
- */
-static int
-cvs_release_dir(CVSFILE *cf, void *arg)
-{
- FILE *fp;
- int j, l;
- char *wdir, cwd[MAXPATHLEN];
- char buf[256], dpath[MAXPATHLEN], updcmd[1024];
- struct stat st;
- struct cvsroot *root;
-
- j = 0;
-
- root = CVS_DIR_ROOT(cf);
-
- /* XXX kept for compat reason of `cvs update' output */
- /* save current working directory for further use */
- if ((wdir = getcwd(cwd, sizeof(cwd))) == NULL)
- fatal("getcwd failed");
-
- cvs_file_getpath(cf, dpath, sizeof(dpath));
-
- if (cf->cf_type == DT_DIR) {
- if (!strcmp(cf->cf_name, "."))
- return (0);
-
- /* chdir before running the `cvs update' command */
- cvs_chdir(dpath, 0);
-
- /* test if dir has CVS/ directory */
- if (stat(CVS_PATH_CVSDIR, &st) == -1) {
- if (verbosity > 0)
- cvs_log(LP_ERR,
- "no repository directory: %s", dpath);
- return (0);
- }
- } else {
- if (verbosity > 0)
- cvs_log(LP_ERR, "no such directory: %s", dpath);
- return (0);
- }
-
- /* construct `cvs update' command */
- l = snprintf(updcmd, sizeof(updcmd), "%s %s %s update",
- __progname, UPDCMD_FLAGS, root->cr_str);
- if (l == -1 || l >= (int)sizeof(updcmd))
- fatal("cvs_release_dir: `cvs update' command string overflow");
-
- /* XXX we should try to avoid a new connection ... */
- cvs_log(LP_TRACE, "cvs_release_dir() popen(%s,r)", updcmd);
- if ((fp = popen(updcmd, "r")) == NULL)
- fatal("cannot run command `%s'", updcmd);
-
- while (fgets(buf, (int)sizeof(buf), fp) != NULL) {
- if (strchr("ACMPRU", buf[0]))
- j++;
- (void)fputs(buf, stdout);
- }
-
- if (pclose(fp) != 0) {
- cvs_log(LP_ERR, "unable to release `%s'", dpath);
-
- /* change back to original working dir */
- cvs_chdir(wdir, 0);
- }
-
- printf("You have [%d] altered file%s in this repository.\n",
- j, j > 1 ? "s" : "");
- while (fgets(buf, (int)sizeof(buf), fp) != NULL) {
- if (strchr("ACMPRU", buf[0]))
- j++;
- (void)fputs(buf, stdout);
- }
-
- printf("Are you sure you want to release %sdirectory `%s': ",
- dflag ? "(and delete) " : "", dpath);
-
- if (cvs_yesno() == -1) { /* No */
- fprintf(stderr,
- "** `%s' aborted by user choice.\n", cvs_command);
-
- /* change back to original working dir */
- cvs_chdir(wdir, 0);
-
- return (-1);
- }
-
- /* change back to original working dir */
- cvs_chdir(wdir, 0);
-
- if (dflag == 1) {
- if (cvs_rmdir(dpath) != 0)
- fatal("cvs_release_dir: cvs_rmdir failed");
- }
-
- return (0);
-}
diff --git a/usr.bin/cvs/remove.c b/usr.bin/cvs/remove.c
deleted file mode 100644
index 27c9da23e7a..00000000000
--- a/usr.bin/cvs/remove.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/* $OpenBSD: remove.c,v 1.44 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * Copyright (c) 2004, 2005 Xavier Santolaria <xsa@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-extern char *__progname;
-
-
-static int cvs_remove_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_remove_remote(CVSFILE *, void *);
-static int cvs_remove_local(CVSFILE *, void *);
-static int cvs_remove_file(const char *);
-
-static int force_remove = 0; /* -f option */
-static int nuked = 0;
-
-struct cvs_cmd cvs_cmd_remove = {
- CVS_OP_REMOVE, CVS_REQ_REMOVE, "remove",
- { "rm", "delete" },
- "Remove an entry from the repository",
- "[-flR] [file ...]",
- "flR",
- NULL,
- CF_IGNORE | CF_RECURSE,
- cvs_remove_init,
- NULL,
- cvs_remove_remote,
- cvs_remove_local,
- NULL,
- NULL,
- CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC
-};
-
-static int
-cvs_remove_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'f':
- force_remove = 1;
- break;
- case 'l':
- cmd->file_flags &= ~CF_RECURSE;
- break;
- case 'R':
- cmd->file_flags |= CF_RECURSE;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- argc -= optind;
- argv += optind;
-
- *arg = optind;
- return (0);
-}
-
-
-static int
-cvs_remove_remote(CVSFILE *cf, void *arg)
-{
- char fpath[MAXPATHLEN];
- struct cvsroot *root;
-
- root = CVS_DIR_ROOT(cf);
-
- if (cf->cf_type == DT_DIR) {
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- else
- cvs_senddir(root, cf);
- return (0);
- }
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- if (cvs_remove_file(fpath) < 0)
- fatal("cvs_remove_remote: cvs_remove_file `%s' failed", fpath);
-
- cvs_sendentry(root, cf);
-
- if (cf->cf_cvstat != CVS_FST_LOST && force_remove != 1) {
- if (cf->cf_cvstat != CVS_FST_ADDED)
- cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name);
-
- if (cf->cf_flags & CVS_FILE_ONDISK)
- cvs_sendfile(root, fpath);
- }
-
- return (0);
-}
-
-static int
-cvs_remove_local(CVSFILE *cf, void *arg)
-{
- int existing, removed;
- char buf[MAXPATHLEN], fpath[MAXPATHLEN];
- CVSENTRIES *entf;
- struct cvs_ent *ent;
-
- existing = removed = 0;
- entf = (CVSENTRIES *)cf->cf_entry;
-
- if (cf->cf_type == DT_DIR) {
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "Removing %s", cf->cf_name);
- return (0);
- }
-
- if (cvs_cmdop != CVS_OP_SERVER) {
- cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- if (cvs_remove_file(fpath) < 0)
- fatal("cvs_remove_local: cvs_remove_file `%s' failed",
- fpath);
- }
-
- if (nuked == 0) {
- existing++;
- if (verbosity > 1)
- cvs_log(LP_WARN, "file `%s' still in working directory",
- cf->cf_name);
- } else if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
- if (verbosity > 1)
- cvs_log(LP_WARN, "nothing known about `%s'",
- cf->cf_name);
- return (0);
- } else if (cf->cf_cvstat == CVS_FST_ADDED) {
- if (cvs_ent_remove(entf, cf->cf_name, 0) == -1)
- fatal("cvs_remove_local: cvs_ent_remove failed");
-
- if (strlcpy(buf, CVS_PATH_CVSDIR, sizeof(buf)) >= sizeof(buf) ||
- strlcat(buf, "/", sizeof(buf)) >= sizeof(buf) ||
- strlcat(buf, cf->cf_name, sizeof(buf)) >= sizeof(buf) ||
- strlcat(buf, CVS_DESCR_FILE_EXT,
- sizeof(buf)) >= sizeof(buf))
- fatal("cvs_remove_local: path truncation");
-
- if (cvs_unlink(buf) == -1)
- fatal("cvs_remove_local: cvs_unlink `%s' failed", buf);
-
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "removed `%s'", cf->cf_name);
- return (0);
- } else if (cf->cf_cvstat == CVS_FST_REMOVED) {
- if (verbosity > 1 )
- cvs_log(LP_WARN,
- "file `%s' already scheduled for removal",
- cf->cf_name);
- return (0);
- } else {
- if ((ent = cvs_ent_get(entf, cf->cf_name)) == NULL)
- fatal("cvs_remove_local: cvs_ent_get failed");
-
- /* Prefix revision with `-' */
- ent->ce_status = CVS_ENT_REMOVED;
- entf->cef_flags &= ~CVS_ENTF_SYNC;
-
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "scheduling file `%s' for removal",
- cf->cf_name);
- removed++;
- }
-
- if (removed != 0) {
- if (verbosity > 0)
- cvs_log(LP_NOTICE, "use '%s commit' to remove %s "
- "permanently", __progname,
- (removed == 1) ? "this file" : "these files");
- return (0);
- }
-
- if (existing != 0) {
- cvs_log(LP_WARN, existing == 1 ?
- "%d file exists; remove it first" :
- "%d files exist; remove them first", existing);
- return (0);
- }
-
- return (0);
-}
-
-/*
- * cvs_remove_file()
- *
- * Physically remove the file.
- * Used by both remote and local handlers.
- * Returns 0 on success, -1 on failure.
- */
-static int
-cvs_remove_file(const char *fpath)
-{
- struct stat st;
-
- /* if -f option is used, physically remove the file */
- if (force_remove == 1) {
- if (cvs_unlink(fpath) == -1)
- return (-1);
- nuked++;
- } else {
- if (stat(fpath, &st) == -1 && errno == ENOENT)
- nuked++;
- }
-
- return (0);
-}
diff --git a/usr.bin/cvs/repository.c b/usr.bin/cvs/repository.c
new file mode 100644
index 00000000000..5bea74ffcb1
--- /dev/null
+++ b/usr.bin/cvs/repository.c
@@ -0,0 +1,130 @@
+/* $OpenBSD: repository.c,v 1.1 2006/05/27 03:30:31 joris Exp $ */
+/*
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include "cvs.h"
+#include "file.h"
+#include "log.h"
+#include "repository.h"
+#include "worklist.h"
+
+struct cvs_wklhead repo_locks;
+
+void
+cvs_repository_unlock(const char *repo)
+{
+ int l;
+ char fpath[MAXPATHLEN];
+
+ cvs_log(LP_TRACE, "cvs_repository_unlock(%s)", repo);
+
+ l = snprintf(fpath, sizeof(fpath), "%s/%s", repo, CVS_LOCK);
+ if (l == -1 || l >= (int)sizeof(fpath))
+ fatal("cvs_repository_unlock: overflow");
+
+ /* XXX - this ok? */
+ cvs_worklist_run(&repo_locks, cvs_worklist_unlink);
+}
+
+void
+cvs_repository_lock(const char *repo)
+{
+ int l, i;
+ uid_t myuid;
+ struct stat st;
+ char fpath[MAXPATHLEN];
+ struct passwd *pw;
+
+ cvs_log(LP_TRACE, "cvs_repository_lock(%s)", repo);
+
+ l = snprintf(fpath, sizeof(fpath), "%s/%s", repo, CVS_LOCK);
+ if (l == -1 || l >= (int)sizeof(fpath))
+ fatal("cvs_repository_lock: overflow");
+
+ myuid = getuid();
+ for (i = 0; i < CVS_LOCK_TRIES; i++) {
+ if (cvs_quit)
+ fatal("received signal %d", sig_received);
+
+ if (stat(fpath, &st) == -1)
+ break;
+
+ if ((pw = getpwuid(st.st_uid)) == NULL)
+ fatal("cvs_repository_lock: %s", strerror(errno));
+
+ cvs_log(LP_NOTICE, "waiting for %s's lock in '%s'",
+ pw->pw_name, repo);
+ sleep(CVS_LOCK_SLEEP);
+ }
+
+ if (i == CVS_LOCK_TRIES)
+ fatal("maximum wait time for lock inside '%s' reached", repo);
+
+ if ((i = open(fpath, O_WRONLY|O_CREAT|O_TRUNC, 0755)) < 0) {
+ if (errno == EEXIST)
+ fatal("cvs_repository_lock: somebody beat us");
+ else
+ fatal("cvs_repostitory_lock: %s: %s",
+ fpath, strerror(errno));
+ }
+
+ (void)close(i);
+ cvs_worklist_add(fpath, &repo_locks);
+}
+
+void
+cvs_repository_getdir(const char *dir, const char *wdir,
+ struct cvs_flisthead *fl, struct cvs_flisthead *dl)
+{
+ int l;
+ DIR *dirp;
+ struct dirent *dp;
+ char *s, fpath[MAXPATHLEN];
+
+ if ((dirp = opendir(dir)) == NULL)
+ fatal("cvs_repository_getdir: failed to open '%s'", dir);
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (!strcmp(dp->d_name, ".") ||
+ !strcmp(dp->d_name, "..") ||
+ !strcmp(dp->d_name, "Attic") ||
+ !strcmp(dp->d_name, CVS_LOCK))
+ continue;
+
+ if (cvs_file_chkign(dp->d_name))
+ continue;
+
+ l = snprintf(fpath, sizeof(fpath), "%s/%s", wdir, dp->d_name);
+ if (l == -1 || l >= (int)sizeof(fpath))
+ fatal("cvs_repository_getdir: overflow");
+
+ /*
+ * Anticipate the file type for sorting, we do not determine
+ * the final file type until we have the fd floating around.
+ */
+ if (dp->d_type == DT_DIR) {
+ cvs_file_get(fpath, dl);
+ } else if (dp->d_type == DT_REG) {
+ if ((s = strrchr(fpath, ',')) != NULL)
+ *s = '\0';
+ cvs_file_get(fpath, fl);
+ }
+ }
+
+ (void)closedir(dirp);
+}
diff --git a/usr.bin/cvs/repository.h b/usr.bin/cvs/repository.h
new file mode 100644
index 00000000000..167a77ba389
--- /dev/null
+++ b/usr.bin/cvs/repository.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REPO_H
+#define REPO_H
+
+#define CVS_LOCK "#cvs.lock"
+#define CVS_LOCK_SLEEP 30
+#define CVS_LOCK_TRIES 5
+
+extern struct cvs_wklhead repo_locks;
+
+void cvs_repository_unlock(const char *);
+void cvs_repository_lock(const char *);
+void cvs_repository_getdir(const char *, const char *,
+ struct cvs_flisthead *, struct cvs_flisthead *);
+
+#endif
diff --git a/usr.bin/cvs/req.c b/usr.bin/cvs/req.c
deleted file mode 100644
index 243cf9f3be3..00000000000
--- a/usr.bin/cvs/req.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/* $OpenBSD: req.c,v 1.44 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "buf.h"
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-extern char *cvs_rootstr;
-extern int cvs_compress;
-extern char *cvs_rsh;
-extern int cvs_trace;
-extern int cvs_nolog;
-extern int cvs_readonly;
-
-
-static int cvs_req_set(int, char *);
-static int cvs_req_noop(int, char *);
-static int cvs_req_root(int, char *);
-static int cvs_req_validreq(int, char *);
-static int cvs_req_validresp(int, char *);
-static int cvs_req_expandmod(int, char *);
-static int cvs_req_directory(int, char *);
-static int cvs_req_useunchanged(int, char *);
-static int cvs_req_case(int, char *);
-static int cvs_req_argument(int, char *);
-static int cvs_req_globalopt(int, char *);
-static int cvs_req_gzipstream(int, char *);
-static int cvs_req_entry(int, char *);
-static int cvs_req_filestate(int, char *);
-
-static int cvs_req_command(int, char *);
-
-
-struct cvs_reqhdlr {
- int (*hdlr)(int, char *);
-} cvs_req_swtab[CVS_REQ_MAX + 1] = {
- { NULL },
- { cvs_req_root },
- { cvs_req_validreq },
- { cvs_req_validresp },
- { cvs_req_directory },
- { NULL },
- { NULL },
- { NULL },
- { cvs_req_entry },
- { NULL },
- { NULL }, /* 10 */
- { cvs_req_filestate },
- { cvs_req_filestate },
- { cvs_req_filestate },
- { cvs_req_useunchanged },
- { NULL },
- { NULL },
- { cvs_req_filestate },
- { cvs_req_case },
- { NULL },
- { cvs_req_argument }, /* 20 */
- { cvs_req_argument },
- { cvs_req_globalopt },
- { cvs_req_gzipstream },
- { NULL },
- { NULL },
- { NULL },
- { NULL },
- { NULL },
- { NULL },
- { NULL }, /* 30 */
- { NULL },
- { NULL },
- { NULL },
- { cvs_req_set },
- { cvs_req_expandmod },
- { cvs_req_command },
- { NULL },
- { NULL },
- { NULL },
- { NULL }, /* 40 */
- { NULL },
- { NULL },
- { NULL },
- { NULL },
- { cvs_req_command },
- { cvs_req_command },
- { NULL },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command }, /* 50 */
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command }, /* 60 */
- { NULL },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_noop },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
- { cvs_req_command },
-};
-
-
-
-/*
- * Argument array built by `Argument' and `Argumentx' requests.
- */
-static char *cvs_req_args[CVS_PROTO_MAXARG];
-
-/* start at 1, because 0 will be the command name */
-static int cvs_req_nargs = 1;
-
-static char *cvs_req_modulename;
-static char *cvs_req_rootpath;
-static char *cvs_req_currentdir;
-extern char cvs_server_tmpdir[MAXPATHLEN];
-static CVSENTRIES *cvs_req_entf;
-
-/*
- * cvs_req_handle()
- *
- * Generic request handler dispatcher. The handler expects the first line
- * of the command as single argument.
- * Returns the return value of the command on success, or -1 on failure.
- */
-int
-cvs_req_handle(char *line)
-{
- char *cp, *cmd;
- struct cvs_req *req;
-
- cmd = line;
-
- cp = strchr(cmd, ' ');
- if (cp != NULL)
- *(cp++) = '\0';
-
- if ((req = cvs_req_getbyname(cmd)) == NULL)
- fatal("cvs_req_handle: cvs_req_getbyname failed");
- else if (cvs_req_swtab[req->req_id].hdlr == NULL)
- fatal("handler for `%s' not implemented", cmd);
-
- return (*cvs_req_swtab[req->req_id].hdlr)(req->req_id, cp);
-}
-
-/*
- * cvs_req_noop()
- */
-static int
-cvs_req_noop(int reqid, char *line)
-{
- cvs_sendresp(CVS_RESP_OK, NULL);
- return (0);
-}
-
-
-static int
-cvs_req_root(int reqid, char *line)
-{
- if (cvs_req_rootpath != NULL) {
- cvs_log(LP_ERR, "duplicate Root request received");
- cvs_printf("Protocol error: Duplicate Root request");
- return (-1);
- }
-
- cvs_req_rootpath = xstrdup(line);
- cvs_rootstr = cvs_req_rootpath;
-
- return (0);
-}
-
-
-static int
-cvs_req_validreq(int reqid, char *line)
-{
- char *vreq;
-
- vreq = cvs_req_getvalid();
- if (vreq == NULL)
- return (-1);
-
- cvs_sendresp(CVS_RESP_VALIDREQ, vreq);
- cvs_sendresp(CVS_RESP_OK, NULL);
-
- return (0);
-}
-
-static int
-cvs_req_validresp(int reqid, char *line)
-{
- char *sp, *ep;
- struct cvs_resp *resp;
-
- sp = line;
- do {
- ep = strchr(sp, ' ');
- if (ep != NULL)
- *(ep++) = '\0';
-
- resp = cvs_resp_getbyname(sp);
- if (resp != NULL)
- ;
-
- if (ep != NULL)
- sp = ep + 1;
- } while (ep != NULL);
-
- return (0);
-}
-
-static int
-cvs_req_directory(int reqid, char *line)
-{
- int pwd;
- size_t dirlen;
- char rdir[MAXPATHLEN];
- char *repo, *s, *p;
-
- pwd = (!strcmp(line, "."));
-
- cvs_getln(NULL, rdir, sizeof(rdir));
-
- STRIP_SLASH(rdir);
-
- if (cvs_req_currentdir != NULL)
- xfree(cvs_req_currentdir);
-
- cvs_req_currentdir = xstrdup(rdir);
-
- dirlen = strlen(cvs_req_currentdir);
-
- /*
- * Lets make sure we always start at the correct
- * directory.
- */
- cvs_chdir(cvs_server_tmpdir, 1);
-
- /*
- * Set repository path.
- */
- if (strlen(cvs_req_rootpath) < dirlen) {
- s = cvs_req_currentdir + strlen(cvs_req_rootpath) + 1;
- if (s >= (cvs_req_currentdir + dirlen))
- fatal("you're bad, go away");
- } else
- s = cvs_req_currentdir;
-
- repo = xstrdup(s);
-
- /*
- * Skip back "foo/bar" part, so we can feed the repo
- * as a startpoint for cvs_create_dir().
- */
- if (!pwd) {
- s = repo + strlen(repo) - strlen(line) - 1;
- if (*s != '/')
- fatal("cvs_req_directory: malformed directory");
-
- *s = '\0';
- }
-
- /*
- * Obtain the modulename, we only need to do this at
- * the very first time we get a Directory request.
- */
- if (cvs_req_modulename == NULL) {
- if ((p = strchr(repo, '/')) != NULL)
- *p = '\0';
-
- cvs_req_modulename = xstrdup(repo);
-
- if (p != NULL)
- *p = '/';
-
- /*
- * Now, create the admin files in the top-level
- * directory for the temp repo.
- */
- cvs_mkadmin(cvs_server_tmpdir, cvs_rootstr, repo, NULL,
- NULL, 0);
- }
-
- /*
- * create the directory plus the administrative files.
- */
- if (cvs_create_dir(line, 1, cvs_rootstr, repo) < 0) {
- xfree(repo);
- return (-1);
- }
-
- /*
- * cvs_create_dir() has already put us in the correct directory
- * so now open it's Entry file for incoming files.
- */
- if (cvs_req_entf != NULL)
- cvs_ent_close(cvs_req_entf);
- cvs_req_entf = cvs_ent_open(".", O_RDWR);
- if (cvs_req_entf == NULL)
- fatal("failed to open Entry file for %s", line);
-
- xfree(repo);
- return (0);
-}
-
-static int
-cvs_req_entry(int reqid, char *line)
-{
- struct cvs_ent *ent;
-
- /* parse received entry */
- if ((ent = cvs_ent_parse(line)) == NULL)
- return (-1);
-
- /* add it to the entry file and done */
- if (cvs_ent_add(cvs_req_entf, ent) < 0)
- fatal("cvs_req_entry: cvs_ent_add: `%s'", ent->ce_name);
-
- /* XXX */
- cvs_ent_write(cvs_req_entf);
-
- return (0);
-}
-
-/*
- * cvs_req_filestate()
- *
- * Handler for the `Modified', `Is-Modified', `Unchanged' and `Questionable'
- * requests, which are all used to report the assumed state of a file from the
- * client.
- */
-static int
-cvs_req_filestate(int reqid, char *line)
-{
- int ret;
- mode_t fmode;
- BUF *fdata;
- struct cvs_ent *ent;
-
- ret = 0;
- switch (reqid) {
- case CVS_REQ_MODIFIED:
- fdata = cvs_recvfile(NULL, &fmode);
- if (fdata == NULL)
- return (-1);
-
- /* write the file */
- cvs_buf_write(fdata, line, fmode);
- cvs_buf_free(fdata);
- break;
- case CVS_REQ_ISMODIFIED:
- break;
- case CVS_REQ_UNCHANGED:
- ent = cvs_ent_get(cvs_req_entf, line);
- if (ent == NULL) {
- cvs_log(LP_ERR,
- "received Unchanged request "
- "for a non-existing file");
- ret = -1;
- } else {
- ent->ce_status = CVS_ENT_UPTODATE;
- }
- break;
- case CVS_REQ_QUESTIONABLE:
- cvs_printf("? %s\n", line);
- break;
- default:
- cvs_log(LP_ERR, "wrong request id type");
- ret = -1;
- break;
- }
-
- /* XXX */
- cvs_req_entf->cef_flags &= ~CVS_ENTF_SYNC;
- cvs_ent_write(cvs_req_entf);
-
- return (ret);
-}
-
-/*
- * cvs_req_expandmod()
- *
- */
-static int
-cvs_req_expandmod(int reqid, char *line)
-{
- cvs_sendresp(CVS_RESP_OK, NULL);
- return (0);
-}
-
-
-/*
- * cvs_req_useunchanged()
- *
- * Handler for the `UseUnchanged' requests. The protocol documentation
- * specifies that this request must be supported by the server and must be
- * sent by the client, though it gives no clue regarding its use.
- */
-static int
-cvs_req_useunchanged(int reqid, char *line)
-{
- return (0);
-}
-
-
-/*
- * cvs_req_case()
- *
- * Handler for the `Case' requests, which toggles case sensitivity ON or OFF
- */
-static int
-cvs_req_case(int reqid, char *line)
-{
- cvs_nocase = 1;
- return (0);
-}
-
-
-static int
-cvs_req_set(int reqid, char *line)
-{
- char *cp, *lp;
-
- lp = xstrdup(line);
- if ((cp = strchr(lp, '=')) == NULL)
- fatal("error in Set request (no = in variable assignment)");
-
- *(cp++) = '\0';
-
- if (cvs_var_set(lp, cp) < 0) {
- xfree(lp);
- return (-1);
- }
-
- xfree(lp);
-
- return (0);
-}
-
-
-static int
-cvs_req_argument(int reqid, char *line)
-{
- char *nap;
-
- if (cvs_req_nargs == CVS_PROTO_MAXARG)
- fatal("too many arguments");
-
- if (reqid == CVS_REQ_ARGUMENT) {
- cvs_req_args[cvs_req_nargs] = xstrdup(line);
- cvs_req_nargs++;
- } else if (reqid == CVS_REQ_ARGUMENTX) {
- if (cvs_req_nargs == 0)
- cvs_log(LP_WARN, "no argument to append to");
- else {
- xasprintf(&nap, "%s%s", cvs_req_args[cvs_req_nargs - 1],
- line);
-
- xfree(cvs_req_args[cvs_req_nargs - 1]);
- cvs_req_args[cvs_req_nargs - 1] = nap;
- }
- }
-
- return (0);
-}
-
-
-static int
-cvs_req_globalopt(int reqid, char *line)
-{
- if (*line != '-' || *(line + 2) != '\0')
- fatal("invalid `Global_option' request format");
-
- switch (*(line + 1)) {
- case 'l':
- cvs_nolog = 1;
- break;
- case 'n':
- cvs_noexec = 1;
- break;
- case 'Q':
- verbosity = 0;
- break;
- case 'q':
- if (verbosity > 1)
- verbosity = 1;
- break;
- case 'r':
- cvs_readonly = 1;
- break;
- case 't':
- cvs_trace = 1;
- break;
- default:
- cvs_log(LP_ERR, "unknown global option `%s'", line);
- return (-1);
- }
-
- return (0);
-}
-
-
-/*
- * cvs_req_gzipstream()
- *
- * Handler for the `Gzip-stream' request, which enables compression at the
- * level given along with the request. After this request has been processed,
- * all further connection data should be compressed.
- */
-static int
-cvs_req_gzipstream(int reqid, char *line)
-{
- char *ep;
- long val;
-
- val = strtol(line, &ep, 10);
- if (line[0] == '\0' || *ep != '\0')
- fatal("invalid Gzip-stream level `%s'", line);
- else if (errno == ERANGE && (val < 0 || val > 9))
- fatal("Gzip-stream level %ld out of range", val);
-
- cvs_compress = (int)val;
-
- return (0);
-}
-
-
-/*
- * cvs_req_command()
- *
- * Generic request handler for CVS command requests (i.e. diff, update, tag).
- */
-static int
-cvs_req_command(int reqid, char *line)
-{
- struct cvs_cmd *cmdp;
-
- cmdp = cvs_findcmdbyreq(reqid);
- if (cmdp == NULL) {
- cvs_sendresp(CVS_RESP_ERROR, NULL);
- return (-1);
- }
-
- /* close the Entry file if it's still open */
- if (cvs_req_entf != NULL)
- cvs_ent_close(cvs_req_entf);
-
- /* fill in the command name */
- cvs_req_args[0] = cmdp->cmd_name;
-
- /* switch to the correct directory */
- if (cmdp->cmd_op != CVS_OP_VERSION)
- cvs_chdir(cvs_server_tmpdir, 1);
-
- if (cvs_startcmd(cmdp, cvs_req_nargs, cvs_req_args) == 0)
- cvs_sendresp(CVS_RESP_OK, NULL);
-
- return (0);
-}
diff --git a/usr.bin/cvs/resp.c b/usr.bin/cvs/resp.c
deleted file mode 100644
index 0877495406e..00000000000
--- a/usr.bin/cvs/resp.c
+++ /dev/null
@@ -1,900 +0,0 @@
-/* $OpenBSD: resp.c,v 1.73 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "buf.h"
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-#define CVS_MTSTK_MAXDEPTH 16
-
-
-static int cvs_resp_validreq (struct cvsroot *, int, char *);
-static int cvs_resp_cksum (struct cvsroot *, int, char *);
-static int cvs_resp_modtime (struct cvsroot *, int, char *);
-static int cvs_resp_m (struct cvsroot *, int, char *);
-static int cvs_resp_ok (struct cvsroot *, int, char *);
-static int cvs_resp_error (struct cvsroot *, int, char *);
-static int cvs_resp_statdir (struct cvsroot *, int, char *);
-static int cvs_resp_sticky (struct cvsroot *, int, char *);
-static int cvs_resp_newentry (struct cvsroot *, int, char *);
-static int cvs_resp_updated (struct cvsroot *, int, char *);
-static int cvs_resp_removed (struct cvsroot *, int, char *);
-static int cvs_resp_mode (struct cvsroot *, int, char *);
-static int cvs_resp_modxpand (struct cvsroot *, int, char *);
-static int cvs_resp_rcsdiff (struct cvsroot *, int, char *);
-static int cvs_resp_template (struct cvsroot *, int, char *);
-static int cvs_resp_copyfile (struct cvsroot *, int, char *);
-static int cvs_resp_createdir (char *);
-
-struct cvs_resphdlr {
- int (*hdlr)(struct cvsroot *, int, char *);
-} cvs_resp_swtab[CVS_RESP_MAX + 1] = {
- { NULL },
- { cvs_resp_ok },
- { cvs_resp_error },
- { cvs_resp_validreq },
- { cvs_resp_newentry },
- { cvs_resp_newentry },
- { cvs_resp_cksum },
- { cvs_resp_copyfile },
- { cvs_resp_updated },
- { cvs_resp_updated },
- { cvs_resp_updated }, /* 10 */
- { cvs_resp_updated },
- { cvs_resp_updated },
- { cvs_resp_rcsdiff },
- { cvs_resp_mode },
- { cvs_resp_modtime },
- { cvs_resp_removed },
- { cvs_resp_removed },
- { cvs_resp_statdir },
- { cvs_resp_statdir },
- { cvs_resp_sticky }, /* 20 */
- { cvs_resp_sticky },
- { cvs_resp_template },
- { NULL },
- { NULL },
- { NULL },
- { cvs_resp_modxpand },
- { NULL },
- { cvs_resp_m },
- { cvs_resp_m },
- { cvs_resp_m }, /* 30 */
- { cvs_resp_m },
- { cvs_resp_m },
-};
-
-/*
- * Instead of opening and closing the Entry file all the time,
- * which caused a huge CPU load and slowed down everything,
- * we keep the Entry file for the directory we are working in
- * open until we encounter a new directory.
- */
-static char cvs_resp_lastdir[MAXPATHLEN] = "";
-static CVSENTRIES *cvs_resp_lastent = NULL;
-static int resp_check_dir(struct cvsroot *, const char *);
-
-/*
- * The MT command uses scoping to tag the data. Whenever we encouter a '+',
- * we push the name of the tag on the stack, and we pop it when we encounter
- * a '-' with the same name.
- */
-
-static char *cvs_mt_stack[CVS_MTSTK_MAXDEPTH];
-static u_int cvs_mtstk_depth = 0;
-
-static time_t cvs_modtime = CVS_DATE_DMSEC;
-
-
-/* last checksum received */
-char *cvs_fcksum = NULL;
-
-mode_t cvs_lastmode = 0;
-
-/* hack to receive the remote version without outputting it */
-extern u_int cvs_version_sent;
-
-
-/*
- * cvs_resp_handle()
- *
- * Generic response handler dispatcher. The handler expects the first line
- * of the command as single argument.
- * Returns the return value of the command on success, or -1 on failure.
- */
-int
-cvs_resp_handle(struct cvsroot *root, char *line)
-{
- int ret;
- char *cp, *cmd;
- struct cvs_resp *resp;
-
- cmd = line;
-
- cp = strchr(cmd, ' ');
- if (cp != NULL)
- *(cp++) = '\0';
-
- resp = cvs_resp_getbyname(cmd);
- if (resp == NULL) {
- return (-1);
- } else if (cvs_resp_swtab[resp->resp_id].hdlr == NULL) {
- cvs_log(LP_ERR, "handler for `%s' not implemented", cmd);
- return (-1);
- }
-
- ret = (*cvs_resp_swtab[resp->resp_id].hdlr)(root, resp->resp_id, cp);
-
- if (ret == -1)
- cvs_log(LP_ERR, "error in handling of `%s' response", cmd);
-
- return (ret);
-}
-
-
-/*
- * cvs_resp_validreq()
- *
- * Handler for the `Valid-requests' response. The list of valid requests is
- * split on spaces and each request's entry in the valid request array is set
- * to 1 to indicate the validity.
- * Returns 0 on success, or -1 on failure.
- */
-static int
-cvs_resp_validreq(struct cvsroot *root, int type, char *line)
-{
- char *sp, *ep;
- struct cvs_req *req;
-
- /* parse the requests */
- sp = line;
- do {
- ep = strchr(sp, ' ');
- if (ep != NULL)
- *ep = '\0';
-
- req = cvs_req_getbyname(sp);
- if (req != NULL)
- CVS_SETVR(root, req->req_id);
-
- if (ep != NULL)
- sp = ep + 1;
- } while (ep != NULL);
-
- return (0);
-}
-
-
-/*
- * cvs_resp_m()
- *
- * Handler for the `M', 'MT', `F' and `E' responses.
- */
-static int
-cvs_resp_m(struct cvsroot *root, int type, char *line)
-{
- char *cp;
- FILE *stream;
-
- stream = NULL;
-
- switch (type) {
- case CVS_RESP_F:
- fflush(stderr);
- return (0);
- case CVS_RESP_M:
- if (cvs_version_sent) {
- /*
- * Instead of outputting the line, we save it as the
- * remote server's version string.
- */
- cvs_version_sent = 0;
- root->cr_version = xstrdup(line);
- return (0);
- }
- stream = stdout;
- break;
- case CVS_RESP_E:
- stream = stderr;
- break;
- case CVS_RESP_MT:
- if (*line == '+') {
- if (cvs_mtstk_depth == CVS_MTSTK_MAXDEPTH) {
- cvs_log(LP_ERR,
- "MT scope stack has reached max depth");
- return (-1);
- }
- cvs_mt_stack[cvs_mtstk_depth] = xstrdup(line + 1);
- cvs_mtstk_depth++;
- } else if (*line == '-') {
- if (cvs_mtstk_depth == 0) {
- cvs_log(LP_ERR, "MT scope stack underflow");
- return (-1);
- } else if (strcmp(line + 1,
- cvs_mt_stack[cvs_mtstk_depth - 1]) != 0) {
- cvs_log(LP_ERR, "mismatch in MT scope stack");
- return (-1);
- }
- xfree(cvs_mt_stack[--cvs_mtstk_depth]);
- } else {
- if (strcmp(line, "newline") == 0)
- putc('\n', stdout);
- else if (strncmp(line, "fname ", (size_t)6) == 0)
- printf("%s", line + 6);
- else {
- /* assume text */
- cp = strchr(line, ' ');
- if (cp != NULL)
- printf("%s", cp + 1);
- }
- }
-
- return (0);
- case CVS_RESP_MBINARY:
- cvs_log(LP_WARN, "Mbinary not supported in client yet");
- break;
- }
-
- fputs(line, stream);
- fputc('\n', stream);
-
- return (0);
-}
-
-
-/*
- * cvs_resp_ok()
- *
- * Handler for the `ok' response. This handler's job is to
- */
-static int
-cvs_resp_ok(struct cvsroot *root, int type, char *line)
-{
- /*
- * If we still have an Entry file open, close it now.
- */
- if (cvs_resp_lastent != NULL)
- cvs_ent_close(cvs_resp_lastent);
-
- return (1);
-}
-
-
-/*
- * cvs_resp_error()
- *
- * Handler for the `error' response. This handler's job is to
- * show the error message given by the server.
- */
-static int
-cvs_resp_error(struct cvsroot *root, int type, char *line)
-{
- if (line == NULL)
- return (1);
-
- /* XXX - GNU cvs sends an empty error message
- * at the end of the diff command, even for successfull
- * diff.
- */
- if (strlen(line) == 1 && *line == ' ')
- return (1);
-
- fprintf(stderr, "%s\n", line);
- return (1);
-}
-
-
-/*
- * cvs_resp_statdir()
- *
- * Handler for the `Clear-static-directory' and `Set-static-directory'
- * responses.
- */
-static int
-cvs_resp_statdir(struct cvsroot *root, int type, char *line)
-{
- int fd;
- char rpath[MAXPATHLEN], statpath[MAXPATHLEN];
-
- /* remote directory line */
- cvs_getln(root, rpath, sizeof(rpath));
-
- STRIP_SLASH(line);
-
- /*
- * Create the directory if it does not exist.
- */
- if (cvs_resp_createdir(line) < 0)
- return (-1);
- if (strlcpy(statpath, line, sizeof(statpath)) >= sizeof(statpath) ||
- strlcat(statpath, "/", sizeof(statpath)) >= sizeof(statpath) ||
- strlcat(statpath, CVS_PATH_STATICENTRIES,
- sizeof(statpath)) >= sizeof(statpath)) {
- cvs_log(LP_ERR, "Entries.static path truncation");
- return (-1);
- }
-
- if (cvs_noexec == 0) {
- if (type == CVS_RESP_CLRSTATDIR &&
- cvs_unlink(statpath) == -1) {
- return (-1);
- } else if (type == CVS_RESP_SETSTATDIR) {
- fd = open(statpath, O_CREAT|O_TRUNC|O_WRONLY, 0644);
- if (fd == -1) {
- cvs_log(LP_ERRNO,
- "failed to set static directory on %s",
- line);
- return (-1);
- }
- (void)close(fd);
-
- }
- }
-
- return (0);
-}
-
-/*
- * cvs_resp_sticky()
- *
- * Handler for the `Clear-sticky' and `Set-sticky' responses. If the
- * specified directory doesn't exist, we create it.
- */
-static int
-cvs_resp_sticky(struct cvsroot *root, int type, char *line)
-{
- char buf[MAXPATHLEN];
-
- /* get the remote path */
- cvs_getln(root, buf, sizeof(buf));
-
- STRIP_SLASH(line);
-
- if (cvs_resp_createdir(line) < 0)
- return (-1);
-
- return (0);
-}
-
-/*
- * Shared code for cvs_resp[static, sticky]
- *
- * Looks if the directory requested exists, if it doesn't it will
- * create it plus all administrative files as well.
- */
-static int
-cvs_resp_createdir(char *line)
-{
- CVSFILE *base, *cf;
- CVSENTRIES *entf;
- struct stat st;
- struct cvs_ent *ent;
- char *file, subdir[MAXPATHLEN], buf[CVS_ENT_MAXLINELEN];
-
- entf = NULL;
- cf = NULL;
-
- /*
- * we do not want to handle the '.' case,
- * so return early.
- */
- if (!strcmp(line, "."))
- return (0);
-
- cvs_splitpath(line, subdir, sizeof(subdir), &file);
- base = cvs_file_loadinfo(subdir, CF_NOFILES, NULL, NULL, 1);
- if (base == NULL)
- return (-1);
-
- /*
- * If <line> doesn't exist, we create it.
- */
- if (stat(line, &st) == -1) {
- if (errno != ENOENT) {
- cvs_log(LP_ERRNO, "failed to stat `%s'", line);
- return (-1);
- }
-
- cf = cvs_file_create(base, line, DT_DIR, 0755);
- } else {
- cf = cvs_file_loadinfo(line, CF_NOFILES, NULL, NULL, 1);
- }
-
- if (cf == NULL) {
- cvs_file_free(base);
- return (-1);
- }
-
- /*
- * If the Entries file for the parent is already
- * open, operate on that, instead of reopening it
- * and invalidating the opened list.
- */
- if (!strcmp(subdir, cvs_resp_lastdir))
- entf = cvs_resp_lastent;
- else
- entf = cvs_ent_open(subdir, O_WRONLY);
-
- /*
- * see if the entry is still present. If not, we add it again.
- */
- if (entf != NULL) {
- if ((ent = cvs_ent_get(entf, cf->cf_name)) == NULL) {
- if (strlcpy(buf, "D/", sizeof(buf)) >= sizeof(buf) ||
- strlcat(buf, cf->cf_name, sizeof(buf)) >=
- sizeof(buf) ||
- strlcat(buf, "////", sizeof(buf)) >= sizeof(buf)) {
- cvs_file_free(cf);
- cvs_file_free(base);
- return (-1);
- }
-
- ent = cvs_ent_parse(buf);
- if (ent == NULL)
- cvs_log(LP_ERR,
- "failed to create directory entry");
- else
- cvs_ent_add(entf, ent);
- }
-
- if (strcmp(subdir, cvs_resp_lastdir))
- cvs_ent_close(entf);
- }
-
- cvs_file_free(cf);
- cvs_file_free(base);
- return (0);
-}
-
-
-/*
- * cvs_resp_newentry()
- *
- * Handler for the `New-entry' response and `Checked-in' responses.
- * In the case of `New-entry', we expect the entry line
- */
-static int
-cvs_resp_newentry(struct cvsroot *root, int type, char *line)
-{
- char entbuf[CVS_ENT_MAXLINELEN];
- struct cvs_ent *ent;
-
- /* get the remote path */
- cvs_getln(root, entbuf, sizeof(entbuf));
-
- /* get the new Entries line */
- cvs_getln(root, entbuf, sizeof(entbuf));
-
- if (resp_check_dir(root, line) < 0)
- return (-1);
-
- if (type == CVS_RESP_NEWENTRY) {
- cvs_ent_addln(cvs_resp_lastent, entbuf);
- } else if (type == CVS_RESP_CHECKEDIN) {
- ent = cvs_ent_parse(entbuf);
- if (ent == NULL) {
- cvs_log(LP_ERR, "failed to parse entry");
- return (-1);
- }
-
- /* timestamp it to now */
- ent->ce_mtime = time(&(ent->ce_mtime));
-
- /* replace the current entry with the one we just received */
- (void)cvs_ent_remove(cvs_resp_lastent, ent->ce_name, 0);
-
- cvs_ent_add(cvs_resp_lastent, ent);
- }
-
- return (0);
-}
-
-
-/*
- * cvs_resp_cksum()
- *
- * Handler for the `Checksum' response. We store the checksum received for
- * the next file in a dynamically-allocated buffer pointed to by <cvs_fcksum>.
- * Upon next file reception, the handler checks to see if there is a stored
- * checksum.
- * The file handler must make sure that the checksums match and free the
- * checksum buffer once it's done to indicate there is no further checksum.
- */
-static int
-cvs_resp_cksum(struct cvsroot *root, int type, char *line)
-{
- if (cvs_fcksum != NULL) {
- cvs_log(LP_WARN, "unused checksum");
- xfree(cvs_fcksum);
- }
-
- cvs_fcksum = xstrdup(line);
-
- return (0);
-}
-
-
-/*
- * cvs_resp_copyfile()
- *
- * Handler for the `Copy-file' response, which is used to copy the contents
- * of a file to another file for which the name is provided. The CVS protocol
- * documentation states that this response is only used prior to a `Merged'
- * response to create a backup of the file.
- */
-static int
-cvs_resp_copyfile(struct cvsroot *root, int type, char *line)
-{
- char path[MAXPATHLEN], newpath[MAXPATHLEN];
- char newname[MAXNAMLEN], *file;
-
- /* read the remote path of the file to copy and its new name */
- cvs_getln(root, path, sizeof(path));
- cvs_getln(root, newname, sizeof(newname));
-
- if ((file = basename(path)) == NULL)
- fatal("no base file name in Copy-file path");
-
- if (strlcpy(path, line, sizeof(path)) >= sizeof(path) ||
- strlcat(path, file, sizeof(path)) >= sizeof(path))
- fatal("source path overflow in Copy-file response");
-
- if (strlcpy(newpath, line, sizeof(newpath)) >= sizeof(newpath) ||
- strlcat(newpath, newname, sizeof(newpath)) >= sizeof(newpath))
- fatal("destination path overflow in Copy-file response");
-
- if (rename(path, newpath) == -1) {
- fatal("cvs_resp_copyfile: rename: `%s'->`%s': %s",
- path, newpath, strerror(errno));
- }
-
- return (0);
-}
-
-
-/*
- * cvs_resp_modtime()
- *
- * Handler for the `Mod-time' file update modifying response. The timestamp
- * given is used to set the last modification time on the next file that
- * will be received.
- */
-static int
-cvs_resp_modtime(struct cvsroot *root, int type, char *line)
-{
- cvs_modtime = cvs_date_parse(line);
- return (0);
-}
-
-
-/*
- * cvs_resp_updated()
- *
- * Handler for the `Updated', `Update-existing', `Created', `Merged' and
- * `Patched' responses, which all have a very similar format.
- */
-static int
-cvs_resp_updated(struct cvsroot *root, int type, char *line)
-{
- int ret;
- mode_t fmode;
- char path[MAXPATHLEN], cksum_buf[CVS_CKSUM_LEN];
- BUF *fbuf;
- struct cvs_ent *ent;
- struct timeval tv[2];
-
- ret = 0;
-
- STRIP_SLASH(line);
-
- /* read the remote path of the file */
- cvs_getln(root, path, sizeof(path));
-
- /* read the new entry */
- cvs_getln(root, path, sizeof(path));
-
- if ((ent = cvs_ent_parse(path)) == NULL)
- return (-1);
-
- if (strlcpy(path, line, sizeof(path)) >= sizeof(path) ||
- strlcat(path, "/", sizeof(path)) >= sizeof(path) ||
- strlcat(path, ent->ce_name, sizeof(path)) >= sizeof(path))
- fatal("Entries path overflow in response");
-
- /*
- * Please be sure the directory does exist.
- */
- if (cvs_resp_createdir(line) < 0)
- return (-1);
-
- if (resp_check_dir(root, line) < 0)
- return (-1);
-
- if (cvs_modtime != CVS_DATE_DMSEC) {
- ent->ce_mtime = cvs_modtime;
- } else
- ent->ce_mtime = time(&(ent->ce_mtime));
-
- if (type == CVS_RESP_UPDEXIST || type == CVS_RESP_UPDATED ||
- type == CVS_RESP_MERGED || type == CVS_RESP_CREATED) {
- if (cvs_ent_remove(cvs_resp_lastent, ent->ce_name, 0) < 0 &&
- type != CVS_RESP_CREATED) {
- cvs_log(LP_WARN, "failed to remove entry for '%s`",
- ent->ce_name);
- }
- }
-
- cvs_ent_add(cvs_resp_lastent, ent);
-
- fbuf = cvs_recvfile(root, &fmode);
- cvs_buf_write(fbuf, path, fmode);
- cvs_buf_free(fbuf);
-
- if (cvs_modtime != CVS_DATE_DMSEC) {
- tv[0].tv_sec = (long)cvs_modtime;
- tv[0].tv_usec = 0;
- tv[1].tv_sec = (long)cvs_modtime;
- tv[1].tv_usec = 0;
- if (utimes(path, tv) == -1)
- cvs_log(LP_ERRNO, "failed to set file timestamps");
- }
-
- /* invalidate last received timestamp */
- cvs_modtime = CVS_DATE_DMSEC;
-
- /* now see if there is a checksum */
- if (cvs_fcksum != NULL) {
- if (cvs_cksum(path, cksum_buf, sizeof(cksum_buf)) < 0)
- ret = -1;
- else if (strcmp(cksum_buf, cvs_fcksum) != 0) {
- cvs_log(LP_ERR, "checksum error on received file");
- (void)unlink(line);
- ret = -1;
- }
-
- xfree(cvs_fcksum);
- cvs_fcksum = NULL;
- }
-
- return (ret);
-}
-
-
-/*
- * cvs_resp_removed()
- *
- * Handler for the `Removed' and `Remove-entry' responses. The `Removed'
- * response is received when both a file and its entry need to be removed from
- * the local copy. The `Remove-entry' is received in cases where the file is
- * already gone but there is still an entry to remove in the Entries file.
- */
-static int
-cvs_resp_removed(struct cvsroot *root, int type, char *line)
-{
- char buf[MAXPATHLEN], base[MAXPATHLEN];
- char fpath[MAXPATHLEN], *file;
-
- cvs_getln(root, buf, sizeof(buf));
-
- cvs_splitpath(buf, base, sizeof(base), &file);
-
- if (strlcpy(fpath, line, sizeof(fpath)) >= sizeof(fpath) ||
- strlcat(fpath, "/", sizeof(fpath)) >= sizeof(fpath) ||
- strlcat(fpath, file, sizeof(fpath)) >= sizeof(fpath))
- fatal("cvs_resp_removed: overflow in path");
-
- if (resp_check_dir(root, line) < 0)
- return (-1);
-
- (void)cvs_ent_remove(cvs_resp_lastent, file, 0);
- if (type == CVS_RESP_REMOVED &&
- (unlink(fpath) == -1 && errno != ENOENT)) {
- cvs_log(LP_ERRNO, "failed to unlink `%s'", file);
- return (-1);
- }
-
- return (0);
-}
-
-
-/*
- * cvs_resp_mode()
- *
- * Handler for the `Mode' response.
- */
-static int
-cvs_resp_mode(struct cvsroot *root, int type, char *line)
-{
- cvs_strtomode(line, &cvs_lastmode);
- return (0);
-}
-
-
-/*
- * cvs_resp_modxpand()
- *
- * Handler for the `Module-expansion' response.
- */
-static int
-cvs_resp_modxpand(struct cvsroot *root, int type, char *line)
-{
- return (0);
-}
-
-/*
- * cvs_resp_rcsdiff()
- *
- * Handler for the `Rcs-diff' response.
- */
-static int
-cvs_resp_rcsdiff(struct cvsroot *root, int type, char *line)
-{
- char file[MAXPATHLEN];
- char buf[CVS_ENT_MAXLINELEN], cksum_buf[CVS_CKSUM_LEN];
- char *fname, *orig, *patch;
- mode_t fmode;
- BUF *res, *fcont, *patchbuf;
- CVSENTRIES *entf;
- struct cvs_ent *ent;
-
- /* get remote path and build local path of file to be patched */
- cvs_getln(root, buf, sizeof(buf));
-
- fname = strrchr(buf, '/');
- if (fname == NULL)
- fname = buf;
-
- if (strlcpy(file, line, sizeof(file)) >= sizeof(file) ||
- strlcat(file, fname, sizeof(file)) >= sizeof(file))
- fatal("cvs_resp_rcsdiff: path truncation");
-
- /* get updated entry fields */
- cvs_getln(root, buf, sizeof(buf));
-
- ent = cvs_ent_parse(buf);
- if (ent == NULL)
- return (-1);
-
- patchbuf = cvs_recvfile(root, &fmode);
- fcont = cvs_buf_load(file, BUF_AUTOEXT);
- if (fcont == NULL)
- return (-1);
-
- cvs_buf_putc(patchbuf, '\0');
- cvs_buf_putc(fcont, '\0');
- orig = cvs_buf_release(fcont);
- patch = cvs_buf_release(patchbuf);
-
- res = cvs_patchfile(orig, patch, rcs_patch_lines);
- if (res == NULL)
- return (-1);
-
- cvs_buf_write(res, file, fmode);
-
- /* now see if there is a checksum */
- if (cvs_fcksum != NULL) {
- if (cvs_cksum(file, cksum_buf, sizeof(cksum_buf)) < 0) {
- }
-
- if (strcmp(cksum_buf, cvs_fcksum) != 0) {
- cvs_log(LP_ERR, "checksum error on received file");
- (void)unlink(file);
- }
-
- xfree(cvs_fcksum);
- cvs_fcksum = NULL;
- }
-
- /* update revision in entries */
- entf = cvs_ent_open(line, O_WRONLY);
- if (entf == NULL)
- return (-1);
-
- cvs_ent_close(entf);
-
- return (0);
-}
-
-
-/*
- * cvs_resp_template()
- *
- * Handler for the `Template' response.
- */
-static int
-cvs_resp_template(struct cvsroot *root, int type, char *line)
-{
- mode_t mode;
- BUF *tmpl;
-
- tmpl = cvs_recvfile(root, &mode);
- cvs_buf_free(tmpl);
-
- return (0);
-}
-
-/*
- * Check if <dir> is the same as the last
- * received directory, if it's not, switch Entry files.
- */
-static int
-resp_check_dir(struct cvsroot *root, const char *dir)
-{
- char cvspath[MAXPATHLEN], repo[MAXPATHLEN];
- struct stat st;
-
- /*
- * Make sure the CVS directory exists.
- */
- if (strlcpy(cvspath, dir, sizeof(cvspath)) >= sizeof(cvspath) ||
- strlcat(cvspath, "/", sizeof(cvspath)) >= sizeof(cvspath) ||
- strlcat(cvspath, CVS_PATH_CVSDIR,
- sizeof(cvspath)) >= sizeof(cvspath))
- fatal("resp_check_dir: path overflow");
-
- if (stat(cvspath, &st) == -1) {
- if (errno != ENOENT)
- return (-1);
- if (cvs_repo_base != NULL) {
- if (strlcpy(repo, cvs_repo_base,
- sizeof(repo)) >= sizeof(repo) ||
- strlcat(repo, "/", sizeof(repo)) >= sizeof(repo) ||
- strlcat(repo, dir, sizeof(repo)) >= sizeof(repo))
- fatal("resp_check_dir: path overflow");
- } else {
- if (strlcpy(repo, dir, sizeof(repo)) >= sizeof(repo))
- fatal("resp_check_dir: path truncation");
- }
-
- cvs_mkadmin(dir, root->cr_str, repo, NULL, NULL, 0);
- }
-
- if (strcmp(dir, cvs_resp_lastdir)) {
- if (cvs_resp_lastent != NULL)
- cvs_ent_close(cvs_resp_lastent);
- cvs_resp_lastent = cvs_ent_open(dir, O_WRONLY);
- if (cvs_resp_lastent == NULL)
- return (-1);
-
- if (strlcpy(cvs_resp_lastdir, dir,
- sizeof(cvs_resp_lastdir)) >= sizeof(cvs_resp_lastdir))
- fatal("resp_check_dir: path truncation");
- } else {
- /* make sure the old one is still open */
- if (cvs_resp_lastent == NULL) {
- cvs_resp_lastent = cvs_ent_open(cvs_resp_lastdir,
- O_WRONLY);
- if (cvs_resp_lastent == NULL)
- return (-1);
- }
- }
-
- return (0);
-}
diff --git a/usr.bin/cvs/root.c b/usr.bin/cvs/root.c
index b1252ed7264..5cabe728e06 100644
--- a/usr.bin/cvs/root.c
+++ b/usr.bin/cvs/root.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: root.c,v 1.31 2006/04/05 01:38:56 ray Exp $ */
+/* $OpenBSD: root.c,v 1.32 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -30,10 +30,8 @@
#include "log.h"
#include "proto.h"
-
extern char *cvs_rootstr;
-
/* keep these ordered with the defines */
const char *cvs_methods[] = {
"",
@@ -126,6 +124,7 @@ cvsroot_parse(const char *str)
fatal("no path specification in CVSROOT");
root->cr_dir = sp;
+ STRIP_SLASH(root->cr_dir);
if (sp == cp) {
if (root->cr_method == CVS_METHOD_NONE)
root->cr_method = CVS_METHOD_LOCAL;
@@ -249,7 +248,7 @@ cvsroot_get(const char *dir)
if ((rootstr = getenv("CVSROOT")) != NULL)
return cvsroot_parse(rootstr);
else
- fatal("cvsroot_get: empty CVSROOT variable");
+ return (NULL);
} else {
fatal("cvsroot_get: fopen: `%s': %s",
CVS_PATH_ROOTSPEC, strerror(errno));
@@ -263,7 +262,7 @@ cvsroot_get(const char *dir)
len = strlen(line);
if (len == 0)
- cvs_log(LP_WARN, "empty %s file", CVS_PATH_ROOTSPEC);
+ cvs_log(LP_ERR, "empty %s file", CVS_PATH_ROOTSPEC);
else if (line[len - 1] == '\n')
line[--len] = '\0';
diff --git a/usr.bin/cvs/server.c b/usr.bin/cvs/server.c
deleted file mode 100644
index ba6d7c819a6..00000000000
--- a/usr.bin/cvs/server.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* $OpenBSD: server.c,v 1.27 2006/01/02 08:11:56 xsa Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-
-/* argument vector built by the `Argument' and `Argumentx' requests */
-char **cvs_args;
-u_int cvs_nbarg = 0;
-u_int cvs_utf8ok = 0;
-u_int cvs_case = 0;
-
-struct cvs_cmd cvs_cmd_server = {
- CVS_OP_SERVER, 0, "server",
- { },
- "Server mode",
- "",
- "",
- NULL,
- 0,
- NULL, NULL, NULL, NULL, NULL, NULL,
- 0
-};
-
-char cvs_server_tmpdir[MAXPATHLEN];
-
-/*
- * cvs_server()
- *
- * Implement the `cvs server' command. As opposed to the general method of
- * CVS client/server implementation, the cvs program merely acts as a
- * redirector to the cvs daemon for most of the tasks.
- *
- * The `cvs server' command is only used on the server side of a remote
- * cvs command. With this command, the cvs program starts listening on
- * standard input for CVS protocol requests.
- */
-int
-cvs_server(int argc, char **argv)
-{
- int l, ret;
- size_t len;
- char reqbuf[512];
-
- if (argc != 1)
- return (CVS_EX_USAGE);
-
- /* make sure standard in and standard out are line-buffered */
- (void)setvbuf(stdin, NULL, _IOLBF, (size_t)0);
- (void)setvbuf(stdout, NULL, _IOLBF, (size_t)0);
-
- /* create the temporary directory */
- l = snprintf(cvs_server_tmpdir, sizeof(cvs_server_tmpdir),
- "%s/cvs-serv%d", cvs_tmpdir, getpid());
- if (l == -1 || l >= (int)sizeof(cvs_server_tmpdir)) {
- errno = ENAMETOOLONG;
- fatal("cvs_server: tmpdir path too long: `%s'",
- cvs_server_tmpdir);
- }
-
- if (mkdir(cvs_server_tmpdir, 0700) == -1)
- fatal("cvs_server: mkdir: `%s': %s",
- cvs_server_tmpdir, strerror(errno));
-
- cvs_chdir(cvs_server_tmpdir, 1);
-
- for (;;) {
- if (fgets(reqbuf, (int)sizeof(reqbuf), stdin) == NULL) {
- if (feof(stdin))
- break;
- else if (ferror(stdin)) {
- (void)cvs_rmdir(cvs_server_tmpdir);
- fatal("cvs_server: fgets failed");
- }
- }
-
- len = strlen(reqbuf);
- if (len == 0)
- continue;
- else if (reqbuf[len - 1] != '\n') {
- (void)cvs_rmdir(cvs_server_tmpdir);
- fatal("cvs_server: truncated request");
- }
- reqbuf[--len] = '\0';
-
- cvs_req_handle(reqbuf);
-
-
- }
-
- /* cleanup the temporary tree */
- ret = cvs_rmdir(cvs_server_tmpdir);
-
- return (ret);
-}
diff --git a/usr.bin/cvs/status.c b/usr.bin/cvs/status.c
index b7d5e786b6c..57901f34b25 100644
--- a/usr.bin/cvs/status.c
+++ b/usr.bin/cvs/status.c
@@ -1,28 +1,18 @@
-/* $OpenBSD: status.c,v 1.56 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: status.c,v 1.57 2006/05/27 03:30:31 joris Exp $ */
/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * Copyright (c) 2005 Xavier Santolaria <xsa@openbsd.org>
- * All rights reserved.
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
@@ -31,244 +21,153 @@
#include "log.h"
#include "proto.h"
-
-#define CVS_STATUS_SEP \
- "==================================================================="
-
-/* Keep this sorted as it is now. See file.h for status values. */
-const char *cvs_statstr[] = {
- "Unknown",
- "Up-to-date",
- "Locally Modified",
- "Locally Added",
- "Locally Removed",
- "Unresolved Conflict",
- "Patched",
- "Needs Checkout",
-};
-
-
-static int cvs_status_init (struct cvs_cmd *, int, char **, int *);
-static int cvs_status_remote (CVSFILE *, void *);
-static int cvs_status_local (CVSFILE *, void *);
-static int cvs_status_pre_exec (struct cvsroot *);
+int cvs_status(int, char **);
+void cvs_status_local(struct cvs_file *);
struct cvs_cmd cvs_cmd_status = {
CVS_OP_STATUS, CVS_REQ_STATUS, "status",
{ "st", "stat" },
"Display status information on checked out files",
"[-lRv]",
- "lRv",
+ "lRv:",
NULL,
- CF_SORT | CF_IGNORE | CF_RECURSE,
- cvs_status_init,
- cvs_status_pre_exec,
- cvs_status_remote,
- cvs_status_local,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2
+ cvs_status
};
-static int verbose = 0;
+#define CVS_STATUS_SEP \
+ "==================================================================="
-static int
-cvs_status_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
+const char *status_tab[] = {
+ "Unknown",
+ "Locally Added",
+ "Locally Removed",
+ "Locally Modified",
+ "Up-to-date",
+ "Needs Checkout",
+ "Needs Checkout",
+ "Needs Merge",
+ "Needs Patch",
+ "Entry Invalid",
+ "Unresolved Conflict",
+ "Classifying error",
+};
+
+int
+cvs_status(int argc, char **argv)
{
int ch;
+ char *arg = ".";
+ struct cvs_recursion cr;
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
+ while ((ch = getopt(argc, argv, cvs_cmd_status.cmd_opts)) != -1) {
switch (ch) {
case 'l':
- cmd->file_flags &= ~CF_RECURSE;
break;
case 'R':
- cmd->file_flags |= CF_RECURSE;
break;
case 'v':
- verbose = 1;
break;
default:
- return (CVS_EX_USAGE);
+ fatal("%s", cvs_cmd_status.cmd_synopsis);
}
}
- *arg = optind;
- return (0);
-}
+ argc -= optind;
+ argv += optind;
-static int
-cvs_status_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method != CVS_METHOD_LOCAL) {
- if (verbose == 1)
- cvs_sendarg(root, "-v", 0);
- }
+ cr.enterdir = NULL;
+ cr.leavedir = NULL;
+ cr.local = cvs_status_local;
+ cr.remote = NULL;
- return (0);
-}
-
-/*
- * cvs_status_remote()
- *
- * Get the status of a single file.
- */
-static int
-cvs_status_remote(CVSFILE *cfp, void *arg)
-{
- char fpath[MAXPATHLEN];
- struct cvsroot *root;
-
- root = CVS_DIR_ROOT(cfp);
-
- if (cfp->cf_type == DT_DIR) {
- if (cfp->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
- else
- cvs_senddir(root, cfp);
- return (0);
- }
-
- cvs_file_getpath(cfp, fpath, sizeof(fpath));
-
- cvs_sendentry(root, cfp);
-
- switch (cfp->cf_cvstat) {
- case CVS_FST_UNKNOWN:
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
- break;
- case CVS_FST_UPTODATE:
- cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
- break;
- case CVS_FST_ADDED:
- case CVS_FST_MODIFIED:
- cvs_sendreq(root, CVS_REQ_MODIFIED, cfp->cf_name);
- cvs_sendfile(root, fpath);
- break;
- default:
- break;
- }
+ if (argc > 0)
+ cvs_file_run(argc, argv, &cr);
+ else
+ cvs_file_run(1, &arg, &cr);
return (0);
}
-static int
-cvs_status_local(CVSFILE *cf, void *arg)
+void
+cvs_status_local(struct cvs_file *cf)
{
- size_t n;
- char buf[MAXNAMLEN], fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
- char numbuf[64], timebuf[32];
- RCSFILE *rf;
- struct rcs_sym *sym;
+ int l;
+ size_t len;
+ const char *status;
+ char buf[128], timebuf[32], revbuf[32];
- if (cf->cf_type == DT_DIR) {
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "Examining %s", cf->cf_name);
- return (0);
- }
+ cvs_log(LP_TRACE, "cvs_status_local(%s)", cf->file_path);
- cvs_file_getpath(cf, fpath, sizeof(fpath));
- cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
+ cvs_file_classify(cf);
- rf = NULL;
- if (cf->cf_cvstat != CVS_FST_UNKNOWN &&
- cf->cf_cvstat != CVS_FST_ADDED) {
- if ((rf = rcs_open(rcspath, RCS_READ)) == NULL)
- fatal("cvs_status_local: rcs_open `%s': %s", rcspath,
- rcs_errstr(rcs_errno));
+ if (cf->file_type == CVS_DIR) {
+ if (verbosity > 1)
+ cvs_log(LP_NOTICE, "Examining %s", cf->file_path);
+ return;
}
- buf[0] = '\0';
-
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_log(LP_WARN, "nothing known about %s", cf->cf_name);
+ cvs_printf("%s\n", CVS_STATUS_SEP);
- if (cf->cf_cvstat == CVS_FST_LOST || cf->cf_cvstat == CVS_FST_UNKNOWN)
- strlcpy(buf, "no file ", sizeof(buf));
- strlcat(buf, cf->cf_name, sizeof(buf));
+ status = status_tab[cf->file_status];
+ if (cf->file_status == FILE_MODIFIED &&
+ cf->file_ent->ce_conflict != NULL)
+ status = "File had conflicts on merge";
- cvs_printf(CVS_STATUS_SEP "\nFile: %-17s\tStatus: %s\n\n",
- buf, cvs_statstr[cf->cf_cvstat]);
+ cvs_printf("File: %-17s\tStatus: %s\n\n", cf->file_name, status);
- if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
- strlcpy(buf, "No entry for ", sizeof(buf));
- strlcat(buf, cf->cf_name, sizeof(buf));
- } else if (cf->cf_cvstat == CVS_FST_ADDED) {
- strlcpy(buf, "New file!", sizeof(buf));
+ if (cf->file_ent == NULL) {
+ l = snprintf(buf, sizeof(buf),
+ "No entry for %s", cf->file_name);
+ if (l == -1 || l >= (int)sizeof(buf))
+ fatal("cvs_status_local: overflow");
+ } else if (cf->file_status == FILE_ADDED) {
+ len = strlcpy(buf, "New file!", sizeof(buf));
+ if (len >= sizeof(buf))
+ fatal("cvs_status_local: truncation");
} else {
- rcsnum_tostr(cf->cf_lrev, numbuf, sizeof(numbuf));
- strlcpy(buf, numbuf, sizeof(buf));
-
- /* Display etime in local mode only. */
- if (cvs_cmdop != CVS_OP_SERVER) {
- strlcat(buf, "\t", sizeof(buf));
+ rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf));
- ctime_r(&(cf->cf_etime), timebuf);
- n = strlen(timebuf);
- if (n > 0 && timebuf[n - 1] == '\n')
- timebuf[--n] = '\0';
-
- strlcat(buf, timebuf, sizeof(buf));
+ if (cf->file_ent->ce_conflict == NULL) {
+ ctime_r(&(cf->file_ent->ce_mtime), timebuf);
+ if (timebuf[strlen(timebuf) - 1] == '\n')
+ timebuf[strlen(timebuf) - 1] = '\0';
+ } else {
+ len = strlcpy(timebuf, cf->file_ent->ce_conflict,
+ sizeof(timebuf));
+ if (len >= sizeof(timebuf))
+ fatal("cvs_status_local: truncation");
}
+
+ l = snprintf(buf, sizeof(buf), "%s\t%s", revbuf, timebuf);
+ if (l == -1 || l >= (int)sizeof(buf))
+ fatal("cvs_status_local: overflow");
}
cvs_printf(" Working revision:\t%s\n", buf);
- if (cf->cf_cvstat == CVS_FST_UNKNOWN ||
- cf->cf_cvstat == CVS_FST_ADDED) {
- strlcpy(buf, "No revision control file", sizeof(buf));
+ buf[0] = '\0';
+ if (cf->file_rcs == NULL) {
+ len = strlcat(buf, "No revision control file", sizeof(buf));
+ if (len >= sizeof(buf))
+ fatal("cvs_status_local: truncation");
} else {
- strlcpy(buf, rcsnum_tostr(rf->rf_head, numbuf, sizeof(numbuf)),
- sizeof(buf));
- strlcat(buf, "\t", sizeof(buf));
- strlcat(buf, rcspath, sizeof(buf));
+ rcsnum_tostr(cf->file_rcs->rf_head, revbuf, sizeof(revbuf));
+ l = snprintf(buf, sizeof(buf), "%s\t%s", revbuf,
+ cf->file_rpath);
+ if (l == -1 || l >= (int)sizeof(buf))
+ fatal("cvs_status_local: overflow");
}
cvs_printf(" Repository revision:\t%s\n", buf);
- /* If the file is unknown, no other output is needed after this. */
- if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
- cvs_printf("\n");
- return (0);
- }
-
- if (cf->cf_tag != NULL)
- cvs_printf(" Sticky Tag:\t\t%s\n", cf->cf_tag);
- else if (verbosity > 0)
- cvs_printf(" Sticky Tag:\t\t(none)\n");
-
- /* XXX */
- if (verbosity > 0)
- cvs_printf(" Sticky Date:\t\t%s\n", "(none)");
-
- if (cf->cf_opts != NULL)
- cvs_printf(" Sticky Options:\t%s\n", cf->cf_opts);
- else if (verbosity > 0)
- cvs_printf(" Sticky Options:\t(none)\n");
-
- if (verbose == 1) {
- cvs_printf("\n");
- cvs_printf(" Existing Tags:\n");
-
- if (!TAILQ_EMPTY(&(rf->rf_symbols))) {
- TAILQ_FOREACH(sym, &(rf->rf_symbols), rs_list) {
- rcsnum_tostr(sym->rs_num, numbuf,
- sizeof(numbuf));
-
- cvs_printf("\t%-25s\t(%s: %s)\n",
- sym->rs_name,
- RCSNUM_ISBRANCH(sym->rs_num) ? "branch" :
- "revision", numbuf);
- }
- } else {
- cvs_printf("\tNo Tags Exist\n");
- }
+ if (cf->file_ent != NULL) {
+ if (cf->file_ent->ce_tag != NULL)
+ cvs_printf(" Sticky Tag:\t%s\n",
+ cf->file_ent->ce_tag);
+ if (cf->file_ent->ce_opts != NULL)
+ cvs_printf(" Sticky Options:\t%s\n",
+ cf->file_ent->ce_opts);
}
cvs_printf("\n");
-
- if (rf != NULL)
- rcs_close(rf);
-
- return (0);
}
diff --git a/usr.bin/cvs/tag.c b/usr.bin/cvs/tag.c
deleted file mode 100644
index 12199a2b513..00000000000
--- a/usr.bin/cvs/tag.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/* $OpenBSD: tag.c,v 1.43 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * Copyright (c) 2004 Joris Vink <joris@openbsd.org>
- * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-#define TAG_BRANCH (1<<0)
-#define TAG_DELETE (1<<1)
-#define TAG_FORCE_HEAD (1<<2)
-#define TAG_FORCE_RM (1<<3)
-#define UPTODATE (1<<4)
-
-static int cvs_tag_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_tag_local(CVSFILE *, void *);
-static int cvs_tag_remote(CVSFILE *, void *);
-static int cvs_tag_pre_exec(struct cvsroot *);
-
-static int runflags = 0;
-static char *tag_name = NULL;
-static char *tag_date = NULL;
-static char *tag_oldname = NULL;
-
-struct cvs_cmd cvs_cmd_tag = {
- CVS_OP_TAG, CVS_REQ_TAG, "tag",
- { "ta", "freeze" },
- "Add a symbolic tag to checked out version of files",
- "[-bcdFflR] [-D date | -r rev] tag [file ...]",
- "bcD:dFflRr:",
- NULL,
- CF_SORT | CF_IGNORE | CF_RECURSE,
- cvs_tag_init,
- cvs_tag_pre_exec,
- cvs_tag_remote,
- cvs_tag_local,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
-};
-
-
-struct cvs_cmd cvs_cmd_rtag = {
- CVS_OP_RTAG, CVS_REQ_TAG, "rtag",
- { "rt", "rfreeze" },
- "Add a symbolic tag to a module",
- "[-abdFflnR] [-D date | -r rev] tag modules ...",
- "abD:fFflnRr:",
- NULL,
- CF_SORT | CF_IGNORE | CF_RECURSE,
- cvs_tag_init,
- cvs_tag_pre_exec,
- cvs_tag_remote,
- cvs_tag_local,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
-};
-
-static int
-cvs_tag_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- tag_date = tag_oldname = NULL;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'b':
- runflags |= TAG_BRANCH;
- break;
- case 'c':
- runflags |= UPTODATE;
- break;
- case 'd':
- runflags |= TAG_DELETE;
- break;
- case 'F':
- runflags |= TAG_FORCE_RM;
- break;
- case 'f':
- runflags |= TAG_FORCE_HEAD;
- break;
- case 'D':
- tag_date = optarg;
- break;
- case 'l':
- cmd->file_flags &= ~CF_RECURSE;
- break;
- case 'R':
- cmd->file_flags |= CF_RECURSE;
- break;
- case 'r':
- tag_oldname = optarg;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- *arg = optind;
- argc -= optind;
- argv += optind;
-
- if (argc == 0)
- return (CVS_EX_USAGE);
- else {
- tag_name = argv[0];
- argc--;
- argv++;
- *arg += 1;
- }
-
- if (!rcs_sym_check(tag_name))
- fatal("tag `%s' must not contain the characters `%s'",
- tag_name, RCS_SYM_INVALCHAR);
-
- if ((runflags & TAG_BRANCH) && (runflags & TAG_DELETE)) {
- cvs_log(LP_WARN, "ignoring -b with -d options");
- runflags &= ~TAG_BRANCH;
- }
-
- if ((runflags & TAG_DELETE) && tag_oldname != NULL)
- tag_oldname = NULL;
-
- if ((runflags & TAG_DELETE) && tag_date != NULL)
- tag_date = NULL;
-
- if ((tag_oldname != NULL) && tag_date != NULL) {
- cvs_log(LP_ERR, "the -D and -r options are mutually exclusive");
- return (CVS_EX_USAGE);
- }
-
- return (0);
-}
-
-static int
-cvs_tag_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method != CVS_METHOD_LOCAL) {
- if (runflags & TAG_BRANCH)
- cvs_sendarg(root, "-b", 0);
-
- if (runflags & UPTODATE)
- cvs_sendarg(root, "-c", 0);
-
- if (runflags & TAG_DELETE)
- cvs_sendarg(root, "-d", 0);
-
- if (runflags & TAG_FORCE_RM)
- cvs_sendarg(root, "-F", 0);
-
- if (runflags & TAG_FORCE_HEAD)
- cvs_sendarg(root, "-f", 0);
-
- if (tag_oldname != NULL) {
- cvs_sendarg(root, "-r", 0);
- cvs_sendarg(root, tag_oldname, 0);
- }
-
- if (tag_date != NULL) {
- cvs_sendarg(root, "-D", 0);
- cvs_sendarg(root, tag_date, 0);
- }
-
- cvs_sendarg(root, tag_name, 0);
- }
- return (0);
-}
-
-
-/*
- * cvs_tag_remote()
- *
- * Get the status of a single file.
- */
-static int
-cvs_tag_remote(CVSFILE *cfp, void *arg)
-{
- char fpath[MAXPATHLEN];
- struct cvsroot *root;
-
- root = CVS_DIR_ROOT(cfp);
-
- if (cfp->cf_type == DT_DIR) {
- cvs_senddir(root, cfp);
- return (0);
- }
-
- cvs_sendentry(root, cfp);
- cvs_file_getpath(cfp, fpath, sizeof(fpath));
-
- switch (cfp->cf_cvstat) {
- case CVS_FST_UNKNOWN:
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
- break;
- case CVS_FST_UPTODATE:
- cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
- break;
- case CVS_FST_MODIFIED:
- cvs_sendreq(root, CVS_REQ_ISMODIFIED, cfp->cf_name);
- break;
- default:
- break;
- }
-
- return (0);
-}
-
-
-static int
-cvs_tag_local(CVSFILE *cf, void *arg)
-{
- char fpath[MAXPATHLEN], numbuf[64], rcspath[MAXPATHLEN];
- RCSFILE *rf;
- RCSNUM *tag_rev;
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
-
- if (cf->cf_type == DT_DIR) {
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "%s %s",
- (runflags & TAG_DELETE) ? "Untagging" : "Tagging",
- fpath);
- return (CVS_EX_OK);
- }
-
- if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
- if (verbosity > 1)
- cvs_log(LP_WARN, "nothing known about %s", fpath);
- return (0);
- } else if (cf->cf_cvstat == CVS_FST_ADDED) {
- if (verbosity > 1)
- cvs_log(LP_WARN,
- "couldn't tag added but un-commited file `%s'",
- fpath);
- return (0);
- } else if (cf->cf_cvstat == CVS_FST_REMOVED) {
- if (verbosity > 1)
- cvs_log(LP_WARN,
- "skipping removed but un-commited file `%s'",
- fpath);
- return (0);
- }
-
- tag_rev = cf->cf_lrev;
-
- cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
-
- if ((rf = rcs_open(rcspath, RCS_READ|RCS_WRITE)) == NULL)
- fatal("cvs_tag_local: rcs_open: %s: %s", rcspath,
- rcs_errstr(rcs_errno));
-
- if (runflags & TAG_DELETE) {
- if (cvs_noexec == 0) {
- if (rcs_sym_remove(rf, tag_name) < 0)
- fatal("failed to remove tag %s from %s",
- tag_name, rcspath);
- }
-
- if (verbosity > 0)
- cvs_printf("D %s\n", fpath);
-
- rcs_close(rf);
- return (0);
- }
-
- if (cvs_noexec == 0) {
- if (rcs_sym_add(rf, tag_name, tag_rev) < 0) {
- rcsnum_tostr(tag_rev, numbuf, sizeof(numbuf));
- fatal("failed to set tag %s to revision %s in %s",
- tag_name, numbuf, rcspath);
- }
- }
-
- if (verbosity > 0)
- cvs_printf("T %s\n", fpath);
-
- rcs_close(rf);
- return (0);
-}
diff --git a/usr.bin/cvs/update.c b/usr.bin/cvs/update.c
index 064770dcabf..e6f5ebf52ad 100644
--- a/usr.bin/cvs/update.c
+++ b/usr.bin/cvs/update.c
@@ -1,40 +1,28 @@
-/* $OpenBSD: update.c,v 1.58 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: update.c,v 1.59 2006/05/27 03:30:31 joris Exp $ */
/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
+ * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
*
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include "cvs.h"
#include "log.h"
-#include "proto.h"
#include "diff.h"
+#include "proto.h"
-static int cvs_update_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_update_pre_exec(struct cvsroot *);
-static int cvs_update_remote(CVSFILE *, void *);
-static int cvs_update_local(CVSFILE *, void *);
+int cvs_update(int, char **);
struct cvs_cmd cvs_cmd_update = {
CVS_OP_UPDATE, CVS_REQ_UPDATE, "update",
@@ -44,40 +32,24 @@ struct cvs_cmd cvs_cmd_update = {
"[-t id] ...",
"ACD:dfI:j:k:lPpQqRr:t:",
NULL,
- CF_SORT | CF_RECURSE | CF_IGNORE | CF_NOSYMS,
- cvs_update_init,
- cvs_update_pre_exec,
- cvs_update_remote,
- cvs_update_local,
- NULL,
- NULL,
- CVS_CMD_ALLOWSPEC | CVS_CMD_SENDARGS2 | CVS_CMD_SENDDIR
+ cvs_update
};
-static char *date, *rev, *koptstr;
-static int dflag, Aflag;
-static int kflag = RCS_KWEXP_DEFAULT;
-
-static int
-cvs_update_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
+int
+cvs_update(int argc, char **argv)
{
int ch;
+ char *arg = ".";
+ struct cvs_recursion cr;
- dflag = Aflag = 0;
- date = NULL;
- rev = NULL;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
+ while ((ch = getopt(argc, argv, cvs_cmd_update.cmd_opts)) != -1) {
switch (ch) {
case 'A':
- Aflag = 1;
break;
case 'C':
case 'D':
- date = optarg;
break;
case 'd':
- dflag = 1;
break;
case 'f':
break;
@@ -86,247 +58,122 @@ cvs_update_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
case 'j':
break;
case 'k':
- koptstr = optarg;
- kflag = rcs_kflag_get(koptstr);
- if (RCS_KWEXP_INVAL(kflag)) {
- cvs_log(LP_ERR,
- "invalid RCS keyword expansion mode");
- rcs_kflag_usage();
- return (CVS_EX_USAGE);
- }
break;
case 'l':
- cmd->file_flags &= ~CF_RECURSE;
break;
case 'P':
- cmd->cmd_flags |= CVS_CMD_PRUNEDIRS;
break;
case 'p':
- cvs_noexec = 1; /* no locks will be created */
break;
case 'Q':
case 'q':
break;
case 'R':
- cmd->file_flags |= CF_RECURSE;
break;
case 'r':
- rev = optarg;
break;
default:
- return (CVS_EX_USAGE);
+ fatal("%s", cvs_cmd_update.cmd_synopsis);
}
}
- *arg = optind;
- return (0);
-}
-
-static int
-cvs_update_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method != CVS_METHOD_LOCAL) {
- if (cvs_cmd_update.cmd_flags & CVS_CMD_PRUNEDIRS)
- cvs_sendarg(root, "-P", 0);
-
- if (Aflag == 1)
- cvs_sendarg(root, "-A", 0);
-
- if (dflag == 1)
- cvs_sendarg(root, "-d", 0);
+ argc -= optind;
+ argv += optind;
- if (rev != NULL) {
- cvs_sendarg(root, "-r", 0);
- cvs_sendarg(root, rev, 0);
- }
+ cr.enterdir = cvs_update_enterdir;
+ cr.leavedir = NULL;
+ cr.local = cvs_update_local;
+ cr.remote = NULL;
- if (date != NULL) {
- cvs_sendarg(root, "-D", 0);
- cvs_sendarg(root, date, 0);
- }
- }
+ if (argc > 0)
+ cvs_file_run(argc, argv, &cr);
+ else
+ cvs_file_run(1, &arg, &cr);
return (0);
}
-/*
- * cvs_update_remote()
- *
- * Update a single file. In the case where we act as client, send any
- * pertinent information about that file to the server.
- */
-static int
-cvs_update_remote(CVSFILE *cf, void *arg)
+void
+cvs_update_enterdir(struct cvs_file *cf)
{
- char fpath[MAXPATHLEN];
- struct cvsroot *root;
+ int l;
+ char *entry;
+ CVSENTRIES *entlist;
- root = CVS_DIR_ROOT(cf);
+ cvs_log(LP_TRACE, "cvs_update_enterdir(%s)", cf->file_path);
- if (cf->cf_type == DT_DIR) {
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- else
- cvs_senddir(root, cf);
- return (0);
- }
-
- cvs_file_getpath(cf, fpath, sizeof(fpath));
+ cvs_file_classify(cf);
- cvs_sendentry(root, cf);
+ if (cf->file_status == DIR_CREATE) {
+ cvs_mkpath(cf->file_path);
+ if ((cf->fd = open(cf->file_path, O_RDONLY)) == -1)
+ fatal("cvs_update_enterdir: %s", strerror(errno));
- if (!(cf->cf_flags & CVS_FILE_ONDISK))
- return (0);
+ entry = xmalloc(CVS_ENT_MAXLINELEN);
+ l = snprintf(entry, CVS_ENT_MAXLINELEN, "D/%s////",
+ cf->file_name);
+ if (l == -1 || l >= CVS_ENT_MAXLINELEN)
+ fatal("cvs_update_enterdir: overflow");
- switch (cf->cf_cvstat) {
- case CVS_FST_UNKNOWN:
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- break;
- case CVS_FST_UPTODATE:
- cvs_sendreq(root, CVS_REQ_UNCHANGED, cf->cf_name);
- break;
- case CVS_FST_ADDED:
- case CVS_FST_MODIFIED:
- cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name);
- cvs_sendfile(root, fpath);
- break;
- default:
- break;
+ entlist = cvs_ent_open(cf->file_wd);
+ cvs_ent_add(entlist, entry);
+ cvs_ent_close(entlist, ENT_SYNC);
+ xfree(entry);
}
-
- return (0);
}
-/*
- * cvs_update_local()
- */
-static int
-cvs_update_local(CVSFILE *cf, void *arg)
+void
+cvs_update_local(struct cvs_file *cf)
{
- int islocal, revdiff;
- char fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
- RCSFILE *rf;
- RCSNUM *frev;
- BUF *fbuf;
-
- revdiff = 0;
- rf = NULL;
- frev = NULL;
- islocal = (cvs_cmdop != CVS_OP_SERVER);
+ CVSENTRIES *entlist;
- cvs_file_getpath(cf, fpath, sizeof(fpath));
+ cvs_log(LP_TRACE, "cvs_update_local(%s)", cf->file_path);
- if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
- if (verbosity > 1)
- cvs_printf("? %s\n", fpath);
- return (CVS_EX_OK);
- }
-
- if (cf->cf_type == DT_DIR) {
- if (verbosity > 1)
- cvs_log(LP_NOTICE, "Updating %s", fpath);
- return (CVS_EX_OK);
- }
-
- cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
-
- /*
- * Only open the RCS file for files that have not been added.
- */
- if (cf->cf_cvstat != CVS_FST_ADDED) {
- rf = rcs_open(rcspath, RCS_READ);
-
- /*
- * If there is no RCS file available in the repository
- * directory that matches this file, it's gone.
- * XXX: so what about the Attic?
- */
- if (rf == NULL) {
- cvs_log(LP_WARN, "%s is no longer in the repository",
- fpath);
- if (cvs_checkout_rev(NULL, NULL, cf, fpath,
- islocal, CHECKOUT_REV_REMOVED) < 0)
- fatal("cvs_update_local: cvs_checkout_rev failed");
- return (CVS_EX_OK);
- }
- } else {
- /* There's no need to update a newly added file */
- cvs_printf("A %s\n", fpath);
- return (CVS_EX_OK);
+ if (cf->file_type == CVS_DIR) {
+ if (cf->file_status != FILE_UNKNOWN &&
+ verbosity > 1)
+ cvs_log(LP_NOTICE, "Updating %s", cf->file_path);
+ return;
}
- /* set keyword expansion */
- /* XXX look at cf->cf_opts as well for this */
- rcs_kwexp_set(rf, kflag);
+ cvs_file_classify(cf);
- /* fill in the correct revision */
- if (rev != NULL) {
- if ((frev = rcsnum_parse(rev)) == NULL)
- fatal("cvs_update_local: rcsnum_parse failed");
- } else
- frev = rf->rf_head;
-
- /*
- * Compare the headrevision with the revision we currently have.
- */
- if (cf->cf_lrev != NULL)
- revdiff = rcsnum_cmp(cf->cf_lrev, frev, 0);
-
- switch (cf->cf_cvstat) {
- case CVS_FST_MODIFIED:
- /*
- * If the file has been modified but there is a newer version
- * available, we try to merge it into the existing changes.
- */
- if (revdiff == 1) {
- fbuf = cvs_diff3(rf, fpath, cf->cf_lrev, frev, 0);
- if (fbuf == NULL) {
- cvs_log(LP_ERR, "merge failed");
- break;
- }
-
- /*
- * Please note fbuf will be free'd in cvs_checkout_rev
- */
- if (cvs_checkout_rev(rf, frev, cf, fpath, islocal,
- CHECKOUT_REV_MERGED, fbuf) != -1) {
- cvs_printf("%c %s\n",
- (diff3_conflicts > 0) ? 'C' : 'M',
- fpath);
- if (diff3_conflicts > 0)
- cf->cf_cvstat = CVS_FST_CONFLICT;
- }
- } else {
- cvs_printf("M %s\n", fpath);
- }
+ switch (cf->file_status) {
+ case FILE_UNKNOWN:
+ cvs_printf("? %s\n", cf->file_path);
break;
- case CVS_FST_REMOVED:
- cvs_printf("R %s\n", fpath);
+ case FILE_MODIFIED:
+ if (cf->file_ent->ce_conflict != NULL)
+ cvs_printf("C %s\n", cf->file_path);
+ else
+ cvs_printf("M %s\n", cf->file_path);
break;
- case CVS_FST_CONFLICT:
- cvs_printf("C %s\n", fpath);
+ case FILE_ADDED:
+ cvs_printf("A %s\n", cf->file_path);
break;
- case CVS_FST_LOST:
- if (cvs_checkout_rev(rf, frev, cf, fpath, islocal,
- CHECKOUT_REV_UPDATED) != -1) {
- cf->cf_cvstat = CVS_FST_UPTODATE;
- cvs_printf("U %s\n", fpath);
- }
+ case FILE_REMOVED:
+ cvs_printf("R %s\n", cf->file_path);
break;
- case CVS_FST_UPTODATE:
- if (revdiff == 1) {
- if (cvs_checkout_rev(rf, frev, cf, fpath, islocal,
- CHECKOUT_REV_UPDATED) != -1)
- cvs_printf("P %s\n", fpath);
- }
+ case FILE_CONFLICT:
+ cvs_printf("C %s\n", cf->file_path);
+ break;
+ case FILE_LOST:
+ case FILE_CHECKOUT:
+ case FILE_PATCH:
+ if (cvs_checkout_file(cf, cf->file_rcs->rf_head, 0))
+ cvs_printf("U %s\n", cf->file_path);
+ break;
+ case FILE_MERGE:
+ cvs_printf("needs merge: %s\n", cf->file_path);
+ break;
+ case FILE_UNLINK:
+ (void)unlink(cf->file_path);
+ case FILE_REMOVE_ENTRY:
+ entlist = cvs_ent_open(cf->file_wd);
+ cvs_ent_remove(entlist, cf->file_name);
+ cvs_ent_close(entlist, ENT_SYNC);
break;
default:
break;
}
-
- if (frev != NULL && frev != rf->rf_head)
- rcsnum_free(frev);
- rcs_close(rf);
-
- return (CVS_EX_OK);
}
diff --git a/usr.bin/cvs/util.c b/usr.bin/cvs/util.c
index 6008492c06c..c1768508556 100644
--- a/usr.bin/cvs/util.c
+++ b/usr.bin/cvs/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.78 2006/04/14 02:45:35 deraadt Exp $ */
+/* $OpenBSD: util.c,v 1.79 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* Copyright (c) 2005, 2006 Joris Vink <joris@openbsd.org>
@@ -32,7 +32,6 @@
#include "log.h"
#include "util.h"
-#if !defined(RCSPROG)
/* letter -> mode type map */
static const int cvs_modetypes[26] = {
-1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1,
@@ -67,47 +66,6 @@ static const char *cvs_modestr[8] = {
"", "x", "w", "wx", "r", "rx", "rw", "rwx"
};
-
-
-/*
- * cvs_readrepo()
- *
- * Read the path stored in the `Repository' CVS file for a given directory
- * <dir>, and store that path into the buffer pointed to by <dst>, whose size
- * is <len>.
- */
-int
-cvs_readrepo(const char *dir, char *dst, size_t len)
-{
- size_t dlen, l;
- FILE *fp;
- char repo_path[MAXPATHLEN];
-
- l = cvs_path_cat(dir, "CVS/Repository", repo_path, sizeof(repo_path));
- if (l >= sizeof(repo_path))
- return (-1);
-
- fp = fopen(repo_path, "r");
- if (fp == NULL)
- return (-1);
-
- if (fgets(dst, (int)len, fp) == NULL) {
- if (ferror(fp)) {
- cvs_log(LP_ERRNO, "failed to read from `%s'",
- repo_path);
- }
- (void)fclose(fp);
- return (-1);
- }
- dlen = strlen(dst);
- if (dlen > 0 && dst[dlen - 1] == '\n')
- dst[--dlen] = '\0';
-
- (void)fclose(fp);
- return (0);
-}
-
-
/*
* cvs_strtomode()
*
@@ -141,13 +99,13 @@ cvs_strtomode(const char *str, mode_t *mode)
memset(ms, 0, sizeof ms);
if (sscanf(sp, "%c=%3s", &type, ms) != 2 &&
sscanf(sp, "%c=", &type) != 1) {
- cvs_log(LP_WARN, "failed to scan mode string `%s'", sp);
+ cvs_log(LP_ERR, "failed to scan mode string `%s'", sp);
continue;
}
if (type <= 'a' || type >= 'z' ||
cvs_modetypes[type - 'a'] == -1) {
- cvs_log(LP_WARN,
+ cvs_log(LP_ERR,
"invalid mode type `%c'"
" (`u', `g' or `o' expected), ignoring", type);
continue;
@@ -159,7 +117,7 @@ cvs_strtomode(const char *str, mode_t *mode)
for (sp = ms; *sp != '\0'; sp++) {
if (*sp <= 'a' || *sp >= 'z' ||
cvs_modes[(int)type][*sp - 'a'] == 0) {
- cvs_log(LP_WARN,
+ cvs_log(LP_ERR,
"invalid permission bit `%c'", *sp);
} else
m |= cvs_modes[(int)type][*sp - 'a'];
@@ -169,7 +127,6 @@ cvs_strtomode(const char *str, mode_t *mode)
*mode = m;
}
-
/*
* cvs_modetostr()
*
@@ -241,11 +198,11 @@ int
cvs_cksum(const char *file, char *dst, size_t len)
{
if (len < CVS_CKSUM_LEN) {
- cvs_log(LP_WARN, "buffer too small for checksum");
+ cvs_log(LP_ERR, "buffer too small for checksum");
return (-1);
}
if (MD5File(file, dst) == NULL) {
- cvs_log(LP_ERRNO, "failed to generate checksum for %s", file);
+ cvs_log(LP_ERR, "failed to generate checksum for %s", file);
return (-1);
}
@@ -368,7 +325,6 @@ cvs_getargv(const char *line, char **argv, int argvlen)
return (argc);
}
-
/*
* cvs_makeargv()
*
@@ -395,7 +351,6 @@ cvs_makeargv(const char *line, int *argc)
return (copy);
}
-
/*
* cvs_freeargv()
*
@@ -411,76 +366,6 @@ cvs_freeargv(char **argv, int argc)
xfree(argv[i]);
}
-
-/*
- * cvs_mkadmin()
- *
- * Create the CVS administrative files within the directory <cdir>. If the
- * files already exist, they are kept as is.
- * Returns 0 on success, or -1 on failure.
- */
-int
-cvs_mkadmin(const char *dpath, const char *rootpath, const char *repopath,
- char *tag, char *date, int nb)
-{
- size_t l;
- char path[MAXPATHLEN];
- FILE *fp;
- CVSENTRIES *ef;
- struct stat st;
-
- cvs_log(LP_TRACE, "cvs_mkadmin(%s, %s, %s, %s, %s, %d)",
- dpath, rootpath, repopath, tag ? tag : "", date ? date : "", nb);
-
- l = cvs_path_cat(dpath, CVS_PATH_CVSDIR, path, sizeof(path));
- if (l >= sizeof(path))
- fatal("cvs_mkadmin: path truncation");
-
- if (mkdir(path, 0755) == -1 && errno != EEXIST)
- fatal("cvs_mkadmin: mkdir: `%s': %s", path, strerror(errno));
-
- /* just create an empty Entries file */
- ef = cvs_ent_open(dpath, O_WRONLY);
- if (ef != NULL)
- cvs_ent_close(ef);
-
- l = cvs_path_cat(dpath, CVS_PATH_ROOTSPEC, path, sizeof(path));
- if (l >= sizeof(path))
- fatal("cvs_mkadmin: path truncation");
-
- if (stat(path, &st) == -1 && errno == ENOENT) {
- if ((fp = fopen(path, "w")) == NULL)
- fatal("cvs_mkadmin: fopen: `%s': %s",
- path, strerror(errno));
-
- if (rootpath != NULL)
- fprintf(fp, "%s\n", rootpath);
- (void)fclose(fp);
- }
-
- l = cvs_path_cat(dpath, CVS_PATH_REPOSITORY, path, sizeof(path));
- if (l >= sizeof(path))
- fatal("cvs_mkadmin: path truncation");
-
- if (stat(path, &st) == -1 && errno == ENOENT) {
- if ((fp = fopen(path, "w")) == NULL)
- fatal("cvs_mkadmin: fopen: `%s': %s",
- path, strerror(errno));
-
- if (repopath != NULL)
- fprintf(fp, "%s\n", repopath);
- (void)fclose(fp);
- }
-
- /* create CVS/Tag file (if needed) */
- /* XXX correct? */
- if (tag != NULL || date != NULL)
- (void)cvs_write_tagfile(tag, date, nb);
-
- return (0);
-}
-
-
/*
* cvs_exec()
*/
@@ -491,16 +376,16 @@ cvs_exec(int argc, char **argv, int fds[3])
pid_t pid;
if ((pid = fork()) == -1) {
- cvs_log(LP_ERRNO, "failed to fork");
+ cvs_log(LP_ERR, "failed to fork");
return (-1);
} else if (pid == 0) {
execvp(argv[0], argv);
- cvs_log(LP_ERRNO, "failed to exec %s", argv[0]);
+ cvs_log(LP_ERR, "failed to exec %s", argv[0]);
exit(1);
}
if (waitpid(pid, &ret, 0) == -1)
- cvs_log(LP_ERRNO, "failed to waitpid");
+ cvs_log(LP_ERR, "failed to waitpid");
return (ret);
}
@@ -561,7 +446,7 @@ cvs_unlink(const char *path)
return (0);
if (unlink(path) == -1 && errno != ENOENT) {
- cvs_log(LP_ERRNO, "cannot remove `%s'", path);
+ cvs_log(LP_ERR, "cannot remove `%s'", path);
return (-1);
}
@@ -589,7 +474,7 @@ cvs_rmdir(const char *path)
return (0);
if ((dirp = opendir(path)) == NULL) {
- cvs_log(LP_ERRNO, "failed to open '%s'", path);
+ cvs_log(LP_ERR, "failed to open '%s'", path);
return (-1);
}
@@ -611,7 +496,7 @@ cvs_rmdir(const char *path)
if (rmdir(path) == -1 && errno != ENOENT) {
- cvs_log(LP_ERRNO, "failed to remove '%s'", path);
+ cvs_log(LP_ERR, "failed to remove '%s'", path);
goto done;
}
@@ -622,107 +507,6 @@ done:
}
/*
- * Create a directory, and the parent directories if needed.
- * based upon mkpath() from mkdir.c
- */
-int
-cvs_create_dir(const char *path, int create_adm, char *root, char *repo)
-{
- int ret;
- char *d, *s;
- struct stat sb;
- char rpath[MAXPATHLEN], entry[MAXPATHLEN];
- CVSENTRIES *entf;
- struct cvs_ent *ent;
-
- if (create_adm == 1 && root == NULL)
- fatal("cvs_create_dir failed");
-
- s = xstrdup(path);
- rpath[0] = '\0';
- if (repo != NULL) {
- if (strlcpy(rpath, repo, sizeof(rpath)) >= sizeof(rpath))
- fatal("cvs_create_dir: path truncation");
-
- if (strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath))
- fatal("cvs_create_dir: path truncation");
- }
-
- ret = -1;
- entf = NULL;
- d = strtok(s, "/");
- while (d != NULL) {
- if (stat(d, &sb)) {
- /* try to create the directory */
- if (errno != ENOENT ||
- (mkdir(d, 0755) && errno != EEXIST)) {
- cvs_log(LP_ERRNO, "failed to create `%s'", d);
- goto done;
- }
- } else if (!S_ISDIR(sb.st_mode)) {
- cvs_log(LP_ERR, "`%s' not a directory", d);
- goto done;
- }
-
- /*
- * Create administrative files if requested.
- */
- if (create_adm == 1) {
- if (strlcat(rpath, d, sizeof(rpath)) >= sizeof(rpath))
- fatal("cvs_create_dir: path truncation");
-
- if (strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath))
- fatal("cvs_create_dir: path truncation");
-
- cvs_mkadmin(d, root, rpath, NULL, NULL, 0);
- }
-
- /*
- * Add it to the parent directory entry file.
- * (if any).
- */
- entf = cvs_ent_open(".", O_RDWR);
- if (entf != NULL && strcmp(d, ".")) {
- if (strlcpy(entry, "D/", sizeof(entry)) >=
- sizeof(entry) ||
- strlcat(entry, d, sizeof(entry)) >= sizeof(entry) ||
- strlcat(entry, "////", sizeof(entry)) >=
- sizeof(entry))
- fatal("cvs_create_dir: overflow in entry buf");
-
- if ((ent = cvs_ent_parse(entry)) == NULL) {
- cvs_log(LP_ERR, "failed to parse entry");
- goto done;
- }
-
- cvs_ent_remove(entf, d, 0);
-
- if (cvs_ent_add(entf, ent) < 0) {
- cvs_log(LP_ERR, "failed to add entry");
- goto done;
- }
- }
-
- if (entf != NULL) {
- cvs_ent_close(entf);
- entf = NULL;
- }
-
- /* All went ok, switch to the newly created directory. */
- cvs_chdir(d, 0);
-
- d = strtok(NULL, "/");
- }
-
- ret = 0;
-done:
- if (entf != NULL)
- cvs_ent_close(entf);
- xfree(s);
- return (ret);
-}
-
-/*
* cvs_path_cat()
*
* Concatenate the two paths <base> and <end> and store the generated path
@@ -740,14 +524,14 @@ cvs_path_cat(const char *base, const char *end, char *dst, size_t dlen)
len = strlcpy(dst, base, dlen);
if (len >= dlen - 1) {
errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", dst);
+ fatal("overflow in cvs_path_cat");
} else {
dst[len] = '/';
dst[len + 1] = '\0';
len = strlcat(dst, end, dlen);
if (len >= dlen) {
errno = ENAMETOOLONG;
- cvs_log(LP_ERRNO, "%s", dst);
+ cvs_log(LP_ERR, "%s", dst);
}
}
@@ -755,182 +539,172 @@ cvs_path_cat(const char *base, const char *end, char *dst, size_t dlen)
}
/*
- * cvs_rcs_getpath()
- *
- * Get the RCS path of the file <file> and store it in <buf>, which is
- * of size <len>. For portability, it is recommended that <buf> always be
- * at least MAXPATHLEN bytes long.
- * Returns a pointer to the start of the path on success, or NULL on failure.
+ * a hack to mimic and thus match gnu cvs behaviour.
*/
-char *
-cvs_rcs_getpath(CVSFILE *file, char *buf, size_t len)
+time_t
+cvs_hack_time(time_t oldtime, int togmt)
{
- char *repo;
- struct cvsroot *root;
+ int l;
+ struct tm *t;
+ char tbuf[32];
- root = CVS_DIR_ROOT(file);
- repo = CVS_DIR_REPO(file);
+ if (togmt == 1) {
+ t = gmtime(&oldtime);
+ if (t == NULL)
+ return (0);
+
+ return (mktime(t));
+ }
- if (strlcpy(buf, root->cr_dir, len) >= len ||
- strlcat(buf, "/", len) >= len ||
- strlcat(buf, repo, len) >= len ||
- strlcat(buf, "/", len) >= len ||
- strlcat(buf, file->cf_name, len) >= len ||
- strlcat(buf, RCS_FILE_EXT, len) >= len)
- fatal("cvs_rcs_getpath: path truncation");
+ t = localtime(&oldtime);
- return (buf);
+ l = snprintf(tbuf, sizeof(tbuf), "%d/%d/%d GMT %d:%d:%d",
+ t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour,
+ t->tm_min, t->tm_sec);
+ if (l == -1 || l >= (int)sizeof(tbuf))
+ return (0);
+
+ return (cvs_date_parse(tbuf));
}
-/*
- * cvs_write_tagfile()
- *
- * Write the CVS/Tag file for current directory.
- */
void
-cvs_write_tagfile(char *tag, char *date, int nb)
+cvs_get_repo(const char *dir, char *dst, size_t len)
{
+ int l;
FILE *fp;
- char tagpath[MAXPATHLEN];
+ char *s, buf[MAXPATHLEN], fpath[MAXPATHLEN];
- if (cvs_noexec == 1)
- return;
+ if (strlcpy(buf, dir, sizeof(buf)) >= sizeof(buf))
+ fatal("cvs_get_repo: truncation");
- if (strlcpy(tagpath, CVS_PATH_TAG, sizeof(tagpath)) >= sizeof(tagpath))
- return;
+ l = snprintf(fpath, sizeof(fpath), "%s/%s", dir, CVS_PATH_REPOSITORY);
+ if (l == -1 || l >= (int)sizeof(fpath))
+ fatal("cvs_get_repo: overflow");
+
+ if ((fp = fopen(fpath, "r")) != NULL) {
+ fgets(buf, sizeof(buf), fp);
+
+ if ((s = strrchr(buf, '\n')) != NULL)
+ *s = '\0';
- if (tag != NULL || date != NULL) {
- fp = fopen(tagpath, "w+");
- if (fp == NULL) {
- if (errno != ENOENT)
- cvs_log(LP_NOTICE,
- "failed to open `%s' : %s", tagpath,
- strerror(errno));
- return;
- }
- if (tag != NULL) {
- if (nb != 0)
- fprintf(fp, "N%s\n", tag);
- else
- fprintf(fp, "T%s\n", tag);
- } else {
- fprintf(fp, "D%s\n", date);
- }
(void)fclose(fp);
- } else {
- cvs_unlink(tagpath);
- return;
}
+
+ l = snprintf(dst, len, "%s/%s", current_cvsroot->cr_dir, buf);
+ if (l == -1 || l >= (int)len)
+ fatal("cvs_get_repo: overflow");
}
-/*
- * cvs_parse_tagfile()
- *
- * Parse the CVS/Tag file for current directory.
- *
- * If it contains a branch tag, sets <tagp>.
- * If it contains a date, sets <datep>.
- * If it contains a non-branch tag, sets <nbp>.
- *
- * Returns nothing but an error message, and sets <tagp>, <datep> to NULL
- * and <nbp> to 0.
- */
void
-cvs_parse_tagfile(char **tagp, char **datep, int *nbp)
+cvs_mkadmin(const char *path, const char *root, const char *repo)
{
FILE *fp;
- int linenum;
size_t len;
- char linebuf[128], tagpath[MAXPATHLEN];
-
- if (tagp != NULL)
- *tagp = (char *)NULL;
+ struct stat st;
+ char buf[MAXPATHLEN];
- if (datep != NULL)
- *datep = (char *)NULL;
+ cvs_log(LP_TRACE, "cvs_mkadmin(%s, %s, %s)", path, root, repo);
- if (nbp != NULL)
- *nbp = 0;
+ len = cvs_path_cat(path, CVS_PATH_CVSDIR, buf, sizeof(buf));
+ if (len >= sizeof(buf))
+ fatal("cvs_mkadmin: truncation");
- if (strlcpy(tagpath, CVS_PATH_TAG, sizeof(tagpath)) >= sizeof(tagpath))
+ if (stat(buf, &st) != -1)
return;
- fp = fopen(tagpath, "r");
- if (fp == NULL) {
- if (errno != ENOENT)
- cvs_log(LP_NOTICE, "failed to open `%s' : %s", tagpath,
- strerror(errno));
- return;
- }
+ if (mkdir(buf, 0755) == -1 && errno != EEXIST)
+ fatal("cvs_mkadmin: %s: %s", buf, strerror(errno));
- linenum = 0;
+ len = cvs_path_cat(path, CVS_PATH_ROOTSPEC, buf, sizeof(buf));
+ if (len >= sizeof(buf))
+ fatal("cvs_mkadmin: truncation");
- while (fgets(linebuf, (int)sizeof(linebuf), fp) != NULL) {
- linenum++;
- if ((len = strlen(linebuf)) == 0)
- continue;
- if (linebuf[len -1] != '\n') {
- cvs_log(LP_WARN, "line too long in `%s:%d'", tagpath,
- linenum);
- break;
- }
- linebuf[--len] = '\0';
+ if ((fp = fopen(buf, "w")) == NULL)
+ fatal("cvs_mkadmin: %s: %s", buf, strerror(errno));
- switch (*linebuf) {
- case 'T':
- if (tagp != NULL)
- *tagp = xstrdup(linebuf);
- break;
- case 'D':
- if (datep != NULL)
- *datep = xstrdup(linebuf);
- break;
- case 'N':
- if (tagp != NULL)
- *tagp = xstrdup(linebuf);
- if (nbp != NULL)
- *nbp = 1;
- break;
- default:
- break;
- }
- }
- if (ferror(fp))
- cvs_log(LP_NOTICE, "failed to read line from `%s'", tagpath);
+ fprintf(fp, "%s\n", root);
+ (void)fclose(fp);
+
+ len = cvs_path_cat(path, CVS_PATH_REPOSITORY, buf, sizeof(buf));
+ if (len >= sizeof(buf))
+ fatal("cvs_mkadmin: truncation");
+
+ if ((fp = fopen(buf, "w")) == NULL)
+ fatal("cvs_mkadmin: %s: %s", buf, strerror(errno));
+ fprintf(fp, "%s\n", repo);
+ (void)fclose(fp);
+
+ len = cvs_path_cat(path, CVS_PATH_ENTRIES, buf, sizeof(buf));
+ if (len >= sizeof(buf))
+ fatal("cvs_mkadmin: truncation");
+
+ if ((fp = fopen(buf, "w")) == NULL)
+ fatal("cvs_mkadmin: %s: %s", buf, strerror(errno));
(void)fclose(fp);
}
-/*
- * a hack to mimic and thus match gnu cvs behaviour.
- */
-time_t
-cvs_hack_time(time_t oldtime, int togmt)
+void
+cvs_mkpath(const char *path)
{
- int l;
- struct tm *t;
- char tbuf[32];
+ FILE *fp;
+ size_t len;
+ struct stat st;
+ char *sp, *dp, *dir, rpath[MAXPATHLEN], repo[MAXPATHLEN];
- if (togmt == 1) {
- t = gmtime(&oldtime);
- if (t == NULL)
- return (0);
+ dir = xstrdup(path);
- return (mktime(t));
+ STRIP_SLASH(dir);
+ cvs_log(LP_TRACE, "cvs_mkpath(%s)", dir);
+
+ repo[0] = '\0';
+ rpath[0] = '\0';
+
+ if (cvs_cmdop == CVS_OP_UPDATE) {
+ if ((fp = fopen(CVS_PATH_REPOSITORY, "r")) != NULL) {
+ fgets(repo, sizeof(repo), fp);
+ if (repo[strlen(repo) - 1] == '\n')
+ repo[strlen(repo) - 1] = '\0';
+ (void)fclose(fp);
+ }
}
- t = localtime(&oldtime);
+ for (sp = dir; sp != NULL; sp = dp) {
+ dp = strchr(sp, '/');
+ if (dp != NULL)
+ *(dp++) = '\0';
- l = snprintf(tbuf, sizeof(tbuf), "%d/%d/%d GMT %d:%d:%d",
- t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour,
- t->tm_min, t->tm_sec);
- if (l == -1 || l >= (int)sizeof(tbuf))
- return (0);
+ if (repo[0] != '\0') {
+ len = strlcat(repo, "/", sizeof(repo));
+ if (len >= (int)sizeof(repo))
+ fatal("cvs_mkpath: overflow");
+ }
- return (cvs_date_parse(tbuf));
-}
+ len = strlcat(repo, sp, sizeof(repo));
+ if (len >= (int)sizeof(repo))
+ fatal("cvs_mkpath: overflow");
+
+ if (rpath[0] != '\0') {
+ len = strlcat(rpath, "/", sizeof(rpath));
+ if (len >= (int)sizeof(rpath))
+ fatal("cvs_mkpath: overflow");
+ }
+
+ len = strlcat(rpath, sp, sizeof(rpath));
+ if (len >= (int)sizeof(rpath))
+ fatal("cvs_mkpath: overflow");
-#endif /* !RCSPROG */
+ if (stat(repo, &st) != -1)
+ continue;
+
+ if (mkdir(rpath, 0755) == -1 && errno != EEXIST)
+ fatal("cvs_mkpath: %s: %s", rpath, strerror(errno));
+
+ cvs_mkadmin(rpath, current_cvsroot->cr_dir, repo);
+ }
+
+ xfree(dir);
+}
/*
* Split the contents of a file into a list of lines.
diff --git a/usr.bin/cvs/util.h b/usr.bin/cvs/util.h
index 207fb9d05e2..03ab1430c4d 100644
--- a/usr.bin/cvs/util.h
+++ b/usr.bin/cvs/util.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.h,v 1.4 2006/03/27 06:13:51 pat Exp $ */
+/* $OpenBSD: util.h,v 1.5 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2006 Niall O'Higgins <niallo@openbsd.org>
* All rights reserved.
@@ -27,15 +27,12 @@
#ifndef UTIL_H
#define UTIL_H
-#if !defined(RCSPROG)
-
-
-int cvs_readrepo(const char *, char *, size_t);
+void cvs_get_repo(const char *, char *, size_t);
void cvs_modetostr(mode_t, char *, size_t);
void cvs_strtomode(const char *, mode_t *);
void cvs_splitpath(const char *, char *, size_t, char **);
-int cvs_mkadmin(const char *, const char *, const char *, char *,
- char *, int);
+void cvs_mkadmin(const char *, const char *, const char *);
+void cvs_mkpath(const char *);
int cvs_cksum(const char *, char *, size_t);
int cvs_exec(int, char **, int []);
int cvs_getargv(const char *, char **, int);
@@ -43,8 +40,6 @@ int cvs_chdir(const char *, int);
int cvs_rename(const char *, const char *);
int cvs_unlink(const char *);
int cvs_rmdir(const char *);
-int cvs_create_dir(const char *, int, char *, char *);
-char *cvs_rcs_getpath(CVSFILE *, char *, size_t);
char **cvs_makeargv(const char *, int *);
void cvs_freeargv(char **, int);
void cvs_write_tagfile(char *, char *, int);
@@ -52,9 +47,6 @@ void cvs_parse_tagfile(char **, char **, int *);
size_t cvs_path_cat(const char *, const char *, char *, size_t);
time_t cvs_hack_time(time_t, int);
-#endif /* !RCSPROG */
-
-
struct cvs_line {
char *l_line;
int l_lineno;
diff --git a/usr.bin/cvs/version.c b/usr.bin/cvs/version.c
deleted file mode 100644
index c7ce5bdb4e0..00000000000
--- a/usr.bin/cvs/version.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* $OpenBSD: version.c,v 1.20 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-static int cvs_version_pre_exec(struct cvsroot *);
-
-struct cvs_cmd cvs_cmd_version = {
- CVS_OP_VERSION, CVS_REQ_VERSION, "version",
- { "ve", "ver" },
- "Show current CVS version(s)",
- "",
- "",
- NULL,
- 0,
- NULL,
- cvs_version_pre_exec,
- NULL,
- NULL,
- NULL,
- NULL,
- 0
-};
-
-
-static int
-cvs_version_pre_exec(struct cvsroot *root)
-{
- if (root != NULL && root->cr_method != CVS_METHOD_LOCAL)
- printf("Client: ");
- cvs_printf("%s\n", CVS_VERSION);
-
- if (root != NULL && root->cr_method != CVS_METHOD_LOCAL) {
- cvs_printf("Server: %s\n", root->cr_version == NULL ?
- "(unknown)" : root->cr_version);
- }
-
- return (0);
-}
diff --git a/usr.bin/cvs/watch.c b/usr.bin/cvs/watch.c
deleted file mode 100644
index 5254a18812c..00000000000
--- a/usr.bin/cvs/watch.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* $OpenBSD: watch.c,v 1.12 2006/04/14 02:45:35 deraadt Exp $ */
-/*
- * Copyright (c) 2005 Xavier Santolaria <xsa@openbsd.org>
- * Copyright (c) 2005 Moritz Jodeit <moritz@openbsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include "cvs.h"
-#include "log.h"
-#include "proto.h"
-
-static int cvs_watch_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_watch_pre_exec(struct cvsroot *);
-static int cvs_watch_remote(CVSFILE *, void*);
-static int cvs_watch_local(CVSFILE *, void*);
-
-static int cvs_watchers_init(struct cvs_cmd *, int, char **, int *);
-static int cvs_watchers_local(CVSFILE *, void*);
-
-
-struct cvs_cmd cvs_cmd_watch = {
- CVS_OP_WATCH, CVS_REQ_NOOP, "watch",
- {},
- "Set watches",
- "on | off | add | remove [-lR] [-a action] [file ...]",
- "a:lR",
- NULL,
- CF_SORT | CF_IGNORE | CF_RECURSE,
- cvs_watch_init,
- cvs_watch_pre_exec,
- cvs_watch_remote,
- cvs_watch_local,
- NULL,
- NULL,
- CVS_CMD_SENDDIR | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDARGS2
-};
-
-struct cvs_cmd cvs_cmd_watchers = {
- CVS_OP_WATCHERS, CVS_REQ_WATCHERS, "watchers",
- {},
- "See who is watching a file",
- "[-lR] [file ...]",
- "lR",
- NULL,
- CF_SORT | CF_IGNORE | CF_RECURSE,
- cvs_watchers_init,
- NULL,
- cvs_watch_remote,
- cvs_watchers_local,
- NULL,
- NULL,
- CVS_CMD_SENDDIR | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDARGS2
-};
-
-
-static char *aoptstr = NULL;
-static int watchreq = 0;
-
-static int
-cvs_watch_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- if (argc < 2)
- return (CVS_EX_USAGE);
-
- if (strcmp(argv[1], "on") == 0)
- watchreq = CVS_REQ_WATCH_ON;
- else if (strcmp(argv[1], "off") == 0)
- watchreq = CVS_REQ_WATCH_OFF;
- else if (strcmp(argv[1], "add") == 0)
- watchreq = CVS_REQ_WATCH_ADD;
- else if (strcmp(argv[1], "remove") == 0)
- watchreq = CVS_REQ_WATCH_REMOVE;
- else
- return (CVS_EX_USAGE);
-
- cmd->cmd_req = watchreq;
- optind = 2;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'a':
- /*
- * Only `watch add | remove' support the -a option.
- * Check which command has been issued.
- */
- if (watchreq != CVS_REQ_WATCH_ADD &&
- watchreq != CVS_REQ_WATCH_REMOVE)
- return (CVS_EX_USAGE);
- if (strcmp(optarg, "commit") != 0 &&
- strcmp(optarg, "edit") != 0 &&
- strcmp(optarg, "unedit") != 0 &&
- strcmp(optarg, "all") != 0 &&
- strcmp(optarg, "none") != 0)
- return (CVS_EX_USAGE);
- aoptstr = xstrdup(optarg);
- break;
- case 'l':
- cmd->file_flags &= ~CF_RECURSE;
- break;
- case 'R':
- cmd->file_flags |= CF_RECURSE;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- *arg = optind;
- return (CVS_EX_OK);
-}
-
-
-/*
- * cvs_watch_pre_exec()
- *
- */
-static int
-cvs_watch_pre_exec(struct cvsroot *root)
-{
- if (root->cr_method != CVS_METHOD_LOCAL) {
- if (watchreq != CVS_REQ_WATCH_ADD &&
- watchreq != CVS_REQ_WATCH_REMOVE)
- return (CVS_EX_OK);
-
- if (aoptstr == NULL || strcmp(aoptstr, "all") == 0) {
- /* Defaults to: edit, unedit, commit */
- cvs_sendarg(root, "-a", 0);
- cvs_sendarg(root, "edit", 0);
- cvs_sendarg(root, "-a", 0);
- cvs_sendarg(root, "unedit", 0);
- cvs_sendarg(root, "-a", 0);
- cvs_sendarg(root, "commit", 0);
- } else {
- cvs_sendarg(root, "-a", 0);
- cvs_sendarg(root, aoptstr, 0);
- }
- }
-
- xfree(aoptstr);
-
- return (CVS_EX_OK);
-}
-
-
-/*
- * cvs_watch_local()
- *
- */
-static int
-cvs_watch_local(CVSFILE *cf, void *arg)
-{
- return (CVS_EX_OK);
-}
-
-
-/*
- * cvs_watch_remote()
- *
- */
-static int
-cvs_watch_remote(CVSFILE *cf, void *arg)
-{
- struct cvsroot *root;
-
- root = CVS_DIR_ROOT(cf);
-
- if (cf->cf_type == DT_DIR) {
- if (cf->cf_cvstat == CVS_FST_UNKNOWN)
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- else
- cvs_senddir(root, cf);
- return (0);
- }
-
- cvs_sendentry(root, cf);
-
- switch (cf->cf_cvstat) {
- case CVS_FST_UNKNOWN:
- cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
- break;
- case CVS_FST_UPTODATE:
- cvs_sendreq(root, CVS_REQ_UNCHANGED, cf->cf_name);
- break;
- case CVS_FST_ADDED:
- case CVS_FST_MODIFIED:
- cvs_sendreq(root, CVS_REQ_ISMODIFIED, cf->cf_name);
- break;
- default:
- break;
- }
-
- return (0);
-}
-
-
-/*
- * cvs_watchers_init()
- *
- */
-static int
-cvs_watchers_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
-{
- int ch;
-
- while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
- switch (ch) {
- case 'l':
- cmd->file_flags &= ~CF_RECURSE;
- break;
- case 'R':
- cmd->file_flags |= CF_RECURSE;
- break;
- default:
- return (CVS_EX_USAGE);
- }
- }
-
- *arg = optind;
- return (CVS_EX_OK);
-}
-
-
-/*
- * cvs_watchers_local()
- *
- */
-static int
-cvs_watchers_local(CVSFILE *cf, void *arg)
-{
- return (CVS_EX_OK);
-}
diff --git a/usr.bin/cvs/worklist.h b/usr.bin/cvs/worklist.h
index 8e0dee01674..0a3648ddb47 100644
--- a/usr.bin/cvs/worklist.h
+++ b/usr.bin/cvs/worklist.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: worklist.h,v 1.4 2006/04/10 19:49:44 joris Exp $ */
+/* $OpenBSD: worklist.h,v 1.5 2006/05/27 03:30:31 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
* All rights reserved.
@@ -40,8 +40,4 @@ void cvs_worklist_clean(struct cvs_wklhead *, void (*cb)(struct cvs_worklist *))
void cvs_worklist_unlink(struct cvs_worklist *);
-#if defined(RCSPROG)
-extern struct cvs_wklhead rcs_temp_files;
-#endif
-
#endif