diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2006-11-10 16:31:30 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2006-11-10 16:31:30 +0000 |
commit | ce3eff3e5981dfaf68c27ee50d59fb6721b42f7f (patch) | |
tree | 369a50da53fe0b404cfa5dcf39c7b144bb6c32f8 /usr.bin/rcs/co.c | |
parent | 4cb0eff366ea12c2b02138bf7b320a45efbb5d96 (diff) |
Unlike GNU rcs, our co will not overwrite an existing file, even
if the existing file is not writable. While safer, this can be
annoying. I've changed things to compare the version of the file
being checked out with its current contents and, if they are the
same, to allow the checkout without user intervention. The behavior
when there is a writable version of the file is unchanged. OK xsa@
Diffstat (limited to 'usr.bin/rcs/co.c')
-rw-r--r-- | usr.bin/rcs/co.c | 87 |
1 files changed, 62 insertions, 25 deletions
diff --git a/usr.bin/rcs/co.c b/usr.bin/rcs/co.c index 9e9e07caf31..fdf895bd3a2 100644 --- a/usr.bin/rcs/co.c +++ b/usr.bin/rcs/co.c @@ -1,4 +1,4 @@ -/* $OpenBSD: co.c,v 1.99 2006/11/09 21:47:52 millert Exp $ */ +/* $OpenBSD: co.c,v 1.100 2006/11/10 16:31:29 millert Exp $ */ /* * Copyright (c) 2005 Joris Vink <joris@openbsd.org> * All rights reserved. @@ -27,11 +27,13 @@ #include "includes.h" #include "rcsprog.h" +#include "diff.h" #define CO_OPTSTRING "d:f::I::k:l::M::p::q::r::s:Tu::Vw::x::z::" static void checkout_err_nobranch(RCSFILE *, const char *, const char *, const char *, int); +static int checkout_file_has_diffs(RCSFILE *, RCSNUM *, const char *); int checkout_main(int argc, char **argv) @@ -240,6 +242,7 @@ checkout_rev(RCSFILE *file, RCSNUM *frev, const char *dst, int flags, struct rcs_delta *rdp; struct rcs_lock *lkp; char *fdate; + const char *fstatus; time_t rcsdate, givendate; RCSNUM *rev; @@ -409,33 +412,33 @@ checkout_rev(RCSFILE *file, RCSNUM *frev, const char *dst, int flags, file->rf_path, lcount); } - if (!(flags & PIPEOUT) && stat(dst, &st) != -1 && !(flags & FORCE)) { + if ((flags & (PIPEOUT|FORCE)) == 0 && stat(dst, &st) != -1) { /* - * XXX - Not sure what is "right". If we go according - * to GNU's behavior, an existing file with no writable - * bits is overwritten without prompting the user. - * - * This is dangerous, so we always prompt. - * Unfortunately this interferes with an unlocked - * checkout followed by a locked checkout, which should - * not prompt. One (unimplemented) solution is to check - * if the existing file is the same as the checked out - * revision, and prompt if there are differences. + * Prompt the user if the file is writable or the file is + * not writable but is different from the RCS head version. + * This is different from GNU which will silently overwrite + * the file regardless of its contents so long as it is + * read-only. */ if (st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) - (void)fprintf(stderr, "writable "); - (void)fprintf(stderr, "%s exists%s; ", dst, - (getuid() == st.st_uid) ? "" : - ", and you do not own it"); - (void)fprintf(stderr, "remove it? [ny](n): "); - if (rcs_yesno('n') == 'n') { - if (!(flags & QUIET) && isatty(STDIN_FILENO)) - warnx("%s%s exists; checkout aborted", - (st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ? - "writable " : "", dst); - else - warnx("checkout aborted"); - return (-1); + fstatus = "writable"; + else if (checkout_file_has_diffs(file, frev, dst) != D_SAME) + fstatus = "modified"; + else + fstatus = NULL; + if (fstatus) { + (void)fprintf(stderr, "%s %s exists%s; ", fstatus, dst, + (getuid() == st.st_uid) ? "" : + ", and you do not own it"); + (void)fprintf(stderr, "remove it? [ny](n): "); + if (rcs_yesno('n') == 'n') { + if (!(flags & QUIET) && isatty(STDIN_FILENO)) + warnx("%s %s exists; checkout aborted", + fstatus, dst); + else + warnx("checkout aborted"); + return (-1); + } } } @@ -497,3 +500,37 @@ checkout_err_nobranch(RCSFILE *file, const char *author, const char *date, state ? " and state " + (date || author ? 0:4) : "", state ? state : ""); } + +/* + * checkout_file_has_diffs() + * + * Check for diffs between the working file and its current revision. + * Same return values as rcs_diffreg() + */ +static int +checkout_file_has_diffs(RCSFILE *rfp, RCSNUM *frev, const char *dst) +{ + char *tempfile; + BUF *bp; + int ret; + + tempfile = NULL; + + if ((bp = rcs_getrev(rfp, frev)) == NULL) { + warnx("failed to load revision"); + return (D_ERROR); + } + + (void)xasprintf(&tempfile, "%s/diff.XXXXXXXXXX", rcs_tmpdir); + rcs_buf_write_stmp(bp, tempfile); + rcs_buf_empty(bp); + + diff_format = D_RCSDIFF; + ret = rcs_diffreg(dst, tempfile, bp, 0); + + rcs_buf_free(bp); + unlink(tempfile); + xfree(tempfile); + + return (ret); +} |