diff options
author | 1999-02-28 21:30:22 +0000 | |
---|---|---|
committer | 1999-02-28 21:30:22 +0000 | |
commit | c71bc7e269286e43816004eb0fcd7a55f036cd69 (patch) | |
tree | 794eb682ed86bb344bf2e65b4bee5ea179297b82 /gnu/usr.bin/cvs/src | |
parent | conditionalize use of sbus_testdma() (diff) | |
download | wireguard-openbsd-c71bc7e269286e43816004eb0fcd7a55f036cd69.tar.xz wireguard-openbsd-c71bc7e269286e43816004eb0fcd7a55f036cd69.zip |
Latest version from Cyclic
Diffstat (limited to 'gnu/usr.bin/cvs/src')
41 files changed, 6176 insertions, 984 deletions
diff --git a/gnu/usr.bin/cvs/src/ChangeLog b/gnu/usr.bin/cvs/src/ChangeLog index 8077ce8c027..7acccf5cbfe 100644 --- a/gnu/usr.bin/cvs/src/ChangeLog +++ b/gnu/usr.bin/cvs/src/ChangeLog @@ -1,3 +1,1068 @@ +1999-02-18 Jim Kingdon <http://www.cyclic.com> + + * sanity.sh (files): New test, for a relatively obscure spurious + "Up-to-date check failed" in client/server. + + * main.c (lookup_command_attribute): Don't check for "history" + twice. + +1999-02-17 Jim Kingdon <http://www.cyclic.com> + and Hallvard B Furuseth + + * root.c (parse_cvsroot): Rearrange ifdefs to squelch possible + warnings about statement not reached. + +1999-02-16 Jim Kingdon <http://www.cyclic.com> + + * recurse.c (start_recursion): If we are skipping the current + directory (due to it being from the wrong repository), also adjust + the arguments we send to the server accordingly (like we already + do for the case in which there is no CVS directory). + * sanity.sh (multiroot4): New test, for this. All these tests had + passed locally, but remote multiroot4-12 tests for this fix. + (multiroot): Adjust multiroot-diff-1, multiroot-update-2, + multiroot-tag-1, multiroot-status-1, multiroot-update-3, and + multiroot-log-1 to reflect the cosmetic change this produces (one + less "Diffing ." message). + (multiroot2): multiroot2-8 likewise. + +1999-02-10 Jim Kingdon <http://www.cyclic.com> + + * tag.c (cvstag): Don't pass SEND_NO_CONTENTS if -c specified. + * sanity.sh (tagc): New test, for various tag -c behaviors. + Test tagc-6 tests for this fix. + +1999-02-09 Jim Kingdon <http://www.cyclic.com> + + * error.c (error): Rewrite to no longer use vasprintf (see + ../lib/ChangeLog for rationale). Note the slight change in + interface - callers which want %8.8s or similar formats need to + call sprintf. + * lock.c (lock_wait, lock_obtained): Use sprintf. + +1999-02-08 Jim Kingdon <http://www.cyclic.com> + + * rcs.c (RCS_delete_revs): Pass -a to diff_exec. + * sanity.sh (binfiles3): New tests binfiles3-9 through + binfiles3-13 test for this fix. + * sanity.sh (binfiles): New tests binfiles-o4 and binfiles-o5 + (which don't test this bug, just on general principles). + +1999-02-04 Jim Kingdon <http://www.cyclic.com> + + * lock.c (lock_name): Permissions of directories in LockDir + shouldn't depend on the umask. + * sanity.sh (lockfiles): Set umask and CVSUMASK, to test for this. + +1999-02-01 Jim Kingdon <http://www.cyclic.com> + + * sanity.sh (keywordlog): New tests keywordlog-22 and + keywordlog-23 test keyword expansion and $Log. Adjust other tests + so that revisions differ more from each other, so this is a + better test. + +1999-01-29 Jim Kingdon <http://www.cyclic.com> + + * commit.c (checkaddfile): If options is "", treat it the same as + NULL. Centralize this check, and the one for it starting with + "-k", at the start of the function. + + * rcs.c, rcs.h (RCS_setexpand): New function. + * admin.c (admin_fileproc): Access keyword expansion field via + RCS_getexpand and RCS_setexpand, rather than directly. + * commit.c (checkaddfile): When resurrecting, set the keyword + expansion mode. + * sanity.sh (binfiles3): Adjust tests binfiles3-7 and binfiles3-8 + for the new behavior. + +1999-01-27 Jim Kingdon <http://www.cyclic.com> + + * sanity.sh (multiroot3): Add new variant of multiroot3-10 test + for RELATIVE_REPOS. Move multiroot3-11 test out of the + conditionals; it works the same for remote or local, + RELATIVE_REPOS or no. + + * options.h.in: Make RELATIVE_REPOS the default, as has been + announced as a future direction since 1997-10-11. + * sanity.sh (multiroot): Tweak multiroot-update-1a and + multiroot-update-1b tests to work with either RELATIVE_REPOS or + non-RELATIVE_REPOS. + + * sanity.sh (client-9): Don't assume the time zone. + +1999-01-26 Jim Kingdon <http://www.cyclic.com> + + Fix one facet of the "cvs add -kb" re-adding problem (the other + known facet is tested for by binfiles3-8). + * add.c (add): When re-adding a file, set the keyword expansion + as we normally would. + * sanity.sh (binfiles3): New test binfiles3-6a tests for this. + +1999-01-22 Jim Kingdon <http://www.cyclic.com> + + * sanity.sh (rmadd2): New tests, for undoing a commit. + +1999-01-21 Eric Mumpower <nocturne@cygnus.com> + + * sanity.sh (reposmv): Actually modify CVSROOT in current + environment when calling functions, rather than trying to achieve + the same effect with "CVSROOT=foo functionname". (Many common + bourne shells, including those in SunOS and Solaris 2.4-2.7, + do not properly handle "ENVVAR=foo command" when "command" is + a user-defined shell function rather than an actual executable.) + +1999-01-15 Jim Kingdon <http://www.cyclic.com> + + * sanity.sh (rcs3): Redirect awk's stdin to /dev/null like all the + other awk invocations. GNU awk seems not to read stdin in this + case, but that behavior is hard to reconcile with the Single Unix + Spec and some awks don't do it. + + * sanity.sh (binfiles, binfiles2, binfiles3, server): Use the same + tr trick as in rcs3. People don't seem to have been complaining, + and this should fix server-4 for HPUX. + +1999-01-14 Jim Kingdon <http://www.cyclic.com> + + * client.c (recv_line): If the line we are reading contains a + character which would sign-extend to EOF, don't treat it as end of + file. recv() doesn't report end of file this way and this might + fix bugs with 0xff characters. + +1999-01-14 Larry Jones <larry.jones@sdrc.com> + + * client.c (recv_line): Handle EOF from server. + + * sanity.sh (importc-8, importc-9): Accept anything in the seconds + fields of the timestamps since touch doesn't set it reliably. + (This isn't great, but it's better than nothing.) + +1999-01-14 Jim Kingdon <http://www.cyclic.com> + + * run.c (run_exec): Adjust comment about vfork; this isn't the place + to get into a treatise about fork performance vs. vfork + performance but it isn't quite as simple as whether one has + copy-on-write. + +1999-01-13 Larry Jones <larry.jones@sdrc.com> + + * sanity.sh (dotest_fail): Handle spurrious output from assert better. + + * sanity.sh (rcs3-4, rcs3-5a): Handle even more variants of the + assertion failure message. + +1999-01-12 Larry Jones <larry.jones@sdrc.com> + + * sanity.sh (mtfr-3): ls behavior varies wildly on nonexistant files, + just use echo instead. + +1999-01-11 Jim Meyering <meyering@ascend.com> + + * sanity.sh (mkmodules-temp-file-removal): New test, for this. + * mkmodules.c (mkmodules): Remove each `CVSROOT/.#[0-9]*' temporary + file that's used to check out files listed in CVSROOT/checkoutlist. + Remove extra semicolon at end of line. + +1999-01-11 Larry Jones <larry.jones@sdrc.com> + + * sanity.sh (rcs3-5a): Allow for multiple lines of output before the + assertion failure message. + + * sanity.sh (lockfiles-6, client-8): Work around bug in HP-UX chmod + (doesn't allow anything to follow omitted permissions). + +1999-01-09 Jim Kingdon <http://www.cyclic.com> + + * client.c (set_sticky): Nonfatal error if we can't write it. + * sanity.sh (dirs2-8 through dirs2-14): New tests, for this. + + * sanity.sh (rcs3): Write NUL character with tr not awk, in + accordance with Single Unix Specification. Hopefully will fix + rcs3-7 for HPUX. Will not work on SunOS4, but then again neither + did the old syntax. + +1999-01-05 Jim Kingdon <http://www.cyclic.com> + + * client.c, update.c: Rename MD5* functions to cvs_MD5* per + corresponding change to ../lib/md5.h. + +1999-01-03 Jim Kingdon <http://www.cyclic.com> + + * sanity.sh (client): Give file1 a predictable mode so that the + output in client-9 will not depend on the umask of the user + running the tests. + +1998-12-29 Jim Kingdon <http://www.cyclic.com> + + * client.c (client_senddate): Use date_to_internet rather than + using our own "5/26/1997 13:01:40 GMT" date format. + * main.c (date_to_internet): Check for errors from sscanf. Always + send a four digit year. Send hours, minutes, and seconds as two + digits per RFC822. + * sanity.sh (client): New tests client-8 and client-9 test for this. + + * sanity.sh (rcs2): New tests rcs2-6 through rcs2-8 test for fix + to lib/getdate.y (before the fix, "100 months" or "8 years" would + tend to mean the year 1969, thus the tests would give "cvs update: + file1 is no longer in the repository"). + +1998-12-28 Larry Jones <larry.jones@sdrc.com> + + * entries.c (Register): Return if unable to open log file to avoid + referencing the invalid file pointer. + * sanity.sh (dirs2-7): With above change, no longer fails. + * sanity.sh (rcs3-5a): Another assertion failure message. + * sanity.sh (pserver-4, pserver-5): Some 4.4BSD derived systems spit + out bogus error messages when initgroups is called as non-root. + +1998-12-23 Larry Jones <larry.jones@sdrc.com> + + * sanity.sh (rcs3, dotest_fail): The assertion failure message varies + wildly between different systems and the resulting abort call can + even result in spurrious output. Fix the regexp to accept nearly + anything containing some kind of assertion failure and ensure that + any spurrious output ends up in the output file instead of on the + terminal. + +1998-12-23 Jim Kingdon <http://www.cyclic.com> + + * admin.c, checkout.c, commit.c, cvsrc.c, expand_path.c, + history.c, ignore.c, import.c, log.c, mkmodules.c, modules.c, + myndbm.c, parseinfo.c, rcs.c, remove.c, rtag.c, status.c, subr.c, + tag.c, wrapper.c: Cast all char's to unsigned char before passing + them to ctype.h functions (isalpha, isgraph, isalnum, isspace, + isdigit, isprint, isupper). Whether using ctype.h is the right + thing at all is unclear to me (having the server depend on locale + seems wrong, as we don't necessarily have any good way to set the + right locale, if there even is such a concept as 'right' locale in + this context), but as long as we use ctype.h we might as use it + according to the standards (this affects systems where plain char + is signed but users supply characters with the 8th bit set). + Thanks to Paul Eggert for suggesting this. + +1998-12-22 Jim Kingdon <http://www.cyclic.com> + + * sanity.sh (rcs3): Oops, the earlier fix for srcdir only fixed + the non-remote case, not the remote case. Fix the other occurrence. + +1998-12-22 Jim Kingdon + + * sanity.sh (rcs3): The assertion failure message varies slightly + depending on whether CVS was built with srcdir != ".". Fix regexp. + +1998-12-21 Jim Kingdon + + * rcs.c (RCS_getdate): Reindent Jim Meyering's change; remove + unused variable x_vers. + + * rcs.c: When printing an unexpected character we found in the RCS + file, print it in hex rather than as a character (see comment for + rationale). + * sanity.sh (rcs3): Adjust rcs3-2 and rcs3-7 tests accordingly. + + * sanity.sh (rcs3): New test, for some error handling cases + involving parsing RCS files. + +1998-12-16 Jim Meyering <meyering@ascend.com> + + * rcs.c (RCS_getdate): Handle the case in which a file is first + imported after its initial version has been created. + * sanity.sh (import-after-initial): New test for that. + +1998-12-17 Jim Kingdon + + * server.c (serve_root): Pserver_Repos only exists if + AUTH_SERVER_SUPPORT is defined. + +1998-12-12 Jim Kingdon, and Derek R. Price of Stortek. + + * sanity.sh (multiroot): Change + to ${PLUS}. + +1998-12-12 Jim Kingdon, and Gary Young of Motorola + + * sanity.sh (admin): In tests admin-13, admin-25, and admin-29, + allow 4 digit year in addition to 2 digit year. + +1998-12-12 Jim Kingdon + + * sanity.sh (log): New tests log-14a and log-14b test for -rHEAD + and for HEAD as (nonexistent) file name. + +1998-12-02 Jim Kingdon + + * version.c: Squish version number to 1.10.4.1. + + * version.c: Version 1.10.4. + +1998-11-24 Jim Kingdon + + * recurse.c (do_file_proc): Check for errors from RCS_parse. + * sanity.sh (rcslib-symlink-7 through rcslib-symlink-10): New + tests, test for this. + + * sanity.sh (reposmv-2): Adjust for 22-Nov change to Find_Names. + + * entries.c (Register): If we can't write Entries.Log, make it a + nonfatal error. + * sanity.sh (dirs2): Test for this fix. + + * sanity.sh (dirs2): Clean up working directory at end of test. + +1998-11-23 Jim Kingdon + + * sanity.sh (dirs2): New test, for some more cases involving + deleting directories and such. + + * sanity.sh (dirs): Update for yesterday's change in Find_Names + error handling. The error in dirs-4 is fairly different now; in + dirs-3 and dirs-3a it is the obvious change. + +1998-11-22 Jim Kingdon + + * sanity.sh (release): Move the commments listing "cvs release" + tests from modules2-6 to here. + * release.c (release): Update comment to reflect "? foo" case. + + * find_names.c (Find_Names): If we can't read the repository, make + it a nonfatal error. Tell the caller whether this happened. + (find_rcs): Add comment regarding this behavior. + * recurse.c (do_recursion): If Find_Names gives an error, skip + the directory and print a message saying so. + * sanity.sh (modes3): New test, for this. + +1998-11-18 Jim Kingdon + + * rtag.c (rtag_usage), tag.c (tag_usage): Use "-r rev" + consistently. + + * sanity.sh (conflicts3): Tests conflicts3-24 through + conflicts3-28 test for another case similar to conflicts3-22. + +1998-11-14 Jim Kingdon + + * sanity.sh (diff): New test, for now just tests for the "I know + nothing" message. + + * sanity.sh (conflicts2-142b7 through conflicts2-142b11): New + tests; resurrecting doesn't work from one level up. + + * sanity.sh (mwrap-7): Remote prints the messages in a different + order. + +1998-11-13 Jim Kingdon + + * tag.c (check_fileproc): Log tag deletions. + * rtag.c (check_fileproc): Likewise. + * sanity.sh (taginfo-14 through taginfo-18): New tests, for + these behaviors. + +1998-11-12 Jim Kingdon + + * sanity.sh (mwrap-7): Update for the noexec fix. + + * server.c (server_copy_file): Add comment about noexec. + + * update.c (checkout_file): Handle noexec case involving revbuf + and modes. + (update_fileproc): In case T_NEEDS_MERGE, let merge_file take care + of noexec, so it can tell the user if there would be conflicts. + (merge_file): Print "conflicts found in FILE" message + regardless of noexec. Add comment about checking for whether the + file already contained the changes, and noexec. + * sanity.sh (conflicts-192a): New test, for this. + +1998-10-20 Jim Kingdon + + Use the gzip library on the server. Probably doesn't speed things + up as currently implemented, but does avoid hassles in terms of + finding an external gzip program. + * zlib.c, server.h (gunzip_and_write, read_and_gzip): Now returns + whether a fatal error occurred, rather than expecting error (1, + ...) to work. + * client.c (update_entries, send_modified): Change callers. + * server.c (receive_file): Rewrite gzip code to use + gunzip_and_write rather than filter_through_gunzip. + (server_updated): Likewise, use read_and_gzip rather than + filter_through_gzip. + * client.c, client.h (filter_through_gzip, filter_through_gunzip), + run.c, cvs.h (filter_stream_through_program): Removed; no longer used. + * sanity.sh (server): New tests server-4 and server-5 test + this feature (note that CVS 1.10 also passes these tests; the + behavior is supposed to be unchanged). + +1998-10-19 Jim Kingdon + + * sanity.sh (multiroot3): New test, tests for a few more + multiroot cases. + + * lock.c (lock_name): Set the permissions on each directory we + create to that of the parent directory. + * sanity.sh (lockfiles): New chmod and tests lockfiles-7a and + lockfiles-7b test for this. Adjust lockfiles-5 for new text of + error message. + +1998-10-15 Jim Kingdon + + * server.c (requests): Set RQ_ROOTLESS for "Set". + * sanity.sh (info): Also clean up $HOME/.cvsrc. + (server): Test that we can send Set before Root (had been tested + by crerepos-6b, but only if you ran the info test first). Tests + for this fix. + +1998-10-14 Jim Kingdon + + * subr.c (expand_string): Tweak the algorithm so that the size + that it allocates is generally a power of two. + +1998-10-14 Eivind Eklund and Jim Kingdon + + * commit.c (commit): For the client, don't worry about whether we + are root. + +1998-10-13 Jim Kingdon + + * server.h (struct request): Change status field to flags and add + RQ_ROOTLESS. + * client.c (handle_valid_requests, supported_request): Change + status to flags. + * server.c (requests): Change status to flags. Add RQ_ROOTLESS. + * server.c (server): If not RQ_ROOTLESS, and we haven't gotten a + Root request, give an error. + +1998-10-12 Jim Kingdon + + * version.c: Slide version number to 1.10.3.1. + + * Version 1.10.3. + + * sanity.sh (modules2-17): Update for 9 Oct 1998 change to + update_dirent_proc. + +1998-10-11 Jim Kingdon + + * commit.c (checkaddfile, commit_fileproc): A numeric value for + 'tag' does not mean that we are adding on a branch. + * sanity.sh (keywordlog): Adjust this test, to test for this + (replaces comment saying we should be doing it). + (rmadd): Likewise. + + * sanity.sh (rmadd): New test, tests for various existing + behaviors with "cvs ci -r". + +1998-10-09 Jim Kingdon + + * update.c (update_dirent_proc): For local CVS, if the directory + does not exist in the working directory nor in the repository, + just skip it. + * sanity.sh (dirs): New tests dirs-3a, dirs-7 and dirs-8 test for + this and related behaviors. Note that the new behavior was also + the previous behavior for remote; we are only changing it for local. + + * wrapper.c, cvsrc.c, ignore.c: Add comments about ignoring .cvsrc + and friends if we can't find a home directory. + * expand_path.c (expand_path): If we can't find the home + directory, give an error rather than a coredump (or worse). + * login.c (construct_cvspass_filename): Don't use errno in error + message; get_homedir doesn't set it. Add comment about this + message. + +1998-10-07 Jim Kingdon <kingdon@harvey.cyclic.com> + + * diff.c (diff): Set variables to NULL at the start, and free + memory at the end. + * sanity.sh (multiroot2): Add tests for this (before the fix, + multiroot2-12 would abort with "no more than two revisions/dates + can be specified"). + +1998-10-06 Jim Kingdon <kingdon@harvey.cyclic.com> + + * Makefile.in (installcheck check): Remove references to RCSBIN; + they don't do anything now that RCSBIN is ignored. + + * client.c: Clean up horrible confusion about whether stored_mode + or stored_mode_valid (or nothing :-)) indicates whether + stored_mode is allocated. Should fix crashes (for example, on NT + when the server has renamed multiple files from uppercase to + lowercase). + + * sanity.sh (dirs): New tests, tests for some cases involving + admins who do surgery on the repository. + +1998-10-03 Johannes Stezenbach <johannes.stezenbach@propack-data.de> + + * vers_ts.c (Version_TS): If UTIME_EXPECTS_WRITABLE, if + necessary change the file to be writable temporarily to set its + modification time. + +1998-10-03 Jim Kingdon <kingdon@harvey.cyclic.com> + + * client.c (handle_error): Add comment about indicating which + errors are from the server. + +1998-10-01 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (devcom-180): Allow one digit day. + +1998-09-30 Jim Kingdon <kingdon@harvey.cyclic.com> + + * main.c (main): Don't call Name_Root if -d specified. + * recurse.c (do_recursion, do_dir_proc): Don't check CVS/Root + if -d was specified. + * import.c (import): Indentation fix. + * sanity.sh (multiroot): Update for this change. + (reposmv): New test, tests for this. + +1998-09-28 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (multiroot2): New test, tests some nested directory + cases. + +1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (multiroot): Change a few comments which said modules + when they meant directories. + +1998-09-25 Jim Meyering <meyering@ascend.com> + + * sanity.sh (devcom-180): Add 0-9 to the range of characters allowed + in hostname regexp. + +1998-09-25 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (log2): New test log2-7a tests for one error handling + case. Add a comment about another. + +1998-09-24 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh: Change crerepos test back to :ext: (for several + reasons; see comments). + +1998-09-24 Noel Cragg <noel@swish.red-bean.com> + + * sanity.sh (rcslib-symlink-5, rcslib-symlink-6): new tests to + check the operation of "tag" when there are symlinks in the + repository. + + * rcs.c (RCS_checkin): remove old code that resolved the symlink + and call resolve_symlink instead. + (RCS_rewrite): call resolve_symlink before doing anything else to + make sure we're operating on the file and not the symlink. + + * subr.c (resolve_symlink): new routine -- resolves a symbolic + link chain to its destination. + * cvs.h: add prototype. + + * sanity.sh (basica-6.2, basica-6.3): changed match expressions to + reflect new diff output. + + * rcs.c (make_file_label): generate labels for files that include + the pathname so that output from "cvs diff" is useable by patch. + Looks like I came up with the mods as Andy Piper + <andyp@parallax.co.uk>; his patch was on the Cyclic unofficial + patches page. + + * sanity.sh: change remote access method from ext to fork. This + results in a significant speed improvement when running the + testsuite. The ext method on my machine (i586 120MHz Linux 2.0.35 + with TCP wrappers installed) runs in 450% of the time of the local + method while the fork method runs in only 150% of the time of the + local method! Yow! Am I SWAPPING yet?! + (crerepos-6a, crerepos-6b): change to reflect different error + messages for fork method. + (modes-15): same. + + * client.c (connect_to_forked_server): new routine. + (start_server): call the above when method is fork_method. + + * root.c: add a new method named "fork". This method uses the + remote protocol, but does so by forking a "cvs server" process + directly rather than doing "rsh host cvs server" (for example). + This new method has few advantages for day-to-day use, but has + three important benefits for debugging: + + 1) Most secure installations these days don't allow rsh access. + With this new method, we can still test the remote protocol on + these machines because we don't need to be able to make a local + TCP connection. + + 2) Even if installations allow rsh access, they almost always + have TCP wrappers to check permissions by IP/hostname. This + causes a short delay for every connection. For invocations from + the command line, this doesn't matter much, but it adds up to a + significant amount of time when running the testsuite. + + 3) On machines that can't (or do not usually) provide rshd + access (I'm thinking of WNT/W95 in particular), we can now run + tests of the remote protocol using this method. Indeed, we can + run remote protocol tests on any machine that has an + implementation of piped_child(). + + (parse_cvsroot): handle new method. + (error_exit, xstrdup, isabsolute): new stub functions to use when + compiling root.c with the DEBUG option. + (main): fix a few typos. + * cvs.h (CVSmethod): add fork_method. + + * server.c (create_adm_p): use Emptydir as the placeholder + directory instead of "." to avoid problems with "cvs update -d" et + al. + +1998-09-22 Noel Cragg <noel@swish.red-bean.com> + + * sanity.sh (devcom-180): fixed typo in regexp. + + * main.c (main): remove need_to_create_root and related code + (including CVS_IGNORE_REMOTE_ROOT environment variable). The + current implementation (just removed) of rewriting the contents of + the CVS/Root file isn't desirable for a number of reasons: + + 1) Only the top-level CVS/Root directory is updated. If we're + really interested in pointing our WD at another CVSROOT, we + should have a separate command. + + 2) With the new multiroot mods, we don't ever want to rewrite + CVS/Root files in the way the removed code did. Consider: + + cvs -d repository1 co a + cd a + cvs -d repository2 co b + cvs -d repository2 update b + + The update command would rewrite the contents of a/CVS/Root to + the incorrect value. Bad. We then wouldn't be talking to the + correct repository for files in a. + + 3) The removed code seems to be a quick hack to support working + directories checked out from multiple repositories. With the + CVS_IGNORE_REMOTE_ROOT variable set, one could perform commands + as in example 2, above, without worring about updating CVS/Root + files. While in pre-1.10.1 recursive commands wouldn't handle + that working directory hierarchy, one could use commands like + "cvs foo -l" instead. While not great, this allows you (with a + lot of manual interaction) to have a multiroot WD. Since we now + have multiroot mods checked in, we don't need this code. + + (lookup_command_attribute): while we don't need the + CVS_CMD_USES_WORK_DIR flag anymore (since it only was supporting + the need_to_create_root code), I'm leaving it in. It may come in + handy at some later date. + +1998-09-18 Jim Kingdon <kingdon@pennington.cyclic.com> + + * version.c: Advance version number to 1.10.2.1. + + * Version 1.10.2. + +1998-09-13 Jim Kingdon <kingdon@harvey.cyclic.com> + + * client.c: Refuse to Copy-file to another directory + * sanity.sh (client): New test, tests for this. + + * edit.c (editors_fileproc), watch.c (watchers_fileproc): Use + cvs_output rather than writing to stdout. + * sanity.sh (devcom): Use dotest for tests 178, 180, and 183 + (tests that we preserve existing behavior on "cvs editors"). + + * commit.c (check_fileproc): Don't allow commits in Emptydir. + * sanity.sh (emptydir-8): Test for this change in behavior. + + * sanity.sh: Add some compatibility tests to TODO comments at end. + +1998-09-10 Jim Kingdon <kingdon@harvey.cyclic.com> + + * wrapper.c (wrap_add): Remove obsolete comment about -m. + + * server.c (server_updated): Check for error from CVS_UNLINK. + +1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com> + + * server.c (serve_root): Allocate with malloc, not xmalloc. + + * root.c (set_local_cvsroot): Move memory allocation from here... + * server.c (serve_root): ...to here. Fixes error handling. + + * root.c (parse_cvsroot): Don't call check_root_consistent; + parse_cvsroot is only used for local and client. + * root.c (set_local_cvsroot): Move check_root_consistent + functionality from here... + * server.c (serve_root): ...to here. Fixes error handling. Also + made the error more explicit, while I am at it. + * server.c (Pserver_Repos): Now static. + * cvs.h: Don't declare it. + * root.c (check_root_consistent): Removed; no longer needed. + * sanity.sh (pserver): New test, tests for this behavior and some + other basic pserver stuff. + + * update.c (merge_file): Use cvs_output for "already contains the + differences" message. Found this one when I actually observed the + out-of-order bug in Real Life(TM). + +1998-09-09 Jim Kingdon + + * find_names.c (find_dirs): Make sure to zero errno before + going around the loop again. + * find_names.c (find_rcs): Make sure to set save_errno. + (thanks to Alexandre Parenteau for reporting both problems). + +1998-09-09 Jim Kingdon <kingdon@harvey.cyclic.com> and Michael Pakovic + + * edit.c (notify_do): Only free line if it is not NULL. + +1998-09-07 Jim Kingdon <kingdon@harvey.cyclic.com> + + * cvs.h: dirs_sent_to_server should not be inside + AUTH_SERVER_SUPPORT (reported by both Richard Levitte and Murray + Bishop, thanks). + + * lock.c, cvs.h: New variable lock_dir. + * parseinfo.c (parse_config): New option LockDir. + * lock.c (lock_name): New function, abstracts out lock file naming + and also supports LockDir. + * lock.c (lock_simple_remove, Reader_Lock, write_lock, set_lock): + Call it (6 places, to create/remove read/write/master locks). + (Lock_Cleanup): Refuse to reenter this function. + * sanity.sh (lockfiles): New test, tests for this feature. + +1998-09-03 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (multiroot): Expect ${TESTDIR} in output instead of + assuming it is /tmp/cvs-sanity (thanks to Mark D. Baushke of Cisco). + Clean up working directory when done (fixes apparent thinko). + + * server.c (create_adm_p): Fix one "return" which didn't return a + value. + (dirswitch): Check for errors from create_adm_p. + + * sanity.sh: Set LC_ALL rather than just LC_COLLATE. + +Wed Sep 2 02:30:22 1998 Jim Kingdon <kingdon@pennington.cyclic.com> + + * version.c: Bump version number to 1.10.1.1. + + * Version 1.10.1. + +1998-09-01 Jim Kingdon <kingdon@harvey.cyclic.com> + + Administrative note regarding Noel's changes to allow one to + switch from one CVS root to another in a single command: The + ChangeLog entries for the changes which Noel just checked in + appear for 1998-09-01, 1998-08-28, 1998-08-25, 1998-08-19, and + 1998-08-18, rather than being all together. + + * main.c (set_root_directory): Fix whitespace. + (main): Nuke new -m option and just have that message controlled + by -t. + * server.c (server): Revert the CVS_SERVER_SLEEP code back the way + it was in CVS 1.10. Attaching to the parent process is relatively + boring (you can just run "cvs server" under a debugger instead), + but connecting to the child process is what the old code was for. + * recurse.c, server.c: Remove DEBUG_NJC code. + +1998-09-01 Noel Cragg <noel@swish.red-bean.com> + + * server.c (do_cvs_command): add another environment variable, + CVS_SERVER_SLEEP2, after forking to pause the program so one can + attach a debugger. + + * sanity.sh (crerepos): clean up crerepos-18 now that multiroot + works in this case. + (multiroot): finalize tests for local vs. remote operation. + + * recurse.c (start_recursion): near the beginning, save the list + of directories to spoof as command-line arguments, if necessary. + Use that list near the end and call send_file_names to send those + arguments to the server. + (do_argument_proc): removed, since we call send_file_names now. + + * main.c (main): re-initialize dirs_sent_to_server on each pass + through the loop for each CVSROOT. + + * cvs.h: add proto for global variable which keeps track of which + directories have been sent to the server when in client mode. + + * client.c (is_arg_a_parent_or_listed_dir): new function. + (arg_should_not_be_sent_to_server): new function. Tries to decide + whether the given argument should be sent to the server, based on + the current CVSROOT and the list of directories sent to the + server. + (send_repository): add the directory name to the list of + directories sent to the server. + (send_file_names): call arg_should_not_be_sent_to_server. + + * add.c (add): switch the order of send_files and send_file_names + to make multiple repository support possible. send_files needs to + create a list of directories being requested so that + send_file_names can decide which command-line arguments to send to + the server for the given current CVSROOT. + * admin.c (admin): same. + * commit.c (commit): same. + * diff.c (diff): same. + * edit.c (editors): same. + * log.c (cvslog): same. + * rcs.c (annotate): same. + * remove.c (cvsremove): same. + * status.c (cvsstatus): same. + * tag.c (cvstag): same. + * update.c (update): same. + * watch.c (watch_addremove): same. + (watchers): same. + +1998-08-31 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh: Remove "debug" function; it was apparently checked + in accidentally by Norbert Kiesel's change. + +1998-08-31 Norbert Kiesel <nk@iname.com> + + * release.c (release): modify last patch to release so that + save_cwd is called only once and restore_cwd is always called when + neccessary. Also fixed a tiny memory leak. + + * sanity.sh (release): added some more tests for "cvs release" + including a test with two dirs and a "no" for the first one (which + fails without the above patch). + +1998-08-28 Noel Cragg <noel@swish.red-bean.com> + + * sanity.sh (crerepos-18): add new comment and change test + slightly to support multiroot. + (multiroot): add more tests. + + * server.c (create_adm_p): new function. + (dirswitch): call create_adm_p. Modify the code to always write a + new CVSADM_REP file, since create_adm_p might have put a + placeholder there and our value is guaranteed to be correct. + (server): move the CVS_SERVER_SLEEP check here so we can debug + things at an earlier stage. + + * recurse.c (start_recursion): add large comment about the ideal + solution to the "Argument xxx" problem. + + * main.c (main): move position of debugging comment for -m flag. + + * diff.c (diff): clear a static variable. + + * client.c (send_file_names): check to see if we should send this + argument to the server based on the contents of the appropriate + CVSADM directory. This avoids "nothing known about foo" messages + and problems with duplicate modules names in multiple + repositories. + (send_a_repository): change method of calculating toplevel_repos + to support multiple CVSROOTs. + (start_server): clear some static variables. + +1998-08-28 Jim Meyering <meyering@ascend.com> + + * sanity.sh (basicc-8, basicc-11): Use `.*' instead of explicit + `Operation not permitted'. Solaris2.5.1 gets a different error: + `Invalid argument'. + +1998-08-26 Eric M. Hopper + + * sanity.sh: Set LC_COLLATE to "C". + +1998-08-25 Noel Cragg <noel@swish.red-bean.com> + + * sanity.sh (multiroot): new set of tests to check the behavior of + multiroot. + + * diff.c (diff): set options value to NULL after freeing to reset + the state for the next time around. + +1998-08-25 Jim Kingdon <kingdon@harvey.cyclic.com> + + Fix problems with trying to rename an open file: + * rcs.c, rcs.h (RCS_setattic): New function. + * commit.c (remove_file, checkaddfile): Call it. + +1998-08-24 Jim Kingdon <kingdon@harvey.cyclic.com> + + * release.c (release): Use save_cwd and restore_cwd to get back to + where we started, rather than hoping that CVS_CHDIR ("..") will do + something useful. This removes the need for most of + release_delete, so remove that function and inline what is left. + * sanity.sh (basicc): Adjust tests for this fix, also some tests + with multiple arguments to "cvs release" (in the non-"-d"-case, it + would seem like the old code would CVS_CHDIR into directories and not + CVS_CHDIR back, but I'm not going to investigate this and it + should be a moot point with this fix.). + + * sanity.sh (basicc): Add tests for a serious bug in "cvs release + -d .". + + More error handling fixes: + * ignore.c (ignore_files): Check for errors from opendir and + readdir. + * find_names.c (Find_Names): Check for errors from find_rcs. + (find_rcs, find_dirs): Comment error handling better; also return + an error if we got one from readdir. + * filesubr.c (deep_remove_dir): Also check for errors from readdir. + * import.c (import_descend): Print message on error from opendir + or readdir. + * commit.c (remove_file): Check for errors from CVS_MKDIR and + CVS_RENAME. + (remove_file): No need to remove the file in the temporary + directory; server.c now informs time_stamp_server of what is going + on via CVS/Entries rather than a file with a kludged up timestamp. + * client.c, entries.c, login.c, logmsg.c, mkmodules.c, patch.c, + remove.c, update.c: Check for errors from unlink_file. + * mkmodules.c (write_dbmfile, rename_dbfile, rename_rcsfile): + Check for errors from fclose, CVS_RENAME, and CVS_STAT. + * mkmodules.c (checkout_file): Clarify error handling convention. + * mkmodules.c (mkmodules): Call checkout_file accordingly. + * entries.c (Entries_Open): Check for errors from fclose. + +1998-08-21 Ian Lance Taylor <ian@cygnus.com> + + * import.c (import): Output suggested merge command using + cvs_output_tagged rather than just cvs_output. Don't put + CVSroot_cmdline in the log file. + * client.c (importmergecmd): New static struct. + (handle_mt): Handle +importmergecmd tag. + * sanity.sh (import): Use an explicit -d in importb-2, to test + whether it is reported in the suggested merge command. + +1998-08-20 Ian Lance Taylor <ian@cygnus.com> + + * sanity.sh (import): Rewrite tests to use dotest. + +1998-08-20 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh: Add comments about binary files and cvs import. + +1998-08-19 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh (importc): Use ${username} in one place where I had + missed it. + + Make import -d work client/server: + * client.c, client.h (client_process_import_file): Take new + argument, for whether -d is specified, and send Checkin-time + request if it is set. + * import.c (import_descend): Pass it. + * main.c, cvs.h (date_to_internet): New function. + * server.c (server_modtime): Call date_to_internet. + * server.c (serve_checkin_time): New function. + (requests): Add "Checkin-time" request. + (serve_modified): If it was sent, set the timestamp in the + temporary directory. + * import.c (import): If the client sends a -d option, complain. + (import): For the server, always use the timestamps from the temp + directory. + (import): Don't send a -d option to the server. + * sanity.sh (importc): Add tests for import -d. + +Wed Aug 19 15:19:13 1998 Larry Jones <larry.jones@sdrc.com> + + * sanity.sh (unedit-without-baserev-5): use ${DOTSTAR} instead + of .* since we expect to match multiple lines. + +1998-08-19 Ian Lance Taylor <ian@cygnus.com> + + * cvs.h (CVSroot_cmdline): Declare. + * root.c (CVSroot_cmdline): Define. + * main.c (main): Set CVSroot_cmdline if the -d option is used. + * import.c (import): If CVSroot_cmdline is not NULL, then mention + an explicit -d option in the suggested merge command line. + +Wed Aug 19 00:28:50 1998 Noel Cragg <noel@swish.red-bean.com> + + * recurse.c (do_dir_proc): don't muck with CVS/Root directories + when running in server mode. + (do_recursion): same. + + * main.c (main): add the command-line option `m' to help debug the + multiroot environment; it prints out the value of CVSROOT for each + iteration through the main loop. Also, changed the main loop so + that it gets executed only once when running in server mode (the + server will only deal with a single CVSROOT). + + * recurse.c (do_recursion): change default for + PROCESS_THIS_DIRECTORY to true; we should always process a + directory's contents unless there's an existing CVS/Root file with + a different root than the current root to tell us otherwise. + (do_dir_proc): same. + +Tue Aug 18 14:30:59 1998 Noel Cragg <noel@swish.red-bean.com> + + * recurse.c (do_recursion): check the current value of CVS/Root + and add it to our list of CVSROOTs if it doesn't exist. Decide + whether or not to process files in this directory based based on + the value of CURRENT_ROOT. + (do_dir_proc): same. + + * main.c: add two new globals -- root_directories and current_root + -- which keep track of the values of CVSROOT we've seen and which + value of CVSROOT we're currently processing. + (main): put the main loop for stepping through cvsroot values + here, since we might need to send command-specific arguments for + every unique non-local cvsroot. Moved blocks of code around so + that one-time initializations happen first (outside the loop) and + the other stuff happens inside the loop. + (set_root_directory): helper function. + + * cvs.h: add prototypes for root_directories and current_root, two + new globals for keeping track of multiple CVSROOT information. + +1998-08-18 Jim Kingdon <kingdon@harvey.cyclic.com> + + * sanity.sh: Don't assume that the shell leaves $^ unexpanded in + an unquoted here-document (suggested by Bart Schaefer to help when + zsh is the shell). + +1998-08-17 Ian Lance Taylor <ian@cygnus.com> + + * commit.c (checkaddfile): Don't call fix_rcs_modes. + (fix_rcs_modes): Remove. + +1998-08-16 Jim Kingdon <kingdon@harvey.cyclic.com> + + * create_adm.c (Create_Admin): Don't condition traces on + SERVER_SUPPORT; SERVER_SUPPORT shouldn't do (much of) anything + independent of server_active. + + * sanity.sh (binfiles3): New test, for yet another binary file + bug (sigh). Thanks to Jason Aten for reporting this one. + +1998-08-15 Jim Kingdon <kingdon@harvey.cyclic.com> + + * rcscmds.c (call_diff_write_output): Update to reflect new + calling convention for the write_output callback. + +1998-08-15 Jim Meyering <meyering@ascend.com> + + * update.c (merge_file): Warn about failed unlink when not due + to ENOENT. + + * server.h (CLIENT_SERVER_STR): New macro + * create_adm.c (Create_Admin): Use it. + * entries.c (Scratch_Entry, Register): Use it. + * filesubr.c (copy_file, xchmod, rename_file, unlink_file): Use it. + * history.c (history_write): Use it. + * modules.c (do_module): Use it. + * no_diff.c (No_Difference): Use it. + * run.c (run_popen): Use it. + * server.c (server_register): Use it. + +1998-08-14 Jim Meyering <meyering@ascend.com> + + * hardlink.c (lookup_file_by_inode): Use existence_error rather than + comparing errno to ENOENT directly. + + * client.c (copy_a_file): Unlink destination before doing copy. + * sanity.sh (join-readonly-conflict): New test for this -- it would + fail only in client/server mode. + + * sanity.sh (rcsmerge-symlink-4): Don't use `test -L', it's not + portable. Instead, match against the output of `ls -l'. + (dotest tag8k-16): Simplify tag-construction code and at the same + time, avoid using expr's `length' and `substr' operators. Not + all versions of expr support those. + +1998-08-14 Jim Kingdon <kingdon@harvey.cyclic.com> + + * version.c: Bump version number to 1.10.0.1. + Thu Aug 13 11:15:24 1998 Noel Cragg <noel@swish.red-bean.com> * version.c: Change version number to 1.10 and name to `Halibut'. @@ -67,14 +1132,14 @@ Sun Jul 26 05:14:41 1998 Noel Cragg <noel@swish.red-bean.com> does not create CVS directories at top-level (except for the obvious "cvs co ."). Added a new configuration option to switch between 1.9 and 1.9.2 behavior. - + * recurse.c (do_argument_proc): new function. (start_recursion): in the case that we've done a command from top-level but have no CVS directory there, the behavior should be the same as "cvs <cmd> dir1 dir2 dir3...". Make sure that the appropriate "Argument" commands are sent to the server by calling walklist with do_argument_proc. - + * client.c (call_in_directory): only create the top-level CVS directory when we're checking out "." explicitly. The server will force creation of this directory in all other cases. diff --git a/gnu/usr.bin/cvs/src/add.c b/gnu/usr.bin/cvs/src/add.c index a4eed40d90c..fa569507ab6 100644 --- a/gnu/usr.bin/cvs/src/add.c +++ b/gnu/usr.bin/cvs/src/add.c @@ -240,8 +240,8 @@ add (argc, argv) free (repository); free (filedir); } - send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, 0, 0, SEND_BUILD_DIRS | SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server ("add\012", 0); if (message) free (message); @@ -420,7 +420,7 @@ file `%s' will be added on branch `%s' from version %s", re-adding file %s (in place of dead revision %s)", finfo.fullname, vers->vn_rcs); Register (entries, finfo.file, "0", vers->ts_user, - NULL, + vers->options, vers->tag, NULL, NULL); ++added_files; } diff --git a/gnu/usr.bin/cvs/src/admin.c b/gnu/usr.bin/cvs/src/admin.c index 72cddac616f..3e5f61d1146 100644 --- a/gnu/usr.bin/cvs/src/admin.c +++ b/gnu/usr.bin/cvs/src/admin.c @@ -375,9 +375,9 @@ admin (argc, argv) check_numeric (admin_data.delete_revs + 2, argc, argv); p = strchr (admin_data.delete_revs + 2, ':'); - if (p != NULL && isdigit (p[1])) + if (p != NULL && isdigit ((unsigned char) p[1])) check_numeric (p + 1, argc, argv); - else if (p != NULL && p[1] == ':' && isdigit(p[2])) + else if (p != NULL && p[1] == ':' && isdigit ((unsigned char) p[2])) check_numeric (p + 2, argc, argv); } @@ -414,8 +414,8 @@ admin (argc, argv) for (i = 0; i < admin_data.ac; ++i) send_arg (admin_data.av[i]); - send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, 0, 0, SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server ("admin\012", 0); err = get_responses_and_close (); goto return_it; @@ -492,7 +492,7 @@ admin_fileproc (callerdat, finfo) if (admin_data->branch != NULL) { char *branch = &admin_data->branch[2]; - if (*branch != '\0' && ! isdigit (*branch)) + if (*branch != '\0' && ! isdigit ((unsigned char) *branch)) { branch = RCS_whatbranch (rcs, admin_data->branch + 2); if (branch == NULL) @@ -604,12 +604,9 @@ admin_fileproc (callerdat, finfo) if (admin_data->kflag != NULL) { char *kflag = admin_data->kflag + 2; - if (!rcs->expand || strcmp (rcs->expand, kflag) != 0) - { - if (rcs->expand) - free (rcs->expand); - rcs->expand = xstrdup (kflag); - } + char *oldexpand = RCS_getexpand (rcs); + if (oldexpand == NULL || strcmp (oldexpand, kflag) != 0) + RCS_setexpand (rcs, kflag); } /* Handle miscellaneous options. TODO: decide whether any or all diff --git a/gnu/usr.bin/cvs/src/client.c b/gnu/usr.bin/cvs/src/client.c index 222e7f26534..02c31e223ae 100644 --- a/gnu/usr.bin/cvs/src/client.c +++ b/gnu/usr.bin/cvs/src/client.c @@ -148,6 +148,139 @@ static void handle_notified PROTO((char *, int)); static size_t try_read_from_server PROTO ((char *, size_t)); #endif /* CLIENT_SUPPORT */ +#ifdef CLIENT_SUPPORT + +/* We need to keep track of the list of directories we've sent to the + server. This list, along with the current CVSROOT, will help us + decide which command-line arguments to send. */ +List *dirs_sent_to_server = NULL; + +static int is_arg_a_parent_or_listed_dir PROTO((Node *, void *)); + +static int +is_arg_a_parent_or_listed_dir (n, d) + Node *n; + void *d; +{ + char *directory = n->key; /* name of the dir sent to server */ + char *this_argv_elem = (char *) d; /* this argv element */ + + /* Say we should send this argument if the argument matches the + beginning of a directory name sent to the server. This way, + the server will know to start at the top of that directory + hierarchy and descend. */ + + if (strncmp (directory, this_argv_elem, strlen (this_argv_elem)) == 0) + return 1; + + return 0; +} + +static int arg_should_not_be_sent_to_server PROTO((char *)); + +/* Return nonzero if this argument should not be sent to the + server. */ + +static int +arg_should_not_be_sent_to_server (arg) + char *arg; +{ + /* Decide if we should send this directory name to the server. We + should always send argv[i] if: + + 1) the list of directories sent to the server is empty (as it + will be for checkout, etc.). + + 2) the argument is "." + + 3) the argument is a file in the cwd and the cwd is checked out + from the current root + + 4) the argument lies within one of the paths in + dirs_sent_to_server. + + 4) */ + + if (list_isempty (dirs_sent_to_server)) + return 0; /* always send it */ + + if (strcmp (arg, ".") == 0) + return 0; /* always send it */ + + /* We should send arg if it is one of the directories sent to the + server or the parent of one; this tells the server to descend + the hierarchy starting at this level. */ + if (isdir (arg)) + { + if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, arg)) + return 0; + + /* If arg wasn't a parent, we don't know anything about it (we + would have seen something related to it during the + send_files phase). Don't send it. */ + return 1; + } + + /* Try to decide whether we should send arg to the server by + checking the contents of the corresponding CVSADM directory. */ + { + char *t, *this_root; + + /* Calculate "dirname arg" */ + for (t = arg + strlen (arg) - 1; t >= arg; t--) + { + if (ISDIRSEP(*t)) + break; + } + + /* Now we're either poiting to the beginning of the + string, or we found a path separator. */ + if (t >= arg) + { + /* Found a path separator. */ + char c = *t; + *t = '\0'; + + /* First, check to see if we sent this directory to the + server, because it takes less time than actually + opening the stuff in the CVSADM directory. */ + if (walklist (dirs_sent_to_server, is_arg_a_parent_or_listed_dir, + arg)) + { + *t = c; /* make sure to un-truncate the arg */ + return 0; + } + + /* Since we didn't find it in the list, check the CVSADM + files on disk. */ + this_root = Name_Root (arg, (char *) NULL); + *t = c; + } + else + { + /* We're at the beginning of the string. Look at the + CVSADM files in cwd. */ + this_root = Name_Root ((char *) NULL, (char *) NULL); + } + + /* Now check the value for root. */ + if (this_root && current_root + && (strcmp (this_root, current_root) != 0)) + { + /* Don't send this, since the CVSROOTs don't match. */ + free (this_root); + return 1; + } + free (this_root); + } + + /* OK, let's send it. */ + return 0; +} + + +#endif /* CLIENT_SUPPORT */ + #if defined(CLIENT_SUPPORT) || defined(SERVER_SUPPORT) /* Shared with server. */ @@ -710,25 +843,6 @@ int gzip_level; */ int file_gzip_level; -int filter_through_gzip (fd, dir, level, pidp) - int fd, dir, level; - pid_t *pidp; -{ - static char buf[5] = "-"; - static char *gzip_argv[3] = { "gzip", buf }; - - sprintf (buf+1, "%d", level); - return filter_stream_through_program (fd, dir, &gzip_argv[0], pidp); -} - -int filter_through_gunzip (fd, dir, pidp) - int fd, dir; - pid_t *pidp; -{ - static char *gunzip_argv[3] = { "gzip", "-d" }; - return filter_stream_through_program (fd, dir, &gunzip_argv[0], pidp); -} - #endif /* CLIENT_SUPPORT or SERVER_SUPPORT */ #ifdef CLIENT_SUPPORT @@ -737,7 +851,7 @@ int filter_through_gunzip (fd, dir, pidp) * The Repository for the top level of this command (not necessarily * the CVSROOT, just the current directory at the time we do it). */ -static char *toplevel_repos; +static char *toplevel_repos = NULL; /* Working directory when we first started. Note: we could speed things up on some systems by using savecwd.h here instead of just always @@ -770,6 +884,13 @@ handle_error (args, len) return; } ++p; + + /* Next we print the text of the message from the server. We + probably should be prefixing it with "server error" or some + such, because if it is something like "Out of memory", the + current behavior doesn't say which machine is out of + memory. */ + len -= p - args; something_printed = 0; for (; len > 0; --len) @@ -807,7 +928,7 @@ handle_valid_requests (args, len) ; else { - if (rq->status == rq_enableme) + if (rq->flags & RQ_ENABLEME) { /* * Server wants to know if we have this, to enable the @@ -817,16 +938,17 @@ handle_valid_requests (args, len) send_to_server ("\012", 0); } else - rq->status = rq_supported; + rq->flags |= RQ_SUPPORTED; } p = q; } while (q != NULL); for (rq = requests; rq->name != NULL; ++rq) { - if (rq->status == rq_essential) + if ((rq->flags & RQ_SUPPORTED) + || (rq->flags & RQ_ENABLEME)) + continue; + if (rq->flags & RQ_ESSENTIAL) error (1, 0, "request `%s' not supported by server", rq->name); - else if (rq->status == rq_optional) - rq->status = rq_not_supported; } } @@ -1210,7 +1332,14 @@ copy_a_file (data, ent_list, short_pathname, filename) for(p = newname; *p; p++) if(*p == '.' || *p == '#') *p = '_'; #endif - + /* cvsclient.texi has said for a long time that newname must be in the + same directory. Wouldn't want a malicious or buggy server overwriting + ~/.profile, /etc/passwd, or anything like that. */ + if (last_component (newname) != newname) + error (1, 0, "protocol error: Copy-file tried to specify directory"); + + if (unlink_file (newname) && !existence_error (errno)) + error (0, errno, "unable to remove %s", newname); copy_file (filename, newname); free (newname); } @@ -1317,6 +1446,23 @@ static int updated_seen; /* Filename from an "fname" tagged response within +updated/-updated. */ static char *updated_fname; +/* This struct is used to hold data when reading the +importmergecmd + and -importmergecmd tags. We put the variables in a struct only + for namespace issues. FIXME: As noted above, we need to develop a + more systematic approach. */ +static struct +{ + /* Nonzero if we have seen +importmergecmd and not -importmergecmd. */ + int seen; + /* Number of conflicts, from a "conflicts" tagged response. */ + int conflicts; + /* First merge tag, from a "mergetag1" tagged response. */ + char *mergetag1; + /* Second merge tag, from a "mergetag2" tagged response. */ + char *mergetag2; + /* Repository, from a "repository" tagged response. */ + char *repository; +} importmergecmd; /* Nonzero if we should arrange to return with a failure exit status. */ static int failure_exit; @@ -1367,7 +1513,7 @@ handle_checksum (args, len) stored_checksum_valid = 1; } -static int stored_mode_valid; +/* Mode that we got in a "Mode" response (malloc'd), or NULL if none. */ static char *stored_mode; static void handle_mode PROTO ((char *, int)); @@ -1377,12 +1523,9 @@ handle_mode (args, len) char *args; int len; { - if (stored_mode_valid) - error (1, 0, "protocol error: duplicate Mode"); if (stored_mode != NULL) - free (stored_mode); + error (1, 0, "protocol error: duplicate Mode"); stored_mode = xstrdup (args); - stored_mode_valid = 1; } /* Nonzero if time was specified in Mod-time. */ @@ -1622,9 +1765,11 @@ update_entries (data_arg, ent_list, short_pathname, filename) /* The Mode, Mod-time, and Checksum responses should not carry over to a subsequent Created (or whatever) response, even in the error case. */ - stored_mode_valid = 0; if (stored_mode != NULL) + { free (stored_mode); + stored_mode = NULL; + } stored_modtime_valid = 0; stored_checksum_valid = 0; @@ -1701,7 +1846,10 @@ update_entries (data_arg, ent_list, short_pathname, filename) read_from_server (buf, size); if (use_gzip) - gunzip_and_write (fd, short_pathname, buf, size); + { + if (gunzip_and_write (fd, short_pathname, buf, size)) + error (1, 0, "aborting due to compression error"); + } else if (write (fd, buf, size) != size) error (1, errno, "writing %s", short_pathname); } @@ -1747,7 +1895,11 @@ update_entries (data_arg, ent_list, short_pathname, filename) backup = xmalloc (strlen (filename) + 5); strcpy (backup, filename); strcat (backup, "~"); - (void) unlink_file (backup); + if (unlink_file (backup) < 0 + && !existence_error (errno)) + { + error (0, errno, "cannot remove %s", backup); + } if (!isfile (filename)) error (1, 0, "patch original file %s does not exist", short_pathname); @@ -1779,12 +1931,12 @@ update_entries (data_arg, ent_list, short_pathname, filename) run_arg (temp_filename); retcode = run_exec (DEVNULL, RUN_TTY, RUN_TTY, RUN_NORMAL); } - /* FIXME: should we really be silently ignoring errors? */ - (void) unlink_file (temp_filename); + if (unlink_file (temp_filename) < 0) + error (0, errno, "cannot remove %s", temp_filename); if (retcode == 0) { - /* FIXME: should we really be silently ignoring errors? */ - (void) unlink_file (backup); + if (unlink_file (backup) < 0) + error (0, errno, "cannot remove %s", backup); } else { @@ -1798,8 +1950,9 @@ update_entries (data_arg, ent_list, short_pathname, filename) path_tmp = xmalloc (strlen (filename) + 10); strcpy (path_tmp, filename); strcat (path_tmp, ".rej"); - /* FIXME: should we really be silently ignoring errors? */ - (void) unlink_file (path_tmp); + if (unlink_file (path_tmp) < 0 + && !existence_error (errno)) + error (0, errno, "cannot remove %s", path_tmp); free (path_tmp); error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0, @@ -1842,15 +1995,16 @@ update_entries (data_arg, ent_list, short_pathname, filename) { if (stored_checksum_valid) { - struct MD5Context context; + struct cvs_MD5Context context; unsigned char checksum[16]; /* We have a checksum. Check it before writing the file out, so that we don't have to read it back in again. */ - MD5Init (&context); - MD5Update (&context, (unsigned char *) patchedbuf, patchedlen); - MD5Final (checksum, &context); + cvs_MD5Init (&context); + cvs_MD5Update (&context, + (unsigned char *) patchedbuf, patchedlen); + cvs_MD5Final (checksum, &context); if (memcmp (checksum, stored_checksum, 16) != 0) { error (0, 0, @@ -1887,7 +2041,7 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (stored_checksum_valid && ! patch_failed) { FILE *e; - struct MD5Context context; + struct cvs_MD5Context context; unsigned char buf[8192]; unsigned len; unsigned char checksum[16]; @@ -1906,12 +2060,12 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (e == NULL) error (1, errno, "could not open %s", short_pathname); - MD5Init (&context); + cvs_MD5Init (&context); while ((len = fread (buf, 1, sizeof buf, e)) != 0) - MD5Update (&context, buf, len); + cvs_MD5Update (&context, buf, len); if (ferror (e)) error (1, errno, "could not read %s", short_pathname); - MD5Final (checksum, &context); + cvs_MD5Final (checksum, &context); fclose (e); @@ -1958,10 +2112,13 @@ update_entries (data_arg, ent_list, short_pathname, filename) free (buf); } - if (stored_mode_valid) + if (stored_mode != NULL) + { change_mode (filename, stored_mode, 1); - stored_mode_valid = 0; - + free (stored_mode); + stored_mode = NULL; + } + if (stored_modtime_valid) { struct utimbuf t; @@ -2263,7 +2420,20 @@ set_sticky (data, ent_list, short_pathname, filename) FILE *f; read_line (&tagspec); - f = open_file (CVSADM_TAG, "w+"); + + /* FIXME-update-dir: error messages should include the directory. */ + f = CVS_FOPEN (CVSADM_TAG, "w+"); + if (f == NULL) + { + /* Making this non-fatal is a bit of a kludge (see dirs2 + in testsuite). A better solution would be to avoid having + the server tell us about a directory we shouldn't be doing + anything with anyway (e.g. by handling directory + addition/removal better). */ + error (0, errno, "cannot open %s", CVSADM_TAG); + free (tagspec); + return; + } if (fprintf (f, "%s\n", tagspec) < 0) error (1, errno, "writing %s", CVSADM_TAG); if (fclose (f) == EOF) @@ -2568,6 +2738,22 @@ send_repository (dir, repos, update_dir) if (client_prune_dirs) add_prune_candidate (update_dir); + /* Add a directory name to the list of those sent to the + server. */ + if (update_dir && (*update_dir != '\0') + && (strcmp (update_dir, ".") != 0) + && (findnode (dirs_sent_to_server, update_dir) == NULL)) + { + Node *n; + n = getnode (); + n->type = UNKNOWN; + n->key = xstrdup (update_dir); + n->data = NULL; + + if (addnode (dirs_sent_to_server, n)) + error (1, 0, "cannot add directory %s to list", n->key); + } + /* 80 is large enough for any of CVSADM_*. */ adm_name = xmalloc (strlen (dir) + 80); @@ -2762,47 +2948,55 @@ send_a_repository (dir, repository, update_dir) * directories (and cvs invoked on the containing * directory). I'm not sure the latter case needs to * work. + * + * 21 Aug 1998: Well, Mr. Above-Comment-Writer, it + * does need to work after all. When we are using the + * client in a multi-cvsroot environment, it will be + * fairly common that we have the above case (e.g., + * cwd checked out from one repository but + * subdirectory checked out from another). We can't + * assume that by walking up a directory in our wd we + * necessarily walk up a directory in the repository. */ /* * This gets toplevel_repos wrong for "cvs update ../foo" * but I'm not sure toplevel_repos matters in that case. */ - int slashes_in_update_dir; - int slashes_skipped; - char *p; - /* - * Strip trailing slashes from the name of the update directory. - * Otherwise, running `cvs update dir/' provokes the failure - * `protocol error: illegal directory syntax in dir/' when - * running in client/server mode. - */ - strip_trailing_slashes (update_dir); + int repository_len, update_dir_len; - slashes_in_update_dir = 0; - for (p = update_dir; *p != '\0'; ++p) - if (*p == '/') - ++slashes_in_update_dir; + strip_trailing_slashes (update_dir); - slashes_skipped = 0; - p = repository + strlen (repository); - while (1) + repository_len = strlen (repository); + update_dir_len = strlen (update_dir); + + /* Try to remove the path components in UPDATE_DIR + from REPOSITORY. If the path elements don't exist + in REPOSITORY, or the removal of those path + elements mean that we "step above" + CVSroot_directory, set toplevel_repos to + CVSroot_directory. */ + if ((repository_len > update_dir_len) + && (strcmp (repository + repository_len - update_dir_len, + update_dir) == 0) + /* TOPLEVEL_REPOS shouldn't be above CVSroot_directory */ + && ((repository_len - update_dir_len) + > strlen (CVSroot_directory))) { - if (p == repository) - error (1, 0, - "internal error: not enough slashes in %s", - repository); - if (*p == '/') - ++slashes_skipped; - if (slashes_skipped < slashes_in_update_dir + 1) - --p; - else - break; + /* The repository name contains UPDATE_DIR. Set + toplevel_repos to the repository name without + UPDATE_DIR. */ + + toplevel_repos = xmalloc (repository_len - update_dir_len); + /* Note that we don't copy the trailing '/'. */ + strncpy (toplevel_repos, repository, + repository_len - update_dir_len - 1); + toplevel_repos[repository_len - update_dir_len - 1] = '\0'; + } + else + { + toplevel_repos = xstrdup (CVSroot_directory); } - toplevel_repos = xmalloc (p - repository + 1); - /* Note that we don't copy the trailing '/'. */ - strncpy (toplevel_repos, repository, p - repository); - toplevel_repos[p - repository] = '\0'; } } } @@ -3047,10 +3241,61 @@ handle_mt (args, len) case '+': if (strcmp (tag, "+updated") == 0) updated_seen = 1; + else if (strcmp (tag, "+importmergecmd") == 0) + importmergecmd.seen = 1; break; case '-': if (strcmp (tag, "-updated") == 0) updated_seen = 0; + else if (strcmp (tag, "-importmergecmd") == 0) + { + char buf[80]; + + /* Now that we have gathered the information, we can + output the suggested merge command. */ + + if (importmergecmd.conflicts == 0 + || importmergecmd.mergetag1 == NULL + || importmergecmd.mergetag2 == NULL + || importmergecmd.repository == NULL) + { + error (0, 0, + "invalid server: incomplete importmergecmd tags"); + break; + } + + sprintf (buf, "\n%d conflicts created by this import.\n", + importmergecmd.conflicts); + cvs_output (buf, 0); + cvs_output ("Use the following command to help the merge:\n\n", + 0); + cvs_output ("\t", 1); + cvs_output (program_name, 0); + if (CVSroot_cmdline != NULL) + { + cvs_output (" -d ", 0); + cvs_output (CVSroot_cmdline, 0); + } + cvs_output (" checkout -j", 0); + cvs_output (importmergecmd.mergetag1, 0); + cvs_output (" -j", 0); + cvs_output (importmergecmd.mergetag2, 0); + cvs_output (" ", 1); + cvs_output (importmergecmd.repository, 0); + cvs_output ("\n\n", 0); + + /* Clear the static variables so that everything is + ready for any subsequent importmergecmd tag. */ + importmergecmd.conflicts = 0; + free (importmergecmd.mergetag1); + importmergecmd.mergetag1 = NULL; + free (importmergecmd.mergetag2); + importmergecmd.mergetag2 = NULL; + free (importmergecmd.repository); + importmergecmd.repository = NULL; + + importmergecmd.seen = 0; + } break; default: if (updated_seen) @@ -3073,6 +3318,21 @@ handle_mt (args, len) or they reflect future extensions that we can safely ignore. */ } + else if (importmergecmd.seen) + { + if (strcmp (tag, "conflicts") == 0) + importmergecmd.conflicts = atoi (text); + else if (strcmp (tag, "mergetag1") == 0) + importmergecmd.mergetag1 = xstrdup (text); + else if (strcmp (tag, "mergetag2") == 0) + importmergecmd.mergetag2 = xstrdup (text); + else if (strcmp (tag, "repository") == 0) + importmergecmd.repository = xstrdup (text); + /* Swallow all other tags. Either they are text for + which we are going to print our own version when we + see -importmergecmd, or they are future extensions + we can safely ignore. */ + } else if (strcmp (tag, "newline") == 0) printf ("\n"); else if (text != NULL) @@ -3424,7 +3684,7 @@ supported_request (name) for (rq = requests; rq->name; rq++) if (!strcmp (rq->name, name)) - return rq->status == rq_supported; + return (rq->flags & RQ_SUPPORTED) != 0; error (1, 0, "internal error: testing support for unknown option?"); /* NOTREACHED */ return 0; @@ -3490,7 +3750,6 @@ recv_line (sock, resultp) int sock; char **resultp; { - int c; char *result; size_t input_index = 0; size_t result_size = 80; @@ -3500,23 +3759,16 @@ recv_line (sock, resultp) while (1) { char ch; - if (recv (sock, &ch, 1, 0) < 0) + int n; + n = recv (sock, &ch, 1, 0); + if (n <= 0) error (1, 0, "recv() from server %s: %s", CVSroot_hostname, - SOCK_STRERROR (SOCK_ERRNO)); - c = ch; - - if (c == EOF) - { - free (result); - - /* It's end of file. */ - error (1, 0, "end of file from server"); - } + n == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO)); - if (c == '\012') + if (ch == '\012') break; - result[input_index++] = c; + result[input_index++] = ch; while (input_index + 1 >= result_size) { result_size *= 2; @@ -3535,6 +3787,28 @@ recv_line (sock, resultp) return input_index; } +/* Connect to a forked server process. */ + +void +connect_to_forked_server (tofdp, fromfdp) + int *tofdp, *fromfdp; +{ + /* This is pretty simple. All we need to do is choose the correct + cvs binary and call piped_child. */ + + char *command[3]; + + command[0] = getenv ("CVS_SERVER"); + if (! command[0]) + command[0] = "cvs"; + + command[1] = "server"; + command[2] = NULL; + + if (! piped_child (command, tofdp, fromfdp)) + error (1, 0, "could not fork server process"); +} + /* Connect to the authenticating server. If VERIFY_ONLY is non-zero, then just verify that the password is @@ -3960,6 +4234,13 @@ start_server () int tofd, fromfd; char *log = getenv ("CVS_CLIENT_LOG"); + + /* Clear our static variables for this invocation. */ + if (toplevel_repos != NULL) + free (toplevel_repos); + toplevel_repos = NULL; + + /* Note that generally speaking we do *not* fall back to a different way of connecting if the first one does not work. This is slow (*really* slow on a 14.4kbps link); the clean way to have a CVS @@ -4020,6 +4301,10 @@ the :server: access method is not supported by this port of CVS"); #endif break; + case fork_method: + connect_to_forked_server (&tofd, &fromfd); + break; + default: error (1, 0, "\ (start_server internal error): unknown access method"); @@ -4119,7 +4404,11 @@ the :server: access method is not supported by this port of CVS"); free (last_update_dir); last_update_dir = NULL; stored_checksum_valid = 0; - stored_mode_valid = 0; + if (stored_mode != NULL) + { + free (stored_mode); + stored_mode = NULL; + } if (strcmp (command_name, "init") != 0) { @@ -4648,9 +4937,10 @@ send_modified (file, short_pathname, vers) { size_t newsize = 0; - read_and_gzip (fd, short_pathname, (unsigned char **)&buf, - &bufsize, &newsize, - file_gzip_level); + if (read_and_gzip (fd, short_pathname, (unsigned char **)&buf, + &bufsize, &newsize, + file_gzip_level)) + error (1, 0, "aborting due to compression error"); if (close (fd) < 0) error (0, errno, "warning: can't close %s", short_pathname); @@ -5050,7 +5340,7 @@ send_file_names (argc, argv, flags) int i; int level; int max_level; - + /* The fact that we do this here as well as start_recursion is a bit of a performance hit. Perhaps worth cleaning up someday. */ if (flags & SEND_EXPAND_WILD) @@ -5091,6 +5381,9 @@ send_file_names (argc, argv, flags) char *p = argv[i]; char *line = NULL; + if (arg_should_not_be_sent_to_server (argv[i])) + continue; + #ifdef FILENAMES_CASE_INSENSITIVE /* We want to send the file name as it appears in CVS/Entries. We put this inside an ifdef @@ -5224,7 +5517,7 @@ client_import_setup (repository) */ int client_process_import_file (message, vfile, vtag, targc, targv, repository, - all_files_binary) + all_files_binary, modtime) char *message; char *vfile; char *vtag; @@ -5232,6 +5525,9 @@ client_process_import_file (message, vfile, vtag, targc, targv, repository, char *targv[]; char *repository; int all_files_binary; + + /* Nonzero for "import -d". */ + int modtime; { char *update_dir; char *fullname; @@ -5281,6 +5577,28 @@ client_process_import_file (message, vfile, vtag, targc, targv, repository, error (0, 0, "warning: ignoring -k options due to server limitations"); } + if (modtime) + { + if (supported_request ("Checkin-time")) + { + struct stat sb; + char *rcsdate; + char netdate[MAXDATELEN]; + + if (CVS_STAT (vfile, &sb) < 0) + error (1, errno, "cannot stat %s", fullname); + rcsdate = date_from_time_t (sb.st_mtime); + date_to_internet (netdate, rcsdate); + free (rcsdate); + + send_to_server ("Checkin-time ", 0); + send_to_server (netdate, 0); + send_to_server ("\012", 1); + } + else + error (0, 0, + "warning: ignoring -d option due to server limitations"); + } send_modified (vfile, fullname, &vers); if (vers.options != NULL) free (vers.options); @@ -5466,27 +5784,15 @@ option_with_arg (option, arg) We then convert that to the format required in the protocol (including the "-D" option) and send it. According to - cvsclient.texi, RFC 822/1123 format is preferred, but for now we - use the format that we always have, for - conservatism/laziness/paranoia. As far as I know all servers - support the RFC 822/1123 format, so probably there would be no - particular danger in switching. */ + cvsclient.texi, RFC 822/1123 format is preferred. */ void client_senddate (date) const char *date; { - int year, month, day, hour, minute, second; - char buf[100]; - - if (sscanf (date, SDATEFORM, &year, &month, &day, &hour, &minute, &second) - != 6) - { - error (1, 0, "client_senddate: sscanf failed on date"); - } + char buf[MAXDATELEN]; - sprintf (buf, "%d/%d/%d %d:%d:%d GMT", month, day, year, - hour, minute, second); + date_to_internet (buf, (char *)date); option_with_arg ("-D", buf); } diff --git a/gnu/usr.bin/cvs/src/client.h b/gnu/usr.bin/cvs/src/client.h index 996dc63366c..c323cf38ffb 100644 --- a/gnu/usr.bin/cvs/src/client.h +++ b/gnu/usr.bin/cvs/src/client.h @@ -6,8 +6,6 @@ extern int change_mode PROTO((char *, char *, int)); extern int gzip_level; extern int file_gzip_level; -extern int filter_through_gzip PROTO((int, int, int, pid_t *)); -extern int filter_through_gunzip PROTO((int, int, pid_t *)); #if defined (CLIENT_SUPPORT) || defined (SERVER_SUPPORT) @@ -195,7 +193,8 @@ extern char *toplevel_wd; extern void client_import_setup PROTO((char *repository)); extern int client_process_import_file PROTO((char *message, char *vfile, char *vtag, - int targc, char *targv[], char *repository, int all_files_binary)); + int targc, char *targv[], char *repository, int all_files_binary, + int modtime)); extern void client_import_done PROTO((void)); extern void client_notify PROTO((char *, char *, char *, int, char *)); #endif /* CLIENT_SUPPORT */ diff --git a/gnu/usr.bin/cvs/src/create_adm.c b/gnu/usr.bin/cvs/src/create_adm.c index c51785c317c..7f8f581b0b9 100644 --- a/gnu/usr.bin/cvs/src/create_adm.c +++ b/gnu/usr.bin/cvs/src/create_adm.c @@ -36,15 +36,13 @@ Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn) char *reposcopy; char *tmp; -#ifdef SERVER_SUPPORT if (trace) { - fprintf (stderr, "%c-> Create_Admin (%s, %s, %s, %s, %s, %d, %d)\n", - (server_active) ? 'S' : ' ', + fprintf (stderr, "%s-> Create_Admin (%s, %s, %s, %s, %s, %d, %d)\n", + CLIENT_SERVER_STR, dir, update_dir, repository, tag ? tag : "", date ? date : "", nonbranch, warn); } -#endif if (noexec) return 0; diff --git a/gnu/usr.bin/cvs/src/cvsrc.c b/gnu/usr.bin/cvs/src/cvsrc.c index e35ec219b72..accc53fa761 100644 --- a/gnu/usr.bin/cvs/src/cvsrc.c +++ b/gnu/usr.bin/cvs/src/cvsrc.c @@ -65,6 +65,11 @@ read_cvsrc (argc, argv, cmdname) /* determine filename for ~/.cvsrc */ homedir = get_homedir (); + /* If we can't find a home directory, ignore ~/.cvsrc. This may + make tracking down problems a bit of a pain, but on the other + hand it might be obnoxious to complain when CVS will function + just fine without .cvsrc (and many users won't even know what + .cvsrc is). */ if (!homedir) return; @@ -96,7 +101,7 @@ read_cvsrc (argc, argv, cmdname) /* stop if we match the current command */ if (!strncmp (line, cmdname, command_len) - && isspace (*(line + command_len))) + && isspace ((unsigned char) *(line + command_len))) { found = 1; break; diff --git a/gnu/usr.bin/cvs/src/diff.c b/gnu/usr.bin/cvs/src/diff.c index 341c04c248f..aa35885af30 100644 --- a/gnu/usr.bin/cvs/src/diff.c +++ b/gnu/usr.bin/cvs/src/diff.c @@ -40,7 +40,13 @@ static enum diff_file diff_file_nodiff PROTO ((struct file_info *finfo, static int diff_fileproc PROTO ((void *callerdat, struct file_info *finfo)); static void diff_mark_errors PROTO((int err)); + +/* Global variables. Would be cleaner if we just put this stuff in a + struct like log.c does. */ + +/* Command line tags, from -r option. Points into argv. */ static char *diff_rev1, *diff_rev2; +/* Command line dates, from -D option. Malloc'd. */ static char *diff_date1, *diff_date2; static char *use_rev1, *use_rev2; static int have_rev1_label, have_rev2_label; @@ -224,15 +230,19 @@ diff (argc, argv) * non-recursive/recursive diff. */ - /* For server, need to be able to do this command more than once - (according to the protocol spec, even if the current client - doesn't use it). */ + /* Clean out our global variables (multiroot can call us multiple + times and the server can too, if the client sends several + diff commands). */ if (opts == NULL) { opts_allocated = 1; opts = xmalloc (opts_allocated); } opts[0] = '\0'; + diff_rev1 = NULL; + diff_rev2 = NULL; + diff_date1 = NULL; + diff_date2 = NULL; optind = 0; while ((c = getopt_long (argc, argv, @@ -353,17 +363,18 @@ diff (argc, argv) if (diff_date2) client_senddate (diff_date2); - send_file_names (argc, argv, SEND_EXPAND_WILD); - /* Send the current files unless diffing two revs from the archive */ if (diff_rev2 == NULL && diff_date2 == NULL) send_files (argc, argv, local, 0, 0); else send_files (argc, argv, local, 0, SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); + send_to_server ("diff\012", 0); err = get_responses_and_close (); free (options); + options = NULL; return (err); } #endif @@ -386,6 +397,13 @@ diff (argc, argv) /* clean up */ free (options); + options = NULL; + + if (diff_date1 != NULL) + free (diff_date1); + if (diff_date2 != NULL) + free (diff_date2); + return (err); } diff --git a/gnu/usr.bin/cvs/src/edit.c b/gnu/usr.bin/cvs/src/edit.c index aa0f4c48142..9d9a588cd2a 100644 --- a/gnu/usr.bin/cvs/src/edit.c +++ b/gnu/usr.bin/cvs/src/edit.c @@ -89,8 +89,8 @@ watch_onoff (argc, argv) if (local) send_arg ("-l"); - send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, local, 0, SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server (turning_on ? "watch-on\012" : "watch-off\012", 0); return get_responses_and_close (); } @@ -876,7 +876,8 @@ notify_do (type, filename, who, val, watches, repository) error (0, errno, "cannot close %s", usersname); } free (usersname); - free (line); + if (line != NULL) + free (line); if (args.notifyee == NULL) { @@ -1008,29 +1009,29 @@ editors_fileproc (callerdat, finfo) if (them == NULL) return 0; - fputs (finfo->fullname, stdout); + cvs_output (finfo->fullname, 0); p = them; while (1) { - putc ('\t', stdout); + cvs_output ("\t", 1); while (*p != '>' && *p != '\0') - putc (*p++, stdout); + cvs_output (p++, 1); if (*p == '\0') { /* Only happens if attribute is misformed. */ - putc ('\n', stdout); + cvs_output ("\n", 1); break; } ++p; - putc ('\t', stdout); + cvs_output ("\t", 1); while (1) { while (*p != '+' && *p != ',' && *p != '\0') - putc (*p++, stdout); + cvs_output (p++, 1); if (*p == '\0') { - putc ('\n', stdout); + cvs_output ("\n", 1); goto out; } if (*p == ',') @@ -1039,9 +1040,9 @@ editors_fileproc (callerdat, finfo) break; } ++p; - putc ('\t', stdout); + cvs_output ("\t", 1); } - putc ('\n', stdout); + cvs_output ("\n", 1); } out:; return 0; @@ -1086,8 +1087,8 @@ editors (argc, argv) if (local) send_arg ("-l"); - send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, local, 0, SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server ("editors\012", 0); return get_responses_and_close (); } diff --git a/gnu/usr.bin/cvs/src/entries.c b/gnu/usr.bin/cvs/src/entries.c index aeab31356c3..7e258a97dc2 100644 --- a/gnu/usr.bin/cvs/src/entries.c +++ b/gnu/usr.bin/cvs/src/entries.c @@ -157,7 +157,9 @@ write_entries (list) rename_file (entfilename, CVSADM_ENT); /* now, remove the log file */ - unlink_file (CVSADM_ENTLOG); + if (unlink_file (CVSADM_ENTLOG) < 0 + && !existence_error (errno)) + error (0, errno, "cannot remove %s", CVSADM_ENTLOG); } /* @@ -171,12 +173,8 @@ Scratch_Entry (list, fname) Node *node; if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> Scratch_Entry(%s)\n", - (server_active) ? 'S' : ' ', fname); -#else - (void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname); -#endif + (void) fprintf (stderr, "%s-> Scratch_Entry(%s)\n", + CLIENT_SERVER_STR, fname); /* hashlookup to see if it is there */ if ((node = findnode_fn (list, fname)) != NULL) @@ -231,18 +229,11 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict) if (trace) { -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> Register(%s, %s, %s%s%s, %s, %s %s)\n", - (server_active) ? 'S' : ' ', + (void) fprintf (stderr, "%s-> Register(%s, %s, %s%s%s, %s, %s %s)\n", + CLIENT_SERVER_STR, fname, vn, ts ? ts : "", ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "", options, tag ? tag : "", date ? date : ""); -#else - (void) fprintf (stderr, "-> Register(%s, %s, %s%s%s, %s, %s %s)\n", - fname, vn, ts ? ts : "", - ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "", - options, tag ? tag : "", date ? date : ""); -#endif } entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date, @@ -252,7 +243,15 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict) if (!noexec) { entfilename = CVSADM_ENTLOG; - entfile = open_file (entfilename, "a"); + entfile = CVS_FOPEN (entfilename, "a"); + + if (entfile == NULL) + { + /* Warning, not error, as in write_entries. */ + /* FIXME-update-dir: should be including update_dir in message. */ + error (0, errno, "cannot open %s", entfilename); + return; + } if (fprintf (entfile, "A ") < 0) error (1, errno, "cannot write %s", entfilename); @@ -507,7 +506,9 @@ Entries_Open (aflag, update_dir) (void) AddEntryNode (entries, ent); } - fclose (fpin); + if (fclose (fpin) < 0) + /* FIXME-update-dir: should include update_dir in message. */ + error (0, errno, "cannot close %s", CVSADM_ENT); } fpin = CVS_FOPEN (CVSADM_ENTLOG, "r"); @@ -535,7 +536,9 @@ Entries_Open (aflag, update_dir) } } do_rewrite = 1; - fclose (fpin); + if (fclose (fpin) < 0) + /* FIXME-update-dir: should include update_dir in message. */ + error (0, errno, "cannot close %s", CVSADM_ENTLOG); } /* Update the list private data to indicate whether subdirectory diff --git a/gnu/usr.bin/cvs/src/error.c b/gnu/usr.bin/cvs/src/error.c index 9dcc162261e..64b686cae44 100644 --- a/gnu/usr.bin/cvs/src/error.c +++ b/gnu/usr.bin/cvs/src/error.c @@ -61,8 +61,6 @@ void exit (); extern char *strerror (); #endif -extern int vasprintf (); - void error_exit PROTO ((void)) { @@ -80,7 +78,10 @@ error_exit PROTO ((void)) } /* Print the program name and error message MESSAGE, which is a printf-style - format string with optional args. + format string with optional args. This is a very limited printf subset: + %s, %d, %c, %x and %% only (without anything between the % and the s, + d, &c). Callers who want something fancier can use sprintf. + If ERRNUM is nonzero, print its corresponding system error message. Exit with status EXIT_FAILURE if STATUS is nonzero. If MESSAGE is "", no need to print a message. @@ -100,7 +101,7 @@ error_exit PROTO ((void)) /* VARARGS */ void -#if defined (HAVE_VPRINTF) && defined (__STDC__) +#if defined (__STDC__) error (int status, int errnum, const char *message, ...) #else error (status, errnum, message, va_alist) @@ -110,116 +111,84 @@ error (status, errnum, message, va_alist) va_dcl #endif { - /* Prevent strtoul (via int_vasprintf) from clobbering it. */ int save_errno = errno; -#ifdef HAVE_VPRINTF if (message[0] != '\0') { va_list args; - char *mess = NULL; - char *entire; - size_t len; - - VA_START (args, message); - vasprintf (&mess, message, args); - va_end (args); - - if (mess == NULL) + const char *p; + char *q; + char *str; + int num; + unsigned int unum; + int ch; + unsigned char buf[100]; + + cvs_outerr (program_name, 0); + if (command_name && *command_name) { - entire = NULL; - status = 1; + cvs_outerr (" ", 1); + if (status != 0) + cvs_outerr ("[", 1); + cvs_outerr (command_name, 0); + if (status != 0) + cvs_outerr (" aborted]", 0); } - else + cvs_outerr (": ", 2); + + VA_START (args, message); + p = message; + while ((q = strchr (p, '%')) != NULL) { - len = strlen (mess) + strlen (program_name) + 80; - if (command_name != NULL) - len += strlen (command_name); - if (errnum != 0) - len += strlen (strerror (errnum)); - entire = malloc (len); - if (entire == NULL) - { - free (mess); - status = 1; - } - else + static const char msg[] = + "\ninternal error: bad % in error()\n"; + if (q - p > 0) + cvs_outerr (p, q - p); + + switch (q[1]) { - strcpy (entire, program_name); - if (command_name != NULL && command_name[0] != '\0') - { - strcat (entire, " "); - if (status != 0) - strcat (entire, "["); - strcat (entire, command_name); - if (status != 0) - strcat (entire, " aborted]"); - } - strcat (entire, ": "); - strcat (entire, mess); - if (errnum != 0) - { - strcat (entire, ": "); - strcat (entire, strerror (errnum)); - } - strcat (entire, "\n"); - free (mess); + case 's': + str = va_arg (args, char *); + cvs_outerr (str, strlen (str)); + break; + case 'd': + num = va_arg (args, int); + sprintf (buf, "%d", num); + cvs_outerr (buf, strlen (buf)); + break; + case 'x': + unum = va_arg (args, unsigned int); + sprintf (buf, "%x", unum); + cvs_outerr (buf, strlen (buf)); + break; + case 'c': + ch = va_arg (args, int); + buf[0] = ch; + cvs_outerr (buf, 1); + break; + case '%': + cvs_outerr ("%", 1); + break; + default: + cvs_outerr (msg, sizeof (msg) - 1); + /* Don't just keep going, because q + 1 might point to the + terminating '\0'. */ + goto out; } + p = q + 2; } - cvs_outerr (entire ? entire : "out of memory\n", 0); - if (entire != NULL) - free (entire); - } - -#else /* No HAVE_VPRINTF */ - /* I think that all relevant systems have vprintf these days. But - just in case, I'm leaving this code here. */ - - if (message[0] != '\0') - { - FILE *out = stderr; + cvs_outerr (p, strlen (p)); + out: + va_end (args); - if (error_use_protocol) + if (errnum != 0) { - out = stdout; - printf ("E "); + cvs_outerr (": ", 2); + cvs_outerr (strerror (errnum), 0); } - - if (command_name && *command_name) - { - if (status) - fprintf (out, "%s [%s aborted]: ", program_name, command_name); - else - fprintf (out, "%s %s: ", program_name, command_name); - } - else - fprintf (out, "%s: ", program_name); - -#ifdef HAVE_VPRINTF - VA_START (args, message); - vfprintf (out, message, args); - va_end (args); -#else -#ifdef HAVE_DOPRNT - _doprnt (message, &args, out); -#else - fprintf (out, message, a1, a2, a3, a4, a5, a6, a7, a8); -#endif -#endif - if (errnum) - fprintf (out, ": %s", strerror (errnum)); - putc ('\n', out); - - /* In the error_use_protocol case, this probably does - something useful. In most other cases, I suspect it is a - noop (either stderr is line buffered or we haven't written - anything to stderr) or unnecessary (if stderr is not line - buffered, maybe there is a reason....). */ - fflush (out); + cvs_outerr ("\n", 1); } -#endif /* No HAVE_VPRINTF */ - if (status) error_exit (); errno = save_errno; diff --git a/gnu/usr.bin/cvs/src/expand_path.c b/gnu/usr.bin/cvs/src/expand_path.c index 5cf414e35d7..25e561cc0e6 100644 --- a/gnu/usr.bin/cvs/src/expand_path.c +++ b/gnu/usr.bin/cvs/src/expand_path.c @@ -43,7 +43,7 @@ variable_set (nameval) Node *node; p = nameval; - while (isalnum (*p) || *p == '_') + while (isalnum ((unsigned char) *p) || *p == '_') ++p; if (*p != '=') error (1, 0, "illegal character in user variable name in %s", nameval); @@ -133,7 +133,7 @@ expand_path (name, file, line) { if (flag ? *s =='}' - : isalnum (*s) == 0 && *s != '_') + : isalnum ((unsigned char) *s) == 0 && *s != '_') break; doff = d - mybuf; expand_string (&mybuf, &mybuf_size, doff + 1); @@ -214,6 +214,9 @@ expand_path (name, file, line) t = ps->pw_dir; #endif } + if (t == NULL) + error (1, 0, "cannot find home directory"); + doff = d - buf; expand_string (&buf, &buf_size, doff + 1); d = buf + doff; @@ -283,7 +286,7 @@ expand_variable (name, file, line) return Editor; else if (strcmp (name, "USER") == 0) return getcaller (); - else if (isalpha (name[0])) + else if (isalpha ((unsigned char) name[0])) { /* These names are reserved for future versions of CVS, so that is why it is an error. */ diff --git a/gnu/usr.bin/cvs/src/filesubr.c b/gnu/usr.bin/cvs/src/filesubr.c index 1c24b2f64fa..f3da62a5efd 100644 --- a/gnu/usr.bin/cvs/src/filesubr.c +++ b/gnu/usr.bin/cvs/src/filesubr.c @@ -34,12 +34,8 @@ copy_file (from, to) int fdin, fdout; if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> copy(%s,%s)\n", - (server_active) ? 'S' : ' ', from, to); -#else - (void) fprintf (stderr, "-> copy(%s,%s)\n", from, to); -#endif + (void) fprintf (stderr, "%s-> copy(%s,%s)\n", + CLIENT_SERVER_STR, from, to); if (noexec) return; @@ -377,14 +373,9 @@ xchmod (fname, writable) } if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> chmod(%s,%o)\n", - (server_active) ? 'S' : ' ', fname, + (void) fprintf (stderr, "%s-> chmod(%s,%o)\n", + CLIENT_SERVER_STR, fname, (unsigned int) mode); -#else - (void) fprintf (stderr, "-> chmod(%s,%o)\n", fname, - (unsigned int) mode); -#endif if (noexec) return; @@ -401,12 +392,8 @@ rename_file (from, to) const char *to; { if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> rename(%s,%s)\n", - (server_active) ? 'S' : ' ', from, to); -#else - (void) fprintf (stderr, "-> rename(%s,%s)\n", from, to); -#endif + (void) fprintf (stderr, "%s-> rename(%s,%s)\n", + CLIENT_SERVER_STR, from, to); if (noexec) return; @@ -422,12 +409,8 @@ unlink_file (f) const char *f; { if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> unlink(%s)\n", - (server_active) ? 'S' : ' ', f); -#else - (void) fprintf (stderr, "-> unlink(%s)\n", f); -#endif + (void) fprintf (stderr, "%s-> unlink(%s)\n", + CLIENT_SERVER_STR, f); if (noexec) return (0); @@ -506,6 +489,7 @@ deep_remove_dir (path) */ return -1; + errno = 0; while ((dp = readdir (dirp)) != NULL) { char *buf; @@ -539,6 +523,15 @@ deep_remove_dir (path) } } free (buf); + + errno = 0; + } + if (errno != 0) + { + int save_errno = errno; + closedir (dirp); + errno = save_errno; + return -1; } closedir (dirp); return rmdir (path); diff --git a/gnu/usr.bin/cvs/src/find_names.c b/gnu/usr.bin/cvs/src/find_names.c index 4fa795a1f27..6fb927bf6a9 100644 --- a/gnu/usr.bin/cvs/src/find_names.c +++ b/gnu/usr.bin/cvs/src/find_names.c @@ -50,6 +50,11 @@ add_entries_proc (node, closure) return (0); } +/* Find files in the repository and/or working directory. On error, + may either print a nonfatal error and return NULL, or just give + a fatal error. On success, return non-NULL (even if it is an empty + list). */ + List * Find_Names (repository, which, aflag, optentries) char *repository; @@ -85,7 +90,10 @@ Find_Names (repository, which, aflag, optentries) { /* search the repository */ if (find_rcs (repository, files) != 0) - error (1, errno, "cannot open directory %s", repository); + { + error (0, errno, "cannot open directory %s", repository); + goto error_exit; + } /* search the attic too */ if (which & W_ATTIC) @@ -93,7 +101,11 @@ Find_Names (repository, which, aflag, optentries) char *dir; dir = xmalloc (strlen (repository) + sizeof (CVSATTIC) + 10); (void) sprintf (dir, "%s/%s", repository, CVSATTIC); - (void) find_rcs (dir, files); + if (find_rcs (dir, files) != 0 + && !existence_error (errno)) + /* For now keep this a fatal error, seems less useful + for access control than the case above. */ + error (1, errno, "cannot open directory %s", dir); free (dir); } } @@ -101,6 +113,9 @@ Find_Names (repository, which, aflag, optentries) /* sort the list into alphabetical order and return it */ sortlist (files, fsortcmp); return (files); + error_exit: + dellist (&files); + return NULL; } /* @@ -235,7 +250,9 @@ Find_Directories (repository, which, entries) /* * Finds all the ,v files in the argument directory, and adds them to the * files list. Returns 0 for success and non-zero if the argument directory - * cannot be opened. + * cannot be opened, in which case errno is set to indicate the error. + * In the error case LIST is left in some reasonable state (unchanged, or + * containing the files which were found before the error occurred). */ static int find_rcs (dir, list) @@ -251,6 +268,7 @@ find_rcs (dir, list) return (1); /* read the dir, grabbing the ,v files */ + errno = 0; while ((dp = readdir (dirp)) != NULL) { if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0) @@ -265,6 +283,14 @@ find_rcs (dir, list) if (addnode (list, p) != 0) freenode (p); } + errno = 0; + } + if (errno != 0) + { + int save_errno = errno; + (void) closedir (dirp); + errno = save_errno; + return 1; } (void) closedir (dirp); return (0); @@ -275,7 +301,7 @@ find_rcs (dir, list) * the specified list. Sub-directories without a CVS administration * directory are optionally ignored. If ENTRIES is not NULL, all * files on the list are ignored. Returns 0 for success or 1 on - * error. + * error, in which case errno is set to indicate the error. */ static int find_dirs (dir, list, checkadm, entries) @@ -305,6 +331,7 @@ find_dirs (dir, list, checkadm, entries) return (1); /* read the dir, grabbing sub-dirs */ + errno = 0; while ((dp = readdir (dirp)) != NULL) { if (strcmp (dp->d_name, ".") == 0 || @@ -312,34 +339,34 @@ find_dirs (dir, list, checkadm, entries) strcmp (dp->d_name, CVSATTIC) == 0 || strcmp (dp->d_name, CVSLCK) == 0 || strcmp (dp->d_name, CVSREP) == 0) - continue; + goto do_it_again; /* findnode() is going to be significantly faster than stat() because it involves no system calls. That is why we bother with the entries argument, and why we check this first. */ if (entries != NULL && findnode (entries, dp->d_name) != NULL) - continue; + goto do_it_again; if (skip_emptydir && strcmp (dp->d_name, CVSNULLREPOS) == 0) - continue; + goto do_it_again; #ifdef DT_DIR if (dp->d_type != DT_DIR) { if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK) - continue; + goto do_it_again; #endif /* don't bother stating ,v files */ if (CVS_FNMATCH (RCSPAT, dp->d_name, 0) == 0) - continue; + goto do_it_again; expand_string (&tmp, &tmp_size, strlen (dir) + strlen (dp->d_name) + 10); sprintf (tmp, "%s/%s", dir, dp->d_name); if (!isdir (tmp)) - continue; + goto do_it_again; #ifdef DT_DIR } @@ -354,12 +381,12 @@ find_dirs (dir, list, checkadm, entries) { /* we're either unknown or a symlink at this point */ if (dp->d_type == DT_LNK) - continue; + goto do_it_again; #endif /* Note that we only get here if we already set tmp above. */ if (islink (tmp)) - continue; + goto do_it_again; #ifdef DT_DIR } #endif @@ -371,7 +398,7 @@ find_dirs (dir, list, checkadm, entries) + sizeof (CVSADM) + 10)); (void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM); if (!isdir (tmp)) - continue; + goto do_it_again; } /* put it in the list */ @@ -380,6 +407,16 @@ find_dirs (dir, list, checkadm, entries) p->key = xstrdup (dp->d_name); if (addnode (list, p) != 0) freenode (p); + + do_it_again: + errno = 0; + } + if (errno != 0) + { + int save_errno = errno; + (void) closedir (dirp); + errno = save_errno; + return 1; } (void) closedir (dirp); if (tmp != NULL) diff --git a/gnu/usr.bin/cvs/src/hardlink.c b/gnu/usr.bin/cvs/src/hardlink.c index b279aa9c3d0..046cf3a470a 100644 --- a/gnu/usr.bin/cvs/src/hardlink.c +++ b/gnu/usr.bin/cvs/src/hardlink.c @@ -66,7 +66,7 @@ lookup_file_by_inode (filepath) inodestr = (char *) xmalloc (2*sizeof(ino_t)*sizeof(char) + 1); if (stat (file, &sb) < 0) { - if (errno == ENOENT) + if (existence_error (errno)) { /* The file doesn't exist; we may be doing an update on a file that's been removed. A nonexistent file has no diff --git a/gnu/usr.bin/cvs/src/history.c b/gnu/usr.bin/cvs/src/history.c index 8f1e254720e..bc7d1a64207 100644 --- a/gnu/usr.bin/cvs/src/history.c +++ b/gnu/usr.bin/cvs/src/history.c @@ -719,12 +719,8 @@ history_write (type, update_dir, revs, name, repository) } if (trace) -#ifdef SERVER_SUPPORT - fprintf (stderr, "%c-> fopen(%s,a)\n", - (server_active) ? 'S' : ' ', fname); -#else - fprintf (stderr, "-> fopen(%s,a)\n", fname); -#endif + fprintf (stderr, "%s-> fopen(%s,a)\n", + CLIENT_SERVER_STR, fname); if (noexec) goto out; fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666); @@ -971,7 +967,7 @@ expand_modules () * Return a pointer to the character following the newline. */ -#define NEXT_BAR(here) do { while (isspace(*line)) line++; hr->here = line; while ((c = *line++) && c != '|') ; if (!c) return(rtn); *(line - 1) = '\0'; } while (0) +#define NEXT_BAR(here) do { while (isspace((unsigned char) *line)) line++; hr->here = line; while ((c = *line++) && c != '|') ; if (!c) return(rtn); *(line - 1) = '\0'; } while (0) static char * fill_hrec (line, hr) @@ -985,7 +981,7 @@ fill_hrec (line, hr) unsigned long date; memset ((char *) hr, 0, sizeof (*hr)); - while (isspace (*line)) + while (isspace ((unsigned char) *line)) line++; if (!(rtn = strchr (line, '\n'))) return (""); @@ -1062,7 +1058,7 @@ read_hrecs (fname) *(cp + i) = '\0'; for (cp2 = cp; cp2 - cp < i; cp2++) { - if (*cp2 != '\n' && !isprint (*cp2)) + if (*cp2 != '\n' && !isprint ((unsigned char) *cp2)) *cp2 = ' '; } diff --git a/gnu/usr.bin/cvs/src/import.c b/gnu/usr.bin/cvs/src/import.c index 77c617a195c..862dae1e2d1 100644 --- a/gnu/usr.bin/cvs/src/import.c +++ b/gnu/usr.bin/cvs/src/import.c @@ -94,6 +94,17 @@ import (argc, argv) command_name); break; case 'd': +#ifdef SERVER_SUPPORT + if (server_active) + { + /* CVS 1.10 and older clients will send this, but it + doesn't do any good. So tell the user we can't + cope, rather than silently losing. */ + error (0, 0, + "warning: not setting the time of import from the file"); + error (0, 0, "due to client limitations"); + } +#endif use_file_modtime = 1; break; case 'b': @@ -132,6 +143,20 @@ import (argc, argv) if (argc < 3) usage (import_usage); +#ifdef SERVER_SUPPORT + /* This is for handling the Checkin-time request. It might seem a + bit odd to enable the use_file_modtime code even in the case + where Checkin-time was not sent for a particular file. The + effect is that we use the time of upload, rather than the time + when we call RCS_checkin. Since those times are both during + CVS's run, that seems OK, and it is easier to implement than + putting the "was Checkin-time sent" flag in CVS/Entries or some + such place. */ + + if (server_active) + use_file_modtime = 1; +#endif + for (i = 1; i < argc; i++) /* check the tags for validity */ { int j; @@ -170,7 +195,7 @@ import (argc, argv) * must only have two dots in it (like "1.1.1"). */ for (cp = vbranch; *cp != '\0'; cp++) - if (!isdigit (*cp) && *cp != '.') + if (!isdigit ((unsigned char) *cp) && *cp != '.') error (1, 0, "%s is not a numeric branch", vbranch); if (numdots (vbranch) != 2) error (1, 0, "Only branches with two dots are supported: %s", vbranch); @@ -212,9 +237,6 @@ import (argc, argv) { int err; - if (use_file_modtime) - send_arg("-d"); - if (vbranch[0] != '\0') option_with_arg ("-b", vbranch); if (message) @@ -275,29 +297,52 @@ import (argc, argv) { if (!really_quiet) { - char buf[80]; - sprintf (buf, "\n%d conflicts created by this import.\n", - conflicts); - cvs_output (buf, 0); - cvs_output ("Use the following command to help the merge:\n\n", - 0); - cvs_output ("\t", 1); - cvs_output (program_name, 0); - cvs_output (" checkout -j", 0); - cvs_output (argv[1], 0); - cvs_output (":yesterday -j", 0); - cvs_output (argv[1], 0); - cvs_output (" ", 1); - cvs_output (argv[0], 0); - cvs_output ("\n\n", 0); + char buf[20]; + char *buf2; + + cvs_output_tagged ("+importmergecmd", NULL); + cvs_output_tagged ("newline", NULL); + sprintf (buf, "%d", conflicts); + cvs_output_tagged ("conflicts", buf); + cvs_output_tagged ("text", " conflicts created by this import."); + cvs_output_tagged ("newline", NULL); + cvs_output_tagged ("text", + "Use the following command to help the merge:"); + cvs_output_tagged ("newline", NULL); + cvs_output_tagged ("newline", NULL); + cvs_output_tagged ("text", "\t"); + cvs_output_tagged ("text", program_name); + if (CVSroot_cmdline != NULL) + { + cvs_output_tagged ("text", " -d "); + cvs_output_tagged ("text", CVSroot_cmdline); + } + cvs_output_tagged ("text", " checkout -j"); + buf2 = xmalloc (strlen (argv[1]) + 20); + sprintf (buf2, "%s:yesterday", argv[1]); + cvs_output_tagged ("mergetag1", buf2); + free (buf2); + cvs_output_tagged ("text", " -j"); + cvs_output_tagged ("mergetag2", argv[1]); + cvs_output_tagged ("text", " "); + cvs_output_tagged ("repository", argv[0]); + cvs_output_tagged ("newline", NULL); + cvs_output_tagged ("newline", NULL); + cvs_output_tagged ("-importmergecmd", NULL); } + /* FIXME: I'm not sure whether we need to put this information + into the loginfo. If we do, then note that it does not + report any required -d option. There is no particularly + clean way to tell the server about the -d option used by + the client. */ (void) fprintf (logfp, "\n%d conflicts created by this import.\n", conflicts); (void) fprintf (logfp, "Use the following command to help the merge:\n\n"); - (void) fprintf (logfp, "\t%s checkout -j%s:yesterday -j%s %s\n\n", - program_name, argv[1], argv[1], argv[0]); + (void) fprintf (logfp, "\t%s checkout ", program_name); + (void) fprintf (logfp, "-j%s:yesterday -j%s %s\n\n", + argv[1], argv[1], argv[0]); } else { @@ -340,9 +385,9 @@ import (argc, argv) return (err); } -/* - * process all the files in ".", then descend into other directories. - */ +/* Process all the files in ".", then descend into other directories. + Returns 0 for success, or >0 on error (in which case a message + will have been printed). */ static int import_descend (message, vtag, targc, targv) char *message; @@ -361,25 +406,27 @@ import_descend (message, vtag, targc, targv) if ((dirp = CVS_OPENDIR (".")) == NULL) { + error (0, errno, "cannot open directory"); err++; } else { + errno = 0; while ((dp = readdir (dirp)) != NULL) { if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0) - continue; + goto one_more_time_boys; #ifdef SERVER_SUPPORT /* CVS directories are created in the temp directory by server.c because it doesn't special-case import. So don't print a message about them, regardless of -I!. */ if (server_active && strcmp (dp->d_name, CVSADM) == 0) - continue; + goto one_more_time_boys; #endif if (ign_name (dp->d_name)) { add_log ('I', dp->d_name); - continue; + goto one_more_time_boys; } if ( @@ -418,12 +465,20 @@ import_descend (message, vtag, targc, targv) vtag, targc, targv, repository, keyword_opt != NULL && - keyword_opt[0] == 'b'); + keyword_opt[0] == 'b', + use_file_modtime); else #endif err += process_import_file (message, dp->d_name, vtag, targc, targv); } + one_more_time_boys: + errno = 0; + } + if (errno != 0) + { + error (0, errno, "cannot read directory"); + ++err; } (void) closedir (dirp); } @@ -874,7 +929,7 @@ get_comment (user) */ (void) strcpy (suffix_path, cp); for (cp = suffix_path; *cp; cp++) - if (isupper (*cp)) + if (isupper ((unsigned char) *cp)) *cp = tolower (*cp); suffix = suffix_path; } diff --git a/gnu/usr.bin/cvs/src/log.c b/gnu/usr.bin/cvs/src/log.c index 4502e268bb9..7c57c77ced6 100644 --- a/gnu/usr.bin/cvs/src/log.c +++ b/gnu/usr.bin/cvs/src/log.c @@ -233,8 +233,8 @@ cvslog (argc, argv) for (i = 1; i < argc && argv[i][0] == '-'; i++) send_arg (argv[i]); - send_file_names (argc - i, argv + i, SEND_EXPAND_WILD); send_files (argc - i, argv + i, local, 0, SEND_NO_CONTENTS); + send_file_names (argc - i, argv + i, SEND_EXPAND_WILD); send_to_server ("log\012", 0); err = get_responses_and_close (); @@ -591,11 +591,11 @@ log_fileproc (callerdat, finfo) cvs_output ("\n\t", 2); cp2 = cp; - while (! isspace (*cp2) && *cp2 != '\0') + while (! isspace ((unsigned char) *cp2) && *cp2 != '\0') ++cp2; cvs_output (cp, cp2 - cp); cp = cp2; - while (isspace (*cp) && *cp != '\0') + while (isspace ((unsigned char) *cp) && *cp != '\0') ++cp; } } @@ -734,7 +734,7 @@ log_expand_revlist (rcs, revlist, default_branch) char *branch; /* Print just the head of the branch. */ - if (isdigit (r->first[0])) + if (isdigit ((unsigned char) r->first[0])) nr->first = RCS_getbranch (rcs, r->first, 1); else { @@ -761,7 +761,7 @@ log_expand_revlist (rcs, revlist, default_branch) } else { - if (r->first == NULL || isdigit (r->first[0])) + if (r->first == NULL || isdigit ((unsigned char) r->first[0])) nr->first = xstrdup (r->first); else { @@ -780,7 +780,7 @@ log_expand_revlist (rcs, revlist, default_branch) if (r->last == r->first) nr->last = xstrdup (nr->first); - else if (r->last == NULL || isdigit (r->last[0])) + else if (r->last == NULL || isdigit ((unsigned char) r->last[0])) nr->last = xstrdup (r->last); else { @@ -1356,12 +1356,12 @@ version_compare (v1, v2, len) while (*v1 == '0') ++v1; - for (d1 = 0; isdigit (v1[d1]); ++d1) + for (d1 = 0; isdigit ((unsigned char) v1[d1]); ++d1) ; while (*v2 == '0') ++v2; - for (d2 = 0; isdigit (v2[d2]); ++d2) + for (d2 = 0; isdigit ((unsigned char) v2[d2]); ++d2) ; if (d1 != d2) diff --git a/gnu/usr.bin/cvs/src/login.c b/gnu/usr.bin/cvs/src/login.c index 4ffce36d0fd..46707e24003 100644 --- a/gnu/usr.bin/cvs/src/login.c +++ b/gnu/usr.bin/cvs/src/login.c @@ -48,7 +48,14 @@ construct_cvspass_filename () homedir = get_homedir (); if (! homedir) { - error (1, errno, "could not find out home directory"); + /* FIXME? This message confuses a lot of users, at least + on Win95 (which doesn't set HOMEDRIVE and HOMEPATH like + NT does). I suppose the answer for Win95 is to store the + passwords in the registry or something (??). And .cvsrc + and such too? Wonder what WinCVS does (about .cvsrc, the + right thing for a GUI is to just store the password in + memory only)... */ + error (1, 0, "could not find out home directory"); return (char *) NULL; } @@ -246,7 +253,8 @@ login (argc, argv) /* FIXME: rename_file would make more sense (e.g. almost always faster). */ copy_file (tmp_name, passfile); - unlink_file (tmp_name); + if (unlink_file (tmp_name) < 0) + error (0, errno, "cannot remove %s", tmp_name); chmod (passfile, 0600); free (tmp_name); @@ -437,6 +445,8 @@ logout (argc, argv) */ passfile = construct_cvspass_filename (); + /* FIXME: This should not be in /tmp; that is almost surely a security + hole. Probably should just keep it in memory. */ tmp_name = cvs_temp_name (); if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL) { @@ -476,14 +486,16 @@ logout (argc, argv) if (! found) { printf ("Entry not found for %s\n", CVSroot_original); - unlink_file (tmp_name); + if (unlink_file (tmp_name) < 0) + error (0, errno, "cannot remove %s", tmp_name); } else { /* FIXME: rename_file would make more sense (e.g. almost always faster). */ copy_file (tmp_name, passfile); - unlink_file (tmp_name); + if (unlink_file (tmp_name) < 0) + error (0, errno, "cannot remove %s", tmp_name); chmod (passfile, 0600); } return 0; diff --git a/gnu/usr.bin/cvs/src/logmsg.c b/gnu/usr.bin/cvs/src/logmsg.c index 67194be4f47..6d45ca31cd3 100644 --- a/gnu/usr.bin/cvs/src/logmsg.c +++ b/gnu/usr.bin/cvs/src/logmsg.c @@ -446,7 +446,8 @@ do_verify (message, repository) { /* Since following error() exits, delete the temp file now. */ - unlink_file (fname); + if (unlink_file (fname) < 0) + error (0, errno, "cannot remove %s", fname); error (1, retcode == -1 ? errno : 0, "Message verification failed"); @@ -455,7 +456,8 @@ do_verify (message, repository) /* Delete the temp file */ - unlink_file (fname); + if (unlink_file (fname) < 0) + error (0, errno, "cannot remove %s", fname); free (fname); } } diff --git a/gnu/usr.bin/cvs/src/modules.c b/gnu/usr.bin/cvs/src/modules.c index de95f7eed59..e322086591e 100644 --- a/gnu/usr.bin/cvs/src/modules.c +++ b/gnu/usr.bin/cvs/src/modules.c @@ -147,8 +147,8 @@ do_module (db, mname, m_type, msg, callback_proc, where, + strlen (msg) + (where ? strlen (where) : 0) + (extra_arg ? strlen (extra_arg) : 0)); - sprintf (buf, "%c-> do_module (%s, %s, %s, %s)\n", - (server_active) ? 'S' : ' ', + sprintf (buf, "%s-> do_module (%s, %s, %s, %s)\n", + CLIENT_SERVER_STR, mname, msg, where ? where : "", extra_arg ? extra_arg : ""); cvs_outerr (buf, 0); @@ -192,13 +192,13 @@ do_module (db, mname, m_type, msg, callback_proc, where, { do *cp-- = '\0'; - while (isspace (*cp)); + while (isspace ((unsigned char) *cp)); } else { /* Always strip trailing spaces */ cp = strchr (val.dptr, '\0'); - while (cp > val.dptr && isspace(*--cp)) + while (cp > val.dptr && isspace ((unsigned char) *--cp)) *cp = '\0'; } @@ -315,7 +315,7 @@ do_module (db, mname, m_type, msg, callback_proc, where, { do *cp2-- = '\0'; - while (isspace (*cp2)); + while (isspace ((unsigned char) *cp2)); } value = val.dptr; @@ -362,7 +362,7 @@ do_module (db, mname, m_type, msg, callback_proc, where, spec_opt = cp + 1; /* save the options for later */ if (cp != value) /* strip whitespace if necessary */ - while (isspace (*--cp)) + while (isspace ((unsigned char) *--cp)) *cp = '\0'; if (cp == value) @@ -609,13 +609,13 @@ module `%s' is a request for a file in a module which is not a directory", /* strip whitespace off the end */ do *cp = '\0'; - while (isspace (*--cp)); + while (isspace ((unsigned char) *--cp)); } else next_opt = NULL; /* strip whitespace from front */ - while (isspace (*spec_opt)) + while (isspace ((unsigned char) *spec_opt)) spec_opt++; if (*spec_opt == '\0') @@ -836,15 +836,15 @@ save_d (k, ks, d, ds) cp = d; *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */ - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */ while (*cp) { - if (isspace (*cp)) + if (isspace ((unsigned char) *cp)) { *cp2++ = ' '; - while (isspace (*cp)) + while (isspace ((unsigned char) *cp)) cp++; } else diff --git a/gnu/usr.bin/cvs/src/myndbm.c b/gnu/usr.bin/cvs/src/myndbm.c index 6b15e77412e..f674ac11d9f 100644 --- a/gnu/usr.bin/cvs/src/myndbm.c +++ b/gnu/usr.bin/cvs/src/myndbm.c @@ -263,7 +263,7 @@ mydbm_load_file (fp, list) if (value[0] == '#') continue; /* comment line */ vp = value; - while (*vp && isspace (*vp)) + while (*vp && isspace ((unsigned char) *vp)) vp++; if (*vp == '\0') continue; /* empty line */ @@ -277,12 +277,12 @@ mydbm_load_file (fp, list) char *kp; kp = vp; - while (*vp && !isspace (*vp)) + while (*vp && !isspace ((unsigned char) *vp)) vp++; *vp++ = '\0'; /* NULL terminate the key */ p->type = NDBMNODE; p->key = xstrdup (kp); - while (*vp && isspace (*vp)) + while (*vp && isspace ((unsigned char) *vp)) vp++; /* skip whitespace to value */ if (*vp == '\0') { diff --git a/gnu/usr.bin/cvs/src/no_diff.c b/gnu/usr.bin/cvs/src/no_diff.c index 078343ea6ed..dfca372f5cb 100644 --- a/gnu/usr.bin/cvs/src/no_diff.c +++ b/gnu/usr.bin/cvs/src/no_diff.c @@ -82,13 +82,8 @@ No_Difference (finfo, vers) /* Need to call unlink myself because the noexec variable * has been set to 1. */ if (trace) - (void) fprintf (stderr, "%c-> unlink (%s)\n", -#ifdef SERVER_SUPPORT - (server_active) ? 'S' : ' ', -#else - ' ', -#endif - tocvsPath); + (void) fprintf (stderr, "%s-> unlink (%s)\n", + CLIENT_SERVER_STR, tocvsPath); if ( CVS_UNLINK (tocvsPath) < 0) error (0, errno, "could not remove %s", tocvsPath); } diff --git a/gnu/usr.bin/cvs/src/options.h.in b/gnu/usr.bin/cvs/src/options.h.in index 67e8c40aa04..a3ee047ac3a 100644 --- a/gnu/usr.bin/cvs/src/options.h.in +++ b/gnu/usr.bin/cvs/src/options.h.in @@ -88,13 +88,12 @@ * repository, change the contents of CVS/Root files in your * checked-out code, and CVS will work without problems. * - * This is likely to be the default in the future, but we want to give - * people who may be relying on absolute pathnames time to update - * their scripts/software. + * Therefore, RELATIVE_REPOS is now the default. In the future, this + * is likely to disappear entirely as a compile-time (or other) option, + * so if you have other software which relies on absolute pathnames, + * update them. */ -#ifndef RELATIVE_REPOS -/* #define RELATIVE_REPOS */ -#endif +#define RELATIVE_REPOS 1 /* * When committing or importing files, you must enter a log message. diff --git a/gnu/usr.bin/cvs/src/rcs.h b/gnu/usr.bin/cvs/src/rcs.h index f92988f4b1e..0a281613848 100644 --- a/gnu/usr.bin/cvs/src/rcs.h +++ b/gnu/usr.bin/cvs/src/rcs.h @@ -184,6 +184,7 @@ RCSNode *RCS_parse PROTO((const char *file, const char *repos)); RCSNode *RCS_parsercsfile PROTO((char *rcsfile)); void RCS_fully_parse PROTO((RCSNode *)); void RCS_reparsercsfile PROTO((RCSNode *, FILE **, struct rcsbuffer *)); +extern int RCS_setattic PROTO ((RCSNode *, int)); char *RCS_check_kflag PROTO((const char *arg)); char *RCS_getdate PROTO((RCSNode * rcs, char *date, int force_tag_match)); @@ -211,6 +212,7 @@ char *RCS_branch_head PROTO ((RCSNode *rcs, char *rev)); int RCS_isdead PROTO((RCSNode *, const char *)); char *RCS_getexpand PROTO ((RCSNode *)); +void RCS_setexpand PROTO ((RCSNode *, char *)); int RCS_checkout PROTO ((RCSNode *, char *, char *, char *, char *, char *, RCSCHECKOUTPROC, void *)); int RCS_checkin PROTO ((RCSNode *rcs, char *workfile, char *message, diff --git a/gnu/usr.bin/cvs/src/recurse.c b/gnu/usr.bin/cvs/src/recurse.c index d88bf2be30a..ff8bafd990f 100644 --- a/gnu/usr.bin/cvs/src/recurse.c +++ b/gnu/usr.bin/cvs/src/recurse.c @@ -13,9 +13,6 @@ #include "fileattr.h" #include "edit.h" -#ifdef CLIENT_SUPPORT -static int do_argument_proc PROTO((Node * p, void *closure)); -#endif static int do_dir_proc PROTO((Node * p, void *closure)); static int do_file_proc PROTO((Node * p, void *closure)); static void addlist PROTO((List ** listp, char *key)); @@ -61,23 +58,6 @@ struct frame_and_entries { List *entries; }; -#ifdef CLIENT_SUPPORT -/* This is a callback to send "Argument" commands to the server in the - case we've done a "cvs update" or "cvs commit" in a top-level - directory where there is no CVSADM directory. */ - -static int -do_argument_proc (p, closure) - Node *p; - void *closure; -{ - char *dir = p->key; - send_to_server ("Argument ", 0); - send_to_server (dir, 0); - send_to_server ("\012", 1); - return 0; -} -#endif /* Start a recursive command. @@ -127,6 +107,9 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, int dosrcs; { int i, err = 0; +#ifdef CLIENT_SUPPORT + List *args_to_send_when_finished = NULL; +#endif List *files_by_dir = NULL; struct recursion_frame frame; @@ -169,6 +152,29 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, if (argc == 0) { + int just_subdirs = (which & W_LOCAL) && !isdir (CVSADM); + +#ifdef CLIENT_SUPPORT + if (!just_subdirs + && CVSroot_cmdline == NULL + && client_active) + { + char *root = Name_Root (NULL, update_dir); + if (strcmp (root, current_root) != 0) + /* We're skipping this directory because it is for + a different root. Therefore, we just want to + do the subdirectories only. Processing files would + cause a working directory from one repository to be + processed against a different repository, which could + cause all kinds of spurious conflicts and such. + + Question: what about the case of "cvs update foo" + where we process foo/bar and not foo itself? That + seems to be handled somewhere (else) but why should + it be a separate case? Needs investigation... */ + just_subdirs = 1; + } +#endif /* * There were no arguments, so we'll probably just recurse. The @@ -177,7 +183,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, * process each of the sub-directories, so we pretend like we were * called with the list of sub-dirs of the current dir as args */ - if ((which & W_LOCAL) && !isdir (CVSADM)) + if (just_subdirs) { dirlist = Find_Directories ((char *) NULL, W_LOCAL, (List *) NULL); /* If there are no sub-directories, there is a certain logic in @@ -204,17 +210,21 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, appropriate "Argument" commands to the server. In this case, that won't have happened, so we need to do it here. While this example uses "update", this - generalizes to other commands. */ - - err += walklist (dirlist, do_argument_proc, NULL); + generalizes to other commands. */ + + /* This is the same call to Find_Directories as above. + FIXME: perhaps it would be better to write a + function that duplicates a list. */ + args_to_send_when_finished = Find_Directories ((char *) NULL, + W_LOCAL, + (List *) NULL); } #endif } else addlist (&dirlist, "."); - err += do_recursion (&frame); - goto out; + goto do_the_work; } @@ -335,14 +345,146 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, /* then do_recursion on the dirlist. */ if (dirlist != NULL) + { + do_the_work: err += do_recursion (&frame); - + } + /* Free the data which expand_wild allocated. */ free_names (&argc, argv); - out: free (update_dir); update_dir = NULL; + +#ifdef CLIENT_SUPPORT + if (args_to_send_when_finished != NULL) + { + /* FIXME (njc): in the multiroot case, we don't want to send + argument commands for those top-level directories which do + not contain any subdirectories which have files checked out + from current_root. If we do, and two repositories have a + module with the same name, nasty things could happen. + + This is hard. Perhaps we should send the Argument commands + later in this procedure, after we've had a chance to notice + which directores we're using (after do_recursion has been + called once). This means a _lot_ of rewriting, however. + + What we need to do for that to happen is descend the tree + and construct a list of directories which are checked out + from current_cvsroot. Now, we eliminate from the list all + of those directories which are immediate subdirectories of + another directory in the list. To say that the opposite + way, we keep the directories which are not immediate + subdirectories of any other in the list. Here's a picture: + + a + / \ + B C + / \ + D e + / \ + F G + / \ + H I + + The node in capitals are those directories which are + checked out from current_cvsroot. We want the list to + contain B, C, F, and G. D, H, and I are not included, + because their parents are also checked out from + current_cvsroot. + + The algorithm should be: + + 1) construct a tree of all directory names where each + element contains a directory name and a flag which notes if + that directory is checked out from current_cvsroot + + a0 + / \ + B1 C1 + / \ + D1 e0 + / \ + F1 G1 + / \ + H1 I1 + + 2) Recursively descend the tree. For each node, recurse + before processing the node. If the flag is zero, do + nothing. If the flag is 1, check the node's parent. If + the parent's flag is one, change the current entry's flag + to zero. + + a0 + / \ + B1 C1 + / \ + D0 e0 + / \ + F1 G1 + / \ + H0 I0 + + 3) Walk the tree and spit out "Argument" commands to tell + the server which directories to munge. + + Yuck. It's not clear this is worth spending time on, since + we might want to disable cvs commands entirely from + directories that do not have CVSADM files... + + Anyways, the solution as it stands has modified server.c + (dirswitch) to create admin files [via server.c + (create_adm_p)] in all path elements for a client's + "Directory xxx" command, which forces the server to descend + and serve the files there. client.c (send_file_names) has + also been modified to send only those arguments which are + appropriate to current_root. + + */ + + /* Construct a fake argc/argv pair. */ + + int our_argc = 0, i; + char **our_argv = NULL; + + if (! list_isempty (args_to_send_when_finished)) + { + Node *head, *p; + + head = args_to_send_when_finished->list; + + /* count the number of nodes */ + i = 0; + for (p = head->next; p != head; p = p->next) + i++; + our_argc = i; + + /* create the argument vector */ + our_argv = (char **) xmalloc (sizeof (char *) * our_argc); + + /* populate it */ + i = 0; + for (p = head->next; p != head; p = p->next) + our_argv[i++] = xstrdup (p->key); + } + + /* We don't want to expand widcards, since we've just created + a list of directories directly from the filesystem. */ + send_file_names (our_argc, our_argv, 0); + + /* Free our argc/argv. */ + if (our_argv != NULL) + { + for (i = 0; i < our_argc; i++) + free (our_argv[i]); + free (our_argv); + } + + dellist (&args_to_send_when_finished); + } +#endif + return (err); } @@ -359,6 +501,7 @@ do_recursion (frame) char *srepository; List *entries = NULL; int should_readlock; + int process_this_directory = 1; /* do nothing if told */ if (frame->flags == R_SKIP_ALL) @@ -410,6 +553,55 @@ do_recursion (frame) server_pause_check(); #endif + /* Check the value in CVSADM_ROOT and see if it's in the list. If + not, add it to our lists of CVS/Root directories and do not + process the files in this directory. Otherwise, continue as + usual. THIS_ROOT might be NULL if we're doing an initial + checkout -- check before using it. The default should be that + we process a directory's contents and only skip those contents + if a CVS/Root file exists. + + If we're running the server, we want to process all + directories, since we're guaranteed to have only one CVSROOT -- + our own. */ + +#ifdef SERVER_SUPPORT + if (! server_active + + /* If -d was specified, it should override CVS/Root. + + In the single-repository case, it is long-standing CVS behavior + and makes sense - the user might want another access method, + another server (which mounts the same repository), &c. + + In the multiple-repository case, -d overrides all CVS/Root + files. That is the only plausible generalization I can + think of. */ + && CVSroot_cmdline == NULL) +#endif + { + char *this_root = Name_Root ((char *) NULL, update_dir); + if (this_root != NULL) + { + if (findnode (root_directories, this_root) == NULL) + { + /* Add it to our list. */ + + Node *n = getnode (); + n->type = UNKNOWN; + n->key = xstrdup (this_root); + + if (addnode (root_directories, n)) + error (1, 0, "cannot add new CVSROOT %s", this_root); + + } + + process_this_directory = (strcmp (current_root, this_root) == 0); + + free (this_root); + } + } + /* * Fill in repository with the current repository */ @@ -468,12 +660,26 @@ do_recursion (frame) repository = Name_Repository ((char *) NULL, update_dir); /* find the files and fill in entries if appropriate */ - filelist = Find_Names (repository, lwhich, frame->aflag, &entries); + if (process_this_directory) + { + filelist = Find_Names (repository, lwhich, frame->aflag, + &entries); + if (filelist == NULL) + { + error (0, 0, "skipping directory %s", update_dir); + /* Note that Find_Directories and the filesdoneproc + in particular would do bad things ("? foo.c" in + the case of some filesdoneproc's). */ + goto skip_directory; + } + } } /* find sub-directories if we will recurse */ if (frame->flags != R_SKIP_DIRS) - dirlist = Find_Directories (repository, frame->which, entries); + dirlist = Find_Directories ( + process_this_directory ? repository : NULL, + frame->which, entries); } else { @@ -487,7 +693,7 @@ do_recursion (frame) } /* process the files (if any) */ - if (filelist != NULL && frame->fileproc) + if (process_this_directory && filelist != NULL && frame->fileproc) { struct file_info finfo_struct; struct frame_and_file frfile; @@ -525,11 +731,12 @@ do_recursion (frame) } /* call-back files done proc (if any) */ - if (dodoneproc && frame->filesdoneproc != NULL) + if (process_this_directory && dodoneproc && frame->filesdoneproc != NULL) err = frame->filesdoneproc (frame->callerdat, err, repository, update_dir[0] ? update_dir : ".", entries); + skip_directory: fileattr_write (); fileattr_free (); @@ -589,7 +796,24 @@ do_file_proc (p, closure) strcat (finfo->fullname, finfo->file); if (frfile->frame->dosrcs && repository) + { finfo->rcs = RCS_parse (finfo->file, repository); + + /* OK, without W_LOCAL the error handling becomes relatively + simple. The file names came from readdir() on the + repository and so we know any ENOENT is an error + (e.g. symlink pointing to nothing). Now, the logic could + be simpler - since we got the name from readdir, we could + just be calling RCS_parsercsfile. */ + if (finfo->rcs == NULL + && !(frfile->frame->which & W_LOCAL)) + { + error (0, 0, "could not read RCS file for %s", finfo->fullname); + free (finfo->fullname); + cvs_flushout (); + return 0; + } + } else finfo->rcs = (RCSNode *) NULL; ret = frfile->frame->fileproc (frfile->frame->callerdat, finfo); @@ -625,6 +849,7 @@ do_dir_proc (p, closure) int err = 0; struct saved_cwd cwd; char *saved_update_dir; + int process_this_directory = 1; if (fncmp (dir, CVSADM) == 0) { @@ -760,12 +985,60 @@ but CVS uses %s for its own purposes; skipping %s directory", free (cvsadmdir); } + /* Only process this directory if the root matches. This nearly + duplicates code in do_recursion. */ + +#ifdef SERVER_SUPPORT + if (! server_active + + /* If -d was specified, it should override CVS/Root. + + In the single-repository case, it is long-standing CVS behavior + and makes sense - the user might want another access method, + another server (which mounts the same repository), &c. + + In the multiple-repository case, -d overrides all CVS/Root + files. That is the only plausible generalization I can + think of. */ + && CVSroot_cmdline == NULL) +#endif + { + char *this_root = Name_Root (dir, update_dir); + if (this_root != NULL) + { + if (findnode (root_directories, this_root) == NULL) + { + /* Add it to our list. */ + + Node *n = getnode (); + n->type = UNKNOWN; + n->key = xstrdup (this_root); + + if (addnode (root_directories, n)) + error (1, 0, "cannot add new CVSROOT %s", this_root); + + } + + process_this_directory = (strcmp (current_root, this_root) == 0); + free (this_root); + } + } + /* call-back dir entry proc (if any) */ if (dir_return == R_SKIP_ALL) ; else if (frame->direntproc != NULL) - dir_return = frame->direntproc (frame->callerdat, dir, newrepos, - update_dir, frent->entries); + { + /* If we're doing the actual processing, call direntproc. + Otherwise, assume that we need to process this directory + and recurse. FIXME. */ + + if (process_this_directory) + dir_return = frame->direntproc (frame->callerdat, dir, newrepos, + update_dir, frent->entries); + else + dir_return = R_PROCESS; + } else { /* Generic behavior. I don't see a reason to make the caller specify @@ -811,7 +1084,7 @@ but CVS uses %s for its own purposes; skipping %s directory", (void) strcpy (update_dir, "."); /* call-back dir leave proc (if any) */ - if (frame->dirleaveproc != NULL) + if (process_this_directory && frame->dirleaveproc != NULL) err = frame->dirleaveproc (frame->callerdat, dir, err, update_dir, frent->entries); diff --git a/gnu/usr.bin/cvs/src/release.c b/gnu/usr.bin/cvs/src/release.c index 82429e0d994..ca7945b0ac1 100644 --- a/gnu/usr.bin/cvs/src/release.c +++ b/gnu/usr.bin/cvs/src/release.c @@ -6,10 +6,9 @@ */ #include "cvs.h" +#include "savecwd.h" #include "getline.h" -static void release_delete PROTO((char *dir)); - static const char *const release_usage[] = { "Usage: %s %s [-d] directories...\n", @@ -76,6 +75,7 @@ release (argc, argv) int arg_start_idx; int err = 0; short delete_flag = 0; + struct saved_cwd cwd; #ifdef SERVER_SUPPORT if (server_active) @@ -111,6 +111,10 @@ release (argc, argv) /* We're going to run "cvs -n -q update" and check its output; if * the output is sufficiently unalarming, then we release with no * questions asked. Else we prompt, then maybe release. + * (Well, actually we ask no matter what. Our notion of "sufficiently + * unalarming" doesn't take into account "? foo.c" files, so it is + * up to the user to take note of them, at least currently + * (ignore-193 in testsuite)). */ /* Construct the update command. */ update_cmd = xmalloc (strlen (program_path) @@ -128,6 +132,12 @@ release (argc, argv) } #endif /* CLIENT_SUPPORT */ + /* Remember the directory where "cvs release" was invoked because + all args are relative to this directory and we chdir around. + */ + if (save_cwd (&cwd)) + error_exit (); + arg_start_idx = 0; for (i = arg_start_idx; i < argc; i++) @@ -146,6 +156,8 @@ release (argc, argv) { if (!really_quiet) error (0, 0, "no repository directory: %s", thisarg); + if (restore_cwd (&cwd, NULL)) + error_exit (); continue; } } @@ -190,6 +202,9 @@ release (argc, argv) if ((pclose (fp)) != 0) { error (0, 0, "unable to release `%s'", thisarg); + free (repository); + if (restore_cwd (&cwd, NULL)) + error_exit (); continue; } @@ -203,6 +218,8 @@ release (argc, argv) (void) fprintf (stderr, "** `%s' aborted by user choice.\n", command_name); free (repository); + if (restore_cwd (&cwd, NULL)) + error_exit (); continue; } } @@ -239,7 +256,19 @@ release (argc, argv) } free (repository); - if (delete_flag) release_delete (thisarg); + + if (restore_cwd (&cwd, NULL)) + error_exit (); + + if (delete_flag) + { + /* FIXME? Shouldn't this just delete the CVS-controlled + files and, perhaps, the files that would normally be + ignored and leave everything else? */ + + if (unlink_file_dir (thisarg) < 0) + error (0, errno, "deletion of directory %s failed", thisarg); + } #ifdef CLIENT_SUPPORT if (client_active) @@ -247,6 +276,10 @@ release (argc, argv) #endif /* CLIENT_SUPPORT */ } + if (restore_cwd (&cwd, NULL)) + error_exit (); + free_cwd (&cwd); + #ifdef CLIENT_SUPPORT if (client_active) { @@ -264,37 +297,3 @@ release (argc, argv) free (line); return err; } - - -/* We want to "rm -r" the working directory, but let us be a little - paranoid. */ -static void -release_delete (dir) - char *dir; -{ - struct stat st; - ino_t ino; - - (void) CVS_STAT (".", &st); - ino = st.st_ino; - (void) CVS_CHDIR (".."); - (void) CVS_STAT (dir, &st); - if (ino != st.st_ino) - { - /* This test does not work on cygwin32, because under cygwin32 - the st_ino field is not the same when you refer to a file - by a different name. This is a cygwin32 bug, but then I - don't see what the point of this test is anyhow. */ -#ifndef __CYGWIN32__ - error (0, 0, - "Parent dir on a different disk, delete of %s aborted", dir); - return; -#endif - } - /* - * XXX - shouldn't this just delete the CVS-controlled files and, perhaps, - * the files that would normally be ignored and leave everything else? - */ - if (unlink_file_dir (dir) < 0) - error (0, errno, "deletion of directory %s failed", dir); -} diff --git a/gnu/usr.bin/cvs/src/remove.c b/gnu/usr.bin/cvs/src/remove.c index 9ed32d72a11..2dacdf15988 100644 --- a/gnu/usr.bin/cvs/src/remove.c +++ b/gnu/usr.bin/cvs/src/remove.c @@ -100,9 +100,9 @@ cvsremove (argc, argv) ign_setup (); if (local) send_arg("-l"); - send_file_names (argc, argv, 0); /* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */ send_files (argc, argv, local, 0, 0); + send_file_names (argc, argv, 0); send_to_server ("remove\012", 0); return get_responses_and_close (); } @@ -200,7 +200,9 @@ remove_fileproc (callerdat, finfo) + sizeof (CVSEXT_LOG) + 10); (void) sprintf (fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG); - (void) unlink_file (fname); + if (unlink_file (fname) < 0 + && !existence_error (errno)) + error (0, errno, "cannot remove %s", CVSEXT_LOG); if (!quiet) error (0, 0, "removed `%s'", finfo->fullname); @@ -216,7 +218,7 @@ remove_fileproc (callerdat, finfo) error (0, 0, "file `%s' already scheduled for removal", finfo->fullname); } - else if (vers->tag != NULL && isdigit (*vers->tag)) + else if (vers->tag != NULL && isdigit ((unsigned char) *vers->tag)) { /* Commit will just give an error, and so there seems to be little reason to allow the remove. I mean, conflicts that diff --git a/gnu/usr.bin/cvs/src/root.c b/gnu/usr.bin/cvs/src/root.c index 050e168041e..c650646ecff 100644 --- a/gnu/usr.bin/cvs/src/root.c +++ b/gnu/usr.bin/cvs/src/root.c @@ -18,7 +18,7 @@ Watch out if the enum is changed in cvs.h! */ char *method_names[] = { - "local", "server (rsh)", "pserver", "kserver", "gserver", "ext" + "local", "server (rsh)", "pserver", "kserver", "gserver", "ext", "fork" }; #ifndef DEBUG @@ -268,6 +268,11 @@ error 0 Server configuration missing --allow-root in inetd.conf\n"); return 0; } +/* This global variable holds the global -d option. It is NULL if -d + was not used, which means that we must get the CVSroot information + from the CVSROOT environment variable or from a CVS/Root file. */ + +char *CVSroot_cmdline; /* Parse a CVSROOT variable into its constituent parts -- method, * username, hostname, directory. The prototypical CVSROOT variable @@ -287,30 +292,6 @@ char *CVSroot_username; /* the username or NULL if method == local */ char *CVSroot_hostname; /* the hostname or NULL if method == local */ char *CVSroot_directory; /* the directory name */ -#ifdef AUTH_SERVER_SUPPORT -/* Die if CVSroot_directory and Pserver_Repos don't match. */ -static void -check_root_consistent () -{ - /* FIXME: Should be using a deferred error, as the rest of - serve_root does. As it is now the call to error could conceivably - cause deadlock, as noted in server_cleanup. Best solution would - presumably be to write some code so that error() automatically - defers the error in those cases where that is needed. */ - /* FIXME? Possible that the wording should be more clear (e.g. - Root says "%s" but pserver protocol says "%s" - or something which would aid people who are writing implementations - of the client side of the CVS protocol. I don't see any security - problem with revealing that information. */ - if ((Pserver_Repos != NULL) && (CVSroot_directory != NULL)) - if (strcmp (Pserver_Repos, CVSroot_directory) != 0) - error (1, 0, "repository mismatch: \"%s\" vs \"%s\"", - Pserver_Repos, CVSroot_directory); -} - -#endif /* AUTH_SERVER_SUPPORT */ - - int parse_cvsroot (CVSroot) char *CVSroot; @@ -335,8 +316,9 @@ parse_cvsroot (CVSroot) /* Access method specified, as in * "cvs -d :pserver:user@host:/path", - * "cvs -d :local:e:\path", or - * "cvs -d :kserver:user@host:/path". + * "cvs -d :local:e:\path", + * "cvs -d :kserver:user@host:/path", or + * "cvs -d :fork:/path". * We need to get past that part of CVSroot before parsing the * rest of it. */ @@ -363,6 +345,8 @@ parse_cvsroot (CVSroot) CVSroot_method = server_method; else if (strcmp (method, "ext") == 0) CVSroot_method = ext_method; + else if (strcmp (method, "fork") == 0) + CVSroot_method = fork_method; else { error (0, 0, "unknown method in CVSroot: %s", CVSroot); @@ -391,7 +375,8 @@ parse_cvsroot (CVSroot) CVSroot_username = NULL; CVSroot_hostname = NULL; - if (CVSroot_method != local_method) + if ((CVSroot_method != local_method) + && (CVSroot_method != fork_method)) { /* Check to see if there is a username in the string. */ @@ -416,9 +401,6 @@ parse_cvsroot (CVSroot) } CVSroot_directory = cvsroot_copy; -#ifdef AUTH_SERVER_SUPPORT - check_root_consistent (); -#endif /* AUTH_SERVER_SUPPORT */ #if ! defined (CLIENT_SUPPORT) && ! defined (DEBUG) if (CVSroot_method != local_method) @@ -442,10 +424,12 @@ parse_cvsroot (CVSroot) switch (CVSroot_method) { case local_method: + case fork_method: if (CVSroot_username || CVSroot_hostname) { error (0, 0, "can't specify hostname and username in CVSROOT"); - error (0, 0, "when using local access method"); + error (0, 0, "when using %s access method", + CVSroot_method == local_method ? "local" : "fork"); error (0, 0, "(%s)", CVSroot); return 1; } @@ -464,18 +448,20 @@ parse_cvsroot (CVSroot) error (0, 0, "but your CVS executable doesn't support it"); error (0, 0, "(%s)", CVSroot); return 1; -#endif +#else check_hostname = 1; break; +#endif case gserver_method: #ifndef HAVE_GSSAPI error (0, 0, "Your CVSROOT is set for a GSSAPI access method"); error (0, 0, "but your CVS executable doesn't support it"); error (0, 0, "(%s)", CVSroot); return 1; -#endif +#else check_hostname = 1; break; +#endif case server_method: case ext_method: case pserver_method: @@ -504,18 +490,17 @@ parse_cvsroot (CVSroot) /* Set up the global CVSroot* variables as if we're using the local - repository DIR. */ + repository DIR. DIR must point to storage which will last for the + rest of the CVS invocation (for example, the caller might malloc it + and never free it, or free it just before exiting CVS). */ void set_local_cvsroot (dir) char *dir; { - CVSroot_original = xstrdup (dir); + CVSroot_original = dir; CVSroot_method = local_method; CVSroot_directory = CVSroot_original; -#ifdef AUTH_SERVER_SUPPORT - check_root_consistent (); -#endif /* AUTH_SERVER_SUPPORT */ CVSroot_username = NULL; CVSroot_hostname = NULL; client_active = 0; @@ -523,7 +508,11 @@ set_local_cvsroot (dir) #ifdef DEBUG -/* This is for testing the parsing function. */ +/* This is for testing the parsing function. Use + + gcc -I. -I.. -I../lib -DDEBUG root.c -o root + + to compile. */ #include <stdio.h> @@ -531,6 +520,30 @@ char *CVSroot; char *program_name = "testing"; char *command_name = "parse_cvsroot"; /* XXX is this used??? */ +/* Toy versions of various functions when debugging under unix. Yes, + these make various bad assumptions, but they're pretty easy to + debug when something goes wrong. */ + +void +error_exit PROTO ((void)) +{ + exit (1); +} + +char * +xstrdup (str) + const char *str; +{ + return strdup (str); +} + +int +isabsolute (dir) + const char *dir; +{ + return (dir && (*dir == '/')); +} + void main (argc, argv) int argc; @@ -546,7 +559,7 @@ main (argc, argv) if (parse_cvsroot (argv[1])) { - fprintf (stderr, "%s: Parsing failed.", program_name); + fprintf (stderr, "%s: Parsing failed.\n", program_name); exit (1); } printf ("CVSroot: %s\n", argv[1]); diff --git a/gnu/usr.bin/cvs/src/rtag.c b/gnu/usr.bin/cvs/src/rtag.c index 3207c1b3c3c..5fd825f471d 100644 --- a/gnu/usr.bin/cvs/src/rtag.c +++ b/gnu/usr.bin/cvs/src/rtag.c @@ -64,7 +64,7 @@ static int force_tag_move; /* don't move existing tags by default * static const char *const rtag_usage[] = { - "Usage: %s %s [-aflRnF] [-b] [-d] [-r tag|-D date] tag modules...\n", + "Usage: %s %s [-aflRnF] [-b] [-d] [-r rev|-D date] tag modules...\n", "\t-a\tClear tag from removed files that would not otherwise be tagged.\n", "\t-f\tForce a head revision match if tag/date not found.\n", "\t-l\tLocal directory only, not recursive\n", @@ -388,9 +388,16 @@ check_fileproc (callerdat, finfo) { if (delete_flag) { + /* Deleting a tag which did not exist is a noop and + should not be logged. */ addit = 0; } } + else if (delete_flag) + { + free (p->data); + p->data = xstrdup (oversion); + } else if (strcmp(oversion, p->data) == 0) { addit = 0; @@ -458,7 +465,7 @@ pretag_proc(repository, filter) s = xstrdup(filter); for (cp=s; *cp; cp++) { - if (isspace(*cp)) + if (isspace ((unsigned char) *cp)) { *cp = '\0'; break; @@ -583,7 +590,9 @@ rtag_fileproc (callerdat, finfo) } return (0); } - if (numtag && isdigit (*numtag) && strcmp (numtag, version) != 0) + if (numtag + && isdigit ((unsigned char) *numtag) + && strcmp (numtag, version) != 0) { /* diff --git a/gnu/usr.bin/cvs/src/run.c b/gnu/usr.bin/cvs/src/run.c index dc35a78216c..6d2c3b1cec6 100644 --- a/gnu/usr.bin/cvs/src/run.c +++ b/gnu/usr.bin/cvs/src/run.c @@ -175,10 +175,11 @@ run_exec (stin, stout, sterr, flags) /* The output files, if any, are now created. Do the fork and dups. - We use vfork not so much for the sake of unices without - copy-on-write (such systems are rare these days), but for the - sake of systems without an MMU, which therefore can't do - copy-on-write (e.g. Amiga). The other solution is spawn (see + We use vfork not so much for a performance boost (the + performance boost, if any, is modest on most modern unices), + but for the sake of systems without a memory management unit, + which find it difficult or impossible to implement fork at all + (e.g. Amiga). The other solution is spawn (see windows-NT/run.c). */ #ifdef HAVE_VFORK @@ -365,12 +366,8 @@ run_popen (cmd, mode) const char *mode; { if (trace) -#ifdef SERVER_SUPPORT - (void) fprintf (stderr, "%c-> run_popen(%s,%s)\n", - (server_active) ? 'S' : ' ', cmd, mode); -#else - (void) fprintf (stderr, "-> run_popen(%s,%s)\n", cmd, mode); -#endif + (void) fprintf (stderr, "%s-> run_popen(%s,%s)\n", + CLIENT_SERVER_STR, cmd, mode); if (noexec) return (NULL); @@ -440,77 +437,3 @@ close_on_exec (fd) error (1, errno, "can't set close-on-exec flag on %d", fd); #endif } - -/* - * dir = 0 : main proc writes to new proc, which writes to oldfd - * dir = 1 : main proc reads from new proc, which reads from oldfd - * - * Returns: a file descriptor. On failure (i.e., the exec fails), - * then filter_stream_through_program() complains and dies. - */ - -int -filter_stream_through_program (oldfd, dir, prog, pidp) - int oldfd, dir; - char **prog; - pid_t *pidp; -{ - int p[2], newfd; - pid_t newpid; - - if (pipe (p)) - error (1, errno, "cannot create pipe"); -#ifdef USE_SETMODE_BINARY - setmode (p[0], O_BINARY); - setmode (p[1], O_BINARY); -#endif - -#ifdef HAVE_VFORK - newpid = vfork (); -#else - newpid = fork (); -#endif - if (pidp) - *pidp = newpid; - switch (newpid) - { - case -1: - error (1, errno, "cannot fork"); - case 0: - /* child */ - if (dir) - { - /* write to new pipe */ - close (p[0]); - dup2 (oldfd, 0); - dup2 (p[1], 1); - } - else - { - /* read from new pipe */ - close (p[1]); - dup2 (p[0], 0); - dup2 (oldfd, 1); - } - /* Should I be blocking some signals here? */ - execvp (prog[0], prog); - error (1, errno, "couldn't exec %s", prog[0]); - default: - /* parent */ - close (oldfd); - if (dir) - { - /* read from new pipe */ - close (p[1]); - newfd = p[0]; - } - else - { - /* write to new pipe */ - close (p[0]); - newfd = p[1]; - } - close_on_exec (newfd); - return newfd; - } -} diff --git a/gnu/usr.bin/cvs/src/sanity.sh b/gnu/usr.bin/cvs/src/sanity.sh index f97e0369a05..690398441ea 100644 --- a/gnu/usr.bin/cvs/src/sanity.sh +++ b/gnu/usr.bin/cvs/src/sanity.sh @@ -43,6 +43,15 @@ # required to make this script work properly. unset CVSREAD +# We want to invoke a predictable set of i18n behaviors, not whatever +# the user running this script might have set. +# In particular: +# 'sort' and tabs and spaces (LC_COLLATE). +# Messages from getopt (LC_MESSAGES) (in the future, CVS itself might +# also alter its messages based on LC_MESSAGES). +LC_ALL=C +export LC_ALL + # The default value of /tmp/cvs-sanity for TESTDIR is dubious, # because it loses if two people/scripts try to run the tests # at the same time. Some possible solutions: @@ -69,12 +78,6 @@ echo 'This test should produce no other output than this line, and a final "OK". if test x"$1" = x"-r"; then shift remote=yes - # If we're going to do remote testing, make sure 'rsh' works first. - host="`hostname`" - if test "x`${CVS_RSH-rsh} $host -n 'echo hi'`" != "xhi"; then - echo "ERROR: cannot test remote CVS, because \`rsh $host' fails." >&2 - exit 1 - fi else remote=no fi @@ -477,7 +480,8 @@ dotest_fail () fail "$1" else : so far so good - fi + fi 2>${TESTDIR}/dotest.tmp1 + cat ${TESTDIR}/dotest.tmp1 >>${TESTDIR}/dotest.tmp dotest_internal "$@" } @@ -553,25 +557,33 @@ RCSINIT=; export RCSINIT if test x"$*" = x; then # Basic/miscellaneous functionality - tests="basica basicb basicc basic1 deep basic2 commit-readonly" + tests="basica basicb basicc basic1 deep basic2 files commit-readonly" # Branching, tagging, removing, adding, multiple directories - tests="${tests} rdiff death death2 branches branches2" + tests="${tests} rdiff diff death death2 rmadd rmadd2 dirs dirs2" + tests="${tests} branches branches2 tagc" tests="${tests} rcslib multibranch import importb importc" - tests="${tests} join join2 join3" + tests="${tests} import-after-initial" + tests="${tests} join join2 join3 join-readonly-conflict" tests="${tests} new newb conflicts conflicts2 conflicts3" # Checking out various places (modules, checkout -d, &c) tests="${tests} modules modules2 modules3 modules4" + tests="${tests} mkmodules-temp-file-removal" tests="${tests} cvsadm emptydir abspath toplevel toplevel2" # Log messages, error messages. tests="${tests} mflag editor errmsg1 errmsg2" # Watches, binary files, history browsing, &c. tests="${tests} devcom devcom2 devcom3 watch4" tests="${tests} unedit-without-baserev" - tests="${tests} ignore binfiles binfiles2 mcopy binwrap binwrap2" + tests="${tests} ignore binfiles binfiles2 binfiles3" + tests="${tests} mcopy binwrap binwrap2" tests="${tests} binwrap3 mwrap info taginfo config" - tests="${tests} serverpatch log log2 ann ann-id crerepos rcs rcs2" + tests="${tests} serverpatch log log2 ann ann-id" + # Repository Storage (RCS file format, CVS lock files, creating + # a repository without "cvs init", &c). + tests="${tests} crerepos rcs rcs2 rcs3 lockfiles" + # More history browsing, &c. tests="${tests} history" - tests="${tests} big modes modes2 stamps" + tests="${tests} big modes modes2 modes3 stamps" # PreservePermissions stuff: permissions, symlinks et al. tests="${tests} perms symlinks hardlinks" # More tag and branch tests, keywords. @@ -581,6 +593,11 @@ if test x"$*" = x; then tests="${tests} admin reserved" # Nuts and bolts of diffing/merging (diff library, &c) tests="${tests} diffmerge1 diffmerge2" + # Release of multiple directories + tests="${tests} release" + # Multiple root directories and low-level protocol tests. + tests="${tests} multiroot multiroot2 multiroot3 multiroot4" + tests="${tests} reposmv pserver server client" else tests="$*" fi @@ -629,10 +646,13 @@ directory_cmp () CVSROOT_DIRNAME=${TESTDIR}/cvsroot CVSROOT=${CVSROOT_DIRNAME} ; export CVSROOT if test "x$remote" = xyes; then - # Use rsh so we can test it without having to muck with inetd - # or anything like that. Also needed to get CVS_SERVER to - # work. - CVSROOT=:ext:`hostname`:${CVSROOT_DIRNAME} ; export CVSROOT + # Currently we test :fork: and :ext: (see crerepos test). + # Testing :pserver: would be hard (inetd issues). + # Also :ext: and :fork support CVS_SERVER in a convenient way. + # If you want to edit this script to change the next line to + # :ext:, you can run the tests that way. There is a known + # difference in modes-15 (see comments there). + CVSROOT=:fork:${CVSROOT_DIRNAME} ; export CVSROOT CVS_SERVER=${testcvs}; export CVS_SERVER fi @@ -725,8 +745,8 @@ ${PROG} \[[a-z]* aborted\]: failed to set tag BASE to revision 1\.1 in ${TESTDIR RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v retrieving revision 1\.1 diff -c -r1\.1 ssfile -\*\*\* ssfile [0-9/]* [0-9:]* 1\.1 ---- ssfile [0-9/]* [0-9:]* +\*\*\* sdir/ssdir/ssfile [0-9/]* [0-9:]* 1\.1 +--- sdir/ssdir/ssfile [0-9/]* [0-9:]* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\* 1 \*\*\*\* --- 1,2 ---- @@ -738,8 +758,8 @@ ${PLUS} ssfile line 2" RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v retrieving revision 1\.1 diff -c -r1\.1 ssfile -\*\*\* ssfile [0-9/]* [0-9:]* 1\.1 ---- ssfile [0-9/]* [0-9:]* +\*\*\* sdir/ssdir/ssfile [0-9/]* [0-9:]* 1\.1 +--- sdir/ssdir/ssfile [0-9/]* [0-9:]* \*\*\*\*\*\*\*\*\*\*\*\*\*\*\* \*\*\* 1 \*\*\*\* --- 1,2 ---- @@ -1140,6 +1160,8 @@ Directory ${TESTDIR}/cvsroot/second-dir added to the repository" # and then blow it away (don't complain if it does not # exist). But that is perfectly legal; people who are used # to the old behavior especially may be interested. + # FIXME: this test is intended for the TopLevelAdmin=yes case; + # should adjust/move it accordingly. rm -rf CVS dotest basicc-4 "echo *" "first-dir second-dir" dotest basicc-5 "${testcvs} update" \ @@ -1149,8 +1171,28 @@ ${PROG} [a-z]*: Updating second-dir" \ ${PROG} [a-z]*: Updating first-dir ${PROG} [a-z]*: Updating second-dir" + cd first-dir + dotest basicc-6 "${testcvs} release -d" "" + dotest basicc-7 "test -d ../first-dir" "" + dotest basicc-8 "${testcvs} -Q release -d ." \ +"${PROG} release: deletion of directory \. failed: .*" + dotest basicc-9 "test -d ../second-dir" "" + dotest basicc-10 "test -d ../first-dir" "" + # For CVS to make a syntactic check for "." wouldn't suffice. + dotest basicc-11 "${testcvs} -Q release -d ./." \ +"${PROG} release: deletion of directory \./\. failed: .*" cd .. - rm -r 1 + cd .. + + mkdir 2; cd 2 + dotest basicc-12 "${testcvs} -Q co ." "" + dotest basicc-13 "echo *" "CVS CVSROOT first-dir second-dir" + dotest basicc-14 "${testcvs} -Q release first-dir second-dir" "" + dotest basicc-15 "${testcvs} -Q release -d first-dir second-dir" "" + dotest basicc-16 "echo *" "CVS CVSROOT" + + cd .. + rm -r 1 2 rm -rf ${CVSROOT_DIRNAME}/first-dir ;; @@ -2047,6 +2089,108 @@ O [0-9/]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir =first-di rm -rf ${CVSROOT_DIRNAME}/second-dir ;; + files) + # Test of how we specify files on the command line + # (recurse.c and that sort of thing). Vaguely similar to + # tests like basic* and deep. See modules and such tests + # for what happens when we throw in modules and co -d, &c. + + # This particular test is fairly carefully crafted, to spot + # one particular issue with remote. + mkdir 1; cd 1 + dotest files-1 "${testcvs} -q co -l ." "" + mkdir first-dir + dotest files-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + touch tfile + dotest files-3 "${testcvs} add tfile" \ +"${PROG} [a-z]*: scheduling file .tfile. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest files-4 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/tfile,v +done +Checking in tfile; +${TESTDIR}/cvsroot/first-dir/tfile,v <-- tfile +initial revision: 1\.1 +done" + dotest files-5 "${testcvs} -q tag -b C" "T tfile" + dotest files-6 "${testcvs} -q update -r C" "" + mkdir dir + dotest files-7 "${testcvs} add dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir/dir added to the repository +--> Using per-directory sticky tag .C'" + cd dir + touch .file + dotest files-6 "${testcvs} add .file" \ +"${PROG} [a-z]*: scheduling file .\.file' for addition on branch .C. +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + mkdir sdir + dotest files-7 "${testcvs} add sdir" \ +"Directory ${TESTDIR}/cvsroot/first-dir/dir/sdir added to the repository +--> Using per-directory sticky tag .C'" + cd sdir + mkdir ssdir + dotest files-8 "${testcvs} add ssdir" \ +"Directory ${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir added to the repository +--> Using per-directory sticky tag .C'" + cd ssdir + touch .file + dotest files-9 "${testcvs} add .file" \ +"${PROG} [a-z]*: scheduling file .\.file' for addition on branch .C. +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + cd ../.. + dotest files-10 "${testcvs} -q ci -m test" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v +done +Checking in \.file; +${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v <-- \.file +new revision: 1\.1\.2\.1; previous revision: 1\.1 +done +RCS file: ${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v +done +Checking in sdir/ssdir/\.file; +${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file +new revision: 1\.1\.2\.1; previous revision: 1\.1 +done" + dotest files-11 \ +"${testcvs} commit -m test -f ./.file ./sdir/ssdir/.file" \ +"Checking in \.file; +${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v <-- \.file +new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 +done +Checking in \./sdir/ssdir/\.file; +${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file +new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 +done" + if test "$remote" = yes; then + # This is a bug, looks like that toplevel_repos cruft in + # client.c is coming back to haunt us. + # May want to think about the whole issue, toplevel_repos + # has always been crufty and trying to patch it up again + # might be a mistake. + dotest_fail files-12 \ +"${testcvs} commit -f -m test ./sdir/ssdir/.file ./.file" \ +"${PROG} server: Up-to-date check failed for .\.file' +${PROG} \[server aborted\]: correct above errors first!" + else + dotest files-12 \ +"${testcvs} commit -f -m test ./sdir/ssdir/.file ./.file" \ +"Checking in \./sdir/ssdir/\.file; +${TESTDIR}/cvsroot/first-dir/dir/sdir/ssdir/Attic/\.file,v <-- \.file +new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2 +done +Checking in \.file; +${TESTDIR}/cvsroot/first-dir/dir/Attic/\.file,v <-- \.file +new revision: 1\.1\.2\.3; previous revision: 1\.1\.2\.2 +done" + fi + cd ../../.. + + rm -r 1 + rm -rf ${CVSROOT_DIRECTORY}/first-dir + ;; + commit-readonly) mkdir 1; cd 1 module=x @@ -2194,6 +2338,31 @@ diff -c /dev/null trdiff/new:1\.1 rm -rf ${CVSROOT_DIRNAME}/trdiff ;; + diff) + # Various tests specific to the "cvs diff" command. + # Related tests: + # death2: -N + # rcslib: cvs diff and $Name. + # rdiff: cvs rdiff. + # diffmerge*: nuts and bolts (stuff within diff library) + mkdir 1; cd 1 + dotest diff-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest diff-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + + # diff is anomalous. Most CVS commands print the "nothing + # known" message (or worse yet, no message in some cases) but + # diff says "I know nothing". Shrug. + dotest_fail diff-3 "${testcvs} diff xyzpdq" \ +"${PROG} [a-z]*: I know nothing about xyzpdq" + + cd ../.. + rm -rf ${CVSROOT_DIRNAME}/first-dir + rm -r 1 + ;; + death) # next dive. test death support. @@ -2894,6 +3063,473 @@ ${PLUS} first revision" cd .. ; rm -rf first-dir ${CVSROOT_DIRNAME}/first-dir ;; + rmadd) + # More tests of adding and removing files. + # In particular ci -r. + # Other ci -r tests: + # * editor-9: checking in a modified file, + # where "ci -r" means a branch. + # * basica-8a1: checking in a modified file with numeric revision. + # * basica-8a2: likewise. + # * keywordlog-4: adding a new file with numeric revision. + mkdir 1; cd 1 + dotest rmadd-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest rmadd-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + echo first file1 >file1 + dotest rmadd-3 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + + dotest_fail rmadd-4 "${testcvs} -q ci -r 1.2.2.4 -m add" \ +"${PROG} [a-z]*: cannot add file .file1' with revision .1\.2\.2\.4'; must be on trunk +${PROG} \[[a-z]* aborted\]: correct above errors first!" + dotest_fail rmadd-5 "${testcvs} -q ci -r 1.2.2 -m add" \ +"${PROG} [a-z]*: cannot add file .file1' with revision .1\.2\.2'; must be on trunk +${PROG} \[[a-z]* aborted\]: correct above errors first!" + dotest_fail rmadd-6 "${testcvs} -q ci -r mybranch -m add" \ +"${PROG} \[[a-z]* aborted\]: no such tag mybranch" + + # The thing with the trailing periods strikes me as a very + # bizarre behavior, but it would seem to be intentional + # (see commit.c). It probably could go away.... + dotest rmadd-7 "${testcvs} -q ci -r 7.... -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +done +Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +initial revision: 7\.1 +done" + if test "$remote" = yes; then + # I guess remote doesn't set a sticky tag in this case. + # Kind of odd, in the sense that rmadd-24a does set one + # both local and remote. + dotest_fail rmadd-7a "test -f CVS/Tag" + echo T7 >CVS/Tag + else + dotest rmadd-7a "cat CVS/Tag" "T7" + fi + + dotest rmadd-8 "${testcvs} -q tag -b mybranch" "T file1" + dotest rmadd-9 "${testcvs} -q tag mynonbranch" "T file1" + + touch file2 + # The previous "cvs ci -r" set a sticky tag of '7'. Seems a + # bit odd, and I guess commit.c (findmaxrev) makes '7' sticky + # tags unnecessary (?). I kind of suspect that it should be + # saying "sticky tag is not a branch" like keywordlog-4b. + # Or something. + dotest rmadd-10 "${testcvs} add file2" \ +"${PROG} [a-z]*: scheduling file .file2. for addition on branch .7' +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + # As in the previous example, CVS is confused.... + dotest rmadd-11 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file2,v +done +Checking in file2; +${TESTDIR}/cvsroot/first-dir/file2,v <-- file2 +initial revision: 7\.1 +done" + + dotest rmadd-12 "${testcvs} -q update -A" "" + touch file3 + dotest rmadd-13 "${testcvs} add file3" \ +"${PROG} [a-z]*: scheduling file .file3. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + # Huh? file2 is not up to date? Seems buggy to me.... + dotest_fail rmadd-14 "${testcvs} -q ci -r mybranch -m add" \ +"${PROG} [a-z]*: Up-to-date check failed for .file2' +${PROG} \[[a-z]* aborted\]: correct above errors first!" + # Whatever, let's not let file2 distract us.... + dotest rmadd-15 "${testcvs} -q ci -r mybranch -m add file3" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/Attic/file3,v +done +Checking in file3; +${TESTDIR}/cvsroot/first-dir/Attic/file3,v <-- file3 +new revision: 1\.1\.2\.1; previous revision: 1\.1 +done" + + touch file4 + dotest rmadd-16 "${testcvs} add file4" \ +"${PROG} [a-z]*: scheduling file .file4. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + # Same "Up-to-date check" issues as in rmadd-14. + # The "no such tag" thing is due to the fact that we only + # update val-tags when the tag is used (might be more of a + # bug than a feature, I dunno). + dotest_fail rmadd-17 \ +"${testcvs} -q ci -r mynonbranch -m add file4" \ +"${PROG} \[[a-z]* aborted\]: no such tag mynonbranch" + # Try to make CVS write val-tags. + dotest rmadd-18 "${testcvs} -q update -p -r mynonbranch file1" \ +"first file1" + # Oops, -p suppresses writing val-tags (probably a questionable + # behavior). + dotest_fail rmadd-19 \ +"${testcvs} -q ci -r mynonbranch -m add file4" \ +"${PROG} \[[a-z]* aborted\]: no such tag mynonbranch" + # Now make CVS write val-tags for real. + dotest rmadd-20 "${testcvs} -q update -r mynonbranch file1" "" + # Oops - CVS isn't distinguishing between a branch tag and + # a non-branch tag. + dotest rmadd-21 \ +"${testcvs} -q ci -r mynonbranch -m add file4" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/Attic/file4,v +done +Checking in file4; +${TESTDIR}/cvsroot/first-dir/Attic/file4,v <-- file4 +new revision: 1\.1\.2\.1; previous revision: 1\.1 +done" + + # OK, we add this one in a vanilla way, but then check in + # a modification with ci -r and sniff around for sticky tags. + echo file5 >file5 + dotest rmadd-22 "${testcvs} add file5" \ +"${PROG} [a-z]*: scheduling file .file5. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + if test "$remote" = yes; then + # Interesting bug (or missing feature) here. findmaxrev + # gets the major revision from the Entries. Well, remote + # doesn't send the entries for files which are not involved. + dotest rmadd-23 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file5,v +done +Checking in file5; +${TESTDIR}/cvsroot/first-dir/file5,v <-- file5 +initial revision: 1\.1 +done" + dotest rmadd-23-workaround \ +"${testcvs} -q ci -r 7 -m bump-it file5" \ +"Checking in file5; +${TESTDIR}/cvsroot/first-dir/file5,v <-- file5 +new revision: 7\.1; previous revision: 1\.1 +done" + else + dotest rmadd-23 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file5,v +done +Checking in file5; +${TESTDIR}/cvsroot/first-dir/file5,v <-- file5 +initial revision: 7\.1 +done" + fi + echo change it >file5 + dotest_fail rmadd-24 "${testcvs} -q ci -r 4.8 -m change file5" \ +"Checking in file5; +${TESTDIR}/cvsroot/first-dir/file5,v <-- file5 +${PROG} [a-z]*: ${TESTDIR}/cvsroot/first-dir/file5,v: revision 4\.8 too low; must be higher than 7\.1 +${PROG} [a-z]*: could not check in file5 +7\.1 unlocked" + dotest rmadd-24a "${testcvs} -q ci -r 8.4 -m change file5" \ +"Checking in file5; +${TESTDIR}/cvsroot/first-dir/file5,v <-- file5 +new revision: 8\.4; previous revision: 7\.1 +done" + # I'm not really sure that a sticky tag make sense here. + # It seems to be longstanding behavior for what that is worth. + dotest rmadd-25 "${testcvs} status file5" \ +"=================================================================== +File: file5 Status: Up-to-date + + Working revision: 8\.4.* + Repository revision: 8\.4 ${TESTDIR}/cvsroot/first-dir/file5,v + Sticky Tag: 8\.4 + Sticky Date: (none) + Sticky Options: (none)" + + cd ../.. + rm -r 1 + rm -rf ${CVSROOT_DIRNAME}/first-dir + ;; + + rmadd2) + # Tests of undoing commits, including in the presence of + # adding and removing files. See join for a list of -j tests. + mkdir 1; cd 1 + dotest rmadd2-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest rmadd2-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + echo 'initial contents' >file1 + dotest rmadd2-3 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest rmadd2-4 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +done +Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +initial revision: 1\.1 +done" + dotest rmadd2-5 "${testcvs} rm -f file1" \ +"${PROG} [a-z]*: scheduling .file1. for removal +${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently" + dotest rmadd2-6 "${testcvs} -q ci -m remove" \ +"Removing file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: delete; previous revision: 1\.1 +done" + dotest rmadd2-7 "${testcvs} -q update -j 1.2 -j 1.1 file1" "U file1" + dotest rmadd2-8 "${testcvs} -q ci -m readd" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.3; previous revision: 1\.2 +done" + echo 'new contents' >file1 + dotest rmadd2-9 "${testcvs} -q ci -m modify" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.4; previous revision: 1\.3 +done" + dotest rmadd2-10 "${testcvs} -q update -j 1.4 -j 1.3 file1" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +retrieving revision 1\.4 +retrieving revision 1\.3 +Merging differences between 1\.4 and 1\.3 into file1" + dotest rmadd2-11 "${testcvs} -q ci -m undo" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.5; previous revision: 1\.4 +done" + dotest rmadd2-12 "cat file1" "initial contents" + dotest rmadd2-13 "${testcvs} -q update -p -r 1.3" "initial contents" + + # Hmm, might be a bit odd that this works even if 1.3 is not + # the head. + dotest rmadd2-14 "${testcvs} -q update -j 1.3 -j 1.2 file1" \ +"${PROG} [a-z]*: scheduling file1 for removal" + dotest rmadd2-15 "${testcvs} -q ci -m re-remove" \ +"Removing file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: delete; previous revision: 1\.5 +done" + cd ../.. + + rm -r 1 + rm -rf ${TESTDIR}/cvsroot/first-dir + ;; + + dirs) + # Tests related to removing and adding directories. + # See also: + # conflicts (especially dir1 in conflicts-130): What happens if + # directory exists in repository and a non-CVS-controlled + # directory in the working directory? + # conflicts3-15. More cases, especially where CVS directory + # exists but without CVS/Repository and friends. + # conflicts3-22. Similar to conflicts-130 but there is a file + # in the directory. + # dirs2. Sort of similar to conflicts3-22 but somewhat different. + mkdir imp-dir; cd imp-dir + echo file1 >file1 + mkdir sdir + echo sfile >sdir/sfile + dotest_sort dirs-1 \ +"${testcvs} import -m import-it dir1 vend rel" " + +N dir1/file1 +N dir1/sdir/sfile +No conflicts created by this import +${PROG} [a-z]*: Importing ${TESTDIR}/cvsroot/dir1/sdir" + cd .. + + mkdir 1; cd 1 + dotest dirs-2 "${testcvs} -Q co dir1" "" + + # Various CVS administrators are in the habit of removing + # the repository directory for things they don't want any + # more. I've even been known to do it myself (on rare + # occasions). Not the usual recommended practice, but we want + # to try to come up with some kind of reasonable/documented/sensible + # behavior. + rm -rf ${CVSROOT_DIRNAME}/dir1/sdir + + dotest dirs-3 "${testcvs} update" \ +"${PROG} [a-z]*: Updating dir1 +${PROG} [a-z]*: Updating dir1/sdir +${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/dir1/sdir: No such file or directory +${PROG} [a-z]*: skipping directory dir1/sdir" + dotest dirs-3a "${testcvs} update -d" \ +"${PROG} [a-z]*: Updating dir1 +${PROG} [a-z]*: Updating dir1/sdir +${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/dir1/sdir: No such file or directory +${PROG} [a-z]*: skipping directory dir1/sdir" + + # If we say "yes", then CVS gives errors about not being able to + # create lock files. + if echo no | ${testcvs} release -d dir1/sdir \ + >${TESTDIR}/output.tmp 2>&1; then + pass dirs-4 + else + fail dirs-4 + fi + # The fact that it says "skipping directory " rather than + # "skipping directory dir1/sdir" is some kind of bug. + dotest dirs-4a "cat ${TESTDIR}/output.tmp" \ +"${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/dir1/sdir: No such file or directory +${PROG} [a-z]*: skipping directory +You have \[0\] altered files in this repository\. +Are you sure you want to release (and delete) directory .dir1/sdir': .. .release' aborted by user choice." + + # OK, if "cvs release" won't help, we'll try it the other way... + rm -r dir1/sdir + + dotest dirs-5 "cat dir1/CVS/Entries" \ +"/file1/1.1.1.1/[a-zA-Z0-9 :]*// +D/sdir////" + dotest dirs-6 "${testcvs} update" "${PROG} [a-z]*: Updating dir1" + dotest dirs-7 "cat dir1/CVS/Entries" \ +"/file1/1.1.1.1/[a-zA-Z0-9 :]*// +D/sdir////" + dotest dirs-8 "${testcvs} update -d dir1" \ +"${PROG} [a-z]*: Updating dir1" + + cd .. + + rm -r imp-dir 1 + rm ${TESTDIR}/output.tmp + + # clean up our repositories + rm -rf ${CVSROOT_DIRNAME}/dir1 + ;; + + dirs2) + # See "dirs" for a list of tests involving adding and + # removing directories. + mkdir 1; cd 1 + dotest dirs2-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest dirs2-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + mkdir sdir + dotest dirs2-3 "${testcvs} add sdir" \ +"Directory ${TESTDIR}/cvsroot/first-dir/sdir added to the repository" + touch sdir/file1 + dotest dirs2-4 "${testcvs} add sdir/file1" \ +"${PROG} [a-z]*: scheduling file .sdir/file1. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest dirs2-5 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/file1,v +done +Checking in sdir/file1; +${TESTDIR}/cvsroot/first-dir/sdir/file1,v <-- file1 +initial revision: 1\.1 +done" + rm -r sdir/CVS + if test "$remote" = yes; then + # This is just like conflicts3-23 + dotest_fail dirs2-6 "${testcvs} update -d" \ +"${QUESTION} sdir +${PROG} server: Updating \. +${PROG} update: in directory sdir: +${PROG} update: cannot open CVS/Entries for reading: No such file or directory +${PROG} server: Updating sdir +${PROG} update: move away sdir/file1; it is in the way +C sdir/file1" + rm sdir/file1 + + # This is where things are not just like conflicts3-23 + # As with conflicts3-23, all these CVS/Entries* warnings + # are somewhat doubtful, and we probably should think some + # about whether they should be changed/fixed. + dotest dirs2-7 "${testcvs} update -d" \ +"${QUESTION} sdir +${PROG} server: Updating \. +${PROG} update: in directory sdir: +${PROG} update: cannot open CVS/Entries for reading: No such file or directory +${PROG} server: Updating sdir +U sdir/file1 +${PROG} update: cannot open CVS/Entries.Log: No such file or directory" + else + dotest dirs2-6 "${testcvs} update -d" \ +"${PROG} update: Updating \. +${QUESTION} sdir" + rm sdir/file1 + dotest dirs2-7 "${testcvs} update -d" \ +"${PROG} update: Updating \. +${QUESTION} sdir" + fi + cd ../.. + + # Now, the same thing (more or less) on a branch. + mkdir 2; cd 2 + dotest dirs2-8 "${testcvs} -q co first-dir" 'U first-dir/sdir/file1' + cd first-dir + dotest dirs2-9 "${testcvs} -q tag -b br" "T sdir/file1" + rm -r sdir/CVS + if test "$remote" = yes; then + # Cute little quirk of val-tags; if we don't recurse into + # the directories where the tag is defined, val-tags won't + # get updated. + dotest_fail dirs2-10 "${testcvs} update -d -r br" \ +"${QUESTION} sdir +${PROG} \[server aborted\]: no such tag br" + dotest dirs2-10-rem \ +"${testcvs} -q rdiff -u -r 1.1 -r br first-dir/sdir/file1" \ +"" + dotest_fail dirs2-10-again "${testcvs} update -d -r br" \ +"${QUESTION} sdir +${PROG} server: Updating \. +${PROG} update: in directory sdir: +${PROG} update: cannot open CVS/Entries for reading: No such file or directory +${PROG} update: cannot open CVS/Tag: No such file or directory +${PROG} update: cannot open CVS/Tag: No such file or directory +${PROG} server: Updating sdir +${PROG} update: move away sdir/file1; it is in the way +C sdir/file1 +${PROG} update: cannot open CVS/Tag: No such file or directory" + else + dotest_fail dirs2-10 "${testcvs} update -d -r br" \ +"${PROG} update: in directory sdir: +${PROG} \[update aborted\]: there is no version here; do 'cvs checkout' first" + fi + cd ../.. + + # OK, the above tests make the situation somewhat harder + # than it might be, in the sense that they actually have a + # file which is alive on the branch we are updating. Let's + # try it where it is just a directory where all the files + # have been removed. + mkdir 3; cd 3 + dotest dirs2-11 "${testcvs} -q co -r br first-dir" \ +"U first-dir/sdir/file1" + cd first-dir + # Hmm, this doesn't mention the branch like add does. That's + # an odd non-orthogonality. + dotest dirs2-12 "${testcvs} rm -f sdir/file1" \ +"${PROG} [a-z]*: scheduling .sdir/file1. for removal +${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently" + dotest dirs2-13 "${testcvs} -q ci -m remove" \ +"Removing sdir/file1; +${TESTDIR}/cvsroot/first-dir/sdir/file1,v <-- file1 +new revision: delete; previous revision: 1\.1\.2 +done" + cd ../../2/first-dir + if test "$remote" = yes; then + dotest dirs2-14 "${testcvs} update -d -r br" \ +"${QUESTION} sdir +${PROG} server: Updating \. +${PROG} update: in directory sdir: +${PROG} update: cannot open CVS/Entries for reading: No such file or directory +${PROG} update: cannot open CVS/Tag: No such file or directory +${PROG} update: cannot open CVS/Tag: No such file or directory +${PROG} server: Updating sdir +${PROG} update: cannot open CVS/Tag: No such file or directory" + else + dotest dirs2-14 "${testcvs} update -d -r br" \ +"${PROG} update: Updating \. +${QUESTION} sdir" + fi + cd ../.. + + rm -r 1 2 3 + rm -rf ${TESTDIR}/cvsroot/first-dir + ;; + branches) # More branch tests, including branches off of branches mkdir ${CVSROOT_DIRNAME}/first-dir @@ -3389,6 +4025,58 @@ File: file5 Status: Up-to-date rm -r trunk b1a b1b ;; + tagc) + # Test the tag -c option. + mkdir 1; cd 1 + dotest tagc-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest tagc-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + touch file1 + dotest tagc-3 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest tagc-4 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +done +Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +initial revision: 1\.1 +done" + dotest tagc-5 "${testcvs} -q tag -c tag1" "T file1" + touch file1 + dotest tagc-6 "${testcvs} -q tag -c tag2" "T file1" + # Avoid timestamp granularity bugs (FIXME: CVS should be + # doing the sleep, right?). + sleep 1 + echo myedit >>file1 + dotest_fail tagc-7 "${testcvs} -q tag -c tag3" \ +"${PROG} [a-z]*: file1 is locally modified +${PROG} \[[a-z]* aborted\]: correct the above errors first!" + cd ../.. + mkdir 2 + cd 2 + dotest tagc-8 "${testcvs} -q co first-dir" "U first-dir/file1" + cd ../1/first-dir + dotest tagc-9 "${testcvs} -q ci -m modify" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.2; previous revision: 1\.1 +done" + cd ../../2/first-dir + # That this is an error is a bug. Although the bug has existed + # since tag -c was created, I don't think there would be a + # compatibility problem with just fixing it. + dotest_fail tagc-10 "${testcvs} -q tag -c tag4" \ +"${PROG} [a-z]*: file1 is locally modified +${PROG} \[[a-z]* aborted\]: correct the above errors first!" + cd ../.. + + rm -r 1 2 + rm -rf ${CVSROOT_DIRNAME}/first-dir + ;; + rcslib) # Test librarification of RCS. # First: test whether `cvs diff' handles $Name expansion @@ -3603,7 +4291,46 @@ two ${TESTDIR}/cvsroot/first-dir/file1,v <-- file2 new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1 done" - dotest rcslib-symlink-4 "test -L ${CVSROOT_DIRNAME}/first-dir/file2,v" + dotest rcslib-symlink-4 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \ +".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v" + # Test 5 reveals a problem with having symlinks in the + # repository. CVS will try to tag both of the files + # separately. After processing one, it will do the same + # operation to the other, which is actually the same file, + # so the tag will already be there. FIXME: do we bother + # changing operations to notice cases like this? This + # strikes me as a difficult problem. -Noel + dotest rcslib-symlink-5 "${testcvs} tag the_tag" \ +"${PROG} [a-z]*: Tagging . +T file1 +W file2 : the_tag already exists on version 1.1.2.1 : NOT MOVING tag to version 1.1.2.2" + dotest rcslib-symlink-6 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \ +".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v" + + # Symlinks tend to interact poorly with the Attic. + cd .. + mkdir 2; cd 2 + dotest rcslib-symlink-7 "${testcvs} -q co first-dir" \ +"U first-dir/file1 +U first-dir/file2" + cd first-dir + dotest rcslib-symlink-8 "${testcvs} rm -f file2" \ +"${PROG} [a-z]*: scheduling .file2. for removal +${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently" + dotest rcslib-symlink-9 "${testcvs} -q ci -m rm-it" \ +"Removing file2; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file2 +new revision: delete; previous revision: 1\.2 +done" + # OK, why this message happens twice is relatively clear + # (the check_* and rtag_* calls to start_recursion). + # Why it happens a third time I didn't try to find out. + dotest rcslib-symlink-10 \ +"${testcvs} -q rtag -b -r the_tag brtag first-dir" \ +"${PROG} [a-z]*: could not read RCS file for file2 +${PROG} [a-z]*: could not read RCS file for first-dir/file2 +${PROG} [a-z]*: could not read RCS file for first-dir/file2" + cd .. cd .. @@ -3613,7 +4340,7 @@ done" fi rm -rf ${CVSROOT_DIRNAME}/first-dir - rm -r first-dir + rm -r first-dir 2 ;; multibranch) @@ -3718,7 +4445,7 @@ modify-on-br1 mkdir import-dir ; cd import-dir for i in 1 2 3 4 ; do - echo imported file"$i" > imported-f"$i" + echo imported file"$i" > imported-f"$i" done # This directory should be on the default ignore list, @@ -3729,157 +4456,164 @@ modify-on-br1 echo 'import should not expand $''Id$' >>imported-f2 cp imported-f2 ../imported-f2-orig.tmp - if ${CVS} import -m first-import first-dir vendor-branch junk-1_0 ; then - pass 96 - else - fail 96 - fi + dotest_sort import-96 \ +"${testcvs} import -m first-import first-dir vendor-branch junk-1_0" \ +" + +I first-dir/RCS +N first-dir/imported-f1 +N first-dir/imported-f2 +N first-dir/imported-f3 +N first-dir/imported-f4 +No conflicts created by this import" + + dotest import-96.5 "cmp ../imported-f2-orig.tmp imported-f2" '' - if cmp ../imported-f2-orig.tmp imported-f2; then - pass 96.5 - else - fail 96.5 - fi cd .. # co - if ${CVS} co first-dir ; then - pass 97 - else - fail 97 - fi + dotest import-97 "${testcvs} -q co first-dir" \ +"U first-dir/imported-f1 +U first-dir/imported-f2 +U first-dir/imported-f3 +U first-dir/imported-f4" cd first-dir + for i in 1 2 3 4 ; do - if test -f imported-f"$i" ; then - pass 98-$i - else - fail 98-$i - fi + dotest import-98-$i "test -f imported-f$i" '' done - if test -d RCS; then - fail 98.5 - else - pass 98.5 - fi + dotest_fail import-98.5 "test -d RCS" '' # remove rm imported-f1 - if ${CVS} rm imported-f1 2>> ${LOGFILE}; then - pass 99 - else - fail 99 - fi + dotest import-99 "${testcvs} rm imported-f1" \ +"${PROG}"' [a-z]*: scheduling `imported-f1'\'' for removal +'"${PROG}"' [a-z]*: use .'"${PROG}"' commit. to remove this file permanently' # change echo local-change >> imported-f2 # commit - if ${CVS} ci -m local-changes >> ${LOGFILE} 2>&1; then - pass 100 - else - fail 100 - fi + dotest import-100 "${testcvs} ci -m local-changes" \ +"${PROG} [a-z]*: Examining . +Removing imported-f1; +${TESTDIR}/cvsroot/first-dir/imported-f1,v <-- imported-f1 +new revision: delete; previous revision: 1\.1\.1\.1 +done +Checking in imported-f2; +${TESTDIR}/cvsroot/first-dir/imported-f2,v <-- imported-f2 +new revision: 1\.2; previous revision: 1\.1 +done" # log - if ${CVS} log imported-f1 | grep '1.1.1.2 (dead)' ; then - fail 101 - else - pass 101 - fi + dotest import-101 "${testcvs} log imported-f1" \ +" +RCS file: ${TESTDIR}/cvsroot/first-dir/Attic/imported-f1,v +Working file: imported-f1 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + junk-1_0: 1\.1\.1\.1 + vendor-branch: 1\.1\.1 +keyword substitution: kv +total revisions: 3; selected revisions: 3 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: dead; lines: ${PLUS}0 -0 +local-changes +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +branches: 1\.1\.1; +Initial revision +---------------------------- +revision 1\.1\.1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}0 -0 +first-import +=============================================================================" # update into the vendor branch. - if ${CVS} update -rvendor-branch ; then - pass 102 - else - fail 102 - fi + dotest import-102 "${testcvs} update -rvendor-branch" \ +"${PROG} [a-z]*: Updating . +[UP] imported-f1 +[UP] imported-f2" # remove file4 on the vendor branch rm imported-f4 - - if ${CVS} rm imported-f4 2>> ${LOGFILE}; then - pass 103 - else - fail 103 - fi + dotest import-103 "${testcvs} rm imported-f4" \ +"${PROG}"' [a-z]*: scheduling `imported-f4'\'' for removal +'"${PROG}"' [a-z]*: use .'"${PROG}"' commit. to remove this file permanently' # commit - if ${CVS} ci -m vendor-removed imported-f4 >>${LOGFILE}; then - pass 104 - else - fail 104 - fi + dotest import-104 \ +"${testcvs} ci -m vendor-removed imported-f4" \ +"Removing imported-f4; +${TESTDIR}/cvsroot/first-dir/imported-f4,v <-- imported-f4 +new revision: delete; previous revision: 1\.1\.1\.1 +done" # update to main line - if ${CVS} update -A 2>> ${LOGFILE}; then - pass 105 - else - fail 105 - fi + dotest import-105 "${testcvs} -q update -A" \ +"${PROG} [a-z]*: warning: imported-f1 is not (any longer) pertinent +[UP] imported-f2" # second import - file4 deliberately unchanged cd ../import-dir for i in 1 2 3 ; do - echo rev 2 of file $i >> imported-f"$i" + echo rev 2 of file $i >> imported-f"$i" done cp imported-f2 ../imported-f2-orig.tmp - if ${CVS} import -m second-import first-dir vendor-branch junk-2_0 ; then - pass 106 - else - fail 106 - fi - if cmp ../imported-f2-orig.tmp imported-f2; then - pass 106.5 - else - fail 106.5 - fi + dotest_sort import-106 \ +"${testcvs} import -m second-import first-dir vendor-branch junk-2_0" \ +" + + + ${PROG} checkout -jvendor-branch:yesterday -jvendor-branch first-dir +2 conflicts created by this import. +C first-dir/imported-f1 +C first-dir/imported-f2 +I first-dir/RCS +U first-dir/imported-f3 +U first-dir/imported-f4 +Use the following command to help the merge:" + + dotest import-106.5 "cmp ../imported-f2-orig.tmp imported-f2" \ +'' + cd .. + rm imported-f2-orig.tmp # co - if ${CVS} co first-dir ; then - pass 107 - else - fail 107 - fi + dotest import-107 "${testcvs} co first-dir" \ +"${PROG} [a-z]*: Updating first-dir +[UP] first-dir/imported-f3 +[UP] first-dir/imported-f4" cd first-dir - if test -f imported-f1 ; then - fail 108 - else - pass 108 - fi + dotest_fail import-108 "test -f imported-f1" '' for i in 2 3 ; do - if test -f imported-f"$i" ; then - pass 109-$i - else - fail 109-$i - fi + dotest import-109-$i "test -f imported-f$i" '' done # check vendor branch for file4 - if ${CVS} update -rvendor-branch ; then - pass 110 - else - fail 110 - fi + dotest import-110 "${testcvs} -q update -rvendor-branch" \ +"[UP] imported-f1 +[UP] imported-f2" - if test -f imported-f4 ; then - pass 111 - else - fail 111 - fi + dotest import-111 "test -f imported-f4" '' # update to main line - if ${CVS} update -A 2>> ${LOGFILE}; then - pass 112 - else - fail 112 - fi + dotest import-112 "${testcvs} -q update -A" \ +"${PROG} [a-z]*: warning: imported-f1 is not (any longer) pertinent +[UP] imported-f2" cd .. @@ -3894,18 +4628,10 @@ rcsmerge: warning: conflicts during merge" cd first-dir - if test -f imported-f1 ; then - fail 114 - else - pass 114 - fi + dotest_fail import-114 "test -f imported-f1" '' for i in 2 3 ; do - if test -f imported-f"$i" ; then - pass 115-$i - else - fail 115-$i - fi + dotest import-115-$i "test -f imported-f$i" '' done dotest import-116 'cat imported-f2' \ @@ -3950,12 +4676,14 @@ No conflicts created by this import" echo 'FreeMunger sources' >file2 # Not completely sure how the conflict detection is supposed to # be working here (haven't really thought about it). + # We use an explicit -d option to test that it is reflected + # in the suggested checkout. dotest_sort importb-2 \ -"${testcvs} import -m add -b 1.1.3 first-dir freemunger freemunger-1_0" \ +"${testcvs} -d ${CVSROOT} import -m add -b 1.1.3 first-dir freemunger freemunger-1_0" \ " - ${PROG} checkout -jfreemunger:yesterday -jfreemunger first-dir + ${PROG} -d ${CVSROOT} checkout -jfreemunger:yesterday -jfreemunger first-dir 2 conflicts created by this import. C first-dir/file1 C first-dir/file2 @@ -4024,16 +4752,25 @@ add importc) # Test importing a bunch o' files in a bunch o' directories. + # Also the -d option. mkdir 1; cd 1 mkdir adir bdir cdir mkdir adir/sub1 adir/sub2 mkdir adir/sub1/ssdir mkdir bdir/subdir touch adir/sub1/file1 adir/sub2/file2 adir/sub1/ssdir/ssfile - touch bdir/subdir/file1 - touch cdir/cfile + # If I'm correctly reading the Single Unix Specification, + # version 2, then "touch -t 197107040343" or "touch -t 203412251801" + # should work. But GNU touch seems to have other ideas. + # I sort of wonder if this is lossage by the standards bodies, + # I'm not sure. + # Note that some versions of touch when used without -t don't handle + # y2k and/or set the seconds reliably. + # We should probably find a different way of doing this. + touch 0704034371 bdir/subdir/file1 + touch 1225180134 cdir/cfile dotest_sort importc-1 \ -"${testcvs} import -m import-it first-dir vendor release" \ +"${testcvs} import -d -m import-it first-dir vendor release" \ " N first-dir/adir/sub1/file1 @@ -4092,6 +4829,63 @@ ${TESTDIR}/cvsroot/first-dir/cdir/cfile,v <-- cfile new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 done" fi + + # TODO: should also be testing "import -d" when we update + # an existing file. + dotest importc-8 "${testcvs} -q log cdir/cfile" " +RCS file: ${TESTDIR}/cvsroot/first-dir/cdir/cfile,v +Working file: cdir/cfile +head: 1\.1 +branch: 1\.1\.1 +locks: strict +access list: +symbolic names: + wip_test: 1\.1\.1\.1\.0\.2 + release: 1\.1\.1\.1 + vendor: 1\.1\.1 +keyword substitution: kv +total revisions: 3; selected revisions: 3 +description: +---------------------------- +revision 1\.1 +date: 2034/12/2[4-6] [0-9][0-9]:01:[0-9][0-9]; author: ${username}; state: Exp; +branches: 1\.1\.1; +Initial revision +---------------------------- +revision 1\.1\.1\.1 +date: 2034/12/2[4-6] [0-9][0-9]:01:[0-9][0-9]; author: ${username}; state: Exp; lines: ${PLUS}0 -0 +branches: 1\.1\.1\.1\.2; +import-it +---------------------------- +revision 1\.1\.1\.1\.2\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +modify +=============================================================================" + + dotest importc-9 "${testcvs} -q log bdir/subdir/file1" " +RCS file: ${TESTDIR}/cvsroot/first-dir/bdir/subdir/file1,v +Working file: bdir/subdir/file1 +head: 1\.1 +branch: 1\.1\.1 +locks: strict +access list: +symbolic names: + wip_test: 1\.1\.1\.1\.0\.2 + release: 1\.1\.1\.1 + vendor: 1\.1\.1 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.1 +date: 1971/07/0[3-5] [0-9][0-9]:43:[0-9][0-9]; author: ${username}; state: Exp; +branches: 1\.1\.1; +Initial revision +---------------------------- +revision 1\.1\.1\.1 +date: 1971/07/0[3-5] [0-9][0-9]:43:[0-9][0-9]; author: ${username}; state: Exp; lines: ${PLUS}0 -0 +import-it +=============================================================================" cd .. cd .. @@ -4099,6 +4893,62 @@ done" rm -rf ${CVSROOT_DIRNAME}/first-dir ;; + import-after-initial) + # Properly handle the case in which the first version of a + # file is created by a regular cvs add and commit, and there + # is a subsequent cvs import of the same file. cvs update with + # a date tag must resort to searching the vendor branch only if + # the initial version of the file was created at the same time + # as the initial version on the vendor branch. + + mkdir 1; cd 1 + module=x + + echo > unused-file + + # Create the module. + dotest import-after-initial-1 \ + "$testcvs -Q import -m. $module X Y" '' + + file=m + # Check it out and add a file. + dotest import-after-initial-2 "$testcvs -Q co $module" '' + cd $module + echo original > $file + dotest import-after-initial-3 "${testcvs} -Q add $file" \ +"${PROG}"' [a-z]*: use .'"${PROG}"' commit. to add this file permanently' + dotest import-after-initial-4 "${testcvs} -Q ci -m. $file" \ +"RCS file: ${TESTDIR}/cvsroot/$module/$file,v +done +Checking in $file; +${TESTDIR}/cvsroot/$module/$file,v <-- $file +initial revision: 1\.1 +done" + + # Delay a little so the following import isn't done in the same + # second as the preceding commit. + sleep 2 + + # Do the first import of $file *after* $file already has an + # initial version. + mkdir sub + cd sub + echo newer-via-import > $file + dotest import-after-initial-5 \ + "$testcvs -Q import -m. $module X Y2" '' + cd .. + + # Sleep a second so we're sure to be after the second of the import. + sleep 1 + + dotest import-after-initial-6 \ + "$testcvs -Q update -p -D now $file" 'original' + + cd ../.. + rm -rf 1 + rm -rf ${CVSROOT_DIRNAME}/$module + ;; + join) # Test doing joins which involve adding and removing files. # Variety of scenarios (see list below), in the context of: @@ -4108,6 +4958,8 @@ done" # See also binfile2, which does similar things with binary files. # See also join2, which tests joining (and update -A) on only # a single file, rather than a directory. + # See also rmadd2, which tests -j cases not involving branches + # (e.g. undoing a commit) # See also join3, which tests some cases involving the greatest # common ancestor. Here is a list of tests according to branch # topology: @@ -4728,6 +5580,60 @@ br2:line1 rm -rf ${CVSROOT_DIRNAME}/first-dir ;; + join-readonly-conflict) + # Demonstrate that cvs-1.9.29 can fail on 2nd and subsequent + # conflict-evoking join attempts. + # Even with that version of CVS, This test failed only in + # client-server mode, and would have been noticed in normal + # operation only for files that were read-only (either due to + # use of cvs' global -r option, setting the CVSREAD envvar, + # or use of watch lists). + mkdir 1; cd 1 + dotest join-readonly-conflict-1 "$testcvs -q co -l ." '' + module=x + mkdir $module + $testcvs -q add $module >>$LOGFILE 2>&1 + cd $module + + file=m + echo trunk > $file + $testcvs -q add $file >>$LOGFILE 2>&1 + $testcvs -q ci -m . $file >>$LOGFILE 2>&1 + + $testcvs tag -b B $file >>$LOGFILE 2>&1 + $testcvs -q update -rB $file >>$LOGFILE 2>&1 + echo branch B > $file + $testcvs ci -m . $file >>$LOGFILE 2>&1 + + rm $file + $testcvs update -A $file >>$LOGFILE 2>&1 + # Make sure $file is read-only. This can happen more realistically + # via patch -- which could be used to apply a delta, yet would + # preserve a file's read-only permissions. + echo conflict > $file; chmod u-w $file + $testcvs update -r B $file >>$LOGFILE 2>&1 + + rm -f $file + $testcvs update -A $file >>$LOGFILE 2>&1 + # This one would fail because cvs couldn't open the existing + # (and read-only) .# file for writing. + echo conflict > $file + + test -w ".#$file.1.1" && fail "$file is writable" + dotest join-readonly-conflict-2 "$testcvs update -r B $file" \ +"RCS file: ${TESTDIR}/cvsroot/$module/$file,v +retrieving revision 1\.1 +retrieving revision 1\.1\.2\.1 +Merging differences between 1\.1 and 1\.1\.2\.1 into $file +rcsmerge: warning: conflicts during merge +${PROG} [a-z]*: conflicts found in $file +C m" + + cd ../.. + rm -rf 1 + rm -rf ${CVSROOT_DIRNAME}/$module + ;; + new) # look for stray "no longer pertinent" messages. mkdir ${CVSROOT_DIRNAME}/first-dir @@ -4973,6 +5879,14 @@ File: a Status: Needs Merge Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none)" + dotest conflicts-129a "${testcvs} -nq update a" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/a,v +retrieving revision 1\.1 +retrieving revision 1\.2 +Merging differences between 1\.1 and 1\.2 into a +rcsmerge: warning: conflicts during merge +${PROG} [a-z]*: conflicts found in a +C a" dotest conflicts-130 "${testcvs} -q update" \ "RCS file: ${TESTDIR}/cvsroot/first-dir/a,v retrieving revision 1\.1 @@ -5163,6 +6077,9 @@ done" U first-dir/abc' cd .. + # BEGIN TESTS USING THE FILE A + # FIXME: would be cleaner to separate them out into their own + # tests; conflicts2 is getting long. # Now test that if one person modifies and commits a # file and a second person removes it, it is a # conflict @@ -5186,7 +6103,46 @@ C a" dotest conflicts2-142b5 "${testcvs} add a" "U a ${PROG} [a-z]*: a, version 1\.1, resurrected" dotest conflicts2-142b6 "${testcvs} -q update" '' + + # Now one level up. + cd .. + dotest conflicts2-142b7 "${testcvs} rm -f first-dir/a" \ +"${PROG} [a-z]*: scheduling .first-dir/a. for removal +${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently" + + if test "$remote" = no; then + # The "nothing known" is a bug. Correct behavior is for a to get + # created, as above. Cause is pretty obvious - add.c + # calls update() without dealing with the fact we are chdir'd. + # Also note that resurrecting 1.2 instead of 1.1 is also a + # bug, I think (the same part of add.c has a comment which says + # "XXX - bugs here; this really resurrect the head" which + # presumably refers to this). + # The fix for both is presumably to call RCS_checkout() or + # something other than update(). + dotest conflicts2-142b8 "${testcvs} add first-dir/a" \ +"${PROG} [a-z]*: nothing known about first-dir +${PROG} [a-z]*: first-dir/a, version 1\.2, resurrected" + cd first-dir + # Now recover from the damage that the 142b8 test did. + dotest conflicts2-142b9 "${testcvs} rm -f a" \ +"${PROG} [a-z]*: scheduling .a. for removal +${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently" + else + # Haven't investigated this one. + dotest_fail conflicts2-142b8 "${testcvs} add first-dir/a" \ +"${PROG} add: in directory \.: +${PROG} \[add aborted\]: there is no version here; do 'cvs checkout' first" + cd first-dir + fi + + # As before, 1.2 instead of 1.1 is a bug. + dotest conflicts2-142b10 "${testcvs} add a" "U a +${PROG} [a-z]*: a, version 1\.2, resurrected" + # As with conflicts2-142b6, check that things are normal again. + dotest conflicts2-142b11 "${testcvs} -q update" '' cd ../.. + # END TESTS USING THE FILE A # Now test that if one person removes a file and # commits it, and a second person removes it, is it @@ -5438,7 +6394,7 @@ ${PROG} [a-z]*: ignoring first-dir/sdir (CVS/Entries missing)" dotest conflicts3-21 "${testcvs} -q update -d sdir" "U sdir/sfile" rm -r sdir/CVS - dotest conflicts3-22 "${testcvs} -q update" "? sdir" + dotest conflicts3-22 "${testcvs} -q update" "${QUESTION} sdir" if test "x$remote" = xyes; then # It isn't particularly swift that CVS prints this # "cannot open CVS/Entries" where it has already printed @@ -5456,6 +6412,37 @@ C sdir/sfile" "${QUESTION} sdir" fi + # Not that it should really affect much, but let's do the case + # where sfile has been removed. For example, suppose that sdir + # had been a CVS-controlled directory which was then removed + # by removing each file (and using update -P or some such). Then + # suppose that the build process creates an sdir directory which + # is not supposed to be under CVS. + rm -r sdir + dotest conflicts3-24 "${testcvs} -q update -d sdir" "U sdir/sfile" + rm sdir/sfile + dotest conflicts3-25 "${testcvs} rm sdir/sfile" \ +"${PROG} [a-z]*: scheduling .sdir/sfile. for removal +${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently" + dotest conflicts3-26 "${testcvs} ci -m remove sdir/sfile" \ +"Removing sdir/sfile; +${TESTDIR}/cvsroot/first-dir/sdir/sfile,v <-- sfile +new revision: delete; previous revision: 1\.1 +done" + rm -r sdir/CVS + dotest conflicts3-27 "${testcvs} -q update" "${QUESTION} sdir" + if test "x$remote" = xyes; then + # Regarding "cannot open CVS/Entries", see comments at + # conflicts3-23. + dotest conflicts3-28 "${testcvs} -q update -PdA" \ +"${QUESTION} sdir +${PROG} update: in directory sdir: +${PROG} update: cannot open CVS/Entries for reading: No such file or directory" + else + dotest conflicts3-28 "${testcvs} -q update -PdA" \ +"${QUESTION} sdir" + fi + cd ../.. rm -r 1 2 @@ -5906,10 +6893,7 @@ ${PROG} [a-z]*: Rebuilding administrative file database" dotest modules2-5 "test -d ampermodule/second-dir" '' # Test ability of cvs release to handle multiple arguments - # Other CVS release tests: - # info-cleanup-0 for "cvs -n release". - # ignore-193 for the text of the question that cvs release asks. - # Also for interactions with cvsignore. + # See comment at "release" for list of other cvs release tests. cd ampermodule if ${testcvs} release -d first-dir second-dir <<EOF >>${LOGFILE} yes @@ -5983,26 +6967,15 @@ U first-dir/amper1" dotest modules2-16 "test -f combmodule/first-dir/amper1" "" cd combmodule rm -r first-dir - # Might be possible to have a more graceful error message, - # but at least for now there is no way to tell CVS that + # At least for now there is no way to tell CVS that # some files/subdirectories come from one repository directory, # and others from another. - if test "$remote" = no; then - dotest_fail modules2-17 "${testcvs} update -d" \ -"${PROG} [a-z]*: Updating \. -${PROG} [a-z]*: Updating first-dir -${PROG} \[[a-z]* aborted\]: cannot open directory ${TESTDIR}/cvsroot/third-dir/first-dir: No such file or directory" - # Clean up the droppings left by the previous command. - # This should definitely not be necessary (I think). - rm -r first-dir - else - # This seems like a pretty sensible behavior to me, in the - # sense that first-dir doesn't "really" exist within - # third-dir, so CVS just acts as if there is nothing there - # to do. - dotest modules2-17 "${testcvs} update -d" \ -"${PROG} server: Updating \." - fi + # This seems like a pretty sensible behavior to me, in the + # sense that first-dir doesn't "really" exist within + # third-dir, so CVS just acts as if there is nothing there + # to do. + dotest modules2-17 "${testcvs} update -d" \ +"${PROG} [a-z]*: Updating \." cd .. dotest modules2-18 "${testcvs} -q co combmodule" \ @@ -6332,6 +7305,30 @@ add-it rm -rf ${CVSROOT_DIRNAME}/first-dir ;; + mkmodules-temp-file-removal) + # When a file listed in checkoutlist doesn't exist, cvs-1.10.4 + # would fail to remove the CVSROOT/.#[0-9]* temporary file it + # creates while mkmodules is in the process of trying to check + # out the missing file. + + mkdir 1; cd 1 + dotest mtfr-1 "${testcvs} -Q co CVSROOT" '' + cd CVSROOT + echo no-such-file >> checkoutlist + dotest mtfr-2 "${testcvs} -Q ci -m. checkoutlist" \ +"Checking in checkoutlist; +$CVSROOT_DIRNAME/CVSROOT/checkoutlist,v <-- checkoutlist +new revision: 1\.2; previous revision: 1\.1 +done +$PROG [a-z]*: Rebuilding administrative file database" + + dotest mtfr-3 "echo $CVSROOT_DIRNAME/CVSROOT/.#[0-9]*" \ + "$CVSROOT_DIRNAME/CVSROOT/\.#\[0-9\]\*" + + cd ../.. + rm -rf 1 + ;; + cvsadm) # These test check the content of CVS' administrative # files as they are checked out in various configurations. @@ -7812,22 +8809,15 @@ done" U dir2d1/sub2d1/file1" cd dir2d1 touch emptyfile - # The fact that CVS lets us add a file here is a CVS bug, right? - # I can just make this an error message (on the add and/or the - # commit) without getting flamed, right? - # Right? - # Right? + # It doesn't make any sense to add a file (or do much of anything + # else) in Emptydir; Emptydir is a placeholder indicating that + # the working directory doesn't correspond to anything in + # the repository. dotest emptydir-7 "${testcvs} add emptyfile" \ "${PROG} [a-z]*: scheduling file .emptyfile. for addition ${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" - dotest emptydir-8 "${testcvs} -q ci -m add" \ -"RCS file: ${TESTDIR}/cvsroot/CVSROOT/Emptydir/emptyfile,v -done -Checking in emptyfile; -${TESTDIR}/cvsroot/CVSROOT/Emptydir/emptyfile,v <-- emptyfile -initial revision: 1\.1 -done -${PROG} [a-z]*: Rebuilding administrative file database" + dotest_fail emptydir-8 "${testcvs} -q ci -m add" \ +"${PROG} \[[a-z]* aborted\]: cannot check in to ${TESTDIR}/cvsroot/CVSROOT/Emptydir" cd .. rm -rf CVS dir2d1 @@ -8806,17 +9796,7 @@ done" pass 177 fi - if ${testcvs} editors >../ans178.tmp; then - pass 178 - else - fail 178 - fi - cat ../ans178.tmp >>${LOGFILE} - if test -s ../ans178.tmp; then - fail 178a - else - pass 178a - fi + dotest devcom-178 "${testcvs} editors" "" if ${testcvs} edit abb; then pass 179 @@ -8824,17 +9804,13 @@ done" fail 179 fi - if ${testcvs} editors >../ans180.tmp; then - pass 180 - else - fail 180 - fi - cat ../ans180.tmp >>${LOGFILE} - if test -s ../ans180.tmp; then - pass 181 - else - fail 181 - fi + # Here we test for the traditional ISO C ctime() date format. + # We assume the C locale; I guess that works provided we set + # LC_ALL at the start of this script but whether these + # strings should vary based on locale does not strike me as + # self-evident. + dotest devcom-180 "${testcvs} editors" \ +"abb ${username} [SMTWF][uoehra][neduit] [JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] GMT [-a-zA-Z_.0-9]* ${TESTDIR}/2/first-dir" echo aaaa >>abb if ${testcvs} ci -m modify abb >>${LOGFILE} 2>&1; then @@ -8845,17 +9821,7 @@ done" # Unedit of a file not being edited should be a noop. dotest 182.5 "${testcvs} unedit abb" '' - if ${testcvs} editors >../ans183.tmp; then - pass 183 - else - fail 183 - fi - cat ../ans183.tmp >>${LOGFILE} - if test -s ../ans183.tmp; then - fail 184 - else - pass 184 - fi + dotest devcom-183 "${testcvs} editors" "" if test -w abb; then fail 185 @@ -9083,7 +10049,7 @@ D _watched=" Fw2 _watched=" # Now write a few more lines, just as if we were a newer version # of CVS implementing some new feature. - cat <<EOF >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr + cat <<'EOF' >>${CVSROOT_DIRNAME}/first-dir/CVS/fileattr Enew line here G@#$^!@#=& EOF @@ -9250,7 +10216,7 @@ ${PROG} unedit: run update to complete the unedit" # SunOS4.1.4 systems make it this far, but with a corrupted # CVS/Entries file. Demonstrate the corruption! dotest unedit-without-baserev-5 "cat CVS/Entries" \ - "/$file/1\.1\.1\.1/.*" + "/$file/1\.1\.1\.1/${DOTSTAR}" if test "$remote" = yes; then dotest unedit-without-baserev-6 "${testcvs} -q update" "U m" @@ -9476,11 +10442,18 @@ Are you sure you want to release (and delete) directory .second-dir': " binfiles) # Test cvs's ability to handle binary files. + # List of binary file tests: + # * conflicts, "cvs admin": binfiles + # * branching and joining: binfiles2 + # * adding and removing files: binfiles3 + # * -k wrappers: binwrap, binwrap2, binwrap3 + # * "cvs import" and wrappers: binwrap, binwrap2, binwrap3 + # * -k option to "cvs import": none yet, as far as I know. mkdir ${CVSROOT_DIRNAME}/first-dir mkdir 1; cd 1 dotest binfiles-1 "${testcvs} -q co first-dir" '' - awk 'BEGIN { printf "%c%c%c%c%c%c", 2, 10, 137, 0, 13, 10 }' \ - </dev/null >binfile.dat + awk 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ + </dev/null | tr '@' '\000' >binfile.dat cat binfile.dat binfile.dat >binfile2.dat cd first-dir cp ../binfile.dat binfile @@ -9577,7 +10550,6 @@ done" dotest binfiles-13 "${testcvs} -q update -A" '' cd ../.. - rm -r 1 mkdir 3 cd 3 @@ -9713,8 +10685,14 @@ keyword substitution: v total revisions: 1 =============================================================================" + # Check that the contents were right. This isn't the hard case + # (in which RCS_delete_revs does a diff), but might as well. + dotest binfiles-o4 "${testcvs} -q update binfile" "U binfile" + dotest binfiles-o5 "cmp binfile ../../1/binfile.dat" "" + cd ../.. rm -rf ${CVSROOT_DIRNAME}/first-dir + rm -r 1 rm -r 2 ;; @@ -9746,8 +10724,8 @@ total revisions: 1 # each be distinct from each other. We also make sure to include # a few likely end-of-line patterns to make sure nothing is # being munged as if in text mode. - awk 'BEGIN { printf "%c%c%c%c%c%c", 2, 10, 137, 0, 13, 10 }' \ - </dev/null >../binfile + awk 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ + </dev/null | tr '@' '\000' >../binfile cat ../binfile ../binfile >../binfile2 cat ../binfile2 ../binfile >../binfile3 @@ -9902,6 +10880,96 @@ checkin rm -r 1 ;; + binfiles3) + # More binary file tests, especially removing, adding, &c. + # See "binfiles" for a list of binary file tests. + mkdir ${CVSROOT_DIRNAME}/first-dir + mkdir 1; cd 1 + dotest binfiles3-1 "${testcvs} -q co first-dir" '' + awk 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ + </dev/null | tr '@' '\000' >binfile.dat + cd first-dir + echo hello >file1 + dotest binfiles3-2 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest binfiles3-3 "${testcvs} -q ci -m add-it" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +done +Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +initial revision: 1\.1 +done" + rm file1 + dotest binfiles3-4 "${testcvs} rm file1" \ +"${PROG} [a-z]*: scheduling .file1. for removal +${PROG} [a-z]*: use .${PROG} commit. to remove this file permanently" + dotest binfiles3-5 "${testcvs} -q ci -m remove-it" \ +"Removing file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: delete; previous revision: 1\.1 +done" + cp ../binfile.dat file1 + dotest binfiles3-6 "${testcvs} add -kb file1" \ +"${PROG} [a-z]*: re-adding file file1 (in place of dead revision 1\.2) +${PROG} [a-z]*: use .cvs commit. to add this file permanently" + # The idea behind this test is to make sure that the file + # gets opened in binary mode to send to "cvs ci". + dotest binfiles3-6a "cat CVS/Entries" \ +"/file1/0/[A-Za-z0-9 :]*/-kb/ +D" + # TODO: This just tests the case where the old keyword + # expansion mode is the default (RCS_getexpand == NULL + # in checkaddfile()); should also test the case in which + # we are changing it from one non-default value to another. + dotest binfiles3-7 "${testcvs} -q ci -m readd-it" \ +"${PROG} [a-z]*: changing keyword expansion mode to -kb +Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.3; previous revision: 1\.2 +done" + dotest binfiles3-8 "${testcvs} -q log -h -N file1" " +RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +Working file: file1 +head: 1\.3 +branch: +locks: strict +access list: +keyword substitution: b +total revisions: 3 +=============================================================================" + + # OK, now test admin -o on a binary file. See "admin" + # test for a more complete list of admin -o tests. + cp ${TESTDIR}/1/binfile.dat ${TESTDIR}/1/binfile4.dat + echo '%%$$##@@!!jjiiuull' | tr j '\000' >>${TESTDIR}/1/binfile4.dat + cp ${TESTDIR}/1/binfile4.dat ${TESTDIR}/1/binfile5.dat + echo 'aawwee%$$##@@!!jjil' | tr w '\000' >>${TESTDIR}/1/binfile5.dat + + cp ../binfile4.dat file1 + dotest binfiles3-9 "${testcvs} -q ci -m change" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.4; previous revision: 1\.3 +done" + cp ../binfile5.dat file1 + dotest binfiles3-10 "${testcvs} -q ci -m change" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.5; previous revision: 1\.4 +done" + dotest binfiles3-11 "${testcvs} admin -o 1.3::1.5 file1" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +deleting revision 1\.4 +done" + dotest binfiles3-12 "${testcvs} -q update -r 1.3 file1" "U file1" + dotest binfiles3-13 "cmp file1 ${TESTDIR}/1/binfile.dat" "" + + cd ../.. + rm -r 1 + rm -rf ${CVSROOT_DIRNAME}/first-dir + ;; + mcopy) # See comment at "mwrap" test for list of other wrappers tests. # Test cvs's ability to handle nonmergeable files specified with @@ -10447,7 +11515,24 @@ done" cd ../.. cd m1/first-dir echo "changed in m1" >aa - dotest_fail mwrap-7 "${testcvs} -nq update" "C aa" + if test "$remote" = no; then + dotest mwrap-7 "${testcvs} -nq update" \ +"U aa +${PROG} [a-z]*: nonmergeable file needs merge +${PROG} [a-z]*: revision 1\.2 from repository is now in aa +${PROG} [a-z]*: file from working directory is now in \.#aa\.1\.1 +C aa" + else + # The tagged text code swallows up "U aa" but isn't yet up to + # trying to figure out how it interacts with the "C aa" and + # other stuff. The whole deal of having both is pretty iffy. + dotest mwrap-7 "${testcvs} -nq update" \ +"${PROG} [a-z]*: nonmergeable file needs merge +${PROG} [a-z]*: revision 1\.2 from repository is now in aa +${PROG} [a-z]*: file from working directory is now in \.#aa\.1\.1 +C aa +U aa" + fi dotest mwrap-8 "${testcvs} -q update" \ "U aa ${PROG} [a-z]*: nonmergeable file needs merge @@ -10630,6 +11715,7 @@ ${PROG} [a-z]*: Rebuilding administrative file database" fi cd .. rm -r wnt + rm $HOME/.cvsrc rm -rf ${CVSROOT_DIRNAME}/first-dir ;; @@ -10639,8 +11725,6 @@ ${PROG} [a-z]*: Rebuilding administrative file database" # Tests to add: # -F to move - # -d - # rtag mkdir 1; cd 1 dotest taginfo-1 "${testcvs} -q co CVSROOT" "U CVSROOT/${DOTSTAR}" @@ -10708,6 +11792,16 @@ ${PROG} \[[a-z]* aborted\]: correct the above errors first!" # specified or not. dotest taginfo-13 "${testcvs} -nq tag would-be-tag" "T file1" + # Deleting: the cases are basically either the tag existed, + # or it didn't exist. + dotest taginfo-14 "${testcvs} -q tag -d tag1" "D file1" + dotest taginfo-15 "${testcvs} -q tag -d tag1" "" + + # Likewise with rtag. + dotest taginfo-16 "${testcvs} -q rtag tag1 first-dir" "" + dotest taginfo-17 "${testcvs} -q rtag -d tag1 first-dir" "" + dotest taginfo-18 "${testcvs} -q rtag -d tag1 first-dir" "" + # The "br" example should be passing 1.1.2 or 1.1.0.2. # But it turns out that is very hard to implement, since # check_fileproc doesn't know what branch number it will @@ -10722,7 +11816,12 @@ ${PROG} \[[a-z]* aborted\]: correct the above errors first!" dotest taginfo-examine "cat ${TESTDIR}/1/taglog" \ "tag1 add ${TESTDIR}/cvsroot/first-dir file1 1.1 br add ${TESTDIR}/cvsroot/first-dir file1 1.1 -brtag mov ${TESTDIR}/cvsroot/first-dir file1 1.1.2.1" +brtag mov ${TESTDIR}/cvsroot/first-dir file1 1.1.2.1 +tag1 del ${TESTDIR}/cvsroot/first-dir file1 1.1 +tag1 del ${TESTDIR}/cvsroot/first-dir +tag1 add ${TESTDIR}/cvsroot/first-dir file1 1.1 +tag1 del ${TESTDIR}/cvsroot/first-dir file1 1.1 +tag1 del ${TESTDIR}/cvsroot/first-dir" cd .. cd CVSROOT @@ -10859,6 +11958,7 @@ U file1' # -N: log, log2, admin-19a-log # -b, -r: log # -d: rcs + # -s, -R: rcs3 # Check in a file with a few revisions and branches. mkdir ${CVSROOT_DIRNAME}/first-dir @@ -11003,6 +12103,28 @@ description: ${log_rev3} ${log_trailer}" + dotest log-14a "${testcvs} log -rHEAD file1" \ +"${log_header} +${log_tags} +${log_header2} +total revisions: 5; selected revisions: 1 +description: +${log_rev3} +${log_trailer}" + + # The user might not realize that "-r" must not take a space. + # In the error message, HEAD is a file name, not a tag name (which + # might be confusing itself). + dotest_fail log-14b "${testcvs} log -r HEAD file1" \ +"${PROG} [a-z]*: nothing known about HEAD +${log_header} +${log_tags} +${log_header2} +total revisions: 5; selected revisions: 1 +description: +${log_rev3} +${log_trailer}" + dotest log-15 "${testcvs} log -r1.2 file1" \ "${log_header} ${log_tags} @@ -11182,6 +12304,9 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; dotest log2-7 "${testcvs} admin -t${TESTDIR}/descrip file1" \ "RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v done" + dotest_fail log2-7a "${testcvs} admin -t${TESTDIR}/nonexist file1" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +${PROG} \[[a-z]* aborted\]: can't stat ${TESTDIR}/nonexist: No such file or directory" dotest log2-8 "${testcvs} log -N file1" " RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v Working file: file1 @@ -11204,6 +12329,11 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; # See comments in cvs.texinfo for a few more notes on this. if test "x$remote" = xno; then + # TODO: `cvs admin -t "my message" file1' is a request to + # read the message from stdin and to operate on two files. + # Should test that there is an error because "my message" + # doesn't exist. + if echo change from stdin | ${testcvs} admin -t -q file1 then pass log2-9 @@ -11240,6 +12370,7 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; # Tests of "cvs annotate". See also: # basica-10 A simple annotate test # rcs Annotate and the year 2000 + # keywordlog Annotate and $Log. mkdir 1; cd 1 dotest ann-1 "${testcvs} -q co -l ." '' mkdir first-dir @@ -11471,8 +12602,26 @@ ${testcvs} -d ${TESTDIR}/crerepos release -d CVSROOT >>${LOGFILE}; then mkdir crerepos mkdir crerepos/CVSROOT + # Use :ext: rather than :fork:. Most of the tests use :fork:, + # so we want to make sure that we test :ext: _somewhere_. + + # Maybe a bit dubious in the sense that people need to + # have rsh working to run the tests, but at least it + # isn't inetd :-). Might want to think harder about this - + # maybe try :ext:, and if it fails, print a (single, nice) + # message and fall back to :fork:. Maybe testing :ext: + # with our own CVS_RSH rather than worrying about a system one + # would do the trick. + + # Note that we set CVS_SERVER at the beginning. CREREPOS_ROOT=:ext:`hostname`:${TESTDIR}/crerepos + # If we're going to do remote testing, make sure 'rsh' works first. + host="`hostname`" + if test "x`${CVS_RSH-rsh} $host -n 'echo hi'`" != "xhi"; then + echo "ERROR: cannot test remote CVS, because \`rsh $host' fails." >&2 + exit 1 + fi fi if test "x$remote" = "xno"; then @@ -11491,6 +12640,10 @@ ${testcvs} -d ${TESTDIR}/crerepos release -d CVSROOT >>${LOGFILE}; then else # remote # Test that CVS rejects a relative path in CVSROOT. mkdir 1; cd 1 + # Note that having the client reject the pathname (as :fork: + # does), does _not_ test for the bugs we are trying to catch + # here. The point is that malicious clients might send all + # manner of things and the server better protect itself. dotest_fail crerepos-6a \ "${testcvs} -q -d :ext:`hostname`:../crerepos get ." \ "Root ../crerepos must be an absolute pathname" @@ -11560,31 +12713,17 @@ U first-dir/file1" dotest crerepos-17 "${testcvs} -d ${CREREPOS_ROOT} co crerepos-dir" \ "${PROG} [a-z]*: Updating crerepos-dir U crerepos-dir/cfile" - - if test x`cat crerepos-dir/CVS/Repository` = xcrerepos-dir; then - # RELATIVE_REPOS - # Fatal error so that we don't go traipsing through the - # directories which happen to have the same names from the - # wrong repository. - dotest_fail crerepos-18 "${testcvs} -q update" \ -"${PROG} \[[a-z]* aborted\]: cannot open directory ${TESTDIR}/cvsroot/crerepos-dir: .*" '' - else - if test "$remote" = no; then - # The lack of an error doesn't mean CVS is really - # working (things are getting logged to the wrong - # history file and such). - dotest crerepos-18 "${testcvs} -q update" '' - else - # Fatal error so that we don't go traipsing through the - # directories which happen to have the same names from the - # wrong repository. - dotest_fail crerepos-18 "${testcvs} -q update" \ -"protocol error: directory .${TESTDIR}/crerepos/crerepos-dir. not within root .${TESTDIR}/cvsroot." - fi - fi + dotest crerepos-18 "${testcvs} update" \ +"${PROG} [a-z]*: Updating first-dir +${PROG} [a-z]*: Updating crerepos-dir" cd .. + if test "$keep" = yes; then + echo Keeping ${TESTDIR} and exiting due to --keep + exit 0 + fi + rm -r 1 rm -rf ${CVSROOT_DIRNAME}/first-dir ${TESTDIR}/crerepos ;; @@ -12145,6 +13284,32 @@ EOF dotest rcs2-5 "cat ${TESTDIR}/rcs4.tmp" \ "${PROG} \[[a-z]* aborted\]: Can't parse date/time: 2003-02-29 11:30 UT" fi + + dotest rcs2-6 "${testcvs} -q update -p -D 2007-01-07 file1" \ +"head revision" + # This assumes that the clock of the machine running the tests + # is set to at least the year 1998 or so. There don't seem + # to be a lot of ways to test the relative date code (short + # of something like LD_LIBRARY_PRELOAD'ing in our own + # getttimeofday, or hacking the CVS source with testing + # features, which always seems to be problematic since then + # someone feels like documenting them and things go downhill + # from there). + if ${testcvs} -q update -p -D '100 months' file1 \ + >${TESTDIR}/rcs4.tmp 2>&1 + then + dotest rcs2-7 "cat ${TESTDIR}/rcs4.tmp" "head revision" + else + fail rcs2-7 + fi + if ${testcvs} -q update -p -D '8 years' file1 \ + >${TESTDIR}/rcs4.tmp 2>&1 + then + dotest rcs2-8 "cat ${TESTDIR}/rcs4.tmp" "head revision" + else + fail rcs2-8 + fi + rm ${TESTDIR}/rcs4.tmp cd .. @@ -12152,6 +13317,149 @@ EOF rm -rf ${CVSROOT_DIRNAME}/first-dir ;; + rcs3) + # More RCS file tests, in particular at least some of the + # error handling issues. + mkdir ${CVSROOT_DIRNAME}/first-dir + cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v +head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02 +; author jeremiah ;state ; branches; next;desc@@1.1log@@text@head@ +EOF + mkdir 1; cd 1 + # CVS requires whitespace between "desc" and its value. + # The rcsfile(5) manpage doesn't really seem to answer the + # question one way or the other (it has a grammar but almost + # nothing about lexical analysis). + dotest_fail rcs3-1 "${testcvs} -q co first-dir" \ +"${PROG} \[[a-z]* aborted\]: unexpected end of file reading ${TESTDIR}/cvsroot/first-dir/file1,v" + cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v +head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02 +; author jeremiah ;state ; branches; next;desc @@1.1log@@text@head@ +EOF + # Whitespace issues, likewise. + dotest_fail rcs3-2 "${testcvs} -q co first-dir" \ +"${PROG} \[[a-z]* aborted\]: unexpected '.x6c' reading revision number in RCS file ${TESTDIR}/cvsroot/first-dir/file1,v" + cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v +head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02 +; author jeremiah ;state ; branches; next;desc @@1.1 log@@text@head@ +EOF + # Charming array of different messages for similar + # whitespace issues (depending on where the whitespace is). + dotest_fail rcs3-3 "${testcvs} -q co first-dir" \ +"${PROG} \[[a-z]* aborted\]: EOF while looking for value in RCS file ${TESTDIR}/cvsroot/first-dir/file1,v" + cat <<EOF >${CVSROOT_DIRNAME}/first-dir/file1,v +head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02 +; author jeremiah ;state ; branches; next;desc @@1.1 log @@text @head@ +EOF + dotest rcs3-4 "${testcvs} -q co first-dir" 'U first-dir/file1' + if test "$remote" = no; then + # Ouch, didn't expect this one. FIXCVS. Or maybe just remove + # the feature, if this is a -s problem? + dotest_fail rcs3-5 "${testcvs} log -s nostate first-dir/file1" \ +".*[Aa]ssertion.*failed${DOTSTAR}" ".*failed assertion${DOTSTAR}" + else # remote + # Is this a reaction to the lack of TopLevelAdmin or something? + # Seems pretty strange to me. Seems vaguely similar to the + # "no repository" message in errmsg2-16 although I'm leaving + # it here in case there is a difference between "cvs add" and a + # normal start_recursion command like "cvs log". + dotest_fail rcs3-5 "${testcvs} log -s nostate first-dir/file1" \ +"${PROG} log: cannot open CVS/Entries for reading: No such file or directory +${PROG} \[log aborted\]: no repository" + cd first-dir + dotest_fail rcs3-5a "${testcvs} log -s nostate file1" \ +"${DOTSTAR}ssertion.*failed${DOTSTAR}" "${DOTSTAR}failed assertion${DOTSTAR}" + cd .. + fi # remote + + # See remote code above for rationale for cd. + cd first-dir + dotest rcs3-6 "${testcvs} log -R file1" \ +"${TESTDIR}/cvsroot/first-dir/file1,v" + + # OK, now put an extraneous '\0' at the end. + awk </dev/null 'BEGIN { printf "@%c", 10 }' | tr '@' '\000' \ + >>${CVSROOT_DIRNAME}/first-dir/file1,v + dotest_fail rcs3-7 "${testcvs} log -s nostate file1" \ +"${PROG} \[[a-z]* aborted\]: unexpected '.x0' reading revision number in RCS file ${TESTDIR}/cvsroot/first-dir/file1,v" + + cd ../.. + rm -r 1 + rm -rf ${CVSROOT_DIRNAME}/first-dir + ;; + + lockfiles) + # Tests of CVS lock files. + # TODO-maybe: Add a test where we arrange for a loginfo + # script (or some such) to ensure that locks are in place + # so then we can see how they are behaving. + + mkdir 1; cd 1 + mkdir sdir + mkdir sdir/ssdir + echo file >sdir/ssdir/file1 + dotest lockfiles-1 \ +"${testcvs} -Q import -m import-it first-dir bar baz" "" + cd .. + + mkdir 2; cd 2 + dotest lockfiles-2 "${testcvs} -q co first-dir" \ +"U first-dir/sdir/ssdir/file1" + dotest lockfiles-3 "${testcvs} -Q co CVSROOT" "" + cd CVSROOT + echo "LockDir=${TESTDIR}/locks" >config + dotest lockfiles-4 "${testcvs} -q ci -m config-it" \ +"Checking in config; +${TESTDIR}/cvsroot/CVSROOT/config,v <-- config +new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* +done +${PROG} [a-z]*: Rebuilding administrative file database" + cd ../first-dir/sdir/ssdir + # The error message appears twice because Lock_Cleanup only + # stops recursing after the first attempt. + dotest_fail lockfiles-5 "${testcvs} -q update" \ +"${PROG} \[[a-z]* aborted\]: cannot stat ${TESTDIR}/locks: No such file or directory +${PROG} \[[a-z]* aborted\]: cannot stat ${TESTDIR}/locks: No such file or directory" + mkdir ${TESTDIR}/locks + chmod u=rwx,g=r,o= ${TESTDIR}/locks + umask 0077 + CVSUMASK=0077; export CVSUMASK + dotest lockfiles-6 "${testcvs} -q update" "" + # TODO: should also be testing that CVS continues to honor the + # umask and CVSUMASK normally. In the case of the umask, CVS + # doesn't seem to use it for much (although it perhaps should). + dotest lockfiles-7 "ls ${TESTDIR}/locks/first-dir/sdir/ssdir" "" + + # The policy is that when CVS creates new lock directories, they + # inherit the permissions from the parent directory. CVSUMASK + # isn't right, because typically the reason for LockDir is to + # use a different set of permissions. + dotest lockfiles-7a "ls -ld ${TESTDIR}/locks/first-dir" \ +"drwxr----- .*first-dir" + dotest lockfiles-7b "ls -ld ${TESTDIR}/locks/first-dir/sdir/ssdir" \ +"drwxr----- .*first-dir/sdir/ssdir" + + cd ../../.. + dotest lockfiles-8 "${testcvs} -q update" "" + + cd CVSROOT + echo "# nobody here but us comments" >config + dotest lockfiles-cleanup-1 "${testcvs} -q ci -m config-it" \ +"Checking in config; +${TESTDIR}/cvsroot/CVSROOT/config,v <-- config +new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* +done +${PROG} [a-z]*: Rebuilding administrative file database" + cd ../.. + # Perhaps should restore the umask and CVSUMASK to what they + # were before. But the other tests "should" not care about them... + umask 0077 + unset CVSUMASK + rm -r ${TESTDIR}/locks + rm -r 1 2 + rm -rf ${CVSROOT_DIRNAME}/first-dir + ;; + history) # CVSROOT/history tests: # history: various "cvs history" invocations @@ -12368,10 +13676,13 @@ done" if test "x$remote" = xyes; then # The problem here is that the CVSUMASK environment variable # needs to be set on the server (e.g. .bashrc). This is, of - # course, bogus, but that is the way it is currently. + # course, bogus, but that is the way it is currently. The + # first match is for the :ext: method (where the CVSUMASK + # won't be set), while the second is for the :fork: method + # (where it will be). dotest modes-15 \ "ls -l ${TESTDIR}/cvsroot/first-dir/Attic/ac,v" \ -"-r--r--r--.*" +"-r--r--r--.*" "-r--r-----.*" else dotest modes-15 \ "ls -l ${TESTDIR}/cvsroot/first-dir/Attic/ac,v" \ @@ -12431,6 +13742,64 @@ done" rm -rf ${CVSROOT_DIRNAME}/first-dir ;; + modes3) + # Repository permissions. Particularly, what happens if we + # can't read/write in the repository. + # TODO: the case where we can access the repository, just not + # the attic (may that one can remain a fatal error, seems less + # useful for access control). + mkdir 1; cd 1 + dotest modes-1 "${testcvs} -q co -l ." '' + mkdir first-dir second-dir + dotest modes-2 "${testcvs} add first-dir second-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository +Directory ${TESTDIR}/cvsroot/second-dir added to the repository" + touch first-dir/aa second-dir/ab + dotest modes-3 "${testcvs} add first-dir/aa second-dir/ab" \ +"${PROG} [a-z]*: scheduling file .first-dir/aa. for addition +${PROG} [a-z]*: scheduling file .second-dir/ab. for addition +${PROG} [a-z]*: use .${PROG} commit. to add these files permanently" + dotest modes-4 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/aa,v +done +Checking in first-dir/aa; +${TESTDIR}/cvsroot/first-dir/aa,v <-- aa +initial revision: 1\.1 +done +RCS file: ${TESTDIR}/cvsroot/second-dir/ab,v +done +Checking in second-dir/ab; +${TESTDIR}/cvsroot/second-dir/ab,v <-- ab +initial revision: 1\.1 +done" + chmod a= ${TESTDIR}/cvsroot/first-dir + dotest modes-5 "${testcvs} update" \ +"${PROG} [a-z]*: Updating \. +${PROG} [a-z]*: Updating first-dir +${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/first-dir: Permission denied +${PROG} [a-z]*: skipping directory first-dir +${PROG} [a-z]*: Updating second-dir" + + # OK, I can see why one might say the above case could be a + # fatal error, because normally users without access to first-dir + # won't have it in their working directory. But the next + # one is more of a problem if it is fatal. + rm -r first-dir + dotest modes-6 "${testcvs} update -dP" \ +"${PROG} [a-z]*: Updating . +${PROG} [a-z]*: Updating CVSROOT +U ${DOTSTAR} +${PROG} [a-z]*: Updating first-dir +${PROG} [a-z]*: cannot open directory ${TESTDIR}/cvsroot/first-dir: Permission denied +${PROG} [a-z]*: skipping directory first-dir +${PROG} [a-z]*: Updating second-dir" + + cd .. + rm -r 1 + chmod u+rwx ${TESTDIR}/cvsroot/first-dir + rm -rf ${TESTDIR}/cvsroot/first-dir ${TESTDIR}/cvsroot/second-dir + ;; + stamps) # Test timestamps. mkdir 1; cd 1 @@ -12873,6 +14242,8 @@ U file1" "U file1" # "binfiles" (and this test) test "cvs update -k". # "binwrap" tests setting the mode from wrappers. # I don't think any test is testing "cvs import -k". + # Other keyword expansion tests: + # keywordlog - $Log. mkdir 1; cd 1 dotest keyword-1 "${testcvs} -q co -l ." '' mkdir first-dir @@ -13071,22 +14442,18 @@ done" dotest keywordlog-2 "${testcvs} add first-dir" \ "Directory ${TESTDIR}/cvsroot/first-dir added to the repository" cd first-dir - echo change >file1 + echo initial >file1 dotest keywordlog-3 "${testcvs} add file1" \ "${PROG} [a-z]*: scheduling file .file1. for addition ${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" - # Note that we wanted to try "ci -r 1.3 -m add file1" and CVS - # seemed to get all confused, thinking it was adding on a branch - # or something. FIXME? Do something about this? Document it - # in BUGS or someplace? - - dotest keywordlog-4 "${testcvs} -q ci -m add file1" \ + # See "rmadd" for a list of other tests of cvs ci -r. + dotest keywordlog-4 "${testcvs} -q ci -r 1.3 -m add file1" \ "RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v done Checking in file1; ${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 -initial revision: 1\.1 +initial revision: 1\.3 done" cd ../.. @@ -13094,21 +14461,29 @@ done" dotest keywordlog-4a "${testcvs} -q co first-dir" "U first-dir/file1" cd ../1/first-dir - echo 'xx $''Log$' > file1 + echo 'xx $''Log$' >> file1 cat >${TESTDIR}/comment.tmp <<EOF First log line Second log line EOF + # As with rmadd-25, "cvs ci -r" sets a sticky tag. + dotest_fail keywordlog-4b \ +"${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \ +"${PROG} [a-z]*: sticky tag .1\.3. for file .file1. is not a branch +${PROG} \[[a-z]* aborted\]: correct above errors first!" + dotest keywordlog-4c "${testcvs} -q update -A" "M file1" + dotest keywordlog-5 "${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \ "Checking in file1; ${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 +new revision: 1\.4; previous revision: 1\.3 done" rm -f ${TESTDIR}/comment.tmp dotest keywordlog-6 "${testcvs} -q tag -b br" "T file1" dotest keywordlog-7 "cat file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx" @@ -13116,8 +14491,9 @@ xx" cd ../../2/first-dir dotest keywordlog-8 "${testcvs} -q update" "[UP] file1" dotest keywordlog-9 "cat file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx" @@ -13127,14 +14503,15 @@ xx" dotest keywordlog-10 "${testcvs} ci -m modify file1" \ "Checking in file1; ${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 +new revision: 1\.5; previous revision: 1\.4 done" dotest keywordlog-11 "cat file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.3 [0-9/]* [0-9:]* ${username} +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.5 [0-9/]* [0-9:]* ${username} xx modify xx -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx @@ -13143,11 +14520,12 @@ change" cd ../../2/first-dir dotest keywordlog-12 "${testcvs} -q update" "[UP] file1" dotest keywordlog-13 "cat file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.3 [0-9/]* [0-9:]* ${username} +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.5 [0-9/]* [0-9:]* ${username} xx modify xx -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx @@ -13159,14 +14537,15 @@ change" dotest keywordlog-15 "${testcvs} -q ci -m br-modify" \ "Checking in file1; ${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 -new revision: 1\.2\.2\.1; previous revision: 1\.2 +new revision: 1\.4\.2\.1; previous revision: 1\.4 done" dotest keywordlog-16 "cat file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.2\.2\.1 [0-9/]* [0-9:]* ${username} +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username} xx br-modify xx -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx @@ -13174,43 +14553,79 @@ br-change" cd ../../2/first-dir dotest keywordlog-17 "${testcvs} -q update -r br" "[UP] file1" dotest keywordlog-18 "cat file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.2\.2\.1 [0-9/]* [0-9:]* ${username} +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username} xx br-modify xx -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx br-change" cd ../.. dotest keywordlog-19 "${testcvs} -q co -p -r br first-dir/file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.2\.2\.1 [0-9/]* [0-9:]* ${username} +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.4\.2\.1 [0-9/]* [0-9:]* ${username} xx br-modify xx -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx br-change" dotest keywordlog-20 "${testcvs} -q co -p first-dir/file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.3 [0-9/]* [0-9:]* ${username} +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.5 [0-9/]* [0-9:]* ${username} xx modify xx -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx change" - dotest keywordlog-21 "${testcvs} -q co -p -r 1.2 first-dir/file1" \ -"xx "'\$'"Log: file1,v "'\$'" -xx Revision 1\.2 [0-9/]* [0-9:]* ${username} + dotest keywordlog-21 "${testcvs} -q co -p -r 1.4 first-dir/file1" \ +"initial +xx "'\$'"Log: file1,v "'\$'" +xx Revision 1\.4 [0-9/]* [0-9:]* ${username} xx First log line xx Second log line xx" + cd 2/first-dir + # OK, the basic rule for keyword expansion is that it + # happens on checkout. And the rule for annotate is that + # it annotates a checked-in revision, rather than a checked-out + # file. So, although it is kind of confusing that the latest + # revision does not appear in the annotated output, and the + # annotated output does not quite match what you'd get with + # update or checkout, the behavior is more or less logical. + # The same issue occurs with annotate and other keywords, + # I think, although it is particularly noticeable for $Log. + dotest keywordlog-22 "${testcvs} ann -r br file1" \ +"Annotations for file1 +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +1\.3 (${username} *[0-9a-zA-Z-]*): initial +1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx "'\$'"Log: file1,v "'\$'" +1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx Revision 1\.4 [0-9/]* [0-9:]* ${username} +1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx First log line +1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx Second log line +1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): xx +1\.4\.2\.1 (${username} *[0-9a-zA-Z-]*): br-change" + dotest keywordlog-23 "${testcvs} ann -r HEAD file1" \ +"Annotations for file1 +\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* +1\.3 (${username} *[0-9a-zA-Z-]*): initial +1\.5 (${username} *[0-9a-zA-Z-]*): xx "'\$'"Log: file1,v "'\$'" +1\.5 (${username} *[0-9a-zA-Z-]*): xx Revision 1\.4 [0-9/]* [0-9:]* ${username} +1\.5 (${username} *[0-9a-zA-Z-]*): xx First log line +1\.5 (${username} *[0-9a-zA-Z-]*): xx Second log line +1\.5 (${username} *[0-9a-zA-Z-]*): xx +1\.5 (${username} *[0-9a-zA-Z-]*): change" + cd ../.. + rm -r 1 2 rm -rf ${CVSROOT_DIRNAME}/first-dir ;; @@ -13621,14 +15036,13 @@ done" dotest tag8k-15 "$testcvs -Q tag $t-9 $file" '' dotest tag8k-16 "$testcvs -Q tag $t-a $file" '' - # Determine the length of the author value. + # Extract the author value. name=`sed -n 's/.*; author \([^;]*\);.*/\1/p' ${TESTDIR}/cvsroot/$module/$file,v|head -1` - name_len=`expr length $name` + # Form a suffix string of length (16 - length($name)). # CAREFUL: this will lose if $name is longer than 16. - # Then, form a string of length 16 - $name_len. - add_len=`expr 16 - $name_len` - suffix=`expr substr 1234567890123456 1 $add_len` + sed_pattern=`echo $name|sed s/././g` + suffix=`echo 1234567890123456|sed s/$sed_pattern//` # Add a final tag with length chosen so that it will push the # offset of the `;' in the 2nd occurrence of `;\tauthor' in the @@ -13663,7 +15077,8 @@ done" # head-o1 (::branch, where this deletes a revision or is noop) # branches-o1 (::branch, similar, with different branch topology) # log-o1 (1.3.2.1::) - # binfiles-o1 (1.3:: and ::1.3) + # binfiles-o1 (1.3:: and ::1.3; binary files) + # binfiles3-9 (binary files) # Also could be testing: # 1.3.2.6::1.3.2.8 # 1.3.2.6::1.3.2 @@ -13803,6 +15218,7 @@ modify-on-branch # test for what CVS actually exports, and figure we can revise # the check as needed (within the confines of the RCS5 format as # documented in RCSFILES). + # Note that we must accept either 2 or 4 digit year. dotest admin-13 "cat ${CVSROOT_DIRNAME}/first-dir/file1,v" \ "head 1\.1; branch 1\.1\.2; @@ -13817,13 +15233,13 @@ comment @xx@; 1\.1 -date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; +date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; branches 1\.1\.2\.1; next ; 1\.1\.2\.1 -date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo; +date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo; branches; next ; @@ -14222,13 +15638,13 @@ comment @xx@; 1\.1 -date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; +date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; branches 1\.1\.2\.1; next ; 1\.1\.2\.1 -date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo; +date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state foo; branches; next ; @@ -14393,17 +15809,17 @@ comment @# @; 1\.4 -date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; +date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; branches; next 1\.3; 1\.3 -date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; +date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; branches; next 1\.2; 1\.2 -date [0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; +date [0-9][0-9]*\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]; author ${username}; state Exp; branches; next ; @@ -15496,6 +16912,1976 @@ d472 12 rm -rf ${CVSROOT_DIRNAME}/diffmerge2 ;; + release) + # Tests of "cvs release", particularly multiple arguments. + # Other CVS release tests: + # info-cleanup-0 for "cvs -n release". + # ignore-193 for the text of the question that cvs release asks. + # Also for interactions with cvsignore. + # basicc: "-d .", global -Q, no arguments (is a noop), + # "cvs release" without -d, multiple arguments. + # dirs-4: repository directory has been deleted. + # modules2-6: multiple arguments. + + # First the usual setup; create a directory first-dir. + mkdir 1; cd 1 + dotest release-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest release-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + mkdir dir1 + dotest release-3 "${testcvs} add dir1" \ +"Directory ${TESTDIR}/cvsroot/first-dir/dir1 added to the repository" + mkdir dir2 + dotest release-4 "${testcvs} add dir2" \ +"Directory ${TESTDIR}/cvsroot/first-dir/dir2 added to the repository" + cd dir2 + mkdir dir3 + dotest release-5 "${testcvs} add dir3" \ +"Directory ${TESTDIR}/cvsroot/first-dir/dir2/dir3 added to the repository" + + cd ../.. + dotest release-6 "${testcvs} release -d first-dir/dir2/dir3 first-dir/dir1" \ +"You have .0. altered files in this repository. +Are you sure you want to release (and delete) directory .first-dir/dir2/dir3.: \ +You have .0. altered files in this repository. +Are you sure you want to release (and delete) directory .first-dir/dir1.: " <<EOF +yes +yes +EOF + dotest_fail release-7 "test -d first-dir/dir1" '' + dotest_fail release-8 "test -d first-dir/dir2/dir3" '' + dotest release-9 "${testcvs} update" \ +"${PROG} [a-z]*: Updating \. +${PROG} [a-z]*: Updating first-dir +${PROG} [a-z]*: Updating first-dir/dir2" + + cd first-dir + mkdir dir1 + dotest release-10 "${testcvs} add dir1" \ +"Directory ${TESTDIR}/cvsroot/first-dir/dir1 added to the repository" + cd dir2 + mkdir dir3 + dotest release-11 "${testcvs} add dir3" \ +"Directory ${TESTDIR}/cvsroot/first-dir/dir2/dir3 added to the repository" + + cd ../.. + dotest release-12 "${testcvs} release first-dir/dir2/dir3 first-dir/dir1" \ +"You have .0. altered files in this repository. +Are you sure you want to release directory .first-dir/dir2/dir3.: .. .release. aborted by user choice. +You have .0. altered files in this repository. +Are you sure you want to release directory .first-dir/dir1.: " <<EOF +no +yes +EOF + dotest release-13 "${testcvs} release first-dir/dir2/dir3 first-dir/dir2" \ +"You have .0. altered files in this repository. +Are you sure you want to release directory .first-dir/dir2/dir3.: \ +You have .0. altered files in this repository. +Are you sure you want to release directory .first-dir/dir2.: " <<EOF +yes +yes +EOF + dotest release-14 "test -d first-dir/dir1" '' + dotest release-15 "test -d first-dir/dir2/dir3" '' + rm -rf first-dir/dir1 first-dir/dir2 + + dotest release-16 "${testcvs} update" \ +"${PROG} [a-z]*: Updating \. +${PROG} [a-z]*: Updating first-dir" + cd .. + rm -rf 1 + ;; + + multiroot) + + # + # set up two repositories + # + + CVSROOT1_DIRNAME=${TESTDIR}/root1 + CVSROOT2_DIRNAME=${TESTDIR}/root2 + CVSROOT1=${CVSROOT1_DIRNAME} ; export CVSROOT1 + CVSROOT2=${CVSROOT2_DIRNAME} ; export CVSROOT2 + if test "x$remote" = xyes; then + CVSROOT1=:fork:${CVSROOT1_DIRNAME} ; export CVSROOT1 + CVSROOT2=:fork:${CVSROOT2_DIRNAME} ; export CVSROOT2 + fi + testcvs1="${testcvs} -d ${CVSROOT1}" + testcvs2="${testcvs} -d ${CVSROOT2}" + + dotest multiroot-setup-1 "mkdir ${CVSROOT1_DIRNAME} ${CVSROOT2_DIRNAME}" "" + dotest multiroot-setup-2 "${testcvs1} init" "" + dotest multiroot-setup-3 "${testcvs2} init" "" + + # + # create some directories in root1 + # + mkdir 1; cd 1 + dotest multiroot-setup-4 "${testcvs1} co -l ." "${PROG} [a-z]*: Updating ." + mkdir mod1-1 mod1-2 + dotest multiroot-setup-5 "${testcvs1} add mod1-1 mod1-2" \ +"Directory ${CVSROOT1_DIRNAME}/mod1-1 added to the repository +Directory ${CVSROOT1_DIRNAME}/mod1-2 added to the repository" + echo file1-1 > mod1-1/file1-1 + echo file1-2 > mod1-2/file1-2 + dotest multiroot-setup-6 "${testcvs1} add mod1-1/file1-1 mod1-2/file1-2" \ +"${PROG} [a-z]*: scheduling file .mod1-1/file1-1. for addition +${PROG} [a-z]*: scheduling file .mod1-2/file1-2. for addition +${PROG} [a-z]*: use '${PROG} commit' to add these files permanently" + dotest multiroot-setup-7 "${testcvs1} commit -m is" \ +"${PROG} [a-z]*: Examining \. +${PROG} [a-z]*: Examining mod1-1 +${PROG} [a-z]*: Examining mod1-2 +RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v +done +Checking in mod1-1/file1-1; +${CVSROOT1_DIRNAME}/mod1-1/file1-1,v <-- file1-1 +initial revision: 1.1 +done +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v +done +Checking in mod1-2/file1-2; +${CVSROOT1_DIRNAME}/mod1-2/file1-2,v <-- file1-2 +initial revision: 1.1 +done" + cd .. + rm -rf 1 + + # + # create some directories in root2 + # + mkdir 1; cd 1 + dotest multiroot-setup-8 "${testcvs2} co -l ." "${PROG} [a-z]*: Updating ." + mkdir mod2-1 mod2-2 + dotest multiroot-setup-9 "${testcvs2} add mod2-1 mod2-2" \ +"Directory ${CVSROOT2_DIRNAME}/mod2-1 added to the repository +Directory ${CVSROOT2_DIRNAME}/mod2-2 added to the repository" + echo file2-1 > mod2-1/file2-1 + echo file2-2 > mod2-2/file2-2 + dotest multiroot-setup-6 "${testcvs2} add mod2-1/file2-1 mod2-2/file2-2" \ +"${PROG} [a-z]*: scheduling file .mod2-1/file2-1. for addition +${PROG} [a-z]*: scheduling file .mod2-2/file2-2. for addition +${PROG} [a-z]*: use '${PROG} commit' to add these files permanently" + dotest multiroot-setup-10 "${testcvs2} commit -m anyone" \ +"${PROG} [a-z]*: Examining \. +${PROG} [a-z]*: Examining mod2-1 +${PROG} [a-z]*: Examining mod2-2 +RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v +done +Checking in mod2-1/file2-1; +${CVSROOT2_DIRNAME}/mod2-1/file2-1,v <-- file2-1 +initial revision: 1.1 +done +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v +done +Checking in mod2-2/file2-2; +${CVSROOT2_DIRNAME}/mod2-2/file2-2,v <-- file2-2 +initial revision: 1.1 +done" + cd .. + rm -rf 1 + + # check out a few directories, from simple/shallow to + # complex/deep + mkdir 1; cd 1 + + # OK, this case is kind of weird. If we just run things from + # here, without CVS/Root, then CVS will contact the server + # mentioned in CVSROOT (which is irrelevant) which will print + # some messages. Our workaround is to make sure we have a + # CVS/Root file at top level. In the future, it is possible + # the best behavior will be to extend the existing behavior + # ("being called from a directory without CVS administration + # has always meant to process each of the sub-dirs") to also + # do that if there is no CVSROOT, CVS/Root, or -d at top level. + # + # The local case could stumble through the tests without creating + # the top-level CVS/Root, but we create it for local and for + # remote to reduce special cases later in the test. + dotest multiroot-workaround "${testcvs1} -q co -l ." "" + + dotest multiroot-setup-11 "${testcvs1} co mod1-1 mod1-2" \ +"${PROG} [a-z]*: Updating mod1-1 +U mod1-1/file1-1 +${PROG} [a-z]*: Updating mod1-2 +U mod1-2/file1-2" + dotest multiroot-setup-12 "${testcvs2} co mod2-1 mod2-2" \ +"${PROG} [a-z]*: Updating mod2-1 +U mod2-1/file2-1 +${PROG} [a-z]*: Updating mod2-2 +U mod2-2/file2-2" + cd mod1-2 + dotest multiroot-setup-13 "${testcvs2} co mod2-2" \ +"${PROG} [a-z]*: Updating mod2-2 +U mod2-2/file2-2" + cd .. + cd mod2-2 + dotest multiroot-setup-14 "${testcvs1} co mod1-2" \ +"${PROG} [a-z]*: Updating mod1-2 +U mod1-2/file1-2" + cd .. + + # Try to determine whether RELATIVE_REPOS is defined + # so that we can make the following a lot less + # verbose. + + echo "${CVSROOT1_DIRNAME}/mod1-1" > dotest.abs + echo "mod1-1" > dotest.rel + if cmp dotest.abs mod1-1/CVS/Repository >/dev/null 2>&1; then + AREP1="${CVSROOT1_DIRNAME}/" + AREP2="${CVSROOT2_DIRNAME}/" + elif cmp dotest.rel mod1-1/CVS/Repository >/dev/null 2>&1; then + AREP1="" + AREP2="" + else + fail "Cannot figure out if RELATIVE_REPOS is defined." + fi + rm -f dotest.abs dotest.rel + + # + # Make sure that the Root and Repository files contain the + # correct information. + # + dotest multiroot-cvsadm-1a "cat mod1-1/CVS/Root" "${CVSROOT1}" + dotest multiroot-cvsadm-1b "cat mod1-1/CVS/Repository" "${AREP1}mod1-1" + dotest multiroot-cvsadm-2a "cat mod2-1/CVS/Root" "${CVSROOT2}" + dotest multiroot-cvsadm-2b "cat mod2-1/CVS/Repository" "${AREP2}mod2-1" + dotest multiroot-cvsadm-3a "cat mod1-2/CVS/Root" "${CVSROOT1}" + dotest multiroot-cvsadm-3b "cat mod1-2/CVS/Repository" "${AREP1}mod1-2" + dotest multiroot-cvsadm-3c "cat mod1-2/mod2-2/CVS/Root" "${CVSROOT2}" + dotest multiroot-cvsadm-3d "cat mod1-2/mod2-2/CVS/Repository" "${AREP2}mod2-2" + dotest multiroot-cvsadm-4a "cat mod2-2/CVS/Root" "${CVSROOT2}" + dotest multiroot-cvsadm-4b "cat mod2-2/CVS/Repository" "${AREP2}mod2-2" + dotest multiroot-cvsadm-4c "cat mod2-2/mod1-2/CVS/Root" "${CVSROOT1}" + dotest multiroot-cvsadm-4d "cat mod2-2/mod1-2/CVS/Repository" "${AREP1}mod1-2" + + # + # Start testing various cvs commands. Begin with commands + # without extra arguments (e.g. "cvs update", "cvs diff", + # etc. + # + + # Do at least one command with both CVSROOTs to make sure + # that there's not some kind of unexpected dependency on the + # choice of which CVSROOT is specified on the command line. + + if test "${AREP1}" = ""; then + # RELATIVE_REPOS. + dotest multiroot-update-1a "${testcvs1} update" \ +"${PROG} [a-z]*: Updating \. +${PROG} [a-z]*: Updating mod1-1 +${PROG} [a-z]*: Updating mod1-2 +${PROG} [a-z]*: Updating mod1-2/mod2-2 +${PROG} [a-z]*: cannot open directory ${TESTDIR}/root1/mod2-2: No such file or directory +${PROG} [a-z]*: skipping directory mod1-2/mod2-2 +${PROG} [a-z]*: Updating mod2-1 +${PROG} [a-z]*: cannot open directory ${TESTDIR}/root1/mod2-1: No such file or directory +${PROG} [a-z]*: skipping directory mod2-1 +${PROG} [a-z]*: Updating mod2-2 +${PROG} [a-z]*: cannot open directory ${TESTDIR}/root1/mod2-2: No such file or directory +${PROG} [a-z]*: skipping directory mod2-2" + + # Same deal but with -d ${CVSROOT2}. + dotest multiroot-update-1b "${testcvs2} update" \ +"${PROG} [a-z]*: Updating \. +${PROG} [a-z]*: Updating mod1-1 +${PROG} [a-z]*: cannot open directory ${TESTDIR}/root2/mod1-1: No such file or directory +${PROG} [a-z]*: skipping directory mod1-1 +${PROG} [a-z]*: Updating mod1-2 +${PROG} [a-z]*: cannot open directory ${TESTDIR}/root2/mod1-2: No such file or directory +${PROG} [a-z]*: skipping directory mod1-2 +${PROG} [a-z]*: Updating mod2-1 +${PROG} [a-z]*: Updating mod2-2 +${PROG} [a-z]*: Updating mod2-2/mod1-2 +${PROG} [a-z]*: cannot open directory ${TESTDIR}/root2/mod1-2: No such file or directory +${PROG} [a-z]*: skipping directory mod2-2/mod1-2" + else + # non-RELATIVE_REPOS. + if test "$remote" = no; then + # The basic idea is that -d overrides CVS/Root. + # With RELATIVE_REPOS, CVS could print an error when it + # tries to recurse to mod2-2, which doesn't exist in + # this repository (?) With absolute, CVS will just look at the + # CVS/Repository for the other root (and log to the wrong + # history file and that sort of thing). + dotest multiroot-update-1a "${testcvs1} update" \ +"${PROG} update: Updating \. +${PROG} [a-z]*: Updating mod1-1 +${PROG} [a-z]*: Updating mod1-2 +${PROG} [a-z]*: Updating mod1-2/mod2-2 +${PROG} [a-z]*: Updating mod2-1 +${PROG} [a-z]*: Updating mod2-2 +${PROG} [a-z]*: Updating mod2-2/mod1-2" + else + # Hmm, this one is specific to non-RELATIVE_REPOS too I think. + dotest_fail multiroot-update-1a "${testcvs1} update" \ +"protocol error: directory '${TESTDIR}/root2/mod2-2' not within root '${TESTDIR}/root1'" + fi # non-remote + + # Same deal but with -d ${CVSROOT2}. + if test "$remote" = no; then + dotest multiroot-update-1b "${testcvs2} update" \ +"${PROG} update: Updating \. +${PROG} [a-z]*: Updating mod1-1 +${PROG} [a-z]*: Updating mod1-2 +${PROG} [a-z]*: Updating mod1-2/mod2-2 +${PROG} [a-z]*: Updating mod2-1 +${PROG} [a-z]*: Updating mod2-2 +${PROG} [a-z]*: Updating mod2-2/mod1-2" + else + dotest_fail multiroot-update-1b "${testcvs2} update" \ +"protocol error: directory '${TESTDIR}/root1' not within root '${TESTDIR}/root2'" + fi # non-remote + fi # non-RELATIVE_REPOS + + # modify all files and do a diff + + echo bobby >> mod1-1/file1-1 + echo brown >> mod1-2/file1-2 + echo goes >> mod2-1/file2-1 + echo down >> mod2-2/file2-2 + + dotest_status multiroot-diff-1 1 "${testcvs} diff" \ +"${PROG} diff: Diffing \. +${PROG} [a-z]*: Diffing mod1-1 +Index: mod1-1/file1-1 +=================================================================== +RCS file: ${TESTDIR}/root1/mod1-1/file1-1,v +retrieving revision 1\.1 +diff -r1\.1 file1-1 +1a2 +> bobby +${PROG} [a-z]*: Diffing mod1-2 +Index: mod1-2/file1-2 +=================================================================== +RCS file: ${TESTDIR}/root1/mod1-2/file1-2,v +retrieving revision 1\.1 +diff -r1\.1 file1-2 +1a2 +> brown +${PROG} [a-z]*: Diffing mod2-2/mod1-2 +${PROG} [a-z]*: Diffing mod1-2/mod2-2 +${PROG} [a-z]*: Diffing mod2-1 +Index: mod2-1/file2-1 +=================================================================== +RCS file: ${TESTDIR}/root2/mod2-1/file2-1,v +retrieving revision 1\.1 +diff -r1\.1 file2-1 +1a2 +> goes +${PROG} [a-z]*: Diffing mod2-2 +Index: mod2-2/file2-2 +=================================================================== +RCS file: ${TESTDIR}/root2/mod2-2/file2-2,v +retrieving revision 1\.1 +diff -r1\.1 file2-2 +1a2 +> down" \ +"${PROG} server: Diffing \. +${PROG} [a-z]*: Diffing mod1-1 +Index: mod1-1/file1-1 +=================================================================== +RCS file: ${TESTDIR}/root1/mod1-1/file1-1,v +retrieving revision 1\.1 +diff -r1\.1 file1-1 +1a2 +> bobby +${PROG} [a-z]*: Diffing mod1-2 +Index: mod1-2/file1-2 +=================================================================== +RCS file: ${TESTDIR}/root1/mod1-2/file1-2,v +retrieving revision 1\.1 +diff -r1\.1 file1-2 +1a2 +> brown +${PROG} [a-z]*: Diffing mod2-2 +${PROG} [a-z]*: Diffing mod2-2/mod1-2 +${PROG} [a-z]*: Diffing mod1-2 +${PROG} [a-z]*: Diffing mod1-2/mod2-2 +${PROG} [a-z]*: Diffing mod2-1 +Index: mod2-1/file2-1 +=================================================================== +RCS file: ${TESTDIR}/root2/mod2-1/file2-1,v +retrieving revision 1\.1 +diff -r1\.1 file2-1 +1a2 +> goes +${PROG} [a-z]*: Diffing mod2-2 +Index: mod2-2/file2-2 +=================================================================== +RCS file: ${TESTDIR}/root2/mod2-2/file2-2,v +retrieving revision 1\.1 +diff -r1\.1 file2-2 +1a2 +> down" + + + dotest multiroot-commit-1 "${testcvs} commit -m actually" \ +"${PROG} [a-z]*: Examining \. +${PROG} [a-z]*: Examining mod1-1 +${PROG} [a-z]*: Examining mod1-2 +${PROG} [a-z]*: Examining mod2-2/mod1-2 +Checking in mod1-1/file1-1; +${TESTDIR}/root1/mod1-1/file1-1,v <-- file1-1 +new revision: 1.2; previous revision: 1.1 +done +Checking in mod1-2/file1-2; +${TESTDIR}/root1/mod1-2/file1-2,v <-- file1-2 +new revision: 1.2; previous revision: 1.1 +done +${PROG} [a-z]*: Examining mod1-2/mod2-2 +${PROG} [a-z]*: Examining mod2-1 +${PROG} [a-z]*: Examining mod2-2 +Checking in mod2-1/file2-1; +${TESTDIR}/root2/mod2-1/file2-1,v <-- file2-1 +new revision: 1.2; previous revision: 1.1 +done +Checking in mod2-2/file2-2; +${TESTDIR}/root2/mod2-2/file2-2,v <-- file2-2 +new revision: 1.2; previous revision: 1.1 +done" + + dotest multiroot-update-2 "${testcvs} update" \ +"${PROG} update: Updating \. +${PROG} [a-z]*: Updating mod1-1 +${PROG} [a-z]*: Updating mod1-2 +${PROG} [a-z]*: Updating mod2-2/mod1-2 +U mod2-2/mod1-2/file1-2 +${PROG} [a-z]*: Updating mod1-2/mod2-2 +U mod1-2/mod2-2/file2-2 +${PROG} [a-z]*: Updating mod2-1 +${PROG} [a-z]*: Updating mod2-2" \ +"${PROG} server: Updating \. +${PROG} [a-z]*: Updating mod1-1 +${PROG} [a-z]*: Updating mod1-2 +${PROG} [a-z]*: Updating mod2-2 +${PROG} [a-z]*: Updating mod2-2/mod1-2 +P mod2-2/mod1-2/file1-2 +${PROG} [a-z]*: Updating mod1-2 +${PROG} [a-z]*: Updating mod1-2/mod2-2 +P mod1-2/mod2-2/file2-2 +${PROG} [a-z]*: Updating mod2-1 +${PROG} [a-z]*: Updating mod2-2" + + dotest multiroot-tag-1 "${testcvs} tag cattle" \ +"${PROG} tag: Tagging \. +${PROG} [a-z]*: Tagging mod1-1 +T mod1-1/file1-1 +${PROG} [a-z]*: Tagging mod1-2 +T mod1-2/file1-2 +${PROG} [a-z]*: Tagging mod2-2/mod1-2 +${PROG} [a-z]*: Tagging mod1-2/mod2-2 +T mod1-2/mod2-2/file2-2 +${PROG} [a-z]*: Tagging mod2-1 +T mod2-1/file2-1 +${PROG} [a-z]*: Tagging mod2-2" \ +"${PROG} server: Tagging \. +${PROG} [a-z]*: Tagging mod1-1 +T mod1-1/file1-1 +${PROG} [a-z]*: Tagging mod1-2 +T mod1-2/file1-2 +${PROG} [a-z]*: Tagging mod2-2 +${PROG} [a-z]*: Tagging mod2-2/mod1-2 +${PROG} [a-z]*: Tagging mod1-2 +${PROG} [a-z]*: Tagging mod1-2/mod2-2 +T mod1-2/mod2-2/file2-2 +${PROG} [a-z]*: Tagging mod2-1 +T mod2-1/file2-1 +${PROG} [a-z]*: Tagging mod2-2" + + echo anotherfile1-1 > mod1-1/anotherfile1-1 + echo anotherfile2-1 > mod2-1/anotherfile2-1 + echo anotherfile1-2 > mod2-2/mod1-2/anotherfile1-2 + echo anotherfile2-2 > mod1-2/mod2-2/anotherfile2-2 + + if test "x$remote" = xno; then + dotest multiroot-add-1 "${testcvs} add mod1-1/anotherfile1-1 mod2-1/anotherfile2-1 mod2-2/mod1-2/anotherfile1-2 mod1-2/mod2-2/anotherfile2-2" \ +"${PROG} [a-z]*: scheduling file .mod1-1/anotherfile1-1. for addition +${PROG} [a-z]*: scheduling file .mod2-1/anotherfile2-1. for addition +${PROG} [a-z]*: scheduling file .mod2-2/mod1-2/anotherfile1-2. for addition +${PROG} [a-z]*: scheduling file .mod1-2/mod2-2/anotherfile2-2. for addition +${PROG} [a-z]*: use 'cvs commit' to add these files permanently" + else + cd mod1-1 + dotest multiroot-add-1a "${testcvs} add anotherfile1-1" \ +"${PROG} [a-z]*: scheduling file .anotherfile1-1. for addition +${PROG} [a-z]*: use 'cvs commit' to add this file permanently" + cd ../mod2-1 + dotest multiroot-add-1b "${testcvs} add anotherfile2-1" \ +"${PROG} [a-z]*: scheduling file .anotherfile2-1. for addition +${PROG} [a-z]*: use 'cvs commit' to add this file permanently" + cd ../mod2-2/mod1-2 + dotest multiroot-add-1c "${testcvs} add anotherfile1-2" \ +"${PROG} [a-z]*: scheduling file .anotherfile1-2. for addition +${PROG} [a-z]*: use 'cvs commit' to add this file permanently" + cd ../../mod1-2/mod2-2 + dotest multiroot-add-1d "${testcvs} add anotherfile2-2" \ +"${PROG} [a-z]*: scheduling file .anotherfile2-2. for addition +${PROG} [a-z]*: use 'cvs commit' to add this file permanently" + cd ../.. + fi + + dotest multiroot-status-1 "${testcvs} status -v" \ +"${PROG} status: Examining \. +${PROG} [a-z]*: Examining mod1-1 +=================================================================== +File: anotherfile1-1 Status: Locally Added + + Working revision: New file! + Repository revision: No revision control file + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + +=================================================================== +File: file1-1 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod1-2 +=================================================================== +File: file1-2 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod2-2/mod1-2 +=================================================================== +File: anotherfile1-2 Status: Locally Added + + Working revision: New file! + Repository revision: No revision control file + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + +=================================================================== +File: file1-2 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod1-2/mod2-2 +=================================================================== +File: anotherfile2-2 Status: Locally Added + + Working revision: New file! + Repository revision: No revision control file + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + +=================================================================== +File: file2-2 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod2-1 +=================================================================== +File: anotherfile2-1 Status: Locally Added + + Working revision: New file! + Repository revision: No revision control file + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + +=================================================================== +File: file2-1 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod2-2 +=================================================================== +File: file2-2 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2)" \ +"${PROG} server: Examining \. +${PROG} [a-z]*: Examining mod1-1 +=================================================================== +File: anotherfile1-1 Status: Locally Added + + Working revision: New file! + Repository revision: No revision control file + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + +=================================================================== +File: file1-1 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod1-2 +=================================================================== +File: file1-2 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod2-2 +${PROG} [a-z]*: Examining mod2-2/mod1-2 +=================================================================== +File: anotherfile1-2 Status: Locally Added + + Working revision: New file! + Repository revision: No revision control file + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + +=================================================================== +File: file1-2 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod1-2 +${PROG} [a-z]*: Examining mod1-2/mod2-2 +=================================================================== +File: anotherfile2-2 Status: Locally Added + + Working revision: New file! + Repository revision: No revision control file + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + +=================================================================== +File: file2-2 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod2-1 +=================================================================== +File: anotherfile2-1 Status: Locally Added + + Working revision: New file! + Repository revision: No revision control file + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + +=================================================================== +File: file2-1 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2) + +${PROG} [a-z]*: Examining mod2-2 +=================================================================== +File: file2-2 Status: Up-to-date + + Working revision: 1\.2.* + Repository revision: 1\.2 ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none) + + Existing Tags: + cattle (revision: 1\.2)" + + dotest multiroot-commit-2 "${testcvs} commit -m reading" \ +"${PROG} [a-z]*: Examining \. +${PROG} [a-z]*: Examining mod1-1 +${PROG} [a-z]*: Examining mod1-2 +${PROG} [a-z]*: Examining mod2-2/mod1-2 +RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v +done +Checking in mod1-1/anotherfile1-1; +${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v <-- anotherfile1-1 +initial revision: 1\.1 +done +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v +done +Checking in mod2-2/mod1-2/anotherfile1-2; +${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v <-- anotherfile1-2 +initial revision: 1\.1 +done +${PROG} [a-z]*: Examining mod1-2/mod2-2 +${PROG} [a-z]*: Examining mod2-1 +${PROG} [a-z]*: Examining mod2-2 +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v +done +Checking in mod1-2/mod2-2/anotherfile2-2; +${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v <-- anotherfile2-2 +initial revision: 1\.1 +done +RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v +done +Checking in mod2-1/anotherfile2-1; +${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v <-- anotherfile2-1 +initial revision: 1\.1 +done" + + dotest multiroot-update-3 "${testcvs} update" \ +"${PROG} update: Updating \. +${PROG} [a-z]*: Updating mod1-1 +${PROG} [a-z]*: Updating mod1-2 +U mod1-2/anotherfile1-2 +${PROG} [a-z]*: Updating mod2-2/mod1-2 +${PROG} [a-z]*: Updating mod1-2/mod2-2 +${PROG} [a-z]*: Updating mod2-1 +${PROG} [a-z]*: Updating mod2-2 +U mod2-2/anotherfile2-2" \ +"${PROG} server: Updating \. +${PROG} [a-z]*: Updating mod1-1 +${PROG} [a-z]*: Updating mod1-2 +U mod1-2/anotherfile1-2 +${PROG} [a-z]*: Updating mod2-2 +${PROG} [a-z]*: Updating mod2-2/mod1-2 +${PROG} [a-z]*: Updating mod1-2 +${PROG} [a-z]*: Updating mod1-2/mod2-2 +${PROG} [a-z]*: Updating mod2-1 +${PROG} [a-z]*: Updating mod2-2 +U mod2-2/anotherfile2-2" + + dotest multiroot-log-1 "${testcvs} log" \ +"${PROG} log: Logging \. +${PROG} [a-z]*: Logging mod1-1 + +RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v +Working file: mod1-1/anotherfile1-1 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v +Working file: mod1-1/file1-1 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +is +============================================================================= +${PROG} [a-z]*: Logging mod1-2 + +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v +Working file: mod1-2/anotherfile1-2 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v +Working file: mod1-2/file1-2 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +is +============================================================================= +${PROG} [a-z]*: Logging mod2-2/mod1-2 + +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v +Working file: mod2-2/mod1-2/anotherfile1-2 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v +Working file: mod2-2/mod1-2/file1-2 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +is +============================================================================= +${PROG} [a-z]*: Logging mod1-2/mod2-2 + +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v +Working file: mod1-2/mod2-2/anotherfile2-2 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v +Working file: mod1-2/mod2-2/file2-2 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +anyone +============================================================================= +${PROG} [a-z]*: Logging mod2-1 + +RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v +Working file: mod2-1/anotherfile2-1 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v +Working file: mod2-1/file2-1 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +anyone +============================================================================= +${PROG} [a-z]*: Logging mod2-2 + +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v +Working file: mod2-2/anotherfile2-2 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v +Working file: mod2-2/file2-2 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +anyone +=============================================================================" \ +"${PROG} server: Logging \. +${PROG} [a-z]*: Logging mod1-1 + +RCS file: ${CVSROOT1_DIRNAME}/mod1-1/anotherfile1-1,v +Working file: mod1-1/anotherfile1-1 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v +Working file: mod1-1/file1-1 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +is +============================================================================= +${PROG} [a-z]*: Logging mod1-2 + +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v +Working file: mod1-2/anotherfile1-2 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v +Working file: mod1-2/file1-2 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +is +============================================================================= +${PROG} [a-z]*: Logging mod2-2 +${PROG} [a-z]*: Logging mod2-2/mod1-2 + +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/anotherfile1-2,v +Working file: mod2-2/mod1-2/anotherfile1-2 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v +Working file: mod2-2/mod1-2/file1-2 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +is +============================================================================= +${PROG} [a-z]*: Logging mod1-2 +${PROG} [a-z]*: Logging mod1-2/mod2-2 + +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v +Working file: mod1-2/mod2-2/anotherfile2-2 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v +Working file: mod1-2/mod2-2/file2-2 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +anyone +============================================================================= +${PROG} [a-z]*: Logging mod2-1 + +RCS file: ${CVSROOT2_DIRNAME}/mod2-1/anotherfile2-1,v +Working file: mod2-1/anotherfile2-1 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v +Working file: mod2-1/file2-1 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +anyone +============================================================================= +${PROG} [a-z]*: Logging mod2-2 + +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/anotherfile2-2,v +Working file: mod2-2/anotherfile2-2 +head: 1\.1 +branch: +locks: strict +access list: +symbolic names: +keyword substitution: kv +total revisions: 1; selected revisions: 1 +description: +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +reading +============================================================================= + +RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v +Working file: mod2-2/file2-2 +head: 1\.2 +branch: +locks: strict +access list: +symbolic names: + cattle: 1\.2 +keyword substitution: kv +total revisions: 2; selected revisions: 2 +description: +---------------------------- +revision 1\.2 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; lines: ${PLUS}1 -0 +actually +---------------------------- +revision 1\.1 +date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; +anyone +=============================================================================" + + + # After the simple cases, let's execute some commands which + # refer to parts of our checked-out tree (e.g. "cvs update + # mod1-1 mod2-2") + + if test "$keep" = yes; then + echo Keeping ${TESTDIR} and exiting due to --keep + exit 0 + fi + + # clean up after ourselves + cd .. + rm -r 1 + + # clean up our repositories + rm -rf root1 root2 + ;; + + multiroot2) + # More multiroot tests. In particular, nested directories. + + CVSROOT1_DIRNAME=${TESTDIR}/root1 + CVSROOT2_DIRNAME=${TESTDIR}/root2 + CVSROOT1=${CVSROOT1_DIRNAME} ; export CVSROOT1 + CVSROOT2=${CVSROOT2_DIRNAME} ; export CVSROOT2 + if test "x$remote" = xyes; then + CVSROOT1=:fork:${CVSROOT1_DIRNAME} ; export CVSROOT1 + CVSROOT2=:fork:${CVSROOT2_DIRNAME} ; export CVSROOT2 + fi + + dotest multiroot2-1 "${testcvs} -d ${CVSROOT1} init" "" + dotest multiroot2-2 "${testcvs} -d ${CVSROOT2} init" "" + + mkdir imp-dir; cd imp-dir + echo file1 >file1 + mkdir sdir + echo sfile >sdir/sfile + mkdir sdir/ssdir + echo ssfile >sdir/ssdir/ssfile + dotest_sort multiroot2-3 \ +"${testcvs} -d ${CVSROOT1} import -m import-to-root1 dir1 vend rel" " + +N dir1/file1 +N dir1/sdir/sfile +N dir1/sdir/ssdir/ssfile +No conflicts created by this import +${PROG} [a-z]*: Importing ${TESTDIR}/root1/dir1/sdir +${PROG} [a-z]*: Importing ${TESTDIR}/root1/dir1/sdir/ssdir" + cd sdir + dotest_sort multiroot2-4 \ +"${testcvs} -d ${CVSROOT2} import -m import-to-root2 sdir vend2 rel2" " + +N sdir/sfile +N sdir/ssdir/ssfile +No conflicts created by this import +${PROG} [a-z]*: Importing ${TESTDIR}/root2/sdir/ssdir" + cd ../.. + + mkdir 1; cd 1 + # Get TopLevelAdmin-like behavior. + dotest multiroot2-5 "${testcvs} -d ${CVSROOT1} -q co -l ." + dotest multiroot2-5 "${testcvs} -d ${CVSROOT1} -q co dir1" \ +"U dir1/file1 +U dir1/sdir/sfile +U dir1/sdir/ssdir/ssfile" + cd dir1 + dotest multiroot2-6 "${testcvs} -Q release -d sdir" "" + dotest multiroot2-7 "${testcvs} -d ${CVSROOT2} -q co sdir" \ +"U sdir/sfile +U sdir/ssdir/ssfile" + cd .. + # This has one subtle effect - it deals with Entries.Log + # so that the next test doesn't get trace messages for + # Entries.Log + dotest multiroot2-8 "${testcvs} update" \ +"${PROG} update: Updating \. +${PROG} update: Updating dir1 +${PROG} update: Updating dir1/sdir +${PROG} update: Updating dir1/sdir/ssdir" \ +"${PROG} server: Updating \. +${PROG} server: Updating dir1 +${PROG} server: Updating dir1 +${PROG} server: Updating dir1/sdir +${PROG} server: Updating dir1/sdir/ssdir" + # Two reasons we don't run this on the server: (1) the server + # also prints some trace messages, and (2) the server trace + # messages are subject to out-of-order bugs (this one is hard + # to work around). + if test "$remote" = no; then + dotest multiroot2-9 "${testcvs} -t update" \ +"${PROG} update: notice: main loop with CVSROOT=${TESTDIR}/root1 +${PROG} update: Updating \. +${PROG} update: Updating dir1 +${PROG} update: notice: main loop with CVSROOT=${TESTDIR}/root2 +${PROG} update: Updating dir1/sdir +${PROG} update: Updating dir1/sdir/ssdir" + fi + + dotest multiroot2-9 "${testcvs} -q tag tag1" \ +"T dir1/file1 +T dir1/sdir/sfile +T dir1/sdir/ssdir/ssfile" + echo "change it" >>dir1/file1 + echo "change him too" >>dir1/sdir/sfile + dotest multiroot2-10 "${testcvs} -q ci -m modify" \ +"Checking in dir1/file1; +${TESTDIR}/root1/dir1/file1,v <-- file1 +new revision: 1\.2; previous revision: 1\.1 +done +Checking in dir1/sdir/sfile; +${TESTDIR}/root2/sdir/sfile,v <-- sfile +new revision: 1\.2; previous revision: 1\.1 +done" + dotest multiroot2-11 "${testcvs} -q tag tag2" \ +"T dir1/file1 +T dir1/sdir/sfile +T dir1/sdir/ssdir/ssfile" + dotest_status multiroot2-12 1 \ +"${testcvs} -q diff -u -r tag1 -r tag2" \ +"Index: dir1/file1 +=================================================================== +RCS file: ${TESTDIR}/root1/dir1/file1,v +retrieving revision 1\.1\.1\.1 +retrieving revision 1\.2 +diff -u -r1\.1\.1\.1 -r1\.2 +--- dir1/file1 [0-9/]* [0-9:]* 1\.1\.1\.1 +${PLUS}${PLUS}${PLUS} dir1/file1 [0-9/]* [0-9:]* 1\.2 +@@ -1 ${PLUS}1,2 @@ + file1 +${PLUS}change it +Index: dir1/sdir/sfile +=================================================================== +RCS file: ${TESTDIR}/root2/sdir/sfile,v +retrieving revision 1\.1\.1\.1 +retrieving revision 1\.2 +diff -u -r1\.1\.1\.1 -r1\.2 +--- dir1/sdir/sfile [0-9/]* [0-9:]* 1\.1\.1\.1 +${PLUS}${PLUS}${PLUS} dir1/sdir/sfile [0-9/]* [0-9:]* 1\.2 +@@ -1 ${PLUS}1,2 @@ + sfile +${PLUS}change him too" + + if test "$keep" = yes; then + echo Keeping ${TESTDIR} and exiting due to --keep + exit 0 + fi + + # clean up after ourselves + cd .. + rm -r imp-dir 1 + + # clean up our repositories + rm -rf root1 root2 + ;; + + multiroot3) + # More multiroot tests. Directories are side-by-side, not nested. + # Not drastically different from multiroot but it covers somewhat + # different stuff. + + if test "x$remote" = xyes; then + CVSROOT1=:fork:${TESTDIR}/root1 ; export CVSROOT1 + CVSROOT2=:fork:${TESTDIR}/root2 ; export CVSROOT2 + else + CVSROOT1=${TESTDIR}/root1 ; export CVSROOT1 + CVSROOT2=${TESTDIR}/root2 ; export CVSROOT2 + fi + + mkdir 1; cd 1 + dotest multiroot3-1 "${testcvs} -d ${CVSROOT1} init" "" + dotest multiroot3-2 "${testcvs} -d ${CVSROOT1} -q co -l ." "" + mkdir dir1 + dotest multiroot3-3 "${testcvs} add dir1" \ +"Directory ${TESTDIR}/root1/dir1 added to the repository" + dotest multiroot3-4 "${testcvs} -d ${CVSROOT2} init" "" + rm -r CVS + dotest multiroot3-5 "${testcvs} -d ${CVSROOT2} -q co -l ." "" + mkdir dir2 + + # OK, the problem is that CVS/Entries doesn't look quite right, + # I suppose because of the "rm -r". + # For local this fixes it up. + dotest multiroot3-6 "${testcvs} -d ${CVSROOT1} -q co dir1" "" + if test "$remote" = yes; then + # For remote that doesn't do it. Use the quick and dirty fix. + echo "D/dir1////" >CVS/Entries + echo "D/dir2////" >>CVS/Entries + fi + + dotest multiroot3-7 "${testcvs} add dir2" \ +"Directory ${TESTDIR}/root2/dir2 added to the repository" + + touch dir1/file1 dir2/file2 + if test "$remote" = yes; then + # Trying to add them both in one command doesn't work, + # because add.c doesn't do multiroot (it doesn't use recurse.c). + # Furthermore, it can't deal with the parent directory + # having a different root from the child, hence the cd. + cd dir1 + dotest multiroot3-8 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + cd .. + dotest multiroot3-8a "${testcvs} add dir2/file2" \ +"${PROG} [a-z]*: scheduling file .dir2/file2. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + else + dotest multiroot3-8 "${testcvs} add dir1/file1 dir2/file2" \ +"${PROG} [a-z]*: scheduling file .dir1/file1. for addition +${PROG} [a-z]*: scheduling file .dir2/file2. for addition +${PROG} [a-z]*: use .${PROG} commit. to add these files permanently" + fi + + dotest multiroot3-9 "${testcvs} -q ci -m add-them" \ +"RCS file: ${TESTDIR}/root2/dir2/file2,v +done +Checking in dir2/file2; +${TESTDIR}/root2/dir2/file2,v <-- file2 +initial revision: 1\.1 +done +RCS file: ${TESTDIR}/root1/dir1/file1,v +done +Checking in dir1/file1; +${TESTDIR}/root1/dir1/file1,v <-- file1 +initial revision: 1\.1 +done" + + if test "`cat dir1/CVS/Repository`" = "dir1"; then + # RELATIVE_REPOS + # That this is an error is good - we are asking CVS to do + # something which doesn't make sense. + dotest_fail multiroot3-10 \ +"${testcvs} -q -d ${CVSROOT1} diff dir1/file1 dir2/file2" \ +"${PROG} [a-z]*: failed to create lock directory in repository .${TESTDIR}/root1/dir2': No such file or directory +${PROG} [a-z]*: failed to obtain dir lock in repository .${TESTDIR}/root1/dir2' +${PROG} \[[a-z]* aborted\]: read lock failed - giving up" + else + # Not RELATIVE_REPOS. + if test "$remote" = yes; then + # This is good behavior - we are asking CVS to do something + # which doesn't make sense. + dotest_fail multiroot3-10 \ +"${testcvs} -q -d ${CVSROOT1} diff dir1/file1 dir2/file2" \ +"protocol error: directory '${TESTDIR}/root2/dir2' not within root '${TESTDIR}/root1'" + else + # Local isn't as picky as we'd want in terms of getting + # the wrong root. + dotest multiroot3-10 \ +"${testcvs} -q -d ${CVSROOT1} diff dir1/file1 dir2/file2" "" + fi + fi + # This one is supposed to work. + dotest multiroot3-11 "${testcvs} -q diff dir1/file1 dir2/file2" "" + + cd .. + + if test "$keep" = yes; then + echo Keeping ${TESTDIR} and exiting due to --keep + exit 0 + fi + + rm -r 1 + rm -rf ${TESTDIR}/root1 ${TESTDIR}/root2 + unset CVSROOT1 + unset CVSROOT2 + ;; + + multiroot4) + # More multiroot tests, in particular we have two roots with + # similarly-named directories and we try to see that CVS can + # keep them separate. + if test "x$remote" = xyes; then + CVSROOT1=:fork:${TESTDIR}/root1 ; export CVSROOT1 + CVSROOT2=:fork:${TESTDIR}/root2 ; export CVSROOT2 + else + CVSROOT1=${TESTDIR}/root1 ; export CVSROOT1 + CVSROOT2=${TESTDIR}/root2 ; export CVSROOT2 + fi + + mkdir 1; cd 1 + dotest multiroot4-1 "${testcvs} -d ${CVSROOT1} init" "" + dotest multiroot4-2 "${testcvs} -d ${CVSROOT1} -q co -l ." "" + mkdir dircom + dotest multiroot4-3 "${testcvs} add dircom" \ +"Directory ${TESTDIR}/root1/dircom added to the repository" + cd dircom + touch file1 + dotest multiroot4-4 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest multiroot4-5 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/root1/dircom/file1,v +done +Checking in file1; +${TESTDIR}/root1/dircom/file1,v <-- file1 +initial revision: 1\.1 +done" + cd ../.. + mkdir 2; cd 2 + dotest multiroot4-6 "${testcvs} -d ${CVSROOT2} init" "" + dotest multiroot4-7 "${testcvs} -d ${CVSROOT2} -q co -l ." "" + mkdir dircom + dotest multiroot4-8 "${testcvs} add dircom" \ +"Directory ${TESTDIR}/root2/dircom added to the repository" + cd dircom + touch file2 + dotest multiroot4-9 "${testcvs} add file2" \ +"${PROG} [a-z]*: scheduling file .file2. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest multiroot4-10 "${testcvs} -q ci -m add" \ +"RCS file: ${TESTDIR}/root2/dircom/file2,v +done +Checking in file2; +${TESTDIR}/root2/dircom/file2,v <-- file2 +initial revision: 1\.1 +done" + + cd ../.. + cd 1/dircom + # This may look contrived; the real world example which inspired + # it was that a user was changing from local to remote. Cases + # like switching servers (among those mounting the same + # repository) and so on would also look the same. + mkdir sdir2 + dotest multiroot4-11 "${testcvs} -d ${CVSROOT2} add sdir2" \ +"Directory ${TESTDIR}/root2/dircom/sdir2 added to the repository" + + dotest multiroot4-12 "${testcvs} -q update" "" + cd .. + dotest multiroot4-13 "${testcvs} -q update dircom" "" + cd .. + + rm -r 1 2 + rm -rf ${TESTDIR}/root1 ${TESTDIR}/root2 + unset CVSROOT1 + unset CVSROOT2 + ;; + + reposmv) + # More tests of repositories and specifying them. + # Similar to crerepos but that test is probably getting big + # enough. + + if test "x$remote" = xyes; then + CVSROOT1=:fork:${TESTDIR}/root1 ; export CVSROOT1 + CVSROOT_MOVED=:fork:${TESTDIR}/root-moved ; export CVSROOT1 + else + CVSROOT1=${TESTDIR}/root1 ; export CVSROOT1 + CVSROOT_MOVED=${TESTDIR}/root-moved ; export CVSROOT1 + fi + + dotest reposmv-setup-1 "${testcvs} -d ${CVSROOT1} init" "" + mkdir imp-dir; cd imp-dir + echo file1 >file1 + dotest reposmv-setup-2 \ +"${testcvs} -d ${CVSROOT1} import -m add dir1 vendor release" \ +"N dir1/file1 + +No conflicts created by this import" + cd .. + + mkdir 1; cd 1 + dotest reposmv-1 "${testcvs} -d ${CVSROOT1} -Q co dir1" "" + mv ${TESTDIR}/root1 ${TESTDIR}/root-moved + cd dir1 + + # If we didn't have a relative repository, get one now. + dotest reposmv-1a "cat CVS/Repository" \ +"${TESTDIR}/root1/dir1" "dir1" + echo dir1 >CVS/Repository + + # There were some duplicated warnings and such; only test + # for the part of the error message which makes sense. + # Bug: "skipping directory " without filename. + if test "$remote" = no; then + dotest reposmv-2 "${testcvs} update" "${DOTSTAR} +${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1 +${PROG} update: cannot open directory ${TESTDIR}/cvsroot/dir1: No such file or directory +${PROG} update: skipping directory " + else + dotest_fail reposmv-2 "${testcvs} update" \ +"Cannot access ${TESTDIR}/root1/CVSROOT +No such file or directory" + fi + + # CVS/Root overrides $CVSROOT + if test "$remote" = no; then + CVSROOT_SAVED=${CVSROOT} + CVSROOT=${TESTDIR}/root-moved; export CVSROOT + dotest reposmv-3 "${testcvs} update" \ +"${DOTSTAR} +${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1 +${PROG} update: Updating \. +${DOTSTAR}" + CVSROOT=${CVSROOT_SAVED}; export CVSROOT + else + CVSROOT_SAVED=${CVSROOT} + CVSROOT=:fork:${TESTDIR}/root-moved; export CVSROOT + dotest_fail reposmv-3 "${testcvs} update" \ +"Cannot access ${TESTDIR}/root1/CVSROOT +No such file or directory" + CVSROOT=${CVSROOT_SAVED}; export CVSROOT + fi + + if test "$remote" = no; then + # CVS/Root doesn't seem to quite completely override $CVSROOT + # Bug? Not necessarily a big deal if it only affects error + # messages. + CVSROOT_SAVED=${CVSROOT} + CVSROOT=${TESTDIR}/root-none; export CVSROOT + dotest_fail reposmv-4 "${testcvs} update" \ +"${PROG} update: in directory \.: +${PROG} update: ignoring CVS/Root because it specifies a non-existent repository ${TESTDIR}/root1 +${PROG} \[update aborted\]: ${TESTDIR}/root-none/CVSROOT: No such file or directory" + CVSROOT=${CVSROOT_SAVED}; export CVSROOT + else + CVSROOT_SAVED=${CVSROOT} + CVSROOT=:fork:${TESTDIR}/root-none; export CVSROOT + dotest_fail reposmv-4 "${testcvs} update" \ +"Cannot access ${TESTDIR}/root1/CVSROOT +No such file or directory" + CVSROOT=${CVSROOT_SAVED}; export CVSROOT + fi + + # -d overrides CVS/Root + # + # Oddly enough, with CVS 1.10 I think this didn't work for + # local (that is, it would appear that CVS/Root would not + # get used, but would produce an error if it didn't exist). + dotest reposmv-5 "${testcvs} -d ${CVSROOT_MOVED} update" \ +"${PROG} [a-z]*: Updating \." + + # TODO: could also test various other things, like what if the + # user removes CVS/Root (which is legit). Or another set of + # tests would be if both repositories exist but we want to make + # sure that CVS is using the correct one. + + cd ../.. + rm -r imp-dir 1 + rm -rf root1 root2 + unset CVSROOT1 + ;; + + pserver) + # Test basic pserver functionality. + if test "$remote" = yes; then + # First set SystemAuth=no. Not really necessary, I don't + # think, but somehow it seems like the clean thing for + # the testsuite. + mkdir 1; cd 1 + dotest pserver-1 "${testcvs} -Q co CVSROOT" "" + cd CVSROOT + echo "SystemAuth=no" >config + dotest pserver-2 "${testcvs} -q ci -m config-it" \ +"Checking in config; +${TESTDIR}/cvsroot/CVSROOT/config,v <-- config +new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* +done +${PROG} [a-z]*: Rebuilding administrative file database" + echo "testme:q6WV9d2t848B2:`id -un`" \ + >${CVSROOT_DIRNAME}/CVSROOT/passwd + ${testcvs} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF +BEGIN AUTH REQUEST +${CVSROOT_DIRNAME} +testme +Ay::'d +END AUTH REQUEST +EOF + dotest pserver-3 "cat ${TESTDIR}/pserver.tmp" \ +"error 0 Server configuration missing --allow-root in inetd.conf" + + # Sending the Root and noop before waiting for the + # "I LOVE YOU" is bogus, but hopefully we can get + # away with it. + ${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF +BEGIN AUTH REQUEST +${CVSROOT_DIRNAME} +testme +Ay::'d +END AUTH REQUEST +Root ${CVSROOT_DIRNAME} +noop +EOF + dotest pserver-4 "cat ${TESTDIR}/pserver.tmp" \ +"I LOVE YOU${DOTSTAR}ok" + + ${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF +BEGIN AUTH REQUEST +${CVSROOT_DIRNAME} +testme +Ay::'d +END AUTH REQUEST +Root ${TESTDIR}/1 +noop +EOF + dotest pserver-5 "cat ${TESTDIR}/pserver.tmp" \ +"I LOVE YOU${DOTSTAR}E Protocol error: Root says \"${TESTDIR}/1\" but pserver says \"${CVSROOT_DIRNAME}\" +error " + + ${testcvs} --allow-root=${CVSROOT_DIRNAME} pserver >${TESTDIR}/pserver.tmp 2>&1 <<EOF +BEGIN AUTH REQUEST +${CVSROOT_DIRNAME} +testme +Ay::'d^b?hd +END AUTH REQUEST +EOF + dotest pserver-6 "cat ${TESTDIR}/pserver.tmp" \ +"I HATE YOU" + + # Clean up. + echo "# comments only" >config + dotest pserver-cleanup-1 "${testcvs} -q ci -m config-it" \ +"Checking in config; +${TESTDIR}/cvsroot/CVSROOT/config,v <-- config +new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* +done +${PROG} [a-z]*: Rebuilding administrative file database" + cd ../.. + rm -r 1 + rm ${CVSROOT_DIRNAME}/CVSROOT/passwd + fi # skip the whole thing for local + ;; + + server) + # Some tests of the server (independent of the client). + if test "$remote" = yes; then + if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then +Directory bogus +mumble/bar +update +EOF + dotest server-1 "cat ${TESTDIR}/server.tmp" \ +"E Protocol error: Root request missing +error " + else + echo "exit status was $?" >>${LOGFILE} + fail server-1 + fi + + # Could also test for relative pathnames here (so that crerepos-6a + # and crerepos-6b can use :fork:). + if ${testcvs} server >${TESTDIR}/server.tmp <<EOF; then +Set OTHER=variable +Set MYENV=env-value +init ${TESTDIR}/crerepos +EOF + dotest server-2 "cat ${TESTDIR}/server.tmp" "ok" + else + echo "exit status was $?" >>${LOGFILE} + fail server-2 + fi + dotest server-3 "test -d ${TESTDIR}/crerepos/CVSROOT" "" + + # Now some tests of gzip-file-contents (used by jCVS). + awk 'BEGIN { +printf "%c%c%c%c%c%c.6%c%c+I-.%c%c%c%c5%c;%c%c%c%c", +31, 139, 8, 64, 5, 7, 64, 3, 225, 2, 64, 198, 185, 5, 64, 64, 64}' \ + </dev/null | tr '\100' '\000' >gzipped.dat + echo Root ${TESTDIR}/crerepos >session.dat + # Note that the CVS client sends "-b 1.1.1", and this + # test doesn't. But the server also defaults to that. + cat <<EOF >>session.dat +UseUnchanged +gzip-file-contents 3 +Argument -m +Argument msg +Argumentx +Argument dir1 +Argument tag1 +Argument tag2 +Directory . +in-real-life-this-is-funky-but-server-seems-to-ignore-it +Modified file1 +u=rw,g=r,o=r +z25 +EOF + cat gzipped.dat >>session.dat + echo import >>session.dat + if ${testcvs} server >${TESTDIR}/server.tmp <session.dat; then + dotest server-4 "cat ${TESTDIR}/server.tmp" "M N dir1/file1 +M +M No conflicts created by this import +M +ok" + else + echo "exit status was $?" >>${LOGFILE} + fail server-4 + fi + dotest server-5 \ +"${testcvs} -q -d ${TESTDIR}/crerepos co -p dir1/file1" "test" + + if test "$keep" = yes; then + echo Keeping ${TESTDIR} and exiting due to --keep + exit 0 + fi + + rm -rf ${TESTDIR}/crerepos + rm gzipped.dat session.dat + rm ${TESTDIR}/server.tmp + fi # skip the whole thing for local + ;; + + client) + # Some tests of the client (independent of the server). + if test "$remote" = yes; then + cat >${TESTDIR}/serveme <<EOF +#!${TESTSHELL} +# This is admittedly a bit cheezy, in the sense that we make lots +# of assumptions about what the client is going to send us. +# We don't mention Repository, because current clients don't require it. +# Sending these at our own pace, rather than waiting for the client to +# make the requests, is bogus, but hopefully we can get away with it. +echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" +echo "ok" +echo "M special message" +echo "Created first-dir/" +echo "${TESTDIR}/cvsroot/first-dir/file1" +echo "/file1/1.1///" +echo "u=rw,g=rw,o=rw" +echo "4" +echo "xyz" +echo "ok" +cat >/dev/null +EOF + chmod +x ${TESTDIR}/serveme + CVS_SERVER=${TESTDIR}/serveme; export CVS_SERVER + mkdir 1; cd 1 + dotest_fail client-1 "${testcvs} -q co first-dir" \ +"${PROG} \[checkout aborted\]: This server does not support the global -q option\." + dotest client-2 "${testcvs} co first-dir" "special message" + + cat >${TESTDIR}/serveme <<EOF +#!${TESTSHELL} +echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" +echo "ok" +echo "M merge-it" +echo "Copy-file ./" +echo "${TESTDIR}/cvsroot/first-dir/file1" +echo "${TESTDIR}/bogus/.#file1.1.1" +echo "Merged ./" +echo "${TESTDIR}/cvsroot/first-dir/file1" +echo "/file1/1.2///" +echo "u=rw,g=rw,o=rw" +echo "4" +echo "abd" +echo "ok" +cat >/dev/null +EOF + cd first-dir + mkdir ${TESTDIR}/bogus + dotest_fail client-3 "${testcvs} update" "merge-it +${PROG} \[update aborted\]: protocol error: Copy-file tried to specify directory" + cat >${TESTDIR}/serveme <<EOF +#!${TESTSHELL} +echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" +echo "ok" +echo "M merge-it" +echo "Copy-file ./" +echo "${TESTDIR}/cvsroot/first-dir/file1" +echo ".#file1.1.1" +echo "Merged ./" +echo "${TESTDIR}/cvsroot/first-dir/file1" +echo "/file1/1.2///" +echo "u=rw,g=rw,o=rw" +echo "4" +echo "abc" +echo "ok" +cat >/dev/null +EOF + dotest client-4 "${testcvs} update" "merge-it" + dotest client-5 "cat .#file1.1.1" "xyz" + dotest client-6 "cat CVS/Entries" "/file1/1.2/[A-Za-z0-9 :]*// +D" + dotest client-7 "cat file1" "abc" + + cat >${TESTDIR}/serveme <<EOF +#!${TESTSHELL} +echo "Valid-requests Root Valid-responses valid-requests Directory Entry Modified Unchanged Argument Argumentx ci co update" +echo "ok" +echo "M OK, whatever" +echo "ok" +cat >${TESTDIR}/client.tmp +EOF + chmod u=rw,go= file1 + # By specifying the time zone in local time, we don't + # know exactly how that will translate to GMT. + dotest client-8 "${testcvs} update -D 99-10-04" "OK, whatever" + dotest client-9 "cat ${TESTDIR}/client.tmp" \ +"Root ${TESTDIR}/cvsroot +Valid-responses [-a-zA-Z ]* +valid-requests +Argument -D +Argument [34] Oct 1999 [0-9][0-9]:00:00 -0000 +Directory \. +${TESTDIR}/cvsroot/first-dir +Entry /file1/1\.2/// +Modified file1 +u=rw,g=,o= +4 +abc +update" + + cd ../.. + rm -r 1 + rmdir ${TESTDIR}/bogus + rm ${TESTDIR}/serveme + CVS_SERVER=${testcvs}; export CVS_SERVER + fi # skip the whole thing for local + ;; + *) echo $what is not the name of a test -- ignored ;; @@ -15535,6 +18921,13 @@ echo "OK, all tests completed." # server (e.g. set CVS_SERVER to "foobar"). # * Test the contents of adm files other than Root and Repository. # Entries seems the next most important thing. +# * Test the following compatibility issues: +# - The filler fields in "D" entries in CVS/Entries get preserved +# (per cvs.texinfo). +# - Unrecognized entry types in CVS/Entries get ignored (looks like +# this needs to be documented in cvs.texinfo, but is not) +# - Test that unrecognized files in CVS directories (e.g. CVS/Foobar) +# are ignored (per cvs.texinfo). # End of TODO list. # Remove the test directory, but first change out of it. diff --git a/gnu/usr.bin/cvs/src/server.h b/gnu/usr.bin/cvs/src/server.h index f94b7aa32a4..caeff8a7ccc 100644 --- a/gnu/usr.bin/cvs/src/server.h +++ b/gnu/usr.bin/cvs/src/server.h @@ -7,6 +7,16 @@ #define STDERR_FILENO 2 #endif + +/* + * Expand to `S', ` ', or the empty string. Used in `%s-> ...' trace printfs. + */ +#ifdef SERVER_SUPPORT +# define CLIENT_SERVER_STR ((server_active) ? "S" : " ") +#else +# define CLIENT_SERVER_STR "" +#endif + #ifdef SERVER_SUPPORT /* @@ -139,38 +149,30 @@ struct request void (*func) PROTO((char *args)); #endif - /* Stuff for use by the client. */ - enum { - /* - * Failure to implement this request can imply a fatal - * error. This should be set only for commands which were in the - * original version of the protocol; it should not be set for new - * commands. - */ - rq_essential, - - /* Some servers might lack this request. */ - rq_optional, - - /* - * Set by the client to one of the following based on what this - * server actually supports. - */ - rq_supported, - rq_not_supported, - - /* - * If the server supports this request, and we do too, tell the - * server by making the request. - */ - rq_enableme - } status; + /* One or more of the RQ_* flags described below. */ + int flags; + + /* If set, failure to implement this request can imply a fatal + error. This should be set only for commands which were in the + original version of the protocol; it should not be set for new + commands. */ +#define RQ_ESSENTIAL 1 + + /* Set by the client if the server we are talking to supports it. */ +#define RQ_SUPPORTED 2 + + /* If set, and client and server both support the request, the + client should tell the server by making the request. */ +#define RQ_ENABLEME 4 + + /* The server may accept this request before "Root". */ +#define RQ_ROOTLESS 8 }; /* Table of requests ending with an entry with a NULL name. */ extern struct request requests[]; /* Gzip library, see zlib.c. */ -extern void gunzip_and_write PROTO ((int, char *, unsigned char *, size_t)); -extern void read_and_gzip PROTO ((int, char *, unsigned char **, size_t *, - size_t *, int)); +extern int gunzip_and_write PROTO ((int, char *, unsigned char *, size_t)); +extern int read_and_gzip PROTO ((int, char *, unsigned char **, size_t *, + size_t *, int)); diff --git a/gnu/usr.bin/cvs/src/status.c b/gnu/usr.bin/cvs/src/status.c index 541a969a711..c405c454515 100644 --- a/gnu/usr.bin/cvs/src/status.c +++ b/gnu/usr.bin/cvs/src/status.c @@ -77,8 +77,6 @@ cvsstatus (argc, argv) if (local) send_arg("-l"); - send_file_names (argc, argv, SEND_EXPAND_WILD); - /* For a while, we tried setting SEND_NO_CONTENTS here so this could be a fast operation. That prevents the server from updating our timestamp if the timestamp is @@ -94,6 +92,8 @@ cvsstatus (argc, argv) send_files (argc, argv, local, 0, 0); + send_file_names (argc, argv, SEND_EXPAND_WILD); + send_to_server ("status\012", 0); err = get_responses_and_close (); @@ -242,7 +242,7 @@ status_fileproc (callerdat, finfo) } else { - if (isdigit (edata->tag[0])) + if (isdigit ((unsigned char) edata->tag[0])) { cvs_output (" Sticky Tag:\t\t", 0); cvs_output (edata->tag, 0); diff --git a/gnu/usr.bin/cvs/src/subr.c b/gnu/usr.bin/cvs/src/subr.c index 07d516f684c..b2e250c0e40 100644 --- a/gnu/usr.bin/cvs/src/subr.c +++ b/gnu/usr.bin/cvs/src/subr.c @@ -64,7 +64,11 @@ xrealloc (ptr, bytes) memory which is likely to get as big as MAX_INCR shouldn't be doing it in one block which must be contiguous, but since getrcskey does so, we might as well limit the wasted memory to MAX_INCR or so - bytes. */ + bytes. + + MIN_INCR and MAX_INCR should both be powers of two and we generally + try to keep our allocations to powers of two for the most part. + Most malloc implementations these days tend to like that. */ #define MIN_INCR 1024 #define MAX_INCR (2*1024*1024) @@ -84,11 +88,15 @@ expand_string (strptr, n, newsize) while (*n < newsize) { if (*n < MIN_INCR) - *n += MIN_INCR; - else if (*n > MAX_INCR) + *n = MIN_INCR; + else if (*n >= MAX_INCR) *n += MAX_INCR; else + { *n *= 2; + if (*n > MAX_INCR) + *n = MAX_INCR; + } } *strptr = xrealloc (*strptr, *n); } @@ -487,7 +495,7 @@ check_numeric (rev, argc, argv) int argc; char **argv; { - if (rev == NULL || !isdigit (*rev)) + if (rev == NULL || !isdigit ((unsigned char) *rev)) return; /* Note that the check for whether we are processing more than one @@ -534,7 +542,7 @@ make_message_rcslegal (message) } /* Backtrack to last non-space at end of string, and truncate. */ - while (dp > dst && isspace (dp[-1])) + while (dp > dst && isspace ((unsigned char) dp[-1])) --dp; *dp = '\0'; @@ -684,3 +692,49 @@ get_file (name, fullname, mode, buf, bufsize, len) (*buf)[nread] = '\0'; } } + + +/* Follow a chain of symbolic links to its destination. FILENAME + should be a handle to a malloc'd block of memory which contains the + beginning of the chain. This routine will replace the contents of + FILENAME with the destination (a real file). */ + +void +resolve_symlink (filename) + char **filename; +{ + if ((! filename) || (! *filename)) + return; + + while (islink (*filename)) + { + char *newname; +#ifdef HAVE_READLINK + /* The clean thing to do is probably to have each filesubr.c + implement this (with an error if not supported by the + platform, in which case islink would presumably return 0). + But that would require editing each filesubr.c and so the + expedient hack seems to be looking at HAVE_READLINK. */ + newname = xreadlink (*filename); +#else + error (1, 0, "internal error: islink doesn't like readlink"); +#endif + + if (isabsolute (newname)) + { + free (*filename); + *filename = newname; + } + else + { + char *oldname = last_component (*filename); + int dirlen = oldname - *filename; + char *fullnewname = xmalloc (dirlen + strlen (newname) + 1); + strncpy (fullnewname, *filename, dirlen); + strcpy (fullnewname + dirlen, newname); + free (newname); + free (*filename); + *filename = fullnewname; + } + } +} diff --git a/gnu/usr.bin/cvs/src/tag.c b/gnu/usr.bin/cvs/src/tag.c index a5b8794fe10..fa713455d96 100644 --- a/gnu/usr.bin/cvs/src/tag.c +++ b/gnu/usr.bin/cvs/src/tag.c @@ -59,7 +59,7 @@ static List *tlist; static const char *const tag_usage[] = { - "Usage: %s %s [-lRF] [-b] [-d] [-c] [-r tag|-D date] tag [files...]\n", + "Usage: %s %s [-lRF] [-b] [-d] [-c] [-r rev|-D date] tag [files...]\n", "\t-l\tLocal directory only, not recursive.\n", "\t-R\tProcess directories recursively.\n", "\t-d\tDelete the given tag.\n", @@ -178,15 +178,13 @@ cvstag (argc, argv) send_arg (symtag); - send_file_names (argc, argv, SEND_EXPAND_WILD); - - /* SEND_NO_CONTENTS has a mildly bizarre interaction with - check_uptodate; if the timestamp is modified but the file - is unmodified, the check will fail, only to have "cvs diff" - show no differences (and one must do "update" or something to - reset the client's notion of the timestamp). */ + send_files (argc, argv, local, 0, - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); + /* I think the -c case is like "cvs status", in + which we really better be correct rather than + being fast; it is just too confusing otherwise. */ + check_uptodate ? 0 : SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server ("tag\012", 0); return get_responses_and_close (); } @@ -297,9 +295,16 @@ check_fileproc (callerdat, finfo) { if (delete_flag) { + /* Deleting a tag which did not exist is a noop and + should not be logged. */ addit = 0; } } + else if (delete_flag) + { + free (p->data); + p->data = xstrdup (oversion); + } else if (strcmp(oversion, p->data) == 0) { addit = 0; @@ -367,7 +372,7 @@ pretag_proc(repository, filter) s = xstrdup(filter); for (cp=s; *cp; cp++) { - if (isspace(*cp)) + if (isspace ((unsigned char) *cp)) { *cp = '\0'; break; @@ -747,12 +752,12 @@ tag_check_valid (name, argc, argv, local, aflag, repository) int which; /* Numeric tags require only a syntactic check. */ - if (isdigit (name[0])) + if (isdigit ((unsigned char) name[0])) { char *p; for (p = name; *p != '\0'; ++p) { - if (!(isdigit (*p) || *p == '.')) + if (!(isdigit ((unsigned char) *p) || *p == '.')) error (1, 0, "\ Numeric tag %s contains characters other than digits and '.'", name); } @@ -903,7 +908,7 @@ tag_check_valid_join (join_tag, argc, argv, local, aflag, repository) s = strchr (c, ':'); if (s != NULL) { - if (isdigit (join_tag[0])) + if (isdigit ((unsigned char) join_tag[0])) error (1, 0, "Numeric join tag %s may not contain a date specifier", join_tag); diff --git a/gnu/usr.bin/cvs/src/vers_ts.c b/gnu/usr.bin/cvs/src/vers_ts.c index be0f588b419..e1ba32d2c4c 100644 --- a/gnu/usr.bin/cvs/src/vers_ts.c +++ b/gnu/usr.bin/cvs/src/vers_ts.c @@ -34,6 +34,10 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) struct stickydirtag *sdtp; Entnode *entdata; +#ifdef UTIME_EXPECTS_WRITABLE + int change_it_back = 0; +#endif + /* get a new Vers_TS struct */ vers_ts = (Vers_TS *) xmalloc (sizeof (Vers_TS)); memset ((char *) vers_ts, 0, sizeof (*vers_ts)); @@ -209,12 +213,28 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) { t.actime = t.modtime; +#ifdef UTIME_EXPECTS_WRITABLE + if (!iswritable (finfo->file)) + { + xchmod (finfo->file, 1); + change_it_back = 1; + } +#endif /* UTIME_EXPECTS_WRITABLE */ + /* This used to need to ignore existence_errors (for cases like where update.c now clears set_time if noexec, but didn't used to). I think maybe now it doesn't (server_modtime does not like those kinds of cases). */ (void) utime (finfo->file, &t); + +#ifdef UTIME_EXPECTS_WRITABLE + if (change_it_back == 1) + { + xchmod (finfo->file, 0); + change_it_back = 0; + } +#endif /* UTIME_EXPECTS_WRITABLE */ } } } diff --git a/gnu/usr.bin/cvs/src/version.c b/gnu/usr.bin/cvs/src/version.c index 479e5e6af77..ca5a98b21b4 100644 --- a/gnu/usr.bin/cvs/src/version.c +++ b/gnu/usr.bin/cvs/src/version.c @@ -12,8 +12,7 @@ #include "cvs.h" -/* NOTE: remember to remove `Halibut' when patching this code. */ -char *version_string = "\nConcurrent Versions System (CVS) 1.10 `Halibut'"; +char *version_string = "\nConcurrent Versions System (CVS) 1.10.5"; #ifdef CLIENT_SUPPORT #ifdef SERVER_SUPPORT diff --git a/gnu/usr.bin/cvs/src/watch.c b/gnu/usr.bin/cvs/src/watch.c index d9ba1d74171..b2935ac3dd0 100644 --- a/gnu/usr.bin/cvs/src/watch.c +++ b/gnu/usr.bin/cvs/src/watch.c @@ -337,8 +337,8 @@ watch_addremove (argc, argv) send_arg ("-a"); send_arg ("none"); } - send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, local, 0, SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server (the_args.adding ? "watch-add\012" : "watch-remove\012", 0); @@ -437,29 +437,29 @@ watchers_fileproc (callerdat, finfo) if (them == NULL) return 0; - fputs (finfo->fullname, stdout); + cvs_output (finfo->fullname, 0); p = them; while (1) { - putc ('\t', stdout); + cvs_output ("\t", 1); while (*p != '>' && *p != '\0') - putc (*p++, stdout); + cvs_output (p++, 1); if (*p == '\0') { /* Only happens if attribute is misformed. */ - putc ('\n', stdout); + cvs_output ("\n", 1); break; } ++p; - putc ('\t', stdout); + cvs_output ("\t", 1); while (1) { while (*p != '+' && *p != ',' && *p != '\0') - putc (*p++, stdout); + cvs_output (p++, 1); if (*p == '\0') { - putc ('\n', stdout); + cvs_output ("\n", 1); goto out; } if (*p == ',') @@ -468,9 +468,9 @@ watchers_fileproc (callerdat, finfo) break; } ++p; - putc ('\t', stdout); + cvs_output ("\t", 1); } - putc ('\n', stdout); + cvs_output ("\n", 1); } out:; return 0; @@ -515,8 +515,8 @@ watchers (argc, argv) if (local) send_arg ("-l"); - send_file_names (argc, argv, SEND_EXPAND_WILD); send_files (argc, argv, local, 0, SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); send_to_server ("watchers\012", 0); return get_responses_and_close (); } diff --git a/gnu/usr.bin/cvs/src/wrapper.c b/gnu/usr.bin/cvs/src/wrapper.c index e7c540d63cf..2d53c7a981d 100644 --- a/gnu/usr.bin/cvs/src/wrapper.c +++ b/gnu/usr.bin/cvs/src/wrapper.c @@ -118,6 +118,11 @@ void wrap_setup() /* Then add entries found in home dir, (if user has one) and file exists. */ homedir = get_homedir (); + /* If we can't find a home directory, ignore ~/.cvswrappers. This may + make tracking down problems a bit of a pain, but on the other + hand it might be obnoxious to complain when CVS will function + just fine without .cvswrappers (and many users won't even know what + .cvswrappers is). */ if (homedir != NULL) { char *file; @@ -348,9 +353,11 @@ wrap_add (line, isTemp) memset (&e, 0, sizeof(e)); /* Search for the wild card */ - while(*line && isspace(*line)) + while (*line && isspace ((unsigned char) *line)) ++line; - for(temp=line;*line && !isspace(*line);++line) + for (temp = line; + *line && !isspace ((unsigned char) *line); + ++line) ; if(temp==line) return; @@ -423,8 +430,6 @@ wrap_add (line, isTemp) error (1, 0, "Correct above errors first"); break; case 'm': - /* FIXME: look into whether this option is still relevant given - the 24 Jun 96 change to merge_file. */ if(*temp=='C' || *temp=='c') e.mergeMethod=WRAP_COPY; else diff --git a/gnu/usr.bin/cvs/src/zlib.c b/gnu/usr.bin/cvs/src/zlib.c index ca50130261a..fa0c2ad40d0 100644 --- a/gnu/usr.bin/cvs/src/zlib.c +++ b/gnu/usr.bin/cvs/src/zlib.c @@ -430,18 +430,14 @@ compress_buffer_shutdown_output (closure) /* Here is our librarified gzip implementation. It is very minimal but attempts to be RFC1952 compliant. */ -/* Note that currently only the client uses the gzip library. If we - make the server use it too (which should be straightforward), then - filter_stream_through_program, filter_through_gzip, and - filter_through_gunzip can go away. */ /* BUF should contain SIZE bytes of gzipped data (RFC1952/RFC1951). We are to uncompress the data and write the result to the file - descriptor FD. If something goes wrong, give an error message - mentioning FULLNAME as the name of the file for FD (and make it a - fatal error if we can't recover from it). */ + descriptor FD. If something goes wrong, give a nonfatal error message + mentioning FULLNAME as the name of the file for FD. Return 1 if + it is an error we can't recover from. */ -void +int gunzip_and_write (fd, fullname, buf, size) int fd; char *fullname; @@ -455,9 +451,15 @@ gunzip_and_write (fd, fullname, buf, size) unsigned long crc; if (buf[0] != 31 || buf[1] != 139) - error (1, 0, "gzipped data does not start with gzip identification"); + { + error (0, 0, "gzipped data does not start with gzip identification"); + return 1; + } if (buf[2] != 8) - error (1, 0, "only the deflate compression method is supported"); + { + error (0, 0, "only the deflate compression method is supported"); + return 1; + } /* Skip over the fixed header, and then skip any of the variable-length fields. */ @@ -496,9 +498,15 @@ gunzip_and_write (fd, fullname, buf, size) zstr.next_out = outbuf; zstatus = inflate (&zstr, Z_NO_FLUSH); if (zstatus != Z_STREAM_END && zstatus != Z_OK) - compress_error (1, zstatus, &zstr, fullname); + { + compress_error (0, zstatus, &zstr, fullname); + return 1; + } if (write (fd, outbuf, sizeof (outbuf) - zstr.avail_out) < 0) - error (1, errno, "writing decompressed file %s", fullname); + { + error (0, errno, "writing decompressed file %s", fullname); + return 1; + } crc = crc32 (crc, outbuf, sizeof (outbuf) - zstr.avail_out); } while (zstatus != Z_STREAM_END); zstatus = inflateEnd (&zstr); @@ -509,23 +517,31 @@ gunzip_and_write (fd, fullname, buf, size) + (buf[zstr.total_in + 11] << 8) + (buf[zstr.total_in + 12] << 16) + (buf[zstr.total_in + 13] << 24))) - error (1, 0, "CRC error uncompressing %s", fullname); + { + error (0, 0, "CRC error uncompressing %s", fullname); + return 1; + } if (zstr.total_out != (buf[zstr.total_in + 14] + (buf[zstr.total_in + 15] << 8) + (buf[zstr.total_in + 16] << 16) + (buf[zstr.total_in + 17] << 24))) - error (1, 0, "invalid length uncompressing %s", fullname); + { + error (0, 0, "invalid length uncompressing %s", fullname); + return 1; + } + + return 0; } /* Read all of FD and put the gzipped data (RFC1952/RFC1951) into *BUF, replacing previous contents of *BUF. *BUF is malloc'd and *SIZE is its allocated size. Put the actual number of bytes of data in - *LEN. If something goes wrong, give an error message mentioning - FULLNAME as the name of the file for FD (and make it a fatal error - if we can't recover from it). LEVEL is the compression level (1-9). */ + *LEN. If something goes wrong, give a nonfatal error mentioning + FULLNAME as the name of the file for FD, and return 1 if we can't + recover from it). LEVEL is the compression level (1-9). */ -void +int read_and_gzip (fd, fullname, buf, size, len, level) int fd; char *fullname; @@ -542,8 +558,16 @@ read_and_gzip (fd, fullname, buf, size, len, level) if (*size < 1024) { + unsigned char *newbuf; + *size = 1024; - *buf = (unsigned char *) xrealloc (*buf, *size); + newbuf = realloc (*buf, *size); + if (newbuf == NULL) + { + error (0, 0, "out of memory"); + return 1; + } + *buf = newbuf; } (*buf)[0] = 31; (*buf)[1] = 139; @@ -559,7 +583,10 @@ read_and_gzip (fd, fullname, buf, size, len, level) Z_DEFAULT_STRATEGY); crc = crc32 (0, NULL, 0); if (zstatus != Z_OK) - compress_error (1, zstatus, &zstr, fullname); + { + compress_error (0, zstatus, &zstr, fullname); + return 1; + } zstr.avail_out = *size; zstr.next_out = *buf + 10; @@ -569,7 +596,10 @@ read_and_gzip (fd, fullname, buf, size, len, level) nread = read (fd, inbuf, sizeof inbuf); if (nread < 0) - error (1, errno, "cannot read %s", fullname); + { + error (0, errno, "cannot read %s", fullname); + return 1; + } else if (nread == 0) /* End of file. */ finish = 1; @@ -588,9 +618,17 @@ read_and_gzip (fd, fullname, buf, size, len, level) if (zstr.avail_out < 4096) { + unsigned char *newbuf; + offset = zstr.next_out - *buf; *size *= 2; - *buf = xrealloc (*buf, *size); + newbuf = realloc (*buf, *size); + if (newbuf == NULL) + { + error (0, 0, "out of memory"); + return 1; + } + *buf = newbuf; zstr.next_out = *buf + offset; zstr.avail_out = *size - offset; } @@ -618,5 +656,7 @@ read_and_gzip (fd, fullname, buf, size, len, level) zstatus = deflateEnd (&zstr); if (zstatus != Z_OK) compress_error (0, zstatus, &zstr, fullname); + + return 0; } #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */ |