diff options
author | Joris Vink <joris@cvs.openbsd.org> | 2005-12-03 01:02:10 +0000 |
---|---|---|
committer | Joris Vink <joris@cvs.openbsd.org> | 2005-12-03 01:02:10 +0000 |
commit | ef47fbf93d2302d521921cce5f98a093b4779e9f (patch) | |
tree | 50d76a77cc19c09cea910a3890611cb290e63bab | |
parent | 1c6cd252eaeaeedbd87c69d5843ae9550b20ee91 (diff) |
add very basic support for the following stuff:
- checkout in local mode (example: /cvs)
- update in local and server mode (example: /cvs and user@host:/cvs)
- import in local and server mode (example: /cvs and user@host:/cvs)
what remains to be done:
- not all options are supported yet, and update cannot pick up newly
added files yet. these things are pending and will be commited
real soon.
- checkout only works locally right now.
- fix rcs parsing code so that we don't fucking hog 100% cpu
on really BIG BIG BIG ass trees.
mainly tested by pedro@ and myself, thanks a lot pedro!
"go for it" niallo@
-rw-r--r-- | usr.bin/cvs/checkout.c | 107 | ||||
-rw-r--r-- | usr.bin/cvs/cmd.c | 13 | ||||
-rw-r--r-- | usr.bin/cvs/cvs.h | 7 | ||||
-rw-r--r-- | usr.bin/cvs/diff3.c | 18 | ||||
-rw-r--r-- | usr.bin/cvs/entries.c | 11 | ||||
-rw-r--r-- | usr.bin/cvs/file.c | 72 | ||||
-rw-r--r-- | usr.bin/cvs/file.h | 3 | ||||
-rw-r--r-- | usr.bin/cvs/import.c | 24 | ||||
-rw-r--r-- | usr.bin/cvs/rcs.c | 225 | ||||
-rw-r--r-- | usr.bin/cvs/rcs.h | 7 | ||||
-rw-r--r-- | usr.bin/cvs/remove.c | 4 | ||||
-rw-r--r-- | usr.bin/cvs/resp.c | 8 | ||||
-rw-r--r-- | usr.bin/cvs/update.c | 128 | ||||
-rw-r--r-- | usr.bin/cvs/util.c | 31 |
14 files changed, 608 insertions, 50 deletions
diff --git a/usr.bin/cvs/checkout.c b/usr.bin/cvs/checkout.c index 2d363684561..675eccfc108 100644 --- a/usr.bin/cvs/checkout.c +++ b/usr.bin/cvs/checkout.c @@ -1,4 +1,4 @@ -/* $OpenBSD: checkout.c,v 1.40 2005/09/15 17:01:10 xsa Exp $ */ +/* $OpenBSD: checkout.c,v 1.41 2005/12/03 01:02:08 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -43,6 +43,7 @@ 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 *); struct cvs_cmd cvs_cmd_checkout = { CVS_OP_CHECKOUT, CVS_REQ_CO, "checkout", @@ -79,6 +80,9 @@ struct cvs_cmd cvs_cmd_export = { CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR }; +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; @@ -89,6 +93,8 @@ static int kflag = RCS_KWEXP_DEFAULT; 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) { @@ -191,8 +197,15 @@ cvs_checkout_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg) static int cvs_checkout_pre_exec(struct cvsroot *root) { - int i; - char *sp; + int i, ret; + char *sp, repo[MAXPATHLEN]; + + if ((dirp = opendir(".")) == NULL) { + cvs_log(LP_ERRNO, "failed to save cwd"); + return (CVS_EX_DATA); + } + + cwdfd = dirfd(dirp); for (i = 0; i < co_nmod; i++) { if ((sp = strchr(co_mods[i], '/')) != NULL) @@ -215,7 +228,25 @@ cvs_checkout_pre_exec(struct cvsroot *root) *sp = '/'; } - if (root->cr_method != CVS_METHOD_LOCAL) { + if (root->cr_method == CVS_METHOD_LOCAL) { + if ((dirp = opendir(".")) == NULL) + return (CVS_EX_DATA); + cwdfd = dirfd(dirp); + + for (i = 0; i < co_nmod; i++) { + snprintf(repo, sizeof(repo), "%s/%s", root->cr_dir, + co_mods[i]); + 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 @@ -268,3 +299,71 @@ cvs_checkout_pre_exec(struct cvsroot *root) } return (0); } + +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); + } + + root = CVS_DIR_ROOT(cf); + cvs_file_getpath(cf, fpath, sizeof(fpath)); + + snprintf(rcspath, sizeof(rcspath), "%s/%s%s", root->cr_dir, + fpath, RCS_FILE_EXT); + + 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) + return (CVS_EX_FILE); + if (fchdir(cwdfd) < 0) { + cvs_log(LP_ERRNO, "fchdir failed"); + return (CVS_EX_FILE); + } + } else { + /* + * TODO: send responses to client so it'll + * create it's directories. + */ + } + + return (CVS_EX_OK); + } + + if (inattic == 1) + return (CVS_EX_OK); + + if ((rf = rcs_open(rcspath, RCS_READ)) == NULL) { + cvs_log(LP_ERR, "cvs_checkout_local: rcs_open failed"); + return (CVS_EX_DATA); + } + + if (cvs_checkout_rev(rf, rf->rf_head, cf, fpath, + (cvs_cmdop != CVS_OP_SERVER) ? 1 : 0, + CHECKOUT_REV_CREATED) < 0) { + rcs_close(rf); + return (CVS_EX_DATA); + } + + rcs_close(rf); + + cvs_printf("U %s\n", fpath); + return (CVS_EX_OK); +} diff --git a/usr.bin/cvs/cmd.c b/usr.bin/cvs/cmd.c index d891dd43593..bcb7a6fdec9 100644 --- a/usr.bin/cvs/cmd.c +++ b/usr.bin/cvs/cmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd.c,v 1.37 2005/10/22 17:23:21 joris Exp $ */ +/* $OpenBSD: cmd.c,v 1.38 2005/12/03 01:02:08 joris Exp $ */ /* * Copyright (c) 2005 Joris Vink <joris@openbsd.org> * All rights reserved. @@ -38,6 +38,7 @@ #include "log.h" #include "proto.h" +extern char *cvs_rootstr; /* * Command dispatch table @@ -225,6 +226,16 @@ cvs_startcmd(struct cvs_cmd *cmd, int argc, char **argv) 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 = strdup(root->cr_str); + if (cvs_rootstr == NULL) + return (CVS_EX_DATA); + } + cvs_log(LP_TRACE, "cvs_startcmd() CVSROOT=%s", root->cr_str); if ((root->cr_method != CVS_METHOD_LOCAL) && (cvs_connect(root) < 0)) diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h index f08fb3f7316..9e47b394016 100644 --- a/usr.bin/cvs/cvs.h +++ b/usr.bin/cvs/cvs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cvs.h,v 1.87 2005/10/22 17:32:57 joris Exp $ */ +/* $OpenBSD: cvs.h,v 1.88 2005/12/03 01:02:08 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -280,7 +280,7 @@ typedef struct cvs_entries { char *cef_path; u_int cef_flags; - TAILQ_HEAD(, cvs_ent) cef_ent; + TAILQ_HEAD(cvsentrieshead, cvs_ent) cef_ent; struct cvs_ent *cef_cur; } CVSENTRIES; @@ -387,7 +387,7 @@ 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 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 *); @@ -453,5 +453,6 @@ void cvs_freelines(struct cvs_lines *); /* XXX */ int rcs_patch_lines(struct cvs_lines *, struct cvs_lines *); +int cvs_checkout_rev(RCSFILE *, RCSNUM *, CVSFILE *, char *, int, int, ...); #endif /* CVS_H */ diff --git a/usr.bin/cvs/diff3.c b/usr.bin/cvs/diff3.c index 0c98b74a065..498b4dcc780 100644 --- a/usr.bin/cvs/diff3.c +++ b/usr.bin/cvs/diff3.c @@ -1,4 +1,4 @@ -/* $OpenBSD: diff3.c,v 1.6 2005/11/08 16:06:03 xsa Exp $ */ +/* $OpenBSD: diff3.c,v 1.7 2005/12/03 01:02:08 joris Exp $ */ /* * Copyright (C) Caldera International Inc. 2001-2002. @@ -71,7 +71,7 @@ static const char copyright[] = #endif /* not lint */ #ifndef lint -static const char rcsid[] = "$OpenBSD: diff3.c,v 1.6 2005/11/08 16:06:03 xsa Exp $"; +static const char rcsid[] = "$OpenBSD: diff3.c,v 1.7 2005/12/03 01:02:08 joris Exp $"; #endif /* not lint */ #include <sys/queue.h> @@ -235,16 +235,23 @@ cvs_diff3(RCSFILE *rf, char *workfile, RCSNUM *rev1, RCSNUM *rev2) argv[argc++] = path1; argv[argc++] = path2; argv[argc++] = path3; - if ((diff3_conflicts = diff3_internal(argc, argv, workfile, r2)) < 0) + + diff3_conflicts = diff3_internal(argc, argv, workfile, r2); + if (diff3_conflicts < 0) { + cvs_buf_free(diffb); + diffb = NULL; goto out; + } if (cvs_buf_putc(diffb, '\0') < 0) { cvs_buf_free(diffb); + diffb = NULL; goto out; } if (cvs_buf_putc(b1, '\0') < 0) { cvs_buf_free(diffb); + diffb = NULL; goto out; } @@ -258,6 +265,11 @@ cvs_diff3(RCSFILE *rf, char *workfile, RCSNUM *rev1, RCSNUM *rev2) if ((diffb = cvs_patchfile(data, patch, ed_patch_lines)) == NULL) goto out; + if (diff3_conflicts != 0) { + cvs_printf("%d conflict%s found during merge, please correct.\n", + diff3_conflicts, (diff3_conflicts > 1) ? "s" : ""); + } + free(data); free(patch); diff --git a/usr.bin/cvs/entries.c b/usr.bin/cvs/entries.c index 7c959c0ecea..e17ff7d92a3 100644 --- a/usr.bin/cvs/entries.c +++ b/usr.bin/cvs/entries.c @@ -1,4 +1,4 @@ -/* $OpenBSD: entries.c,v 1.50 2005/10/22 17:23:21 joris Exp $ */ +/* $OpenBSD: entries.c,v 1.51 2005/12/03 01:02:08 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -255,7 +255,7 @@ cvs_ent_addln(CVSENTRIES *ef, const char *line) * by <name>. */ int -cvs_ent_remove(CVSENTRIES *ef, const char *name) +cvs_ent_remove(CVSENTRIES *ef, const char *name, int useprev) { struct cvs_ent *ent; @@ -270,7 +270,12 @@ cvs_ent_remove(CVSENTRIES *ef, const char *name) * call to cvs_ent_next(), point to the next element to avoid * keeping an invalid reference. */ - ef->cef_cur = TAILQ_NEXT(ef->cef_cur, ce_list); + if (useprev) { + ef->cef_cur = TAILQ_PREV(ef->cef_cur, + cvsentrieshead, ce_list); + } else { + ef->cef_cur = TAILQ_NEXT(ef->cef_cur, ce_list); + } } TAILQ_REMOVE(&(ef->cef_ent), ent, ce_list); cvs_ent_free(ent); diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c index 709a399b172..d9a4656a1d9 100644 --- a/usr.bin/cvs/file.c +++ b/usr.bin/cvs/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.127 2005/11/12 21:34:48 niallo Exp $ */ +/* $OpenBSD: file.c,v 1.128 2005/12/03 01:02:08 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -427,13 +427,22 @@ cvs_file_getspec(char **fspec, int fsn, int flags, int (*cb)(CVSFILE *, void *), } cvs_error = CVS_EX_OK; - cvs_file_free(cf); /* * Since some commands don't require any files to operate * we can stop right here for those. */ - if (cvs_cmdop == CVS_OP_CHECKOUT || cvs_cmdop == CVS_OP_VERSION) + 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); + } + } + + cvs_file_free(cf); + + if (cvs_cmdop == CVS_OP_VERSION) return (0); for (i = 0; i < fsn; i++) { @@ -838,6 +847,22 @@ cvs_file_getdir(CVSFILE *cf, int flags, int (*cb)(CVSFILE *, void *), 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); + free(cf->cf_dir); + if ((cf->cf_dir = strdup(fpath)) == NULL) + return (-1); + } + nfiles = ndirs = 0; SIMPLEQ_INIT(&dirs); cvs_file_getpath(cf, fpath, sizeof(fpath)); @@ -1199,16 +1224,24 @@ 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 ((cfp = cvs_file_alloc(path, type)) == NULL) return (NULL); cfp->cf_parent = parent; @@ -1268,6 +1301,9 @@ cvs_file_lget(const char *path, int flags, CVSFILE *parent, CVSENTRIES *pent, else cfp->cf_cvstat = CVS_FST_LOST; } + + /* XXX assume 0644 ? */ + cfp->cf_mode = 0644; } if (ent != NULL) { @@ -1300,6 +1336,34 @@ cvs_file_lget(const char *path, int flags, CVSFILE *parent, CVSENTRIES *pent, } } + if (flags & CF_REPO) { + root = CVS_DIR_ROOT(cfp); + + cfp->cf_mode = 0644; + cfp->cf_cvstat = CVS_FST_LOST; + + if ((c = strdup(cfp->cf_dir)) == NULL) { + cvs_file_free(cfp); + return (NULL); + } + + free(cfp->cf_dir); + + if (strcmp(c, root->cr_dir)) { + c += strlen(root->cr_dir) + 1; + if ((cfp->cf_dir = strdup(c)) == NULL) { + cvs_file_free(cfp); + return (NULL); + } + + c -= strlen(root->cr_dir) + 1; + } else { + cfp->cf_dir = NULL; + } + + free(c); + } + if ((cfp->cf_repo != NULL) && (cfp->cf_type == DT_DIR) && !strcmp(cfp->cf_repo, path)) cfp->cf_cvstat = CVS_FST_UPTODATE; @@ -1383,7 +1447,7 @@ cvs_file_prune(char *path) if (cvs_file_prune(fpath)) { empty--; if (entf) - cvs_ent_remove(entf, fpath); + cvs_ent_remove(entf, fpath, 0); } else { empty++; } diff --git a/usr.bin/cvs/file.h b/usr.bin/cvs/file.h index ee2fa5a73b6..d0128700e08 100644 --- a/usr.bin/cvs/file.h +++ b/usr.bin/cvs/file.h @@ -1,4 +1,4 @@ -/* $OpenBSD: file.h,v 1.29 2005/11/12 21:34:48 niallo Exp $ */ +/* $OpenBSD: file.h,v 1.30 2005/12/03 01:02:09 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -50,6 +50,7 @@ struct cvs_entries; #define CF_MKADMIN 0x40 /* create admin files if they're missing */ #define CF_NOSYMS 0x80 /* ignore symbolic links */ #define CF_NOFILES 0x100 /* don't load any files inside a directory */ +#define CF_REPO 0x200 /* we are loading a repository with ,v files */ /* * The cvs_file structure is used to represent any file or directory within diff --git a/usr.bin/cvs/import.c b/usr.bin/cvs/import.c index 39661d7febf..6e3c6a80c4e 100644 --- a/usr.bin/cvs/import.c +++ b/usr.bin/cvs/import.c @@ -1,4 +1,4 @@ -/* $OpenBSD: import.c,v 1.29 2005/11/28 08:49:25 xsa Exp $ */ +/* $OpenBSD: import.c,v 1.30 2005/12/03 01:02:09 joris Exp $ */ /* * Copyright (c) 2004 Joris Vink <joris@openbsd.org> * All rights reserved. @@ -243,6 +243,7 @@ cvs_import_local(CVSFILE *cf, void *arg) size_t len; int l; time_t stamp; + char *fcont; char fpath[MAXPATHLEN], rpath[MAXPATHLEN], repo[MAXPATHLEN]; const char *comment; struct stat fst; @@ -250,6 +251,7 @@ cvs_import_local(CVSFILE *cf, void *arg) struct cvsroot *root; RCSFILE *rf; RCSNUM *rev; + BUF *bp; root = CVS_DIR_ROOT(cf); @@ -367,6 +369,26 @@ cvs_import_local(CVSFILE *cf, void *arg) return (CVS_EX_DATA); } + if ((bp = cvs_buf_load(fpath, BUF_AUTOEXT)) == NULL) { + rcs_close(rf); + (void)unlink(rpath); + return (CVS_EX_DATA); + } + + if (cvs_buf_putc(bp, '\0') < 0) { + rcs_close(rf); + (void)unlink(rpath); + return (CVS_EX_DATA); + } + + fcont = cvs_buf_release(bp); + + if (rcs_deltatext_set(rf, rev, fcont) < 0) { + rcs_close(rf); + (void)unlink(rpath); + return (CVS_EX_DATA); + } + /* add the vendor tag and release tag as symbols */ rcs_close(rf); diff --git a/usr.bin/cvs/rcs.c b/usr.bin/cvs/rcs.c index e2bf717cbcf..f8aa94139fe 100644 --- a/usr.bin/cvs/rcs.c +++ b/usr.bin/cvs/rcs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.c,v 1.104 2005/12/02 21:21:47 joris Exp $ */ +/* $OpenBSD: rcs.c,v 1.105 2005/12/03 01:02:09 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -318,8 +318,10 @@ rcs_open(const char *path, int flags, ...) fmode = va_arg(vap, mode_t); va_end(vap); } else { - rcs_errno = RCS_ERR_ERRNO; + /* XXX, make this command dependant? */ +#if 0 cvs_log(LP_ERR, "RCS file `%s' does not exist", path); +#endif return (NULL); } } else if ((ret == 0) && (flags & RCS_CREATE)) { @@ -2998,3 +3000,222 @@ rcs_state_get(RCSFILE *rfp, RCSNUM *rev) return (rdp->rd_state); } + +static char *month_tab[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; + +/* + * 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; + } + } 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) + time(&rcstime); + + if (type == CHECKOUT_REV_CREATED) { + 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) { + if ((oldrev = rcsnum_alloc()) == NULL) + goto out; + + if (rcsnum_cpy(rev, oldrev, 0) < 0) + goto out; + + if (rcsnum_dec(oldrev) == NULL) + goto out; + + 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_CREATED: + if (cvs_buf_write(bp, fpath, cf->cf_mode) < 0) { + cvs_log(LP_ERR, "failed to update file '%s'", + fpath); + 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) { + 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)); + if (cvs_buf_putc(bp, '\0') < 0) + goto out; + 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) + free(content); + + return (ret); +} diff --git a/usr.bin/cvs/rcs.h b/usr.bin/cvs/rcs.h index ba730c3ba9f..df38304752d 100644 --- a/usr.bin/cvs/rcs.h +++ b/usr.bin/cvs/rcs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.h,v 1.39 2005/12/01 18:22:09 xsa Exp $ */ +/* $OpenBSD: rcs.h,v 1.40 2005/12/03 01:02:09 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -105,6 +105,11 @@ #define RCS_ERR_PARSE 5 #define RCS_ERR_ERRNO 255 +/* used for cvs_checkout_rev */ +#define CHECKOUT_REV_CREATED 1 +#define CHECKOUT_REV_MERGED 2 +#define CHECKOUT_REV_REMOVED 3 + typedef struct rcs_num { u_int rn_len; u_int16_t *rn_id; diff --git a/usr.bin/cvs/remove.c b/usr.bin/cvs/remove.c index e69cd7387fa..b0f2426c7ba 100644 --- a/usr.bin/cvs/remove.c +++ b/usr.bin/cvs/remove.c @@ -1,4 +1,4 @@ -/* $OpenBSD: remove.c,v 1.37 2005/10/07 21:47:32 reyk Exp $ */ +/* $OpenBSD: remove.c,v 1.38 2005/12/03 01:02:09 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * Copyright (c) 2004, 2005 Xavier Santolaria <xsa@openbsd.org> @@ -179,7 +179,7 @@ cvs_remove_local(CVSFILE *cf, void *arg) cf->cf_name); return (0); } else if (cf->cf_cvstat == CVS_FST_ADDED) { - if (cvs_ent_remove(entf, cf->cf_name) == -1) + if (cvs_ent_remove(entf, cf->cf_name, 0) == -1) return (CVS_EX_FILE); l = snprintf(buf, sizeof(buf), "%s/%s%s", diff --git a/usr.bin/cvs/resp.c b/usr.bin/cvs/resp.c index 71e7cfa0394..af9c683c929 100644 --- a/usr.bin/cvs/resp.c +++ b/usr.bin/cvs/resp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: resp.c,v 1.62 2005/11/28 08:49:25 xsa Exp $ */ +/* $OpenBSD: resp.c,v 1.63 2005/12/03 01:02:09 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -526,7 +526,7 @@ cvs_resp_newentry(struct cvsroot *root, int type, char *line) 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); + (void)cvs_ent_remove(cvs_resp_lastent, ent->ce_name, 0); cvs_ent_add(cvs_resp_lastent, ent); } @@ -674,7 +674,7 @@ cvs_resp_updated(struct cvsroot *root, int type, char *line) 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) && + 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); @@ -752,7 +752,7 @@ cvs_resp_removed(struct cvsroot *root, int type, char *line) if (resp_check_dir(root, line) < 0) return (-1); - (void)cvs_ent_remove(cvs_resp_lastent, file); + (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); diff --git a/usr.bin/cvs/update.c b/usr.bin/cvs/update.c index 372ee452f15..62f4cff1c66 100644 --- a/usr.bin/cvs/update.c +++ b/usr.bin/cvs/update.c @@ -1,4 +1,4 @@ -/* $OpenBSD: update.c,v 1.44 2005/08/08 11:37:41 xsa Exp $ */ +/* $OpenBSD: update.c,v 1.45 2005/12/03 01:02:09 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -36,14 +36,13 @@ #include "cvs.h" #include "log.h" #include "proto.h" - +#include "diff.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 *); - struct cvs_cmd cvs_cmd_update = { CVS_OP_UPDATE, CVS_REQ_UPDATE, "update", { "up", "upd" }, @@ -220,13 +219,20 @@ cvs_update_remote(CVSFILE *cf, void *arg) static int cvs_update_local(CVSFILE *cf, void *arg) { - int ret; + int ret, islocal, revdiff; char fpath[MAXPATHLEN], rcspath[MAXPATHLEN]; + char *repo; RCSFILE *rf; + RCSNUM *frev; + BUF *fbuf; + struct cvsroot *root; - ret = 0; + revdiff = ret = 0; rf = NULL; + islocal = (cvs_cmdop != CVS_OP_SERVER); + root = CVS_DIR_ROOT(cf); + repo = CVS_DIR_REPO(cf); cvs_file_getpath(cf, fpath, sizeof(fpath)); if (cf->cf_cvstat == CVS_FST_UNKNOWN) { @@ -235,20 +241,120 @@ cvs_update_local(CVSFILE *cf, void *arg) } if (cf->cf_type == DT_DIR) { - cvs_log(LP_NOTICE, "Updating %s", fpath); + if (verbosity > 1) + cvs_log(LP_NOTICE, "Updating %s", fpath); + return (CVS_EX_OK); } if (cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)) == NULL) return (CVS_EX_DATA); - rf = rcs_open(rcspath, RCS_RDWR); - if (rf == NULL) { - printf("failed here?\n"); + /* + * 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) + return (CVS_EX_FILE); + return (CVS_EX_OK); + } + } + + /* set keyword expansion */ + /* XXX look at cf->cf_opts as well for this */ + if (rcs_kwexp_set(rf, kflag) < 0) { + if (rf != NULL) + rcs_close(rf); return (CVS_EX_DATA); } - rcs_close(rf); + /* fill in the correct revision */ + if (rev != NULL) { + if ((frev = rcsnum_parse(rev)) == NULL) { + if (rf != NULL) + rcs_close(rf); + return (CVS_EX_DATA); + } + } else { + frev = rf->rf_head; + } - return (ret); + /* + * Compare the headrevision with the revision we currently have. + */ + if (rf != NULL && 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); + 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); + } + break; + case CVS_FST_ADDED: + cvs_printf("A %s\n", fpath); + break; + case CVS_FST_REMOVED: + cvs_printf("R %s\n", fpath); + break; + case CVS_FST_CONFLICT: + cvs_printf("C %s\n", fpath); + break; + case CVS_FST_LOST: + if (cvs_checkout_rev(rf, frev, cf, fpath, islocal, + CHECKOUT_REV_CREATED) != -1) { + cf->cf_cvstat = CVS_FST_UPTODATE; + cvs_printf("U %s\n", fpath); + } + break; + case CVS_FST_UPTODATE: + if (revdiff == 1) { + if (cvs_checkout_rev(rf, frev, cf, fpath, islocal, + CHECKOUT_REV_CREATED) != -1) + cvs_printf("P %s\n", fpath); + } + break; + default: + break; + } + + if ((frev != NULL) && (frev != rf->rf_head)) + rcsnum_free(frev); + if (rf != NULL) + rcs_close(rf); + + return (CVS_EX_OK); } diff --git a/usr.bin/cvs/util.c b/usr.bin/cvs/util.c index 2a0f5add309..e9bc82269ad 100644 --- a/usr.bin/cvs/util.c +++ b/usr.bin/cvs/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.55 2005/10/30 11:10:12 xsa Exp $ */ +/* $OpenBSD: util.c,v 1.56 2005/12/03 01:02:09 joris Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> * All rights reserved. @@ -478,7 +478,9 @@ cvs_mkadmin(const char *dpath, const char *rootpath, const char *repopath, } /* create CVS/Tag file (if needed) */ - (void)cvs_write_tagfile(tag, date, nb); + /* XXX correct? */ + if (tag != NULL || date != NULL) + (void)cvs_write_tagfile(tag, date, nb); return (0); } @@ -639,7 +641,7 @@ cvs_create_dir(const char *path, int create_adm, char *root, char *repo) CVSENTRIES *entf; struct cvs_ent *ent; - if (create_adm == 1 && (root == NULL || repo == NULL)) { + if (create_adm == 1 && (root == NULL)) { cvs_log(LP_ERR, "missing stuff in cvs_create_dir"); return (-1); } @@ -647,12 +649,21 @@ cvs_create_dir(const char *path, int create_adm, char *root, char *repo) if ((s = strdup(path)) == NULL) return (-1); - if (strlcpy(rpath, repo, sizeof(rpath)) >= sizeof(rpath) || - strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath)) { - errno = ENAMETOOLONG; - cvs_log(LP_ERRNO, "%s", rpath); - free(s); - return (-1); + rpath[0] = '\0'; + if (repo != NULL) { + if (strlcpy(rpath, repo, sizeof(rpath)) >= sizeof(rpath)) { + errno = ENAMETOOLONG; + cvs_log(LP_ERRNO, "%s", rpath); + free(s); + return (-1); + } + + if (strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath)) { + errno = ENAMETOOLONG; + cvs_log(LP_ERRNO, "%s", rpath); + free(s); + return (-1); + } } ret = -1; @@ -707,7 +718,7 @@ cvs_create_dir(const char *path, int create_adm, char *root, char *repo) goto done; } - cvs_ent_remove(entf, d); + cvs_ent_remove(entf, d, 0); if (cvs_ent_add(entf, ent) < 0) { cvs_log(LP_ERR, "failed to add entry"); |