From 590c411955d6975551ffeaf41d7faf4b26f836d1 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 2 Oct 2000 06:33:59 +0000 Subject: Import cvs-1.11 onto vendor branch. --- contrib/cvs/src/ChangeLog | 1101 ++++++++++++++++++++++ contrib/cvs/src/Makefile.in | 6 +- contrib/cvs/src/add.c | 39 +- contrib/cvs/src/admin.c | 119 ++- contrib/cvs/src/checkout.c | 127 +-- contrib/cvs/src/client.c | 167 +++- contrib/cvs/src/client.h | 1 + contrib/cvs/src/commit.c | 179 ++-- contrib/cvs/src/create_adm.c | 6 +- contrib/cvs/src/cvs.h | 16 +- contrib/cvs/src/edit.c | 23 +- contrib/cvs/src/entries.c | 5 +- contrib/cvs/src/error.c | 9 +- contrib/cvs/src/fileattr.c | 19 +- contrib/cvs/src/filesubr.c | 9 + contrib/cvs/src/hardlink.c | 15 +- contrib/cvs/src/hash.c | 9 +- contrib/cvs/src/hash.h | 4 +- contrib/cvs/src/history.c | 184 ++-- contrib/cvs/src/ignore.c | 31 +- contrib/cvs/src/import.c | 78 +- contrib/cvs/src/lock.c | 12 +- contrib/cvs/src/log.c | 249 +++-- contrib/cvs/src/login.c | 54 +- contrib/cvs/src/logmsg.c | 16 +- contrib/cvs/src/main.c | 94 +- contrib/cvs/src/mkmodules.c | 38 + contrib/cvs/src/modules.c | 202 ++--- contrib/cvs/src/myndbm.c | 3 +- contrib/cvs/src/parseinfo.c | 43 +- contrib/cvs/src/patch.c | 31 +- contrib/cvs/src/rcs.c | 911 ++++++------------- contrib/cvs/src/rcs.h | 8 +- contrib/cvs/src/recurse.c | 13 +- contrib/cvs/src/release.c | 2 +- contrib/cvs/src/remove.c | 1 + contrib/cvs/src/repos.c | 12 +- contrib/cvs/src/root.c | 69 +- contrib/cvs/src/rtag.c | 24 +- contrib/cvs/src/run.c | 12 + contrib/cvs/src/sanity.sh | 2054 ++++++++++++++++++++++++++---------------- contrib/cvs/src/server.c | 527 +++++++---- contrib/cvs/src/subr.c | 58 +- contrib/cvs/src/tag.c | 16 +- contrib/cvs/src/update.c | 252 ++++-- contrib/cvs/src/vers_ts.c | 15 +- contrib/cvs/src/version.c | 48 +- contrib/cvs/src/watch.c | 1 + contrib/cvs/src/zlib.c | 4 +- 49 files changed, 4545 insertions(+), 2371 deletions(-) (limited to 'contrib/cvs/src') diff --git a/contrib/cvs/src/ChangeLog b/contrib/cvs/src/ChangeLog index 0d18891..a33464d 100644 --- a/contrib/cvs/src/ChangeLog +++ b/contrib/cvs/src/ChangeLog @@ -1,3 +1,1104 @@ +2000-09-19 Larry Jones + + * version.c: Version 1.11. + +2000-09-07 Larry Jones + + * Makefile.in: Use @bindir@, @libdir@, @infodir@, and @mandir@ + from autoconf. + +2000-08-23 Larry Jones + + * mkmodules.c (init): Create an empty val-tags file if it doesn't + already exist to avoid problems with users not having sufficient + permissions to create it later. + +2000-09-06 Jim Kingdon + + * main.c (lookup_command_attribute): Add "release" to commands + which can be done by a read-only user. + +2000-08-23 Larry Jones + + * repos.c (Name_Repository): Use pathname_levels to detect attempts + to get above the repository instead of checking for leading .. + which isn't reliable. + * sanity.sh (multiroot3-12 to multiroot3-15): New tests for above. + +2000-08-21 Larry Jones + + * rcs.c (expand_keywords): Handle the unusual case of log == NULL. + (Reported by Craig Metz .) + +2000-08-01 Larry Jones + + * subr.c (pathname_levels): Fix bug that miscounts adjacent + slashes. + (Patch submitted by Tanaka Akira .) + + * loginc.c (login): If available, use getpassphrase instead of + getpass to support long passwords on Solaris. + +2000-07-28 Larry Jones + + * server.c (server_noop): Avoid do_cvs_command() overhead. + (requests): Make noop RQ_ROOTLESS. + +2000-07-27 Noel Cragg + + * root.c (parse_cvsroot): change fork method to behave like other + remote methods -- let the server check that the repository + directory is an absolute pathname. + +2000-07-27 Larry Jones + + * lock.c (set_lock): Include actual lock directory in error message. + * sanity.sh (multiroot3-10): Change to match. + + * sanity.sh (client-3): Allow for a potential "broken pipe". + +2000-07-26 Larry Jones + + * commit.c (commit_filesdoneproc): Flush stdout before running script. + * modules.c (do_module): Ditto. + * update.c (update_dirleave_proc): Ditto. + * server.c (do_cvs_command): Give input from the protocol pipe + precedence over input from stdout/stderr. There's no particularly + good justification for this other than helping to avoid out-of-order + messages in sanity.sh. + + * admin.c (admin_usage): Add the supported options. + + * sanity.sh (info): Try to avoid out-of-order messages. + + * sanity.sh (info): Fix problems when running twice in a row. + +2000-07-17 Larry Jones + + * sanity.sh (modules5-7, cvsadm-1e, emptydir-2): Allow for a nil + commit (can happen if the test is run twice in a row). + +2000-07-19 Pavel Roskin + and Larry Jones + + * mkmodules.c (config_contents): Add a commented out example for + LockDir. Don't suggest PreservePermissions unless it's enabled. + +2000-07-17 Larry Jones + + * login.c (get_cvs_password): Handle malformed ~/.cvspass more + gracefully. + +2000-07-12 Larry Jones + + * sanity.sh (modules5): New tests for module programs. + +2000-07-11 Larry Jones + + * filesubr.c (copy_file, xcmp): Handle systems (like Plan 9) that + don't support mknod() and/or st_rdev. + * import.c (add_rcs_file): Ditto. + * rcs.c (RCS_checkout, RCS_checkin): Ditto. + * update.c (special_file_mismatch): Ditto. + +2000-07-10 Larry Jones + + * zlib.c (gunzip_and_write): Fix type clashes. + + * main.c (main): Remove unused variables. + +2000-07-10 Jim Meyering + + When a command like `cvs update -kk -jT1 -jT2' creates a new file + (because it had the T2 tag, but not T1), the subsequent commit of + that just-added file would effectively set the admin `-kk' option + for that file in the repository. + + * update.c (join_file): Rename global-shadowing local `options' + to `t_options'. + Set file-scoped global `options' to NULL just before + check-out. + * sanity.sh (join-admin): New test for this. + +2000-07-08 Larry Jones + + * version.c, cvs.h (version): New function. + * main.c (cmds[]): Add version command to invoke it. + (main): Also use it in -v. + * server.c (serve_version): New function. + (requests[]): Add version command to invoke it. + +2000-07-06 Karl Fogel + + * sanity.sh (pserver-14): remove this test for portability + reasons (it was only recently added for the 2000-07-04 change). + +2000-07-06 Larry Jones + + sanity.sh (modules-148): Don't test for specific revisions. + + * main.c (main): Catch SIGABRT to try to clean up after assertion + failures. Don't bother SIG_register'ing Lock_Cleanup because + main_cleanup calls it indirectly anyway. + * patch.c (patch): Catch SIGABRT. + * rcs.c (rcs_internal_lockfile): Ditto. + * server.c (server): Ditto. + + * fileattr.c (fileattr_write): Don't delete the unrecog_head list + when writing... + (fileattr_free): Delete it when freeing! + +2000-07-05 Larry Jones + + * admin.c (admin): Handle -t in client so reading from files works + correctly in client/server mode. + * sanity.sh (log2): Update to match. + +2000-07-04 Karl Fogel + + * server.c (pserver_authenticate_connection): use new + getline_safe() during authentication phase, to avoid a + denial-of-service attack in which client sends arbitrary + amounts of data with no newlines. + (Reported by .) + + * sanity.sh: new test pserver-14 for above. + + * myndbm.c: #include getline.h. + (mydbm_load_file): pass new GETLINE_NO_LIMIT flag to getstr(). + +2000-07-03 Larry Jones + + * sanity.sh (modules): Rewrite using dotest. Add "modules-" + prefix to test names. + +2000-06-28 Larry Jones + + * error.c (error_exit): Call rcs_cleanup () to release any rcs locks. + * rcs.c, rcs.h (rcs_cleanup): Make public, close file before trying + to remove (some systems won't remove open files). + (RCS_putdtree): Don't worry about cleaning up before call error + since it now does it for us. + (rcs_internal_lockfile, rcs_internal_unlockfile): Keep track of + lock file fd for rcs_cleanup (). + + * client.c (handle_set_checkin_prog, handle_set_update_prog): + Just ignore the request when exporting. + +2000-06-27 Larry Jones + + * create_adm.c, cvs.h (Create_Admin): Add dotemplate argument. + Change all callers. + * checkout.c (checkout_proc): Don't create CVS/Template if + exporting. + +2000-06-26 Pavel Roskin + and Larry Jones + + * server.c (switch_to_user): Only set CVS_Username if + AUTH_SERVER_SUPPORT is defined. + +2000-06-23 Larry Jones + + * client.c (send_dirent_proc): Don't allocate ignlist if you're + going to skip the directory (plugs memory leak). + (send_dirleave_proc): New function. + (send_files): Use it (plugs memory leak). + * root.c (root_allow_free): Plug memory leaks. + * server.c (serve_directory, serve_notify, check_password, + pserver_authenticate_connection): Ditto. + * update.c (update): Ditto. + + This completes the memory leak shoot-out -- the Purify'ed version + of CVS now runs the entire test suite, both local and remote (except + for remote crerepos, which causes Purify to choke) with *no* memory + leaks. + + * server.c (pserver_authenticate_connection): Don't free null pointer. + +2000-06-21 Larry Jones + + * client.c (update_entries, get_responses_and_close): Plug memory leaks. + * commit.c (find_fileproc, commit): Ditto. + * import.c (import): Ditto. + * log.c (cvslog): Ditto. + * recurse.c (start_recursion): Ditto. + * remove.c (cvsremove): Ditto. + * server.c (fd_buffer_initialize, server_notify, do_cvs_command): Ditto. + (fd_buffer_shutdown): New function. + +2000-06-20 Larry Jones + + * root.c (parse_cvsroot): Put the terminating NUL byte into the + string *before* copying it, not after. :-( + +2000-06-19 Larry Jones + + * main.c (main): Plug memory leaks. + * root.c (parse_cvsroot, set_local_cvsroot): Ditto. + * server.c (serve_root): Ditto. + +2000-06-16 Larry Jones + + * fileattr.c (fileattr_read): Plug memory leak. + * rcs.c (RCS_whatbranch): Ditto. + * update.c (update_dirleave_proc): Ditto. + + * ignore.c (ign_dir_add): Duplicate string so caller can free. + + * modules.c (do_module): Don't write into dbm's memory! + +2000-06-15 Larry Jones + + * checkout.c (checkout_proc): Fix non-ANSI code in call to + findslash(), minor cleanups. + +2000-06-14 Larry Jones + + * tag.c (val_direntproc): Return R_PROCESS instead of 0. + + * client.c (update_entries): Fix type clash calling gunzip_and_write(). + * server.c (receive_file): Fix type clash calling gunzip_and_write(). + (server_updated): Fix type clash calling buf_output(). + * error.c (error): Make buf char instead of unsigned char to avoid + type clashes. + + * modules.c (do_module): Change callback_proc to pass argc by + value instead of by reference: callback procs shouldn't be + messing with the callers argc/argv, it makes correct memory + management impossible. Plug memory leaks. + * cvs.h: Change to match. + * checkout.c (checkout_proc): Ditto; use a local argv array instead + of messing with caller's. + * modules.c (callback_proc): Ditto. + * patch.c (patch_proc): Ditto; use a local argv array instead + of messing with caller's. + * rtag.c (rtag_proc): Ditto; use a local argv array instead + of messing with caller's. + * server.c (expand_proc): Ditto. + * subr.c (line2argv): Change initial argv_allocated back to 1. + + * checkout.c (findslash): Fix non-ANSI code. + + * sanity.sh (modes3): Fix test names. + +2000-06-13 Larry Jones + + * add.c (add): Plug memory leaks. + * admin.c (admin_fileproc): Ditto. + * checkout.c (build_dirs_and_chdir): Ditto. + * edit.c (editors_fileproc): Ditto. + * log.c (cvslog, log_parse_revlist, log_parse_date): Ditto. + * rcs.c (RCS_addaccess): Ditto. + * tag.c (check_fileproc): Ditto. + * vers_ts.c (Version_TS): Ditto. + * watch.c (watchers_fileproc): Ditto. + +2000-06-12 Larry Jones + + * rcs.c (rcsbuf_valword): Set rcsbuf->vlen to keep rcsbuf_valcopy() + from allocating more memory than needed for @ strings. Don't declare + unless PRESERVE_PERMISSIONS_SUPPORT (since not defined). + + * rcs.c (RCS_abandon): New function to abandon changes. + * rcs.h: Declare it. + * admin.c (admin_fileproc): Use it instead of RCS_reparsercsfile. + + * commit.c (commit_fileproc): Fix memory leaks. + * patch.c (patch_fileproc): Ditto. + * rcs.c (RCS_nodeisbranch, RCS_copydeltas): Ditto. + * tag.c (tag_fileproc): Ditto. + * update.c (update): Ditto. + +2000-06-09 Larry Jones + + * rcs.c (RCS_reparsercsfile, RCS_fully_parse, getdelta, + RCS_getdeltatext): Handle newphrases with composite values. + (rcsbuf_getkey): Don't remove @s in composite values -- it makes + it impossible to parse the value! Set special flag to indicate + a composite value. + (rcsbuf_valcopy, rcsbuf_valpolish_internal): Handle composite values. + (putrcsfield): Write composite values. + (RCS_checkin): Set node types in other_delta list. + * hash.h: Add RCSCMPFLD. + * hash.c (nodetypestring): Ditto. + + * rcs.c (getdelta): Never allocate space for value, just return + pointer into rcsbuf (fixes memory leaks). Use rcsbuf_getkey to + read a key and value and then parse the value if needed rather + than trying to read it in bits and pieces with rcsbuf_getid, + rcsbuf_getstring, and rcsbuf_getword. + (RCS_reparsercsfile): Change callers to compensate. + (rcsbuf_valcmp, rcsbuf_valword): New functions. + (rcsbuf_getid, rcsbuf_getstring, rcsbuf_getword): Deleted. + * sanity.sh (rcs3-1): Now get slightly different error message. + +2000-06-08 Larry Jones + + * main.c (usg): Update CVS home page URL. + + * main.c (main): Provide an actual error message for an unknown + command in addition to the usage message. + +2000-06-07 Larry Jones + + * server.c (serve_root, dirswitch, serve_repository, + serve_static_directory, serve_sticky, receive_partial_file, + receive_file, serve_modified, server_write_entries, serve_notify, + serve_checkin_prog, serve_update_prog, server): Don't set + pending_error before calling alloc_pending, it makes it fail; + use alloc_pending instead of malloc when reasonable; be sure to + save errno before calling functions that might change it. + (Patch submitted by Dietmar Petras .) + +2000-06-03 Larry Jones + + * commit.c (checkaddfile): Plug memory leak. + * rcs.c (RCS_checkin): Plug memory leaks. + * server.c (do_cvs_command): Plug file descriptor leaks. + * tag.c (check_fileproc): Plug memory leak. + +2000-05-26 Larry Jones + + * recurse.c (unroll_files_proc): Plug memory leak. + + * recurse.c (addfile): Fix nonportable pointer cast. + + * rcs.c (rcsbuf_getstring, rcsbuf_getword, getdelta): Plug memory + leaks. + +2000-05-25 Larry Jones + + * checkout.c (checkout, build_one_dir, checkout_proc): Move m_type + to file scope and use it instead of continually doing strcmp on + command_name. + (build_one_dir, checkout_proc): Don't allow export if CVSADM + directory already exists. + +2000-05-23 Larry Jones + + * rcs.c (RCS_checkin, RCS_cmp_file): Plug memory leaks. (Patch + submitted by Chris G. Demetriou .) + +2000-05-20 Ian Lance Taylor + + * client.c (connect_to_gserver): Handle server error messages + reasonably. + +2000-05-19 Larry Jones + + * server.c (requests): Make Global_option RQ_ROOTLESS so it can be + used with init. + +2000-05-18 Larry Jones + + * client.c (start_server): Don't do encryption, authentication, + compression, or case insensitivity when doing init because init + is ROOTLESS and they're not. + + * client.c (connect_to_pserver): Include repository and username in + authorization failed message -- if a directory tree crosses multiple + repositories, it can be quite difficult for the user to figure out + which one is the problem. + +2000-05-17 Larry Jones + + * main.c (main): Use full set of options when looking for -f to + avoid misparsing options that take values (previously, -sVAR=foo + was incorrectly parsed as though it were -s -V -A -R -= -f -o -o + because it didn't know that -s takes a value). + * sanity.sh (info-6b): New test for above. + + * sanity.sh (conflicts-status): Fix tests so they work remotely, too. + +2000-05-17 Jim Meyering + + * sanity.sh (TESTDIR): Fix braino in last change: + cd to /tmp before invoking pwd. + + * sanity.sh: Set TESTDIR so that `make check' passes even when /tmp + is a symlink. + (join-36): Use $TESTDIR rather than hard-coding `/tmp/cvs-sanity'. + (conflicts-132): Remove unnecessary `rm aa'. + +2000-05-16 Jim Kingdon + + * cvs.h, checkout.c (safe_location): Make extern. + * import.c (import): Call it rather than reimplementing + (incompletely) the same check. + +2000-05-16 Larry Jones + + * rcs.h, subr.c (file_has_markers): Check for any of the three + conflict marker lines, not just one. + * sanity.sh (conflicts-status): New tests for above. + * sanity.sh: Revise to avoid tripping the above check when merging + changes into sanity.sh itself. + +2000-05-15 Larry Jones + + * update.c (join_file): When registering the result of the merge, + make sure that the version number is valid (vers->vn_rcs may be + null if the file doesn't exist on the branch yet). (Patch submitted + by Robert de Vries .) + * update.c (join_file): Correct diagnostics (previous change was not + correct -- the file *does* exist in the specified revision, it just + doesn't exist in the sandbox). + * sanity.sh (import-113, join): New tests and changes for above. + +2000-05-04 Larry Jones + + * sanity.sh: Look for a useful id program. Since we're getting + the real username for some tests anyway, use it for all the + tests instead of a generic regular expression that may or may + not match the actual username. + +2000-05-04 Larry Jones + + * server.c: More error messages. + +2000-05-02 Donald Sharp + and Larry Jones + + * history.c (report_hrecs): Added code to print out year instead of + just month/day. + * sanity.sh (basic2-64, history): Update to match. + +2000-04-19 Larry Jones + + * server.c (dirswitch): Set pending_error_text in addition to + pending_error to aid in problem determination. + +2000-03-23 Larry Jones + + * mkmodules.c (mkmodules): Return without doing anything if noexec + is set to avoid trashing existing files. + +2000-03-23 Larry Jones + + * main.c: Alphabetize cmds[] and cmd_usage[] and add server + commands to cmd_usage[]. + +2000-03-21 Larry Jones + + * sanity.sh (client-1): May get "Broken pipe" message from the + "server" in addition to the expected output. + +2000-03-17 Larry Jones + + * server.c (switch_to_user): Set CVS_Username if it hasn't already + been set elsewhere. (Patch submitted by Gordon Matzigkeit + ). + +2000-03-13 Larry Jones + + * parseinfo.c: Add extern to logHistory declaration. (Reported by + .) + (parse_config): Reformat logHistory code. + +2000-03-10 Larry Jones + + * add.c (add): Don't try to set cvsroot_len until after checking + for help only -- CVSroot_directory isn't set in that case. + +2000-03-03 Larry Jones + + * mkmodules.c (init): Use mkdir_if_needed to create CVSROOT/Emptydir + so we don't fail if run multiple times. (Reported by KOIE Hidetaka + .) + * sanity.sh (1a): New test for above. + +2000-03-02 Larry Jones + + * main.c: Use identical #if's in the command table and the code + for pserver and kserver to prevent "peculiar" configurations from + having really perverse behavior because the command table entries + are present but the related code isn't. + +2000-03-01 Larry Jones + + * import.c (import): Don't allow importing the repository. + * sanity.sh (errmsg2-20, errmsg2-21): New tests for above. + +2000-03-01 Larry Jones + + * main.c (main): Update year in copyright message. + +2000-03-01 Larry Jones + + * logmsg.c (do_editor): Correct previous change. + +2000-02-29 Larry Jones + + * logmsg.c (do_editor): When reading temp file, check that message + buffer is large enough to hold the next line and expand if needed. + +2000-02-28 Larry Jones + + * commit.c (commit): Use get_file() to read log file correctly + and in text mode rather than binary mode. + + * subr.c (get_file): Ignore bufsize if buf is NULL. Include + terminating NUL byte when estimating required buffer size. + +2000-02-28 Larry Jones + + * sanity.sh (find_tool): New function to replace duplicated code. + +2000-02-25 Larry Jones + + * import.c (add_rcs_file): Don't abort just because lstat fails. + +2000-02-16 Jim Meyering + + Avoid race condition whereby a catchable signal could + end up corrupting the repository. + * commit.c (checkaddfile): Put a critical section around the code + that handles the first commit on the trunk of a file that's already + been committed on a branch. + * cvs.h (Sig_inCrSect): Declare new function. + +2000-02-21 Karl Fogel + + * main.c (main): still check for repository, but not history file + (correction to 2000-02-18 change -- that's what I get for + believing the comment rather than the code). + +2000-02-21 K.J. Paradise + + * history.c mkmodules.c parseinfo.c: control which actions + get logged to the cvs history file via CVSROOT/config file + and LogHistory keyword. (John P Cavanaugh ) + +2000-02-18 Karl Fogel + + * history.c (history_write): don't die if history file not + writable, just warn (unless `really_quiet') and skip out. + + * main.c (main): don't bother checking if history file is + writable. + + * server.c (serve_root): same. + +2000-02-17 Larry Jones + + * sanity.sh (perms symlinks symlinks2 hardlinks): Don't run by + default since PreservePermissions code is now disabled. + +2000-02-17 Larry Jones + + * sanity.sh (import-113): Revise to match Jim Meyering's fix. + +2000-02-16 Larry Jones + + * add.c (add): Don't allow adding files or directories to Emptydir. + (Patch submitted by Chris Cameron .) + * sanity.sh (emptydir): Revise (emptydir-7 and emptydir-8) for this. + +2000-02-16 Jim Meyering + + * update.c (join_file): Correct typo in diagnostic: + change `file %s is present...' to `file %s is not present...'. + +2000-02-10 Larry Jones + + * parseinfo.c (Parse_Info): Treat matching lines with bad expansions + as errors rather than just ignoring. + +2000-02-10 Larry Jones + + * edit.c (edit): Check for invalid characters in hostname and CurDir. + (Reported by "Andrew S. Townley" .) + * sanity.sh (devcom2): New tests for above. + +2000-02-10 Larry Jones + + * cvs.h: Always #include "server.h" to prevent compile errors when + neither CLIENT_SUPPORT nor SERVER_SUPPORT is defined. + (Reported by "Crow, Ian" .) + * log.c (send_one, send_arg_list): Only define when CLIENT_SUPPORT + is defined to prevent link errors. + + * server.c (server): Always create a new temporary directory, don't + try to reuse an existing one since we might not have correct + permissions. Also, include directory name in error messages. + +2000-01-29 Jim Kingdon + + * ignore.c (ignore_files): Correctly set errno to 0 when we go + back to the top of the loop. Fixes spurious errors like "cvs + update: error reading current directory: No such file or + directory". + +2000-01-26 Larry Jones + + * run.c (run_exec): Conditionalize K.J.'s change so that it only + applies when SETXID_SUPPORT is defined since some platforms don't + have setegid(). + +2000-01-26 Larry Jones + + * sanity.sh: Make TESTDIR earlier then use it to check for versions + of expr that don't work right with long expressions. + + * sanity.sh (dotest_line_by_line): Have wc read from stdin so it + doesn't output the file name and confuse expr. Make the output a + bit less verbose and easier to read. + +2000-01-24 K.J. Paradise + + * run.c :> prevents a user from creating a privileged shell from the + text editor when the SETXID_SUPPORT option is selected. This came from + Bob Colle , and is his completely. + +2000-01-22 Jim Kingdon + + * sanity.sh (emptydir): Add a case in which one might hope for a + non-Emptydir result, but which result? + +2000-01-18 Larry Jones + + * main.c (main): Allow -z0 to disable gzip compression. + +2000-01-17 Larry Jones for + K.J. Paradise (kj@sourcegear.com) + + * version.c: Push version number to 1.10.8.1. + + * version.c: Version 1.10.8. + +2000-01-17 Larry Jones + + * mkmodules.c (init): Create CVSROOT/Emptydir to avoid problems + with users not having sufficient permissions to create it later. + +2000-01-04 Larry Jones + + * client.c (get_responses_and_close): Simplify time-stamp race + avoidance code. + * commit.c (commit): Ditto. + * update.c (do_update): Ditto. + (Prompted by patch submitted by Pavel Roskin + .) + + * hardlink.c: sizeof (char) is 1, by definition. + * logmsg.c: Ditto. + * rcs.c: Ditto. + +2000-01-03 Karl Fogel + + * filesubr.c, subr.c (backup_file): moved this function from + filesubr.c to subr.c, at JimK's suggestion. + +2000-01-03 Jim Kingdon + + * sanity.sh (clean): Test the contents of the .#cleanme.txt.1.1 + file, not just its existence. + +2000-01-03 Karl Fogel + + * cvs.h, filesubr.c (backup_file): use `const' for suffix too; + correct suffix length calculation and appending behavior; discard + unnecessary `void' cast. Thanks to Jim Meyering for noticing. + +2000-01-03 Larry Jones + + * sanity.sh (clean): Fix up expected output. + +2000-01-02 John P Cavanaugh + and Karl Fogel + + New -C option to update: overwrites local changes with clean + copies from the repository. (This is an unreversion of the + 1999-12-10 change, further modified to work remotely.) + + * client.h (BACKUP_MODIFIED_FILES): new #define. + + * client.c (struct send_data): new element `backup_modified'. + (send_files): set above element if BACKUP_MODIFIED_FILES flag is + present. + + * filesubr.c (backup_file): new function. + + * cvs.h: prototype for new function `backup_file'. + + * update.c (toss_local_changes): new file-scoped global. + (update): set toss_local_changes if -C flag seen. If + client_active, send "-C" to server, and set SEND_NO_CONTENTS and + BACKUP_MODIFIED_FILES flags before calling send_files(). + + (update_fileproc): if file is modified and toss_local_changes is + set, then back the file up and then check out a fresh copy from + the repository. Also, fixed indentation and formatting for a + particularly bad stretch of code near (but unrelated to) these + changes. + + * sanity.sh: new test `clean', for update -C option. + +1999-12-29 Jim Kingdon + + * history.c (read_hrecs): st_blksize is unsigned long, not int. + This isn't just cosmetic - getting it wrong will cause coredumps + and such on 64 bit machines. + + * import.c (import_descend), ignore.c (ignore_files): Placate gcc + -Wall by parenthesizing foo || (bar && baz). + +1999-12-24 Larry Jones + + * release.c (release): Use fputs to echo lines from update instead + of printf to avoid problems with lines containing "%". (Reported + by Jean-Luc Simard .) + + * history.c (read_hrecs): Allocate a single 2-block buffer instead + of allocating and freeing a buffer for each block. + (fill_hrec): Remove redundant code. + (select_hrec): Plug memory leak. + +1999-12-22 Larry Jones + + * history.c (history): For "modified" or "checkout", sort on + file if user specified -l, even if user also specified a date- + oriented flag. + * sanity.sh (history): Update to match; add new tests. + +1999-12-15 Pavel Roskin + and Larry Jones + + * lock.c (lock_name): fixed assertion failure for the + top-level CVS directory when LockDir is used + * sanity.sh (lockfiles-9): new test for this case + +1999-12-11 Karl Fogel + + * Revert previous change -- it doesn't work remotely yet. + +1999-12-10 John P Cavanaugh + and Karl Fogel + + * update.c: new -C option to update, overwrites local changes with + clean copies from the repository. + Also, fixed indentation and formatting for a particularly bad + stretch of code near these changes in update_fileproc(). + + * sanity.sh: test new update -C option. + +1999-12-10 Larry Jones + + * commit.c (remove_file): Call history_write with update_dir NULL + like Checkin() does for add and modify. + * sanity.sh (basic2-64): Update to match, add "R" records to expected + remote output. + +1999-12-09 K.J. Paradise (kj@sourcegear.com) + + * history.c, commit.c, sanity.sh: found (I think) final + cause of seg fault in history command. Also, added the "R" + history functionality. Fixed basic2-64 so it looks correct for + the change. + +1999-11-30 K.J. Paradise (kj@sourcegear.com) + + * history.c: fixed seg fault caused by 11-03 changes. + off by one in block memory allocations. + +1999-11-29 Karl Fogel + + * login.c (logout): free `tmp_name' when done. + Correct a comment. + +1999-11-29 Larry Jones + + * cvs.h, error.c, import.c: Rename fperror to avoid name clash + on LynxOS. (Reported by Markus Braun .) + +1999-11-23 Larry Jones + + * checkout.c (checkout_proc): Split declaration and initialization + of rp to placate neurotic compilers that gripe about jumping past + an initialization, even when the variable is not subsequently used. + +1999-11-19 Larry Jones + + * server.c (switch_to_user): Correct setgid error messages. + +1999-11-19 Karl Fogel + + * edit.c (unedit_usage, unedit): new struct, use it. Now "cvs + unedit" prints an accurate usage message (formerly it printed the + message for "cvs edit", even though the two commands do not have + identical usages). + +1999-11-19 Larry Jones + + * history.c: Move -e documentation from Flags to Reports. + (history): Add -e to list of report types in error message. + + * history.c (history): Process file arguments before client/server + processing so they get sent to the server. + * sanity.sh (history): New tests for above. (Also remove comments + about variable spacing -- history output is in variable-width + columns with exactly one space between.) + +1999-11-19 Larry Jones + + * sanity.sh: Reestablish check for running as root (using ``id -u'' + instead of ``whoami''). + + * sanity.sh(dotest, dotest_lit, dotest_fail, dotest_status, + dotest_sort): Eval the command so quoting and pipes work right. + (spacefiles, dirs, rcslib, modules, unedit-without-baserev, + ignore, rcs, rcs2, history, tagdate, pserver, server, server2) + Simplify various tests based on above. + +1999-11-19 Karl Fogel + + * mkmodules.c (init): make history file world-writeable after + creating it, since it needs to be writeable for virtually any + CVS operation. + +1999-11-10 Jim Kingdon + + * admin.c: Revert change to add -H command option. The help + invocation is "cvs -H admin" not "cvs admin -H" (see cvs.texinfo, + basicb-21 in sanity.sh; fix to cvs.1) + +1999-11-08 Jim Kingdon + + * log.c (cvslog): If client_active, send options to the server + based on our parsed options rather than trying to send the exact + strings specified (using canonical forms, like RFC822/1123 + dates, in the protocol is just cleaner). + (send_one, send_arg_list): New functions, helpers for above. + * sanity.sh (logopt-6a): New test, for this fix. + +1999-11-09 K.J. Paradise + + * admin.c: made the -H option do what it is documented to + do. a + +1999-11-08 Tom Tromey + + * client.c (connect_to_gserver): Print more error text if gssapi + initialization fails. From Assar Westerlund . + +1999-11-06 Larry Jones + + *sanity.sh(rcs3-5): Remote output can be out-of-order, so need a + more general pattern to match the assertion failure. + +1999-11-05 K.J. Paradise (kj@sourcegear.com) + + * history.c: Added a trap to verify that if a + read(file, buffer,blocksize) returns less than blocksize, + that we really are at the end of the file. I can't easily + come up with a test case where this code gets touched, so + it may cause problems. All sanity tests still pass though. + +1999-11-05 Jim Kingdon + + * sanity.sh (logopt): New test, for Larry's fix. + * sanity.sh (log-18a, rcs-15 to rcs-19): New tests, to test -d + and -r more thoroughly. + +1999-11-05 Larry Jones + + * log.c (cvslog): Fix -s and -d with spaces on client side. + (log_usage): Revert Karl's change once again. + sanity.sh(rcs3-5): No longer get different results from local + and client/server. + +1999-11-04 Karl Fogel + + * log.c (log_usage): Revert Jim Kingdon's reversion of my change + of 1999-11-03. Allowing a space between option and argument + results in lossage; here is a reproduction recipe: run this from + the top of a remote copy of the cvs source tree + + cvs log -d '>1999-03-01' > log-out.with-space + + and then run this (note there's no space after -d now): + + cvs log -d'>1999-03-01' > log-out.no-space + + The resulting files differ; furthermore, a glance at the output of + cvs shows that the first command failed to recurse into + subdirectories. Until this misbehavior can be fixed in the source + code, the documentation should reflect the true state of affairs: + if one simply omits the space, everything works fine. + +1999-11-04 Jim Kingdon + + * log.c (log_usage): Revert Karl's change regarding -d and + -s. A space is allowed (see sanity.sh for example). + +1999-11-03 K.J. Paradise (kj@sourcegear.com> + + * history.c: cleaned up my prior change a bit, per Larry Jones' + comments, and John O'Conner's additional comments about bits of + non MS-Visual C++ compliancy of my code. + +1999-11-04 Larry Jones + + * sanity.sh: Check that tr that correctly handles NULs; if not, try + to find a version that does; if none can be found, warn user. + Also fix warnings for defective expr. + +1999-11-04 Karl Fogel + + Changes for empty/random passwords in anon pserver access: + + * server.c (check_repository_password): if password empty, grant + access no matter what password is received; this is so anon CVS no + longer requires a password but remains backwards-compatible with + all those clients out there. + + * client.c (connect_to_pserver): proceed with login even if + password not found in .cvspass file -- just use empty string as + password. And if such a login fails, print a descriptive error. + + * login.c (get_cvs_password): don't complain if file or password + not found. That condition is no longer a showstopper, now that + empty passwords are permissible. + Cleaned up conditional chaining a bit, too. + + * sanity.sh (pserver-9, pserver-10, pserver-11, pserver-12, + pserver-13): new tests, about empty-password pserver access. + +1999-11-03 K.J. Paradise (kj@sourcegear.com> + + * history.c: modify parsing routines to parse the history + file a block at a time, rather than all at once. This allows + people with large history files and small amount of memory + to still get some functionality out of the history file. + +1999-11-03 Karl Fogel + + * log.c (log_usage): correct usage message for -d and -s options. + Because the space between the option letter and its argument has + been eliminated, I capitalized the argument portion to distinguish + it from the option letter. This makes it slightly inconsistent + with other such usage summaries, but at least it is now both + correct and readable. + +1999-10-22 Larry Jones + + * sanity.sh (dotest_sort): Old versions of tr don't understand \t + so use a literal tab instead. + +1999-10-21 Larry Jones + + * sanity.sh (dotest_sort): Convert any tabs in the output into spaces + before sorting to avoid POSIX.2 sort weirdness. + (import-106, importb-2): Change expected output per above. + +1999-10-18 K.J. Paradise + + Bug: users 'stan' and 'cartman' both have full read/write access + to the cvs repository. 'cartman' does a 'cvs admin -l foo.c'. + 'stan' then does a 'cvs admin -u foo.c'. The lock wouldn't be + removed, and no warning/error would be given. This is now fixed. + * rcs.c:(c.6157) remove caller/user check on the multiple lock + detection routines. Sanity.sh runs with no errors after this fix. + +1999-10-14 Larry Jones + + Make "cvs admin -e" (with no list of users) work: + * admin.c (admin): Remove error message. + (admin_fileproc): If no args for -e, call RCS_delaccess with NULL user. + * rcs.c (RCS_delaccess): Interpret NULL user as request to delete + entire access list. + * sanity.sh (admin-19a-*): Test. + +1999-09-29 Larry Jones + + * entries.c (Subdirs_Known): Use entfilename when opening CVSADM_ENTLOG + like everywhere else. Although this isn't strictly necessary (since + we immediately close it again), it keeps the code consistent and fixes + a bug where an open error reported the wrong file name. + +1999-09-16 Larry Jones + + * log.c (log_parse_revlist): Handle peculiar revision specs like + "-r.", "-r:", and "-r," correctly. (Thanks to Pavel Roskin + for submitting a patch, this fix is + somewhat different.) + * sanity.sh (log): New tests for above. + +1999-09-15 Larry Jones + + * sanity.sh (basica-8b1): New test to check fix for bad diff options + causing cvs to crash. + +1999-09-02 Larry Jones + + * modules.c (do_module): Handle case where module definition has + options and special options but no directory; fix potential problems + running off beginning of string while stripping trailing blanks. + * sanity.sh (modules2): New tests for above. + +1999-08-26 Larry Jones + + * lock.c (lock_name): Remove side-effects from assert() expression + since they won't occur if NDEBUG is defined (not that that's a good + thing to do). (Reported by KOIE Hidetaka .) + +1999-08-25 Larry Jones + + * sanity.sh: Use "${AWK}" instead of "awk" to make it easier for + people to use nawk/gawk/etc.; use an explicit "-print" with find + since some older version don't assume it; rename tests to avoid + duplicate importc-8. (Changes along these lines suggested by + Chris Cameron .) + +1999-08-24 Larry Jones + + * commit.c (check_fileproc): Don't crash when a file has no + repository, just treat it as unknown. (Reported by Stefaan + Diericx .) + * sanity.sh (errmsg2): New tests, for this fix. + +1999-08-18 Larry Jones + + * update.c (special_file_mismatch): Initialize *_hardlinks to + avoid trying to free garbage later on. (Reported by Jan + Scheffczyk .) + +1999-08-17 Larry Jones + + * sanity.sh (basicc-11): Older versions of sh don't understand + ``if ! test...''. (Patch submitted by David J N Begley + .) + +1999-08-17 Larry Jones + + * client.c, hardlink.c, hash.c, hash.h, main.c, recurse.c: Change + enum constant UNKNOWN to avoid conflicts on HPUX 11.0. (Reported + by Laurent Duperval .) + +1999-08-16 Larry Jones + + client.c: Eliminate redundant #if. (Patch submitted by Assar + Westerlund .) + +1999-07-30 Larry Jones + + * rcs.c (RCS_checkin): Terminate cleanly if RCS_addbranch fails + rather than blithely continuing on and crashing. + * sanity.sh (basica): New tests, for this fix. + +1999-07-29 Larry Jones + + * import.c (add_rcs_file): change "cannot lstat" message to include + userfile (the actual file causing the problem) instead of user + (which may or may not be the same). + +1999-07-29 Eric Sink + + * version.c: Push version number to 1.10.7.1. + + * version.c: Version 1.10.7. + 1999-07-28 Eric Sink * sanity.sh: before running basicc-11, we need to see if diff --git a/contrib/cvs/src/Makefile.in b/contrib/cvs/src/Makefile.in index 7cbdca7..d09b0cb 100644 --- a/contrib/cvs/src/Makefile.in +++ b/contrib/cvs/src/Makefile.in @@ -22,13 +22,13 @@ prefix = @prefix@ exec_prefix = @exec_prefix@ # Where to install the executables. -bindir = $(exec_prefix)/bin +bindir = @bindir@ # Where to put the system-wide .cvsrc file -libdir = $(prefix)/lib +libdir = @libdir@ # Where to put the manual pages. -mandir = $(prefix)/man +mandir = @mandir@ # Use cp if you don't have install. INSTALL = @INSTALL@ diff --git a/contrib/cvs/src/add.c b/contrib/cvs/src/add.c index db1f527..dbefda5 100644 --- a/contrib/cvs/src/add.c +++ b/contrib/cvs/src/add.c @@ -59,6 +59,7 @@ add (argc, argv) /* Nonzero if we found a slash, and are thus adding files in a subdirectory. */ int found_slash = 0; + size_t cvsroot_len; if (argc == 1 || argc == -1) usage (add_usage); @@ -92,6 +93,8 @@ add (argc, argv) if (argc <= 0) usage (add_usage); + cvsroot_len = strlen (CVSroot_directory); + /* First some sanity checks. I know that the CVS case is (sort of) also handled by add_directory, but we need to check here so the client won't get all confused in send_file_names. */ @@ -157,7 +160,11 @@ add (argc, argv) start_server (); ign_setup (); - if (options) send_arg(options); + if (options) + { + send_arg (options); + free (options); + } option_with_arg ("-m", message); /* If !found_slash, refrain from sending "Directory", for @@ -219,6 +226,17 @@ add (argc, argv) /* find the repository associated with our current dir */ repository = Name_Repository (NULL, update_dir); + /* don't add stuff to Emptydir */ + if (strncmp (repository, CVSroot_directory, cvsroot_len) == 0 + && ISDIRSEP (repository[cvsroot_len]) + && strncmp (repository + cvsroot_len + 1, + CVSROOTADM, + sizeof CVSROOTADM - 1) == 0 + && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM]) + && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1, + CVSNULLREPOS) == 0) + error (1, 0, "cannot add to %s", repository); + /* before we do anything else, see if we have any per-directory tags */ ParseTag (&tag, &date, &nonbranch); @@ -227,7 +245,7 @@ add (argc, argv) sprintf (rcsdir, "%s/%s", repository, p); Create_Admin (p, argv[i], rcsdir, tag, date, - nonbranch, 0); + nonbranch, 0, 1); if (found_slash) send_a_repository ("", repository, update_dir); @@ -304,6 +322,17 @@ add (argc, argv) /* Find the repository associated with our current dir. */ repository = Name_Repository (NULL, finfo.update_dir); + /* don't add stuff to Emptydir */ + if (strncmp (repository, CVSroot_directory, cvsroot_len) == 0 + && ISDIRSEP (repository[cvsroot_len]) + && strncmp (repository + cvsroot_len + 1, + CVSROOTADM, + sizeof CVSROOTADM - 1) == 0 + && ISDIRSEP (repository[cvsroot_len + sizeof CVSROOTADM]) + && strcmp (repository + cvsroot_len + sizeof CVSROOTADM + 1, + CVSNULLREPOS) == 0) + error (1, 0, "cannot add to %s", repository); + entries = Entries_Open (0, NULL); finfo.repository = repository; @@ -619,6 +648,8 @@ cannot resurrect %s; RCS file removed by second party", finfo.fullname); if (message) free (message); + if (options) + free (options); return (err); } @@ -769,10 +800,8 @@ add_directory (finfo) #ifdef SERVER_SUPPORT if (!server_active) - Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0); -#else - Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0); #endif + Create_Admin (".", finfo->fullname, rcsdir, tag, date, nonbranch, 0, 1); if (tag) free (tag); if (date) diff --git a/contrib/cvs/src/admin.c b/contrib/cvs/src/admin.c index c5af96e..637663a 100644 --- a/contrib/cvs/src/admin.c +++ b/contrib/cvs/src/admin.c @@ -22,7 +22,45 @@ static int admin_fileproc PROTO ((void *callerdat, struct file_info *finfo)); static const char *const admin_usage[] = { - "Usage: %s %s rcs-options files...\n", + "Usage: %s %s [options] files...\n", + "\t-a users Append (comma-separated) user names to access list.\n", + "\t-A file Append another file's access list.\n", + "\t-b[rev] Set default branch (highest branch on trunk if omitted).\n", + "\t-c string Set comment leader.\n", + "\t-e[users] Remove (comma-separated) user names from access list\n", + "\t (all names if omitted).\n", + "\t-I Run interactively.\n", + "\t-k subst Set keyword substitution mode:\n", + "\t kv (Default) Substitue keyword and value.\n", + "\t kvl Substitue keyword, value, and locker (if any).\n", + "\t k Substitue keyword only.\n", + "\t o Preserve original string.\n", + "\t b Like o, but mark file as binary.\n", + "\t v Substitue value only.\n", + "\t-l[rev] Lock revision (latest revision on branch,\n", + "\t latest revision on trunk if omitted).\n", + "\t-L Set strict locking.\n", + "\t-m rev:msg Replace revision's log message.\n", + "\t-n tag[:[rev]] Tag branch or revision. If :rev is omitted,\n", + "\t delete the tag; if rev is omitted, tag the latest\n", + "\t revision on the default branch.\n", + "\t-N tag[:[rev]] Same as -n except override existing tag.\n", + "\t-o range Delete (outdate) specified range of revisions:\n", + "\t rev1::rev2 Between rev1 and rev2, excluding rev1 and rev2.\n", + "\t rev:: After rev on the same branch.\n", + "\t ::rev Before rev on the same branch.\n", + "\t rev Just rev.\n", + "\t rev1:rev2 Between rev1 and rev2, including rev1 and rev2.\n", + "\t rev: rev and following revisions on the same branch.\n", + "\t :rev rev and previous revisions on the same branch.\n", + "\t-q Run quietly.\n", + "\t-s state[:rev] Set revision state (latest revision on branch,\n", + "\t latest revision on trunk if omitted).\n", + "\t-t[file] Get descriptive text from file (stdin if omitted).\n", + "\t-t-string Set descriptive text.\n", + "\t-u[rev] Unlock the revision (latest revision on branch,\n", + "\t latest revision on trunk if omitted).\n", + "\t-U Unset strict locking.\n", "(Specify the --help global option for a list of other help options)\n", NULL }; @@ -53,9 +91,7 @@ struct admin_data /* Keyword substitution mode (-k), e.g. "-kb". */ char *kflag; - /* Description (-t). See sanity.sh for various moanings about - files and stdin and such. "" if -t specified without an - argument. It is "-t" followed by the argument. */ + /* Description (-t). */ char *desc; /* Interactive (-I). Problematic with client/server. */ @@ -191,11 +227,6 @@ admin (argc, argv) break; case 'e': - if (optarg == NULL) - { - error (1, 0, - "removing entire access list not yet implemented"); - } arg_add (&admin_data, 'e', optarg); break; @@ -287,13 +318,15 @@ admin (argc, argv) error (0, 0, "duplicate 't' option"); goto usage_error; } - if (optarg == NULL) - admin_data.desc = xstrdup ("-t"); + if (optarg != NULL && optarg[0] == '-') + admin_data.desc = xstrdup (optarg + 1); else { - admin_data.desc = xmalloc (strlen (optarg) + 5); - strcpy (admin_data.desc, "-t"); - strcat (admin_data.desc, optarg); + size_t bufsize = 0; + size_t len; + + get_file (optarg, optarg, "r", &admin_data.desc, + &bufsize, &len); } break; @@ -417,7 +450,26 @@ admin (argc, argv) if (admin_data.delete_revs != NULL) send_arg (admin_data.delete_revs); if (admin_data.desc != NULL) - send_arg (admin_data.desc); + { + char *p = admin_data.desc; + send_to_server ("Argument -t-", 0); + while (*p) + { + if (*p == '\n') + { + send_to_server ("\012Argumentx ", 0); + ++p; + } + else + { + char *q = strchr (p, '\n'); + if (q == NULL) q = p + strlen (p); + send_to_server (p, q - p); + p = q; + } + } + send_to_server ("\012", 1); + } if (admin_data.quiet) send_arg ("-q"); if (admin_data.kflag != NULL) @@ -598,20 +650,7 @@ admin_fileproc (callerdat, finfo) if (admin_data->desc != NULL) { free (rcs->desc); - rcs->desc = NULL; - if (admin_data->desc[2] == '-') - rcs->desc = xstrdup (admin_data->desc + 3); - else - { - char *descfile = admin_data->desc + 2; - size_t bufsize = 0; - size_t len; - - /* If -t specified with no argument, read from stdin. */ - if (*descfile == '\0') - descfile = NULL; - get_file (descfile, descfile, "r", &rcs->desc, &bufsize, &len); - } + rcs->desc = xstrdup (admin_data->desc); } if (admin_data->kflag != NULL) { @@ -642,6 +681,8 @@ admin_fileproc (callerdat, finfo) if (arg[1] == 'a') for (u = 0; u < argc; ++u) RCS_addaccess (rcs, users[u]); + else if (argc == 0) + RCS_delaccess (rcs, NULL); else for (u = 0; u < argc; ++u) RCS_delaccess (rcs, users[u]); @@ -748,20 +789,24 @@ admin_fileproc (callerdat, finfo) rev = xstrdup (p); } revnum = RCS_gettag (rcs, rev, 0, NULL); - free (rev); if (revnum != NULL) + { n = findnode (rcs->versions, revnum); - if (revnum == NULL || n == NULL) + free (revnum); + } + else + n = NULL; + if (n == NULL) { error (0, 0, "%s: can't set state of nonexisting revision %s", rcs->path, rev); - if (revnum != NULL) - free (revnum); + free (rev); status = 1; continue; } + free (rev); delta = (RCSVers *) n->data; free (delta->state); delta->state = tag; @@ -788,6 +833,7 @@ admin_fileproc (callerdat, finfo) msg = p; n = findnode (rcs->versions, rev); + free (rev); delta = (RCSVers *) n->data; if (delta->text == NULL) { @@ -823,12 +869,7 @@ admin_fileproc (callerdat, finfo) additional message is to make it clear that the previous problems caused CVS to forget about the idea of modifying the RCS file. */ error (0, 0, "cannot modify RCS file for `%s'", finfo->file); - - /* Upon failure, we want to abandon any changes made to the - RCS data structure. Forcing a reparse does the trick, - but leaks memory and is kludgey. Should we export - free_rcsnode_contents for this purpose? */ - RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL); + RCS_abandon (rcs); } exitfunc: diff --git a/contrib/cvs/src/checkout.c b/contrib/cvs/src/checkout.c index a7d942f..1a66b5b 100644 --- a/contrib/cvs/src/checkout.c +++ b/contrib/cvs/src/checkout.c @@ -37,11 +37,10 @@ #include "cvs.h" static char *findslash PROTO((char *start, char *p)); -static int checkout_proc PROTO((int *pargc, char **argv, char *where, +static int checkout_proc PROTO((int argc, char **argv, char *where, char *mwhere, char *mfile, int shorten, int local_specified, char *omodule, char *msg)); -static int safe_location PROTO((void)); static const char *const checkout_usage[] = { @@ -95,6 +94,7 @@ static char *join_rev2 = NULL; static int join_tags_validated = 0; static char *preload_update_dir = NULL; static char *history_name = NULL; +static enum mtype m_type; int checkout (argc, argv) @@ -111,7 +111,6 @@ checkout (argc, argv) char *where = NULL; char *valid_options; const char *const *valid_usage; - enum mtype m_type; /* * A smaller subset of options are allowed for the export command, which @@ -233,7 +232,7 @@ checkout (argc, argv) if (where && pipeout) error (1, 0, "-d and -p are mutually exclusive"); - if (strcmp (command_name, "export") == 0) + if (m_type == EXPORT) { if (!tag && !date) error (1, 0, "must specify a tag or date"); @@ -294,7 +293,7 @@ checkout (argc, argv) send_arg("-A"); if (!shorten) send_arg("-N"); - if (checkout_prune_dirs && strcmp (command_name, "export") != 0) + if (checkout_prune_dirs && m_type == CHECKOUT) send_arg("-P"); client_prune_dirs = checkout_prune_dirs; if (cat) @@ -325,10 +324,7 @@ checkout (argc, argv) client_nonexpanded_setup (); } - send_to_server (strcmp (command_name, "export") == 0 ? - "export\012" : "co\012", - 0); - + send_to_server (m_type == EXPORT ? "export\012" : "co\012", 0); return get_responses_and_close (); } #endif /* CLIENT_SUPPORT */ @@ -355,7 +351,7 @@ checkout (argc, argv) /* If we will be calling history_write, work out the name to pass it. */ - if (strcmp (command_name, "export") != 0 && !pipeout) + if (m_type == CHECKOUT && !pipeout) { if (tag && date) { @@ -379,7 +375,10 @@ checkout (argc, argv) return (err); } -static int +/* FIXME: This is and emptydir_name are in checkout.c for historical + reasons, probably want to move them. */ + +int safe_location () { char *current; @@ -455,7 +454,12 @@ build_one_dir (repository, dirpath, sticky) { FILE *fp; - if (!isfile (CVSADM) && strcmp (command_name, "export") != 0) + if (isfile (CVSADM)) + { + if (m_type == EXPORT) + error (1, 0, "cannot export into a working directory"); + } + else if (m_type == CHECKOUT) { /* I suspect that this check could be omitted. */ if (!isdir (repository)) @@ -471,7 +475,7 @@ build_one_dir (repository, dirpath, sticky) then rewrite it later via WriteTag, once we've had a chance to call RCS_nodeisbranch on each file. */ - 0, 1)) + 0, 1, 1)) return; if (!noexec) @@ -492,9 +496,9 @@ build_one_dir (repository, dirpath, sticky) */ /* ARGSUSED */ static int -checkout_proc (pargc, argv, where_orig, mwhere, mfile, shorten, +checkout_proc (argc, argv, where_orig, mwhere, mfile, shorten, local_specified, omodule, msg) - int *pargc; + int argc; char **argv; char *where_orig; char *mwhere; @@ -504,6 +508,7 @@ checkout_proc (pargc, argv, where_orig, mwhere, mfile, shorten, char *omodule; char *msg; { + char *myargv[2]; int err = 0; int which; char *cp; @@ -665,26 +670,10 @@ checkout_proc (pargc, argv, where_orig, mwhere, mfile, shorten, { /* It's a file, which means we have to screw around with argv. */ - - int i; - - - /* Paranoia check. */ - - if (*pargc > 1) - { - error (0, 0, "checkout_proc: trashing argv elements!"); - for (i = 1; i < *pargc; i++) - { - error (0, 0, "checkout_proc: argv[%d] `%s'", - i, argv[i]); - } - } - - for (i = 1; i < *pargc; i++) - free (argv[i]); - argv[1] = xstrdup (mfile); - (*pargc) = 2; + myargv[0] = argv[0]; + myargv[1] = mfile; + argc = 2; + argv = myargv; } free (path); } @@ -745,7 +734,7 @@ internal error: %s doesn't start with %s in checkout_proc", NT, &c, if the user specifies '\'. Likewise for the call to findslash. */ cp = where + strlen (where); - while (1) + while (cp > where) { struct dir_to_build *new; @@ -761,7 +750,7 @@ internal error: %s doesn't start with %s in checkout_proc", last path element we create should be the top-level directory. */ - if (cp - where) + if (cp > where) { strncpy (new->dirpath, where, cp - where); new->dirpath[cp - where] = '\0'; @@ -769,7 +758,7 @@ internal error: %s doesn't start with %s in checkout_proc", else { /* where should always be at least one character long. */ - assert (strlen (where)); + assert (where[0] != '\0'); strcpy (new->dirpath, "/"); } new->next = head; @@ -841,10 +830,11 @@ internal error: %s doesn't start with %s in checkout_proc", { /* It's a directory in the repository! */ - char *rp = strrchr (reposcopy, '/'); + char *rp; /* We'll always be below CVSROOT, but check for paranoia's sake. */ + rp = strrchr (reposcopy, '/'); if (rp == NULL) error (1, 0, "internal error: %s doesn't contain a slash", @@ -890,7 +880,7 @@ internal error: %s doesn't start with %s in checkout_proc", { /* It may be argued that we shouldn't set any sticky bits for the top-level repository. FIXME? */ - build_one_dir (CVSroot_directory, ".", *pargc <= 1); + build_one_dir (CVSroot_directory, ".", argc <= 1); #ifdef SERVER_SUPPORT /* We _always_ want to have a top-level admin @@ -912,7 +902,7 @@ internal error: %s doesn't start with %s in checkout_proc", contain a CVS subdir yet, but all the others contain CVS and Entries.Static files */ - if (build_dirs_and_chdir (head, *pargc <= 1) != 0) + if (build_dirs_and_chdir (head, argc <= 1) != 0) { error (0, 0, "ignoring module %s", omodule); err = 1; @@ -925,14 +915,15 @@ internal error: %s doesn't start with %s in checkout_proc", { FILE *fp; - if (!noexec && *pargc > 1) + if (!noexec && argc > 1) { /* I'm not sure whether this check is redundant. */ if (!isdir (repository)) error (1, 0, "there is no repository %s", repository); Create_Admin (".", preload_update_dir, repository, - (char *) NULL, (char *) NULL, 0, 0); + (char *) NULL, (char *) NULL, 0, 0, + m_type == CHECKOUT); fp = open_file (CVSADM_ENTSTAT, "w+"); if (fclose(fp) == EOF) error(1, errno, "cannot close %s", CVSADM_ENTSTAT); @@ -955,13 +946,16 @@ internal error: %s doesn't start with %s in checkout_proc", then rewrite it later via WriteTag, once we've had a chance to call RCS_nodeisbranch on each file. */ - 0, 0); + 0, 0, m_type == CHECKOUT); } } else { char *repos; + if (m_type == EXPORT) + error (1, 0, "cannot export into working directory"); + /* get the contents of the previously existing repository */ repos = Name_Repository ((char *) NULL, preload_update_dir); if (fncmp (repository, repos) != 0) @@ -993,7 +987,7 @@ internal error: %s doesn't start with %s in checkout_proc", which = W_REPOS; if (tag != NULL && !tag_validated) { - tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, NULL); + tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, NULL); tag_validated = 1; } } @@ -1002,7 +996,7 @@ internal error: %s doesn't start with %s in checkout_proc", which = W_LOCAL | W_REPOS; if (tag != NULL && !tag_validated) { - tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, + tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, repository); tag_validated = 1; } @@ -1014,10 +1008,10 @@ internal error: %s doesn't start with %s in checkout_proc", if (! join_tags_validated) { if (join_rev1 != NULL) - tag_check_valid_join (join_rev1, *pargc - 1, argv + 1, 0, aflag, + tag_check_valid_join (join_rev1, argc - 1, argv + 1, 0, aflag, repository); if (join_rev2 != NULL) - tag_check_valid_join (join_rev2, *pargc - 1, argv + 1, 0, aflag, + tag_check_valid_join (join_rev2, argc - 1, argv + 1, 0, aflag, repository); join_tags_validated = 1; } @@ -1027,12 +1021,12 @@ internal error: %s doesn't start with %s in checkout_proc", * update recursion processor. We will be recursive unless either local * only was specified, or we were passed arguments */ - if (!(local_specified || *pargc > 1)) + if (!(local_specified || argc > 1)) { - if (strcmp (command_name, "export") != 0 && !pipeout) + if (m_type == CHECKOUT && !pipeout) history_write ('O', preload_update_dir, history_name, where, repository); - else if (strcmp (command_name, "export") == 0 && !pipeout) + else if (m_type == EXPORT && !pipeout) history_write ('E', preload_update_dir, tag ? tag : date, where, repository); err += do_update (0, (char **) NULL, options, tag, date, @@ -1050,7 +1044,7 @@ internal error: %s doesn't start with %s in checkout_proc", /* we are only doing files, so register them */ entries = Entries_Open (0, NULL); - for (i = 1; i < *pargc; i++) + for (i = 1; i < argc; i++) { char *line; Vers_TS *vers; @@ -1087,12 +1081,12 @@ internal error: %s doesn't start with %s in checkout_proc", } /* Don't log "export", just regular "checkouts" */ - if (strcmp (command_name, "export") != 0 && !pipeout) + if (m_type == CHECKOUT && !pipeout) history_write ('O', preload_update_dir, history_name, where, repository); /* go ahead and call update now that everything is set */ - err += do_update (*pargc - 1, argv + 1, options, tag, date, + err += do_update (argc - 1, argv + 1, options, tag, date, force_tag_match, local_specified, 1 /* update -d */, aflag, checkout_prune_dirs, pipeout, which, join_rev1, join_rev2, preload_update_dir); @@ -1109,15 +1103,13 @@ findslash (start, p) char *start; char *p; { - while (p >= start && *p != '/') - p--; - /* FIXME: indexing off the start of the array like this is *NOT* - OK according to ANSI, and will break some of the time on certain - segmented architectures. */ - if (p < start) - return (NULL); - else - return (p); + for (;;) + { + if (*p == '/') return p; + if (p == start) break; + --p; + } + return NULL; } /* Return a newly malloc'd string containing a pathname for CVSNULLREPOS, @@ -1185,5 +1177,14 @@ build_dirs_and_chdir (dirs, sticky) } out: + while (dirs != NULL) + { + if (dirs->repository != NULL) + free (dirs->repository); + nextdir = dirs->next; + free (dirs->dirpath); + free (dirs); + dirs = nextdir; + } return retval; } diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c index 748132a..c451b28 100644 --- a/contrib/cvs/src/client.c +++ b/contrib/cvs/src/client.c @@ -1,3 +1,5 @@ +/* JT thinks BeOS is worth the trouble. */ + /* CVS client-related stuff. This program is free software; you can redistribute it and/or modify @@ -60,7 +62,6 @@ extern char *strerror (); #if HAVE_KERBEROS #define CVS_PORT 1999 -#if HAVE_KERBEROS #include extern char *krb_realmofhost (); @@ -74,8 +75,6 @@ static Key_schedule sched; #endif /* HAVE_KERBEROS */ -#endif /* HAVE_KERBEROS */ - #ifdef HAVE_GSSAPI #ifdef HAVE_GSSAPI_H @@ -1115,7 +1114,7 @@ call_in_directory (pathname, func, data) strcpy (r, "/."); Create_Admin (".", ".", repo, (char *) NULL, - (char *) NULL, 0, 1); + (char *) NULL, 0, 1, 1); free (repo); } @@ -1252,7 +1251,7 @@ warning: server is not creating directories one at a time"); strcpy (r, reposdirname); Create_Admin (dir, dir, repo, - (char *)NULL, (char *)NULL, 0, 0); + (char *)NULL, (char *)NULL, 0, 0, 1); free (repo); b = strrchr (dir, '/'); @@ -1760,6 +1759,7 @@ update_entries (data_arg, ent_list, short_pathname, filename) } free (mode_string); + free (scratch_entries); free (entries_line); /* The Mode, Mod-time, and Checksum responses should not carry @@ -1847,7 +1847,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (use_gzip) { - if (gunzip_and_write (fd, short_pathname, buf, size)) + if (gunzip_and_write (fd, short_pathname, + (unsigned char *) buf, size)) error (1, 0, "aborting due to compression error"); } else if (write (fd, buf, size) != size) @@ -2025,6 +2026,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) free (mode_string); free (buf); + free (scratch_entries); + free (entries_line); return; } @@ -2123,8 +2126,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (file_timestamp) free (file_timestamp); - free (scratch_entries); } + free (scratch_entries); free (entries_line); } @@ -2490,7 +2493,11 @@ handle_set_checkin_prog (args, len) { char *prog; struct save_prog *p; + read_line (&prog); + if (strcmp (command_name, "export") == 0) + return; + p = (struct save_prog *) xmalloc (sizeof (struct save_prog)); p->next = checkin_progs; p->dir = xstrdup (args); @@ -2505,7 +2512,11 @@ handle_set_update_prog (args, len) { char *prog; struct save_prog *p; + read_line (&prog); + if (strcmp (command_name, "export") == 0) + return; + p = (struct save_prog *) xmalloc (sizeof (struct save_prog)); p->next = update_progs; p->dir = xstrdup (args); @@ -2683,7 +2694,7 @@ send_repository (dir, repos, update_dir) { Node *n; n = getnode (); - n->type = UNKNOWN; + n->type = NT_UNKNOWN; n->key = xstrdup (update_dir); n->data = NULL; @@ -3594,19 +3605,15 @@ get_responses_and_close () && waitpid (rsh_pid, (int *) 0, 0) == -1) error (1, errno, "waiting for process %d", rsh_pid); + buf_free (to_server); + buf_free (from_server); server_started = 0; - /* see if we need to sleep before returning */ + /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - time_t now; - - for (;;) - { - (void) time (&now); - if (now != last_register_time) break; - sleep (1); /* to avoid time-stamp races */ - } + while (time ((time_t *) NULL) == last_register_time) + sleep (1); } return errs; @@ -3774,6 +3781,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) int port_number; struct sockaddr_in client_sai; struct hostent *hostinfo; + char no_passwd = 0; /* gets set if no password found */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock == -1) @@ -3818,6 +3826,14 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) /* Get the password, probably from ~/.cvspass. */ password = get_cvs_password (); + + /* Send the empty string by default. This is so anonymous CVS + access doesn't require client to have done "cvs login". */ + if (password == NULL) + { + no_passwd = 1; + password = scramble (""); + } /* Announce that we're starting the authorization protocol. */ if (send (sock, begin, strlen (begin), 0) < 0) @@ -3841,8 +3857,8 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) if (send (sock, end, strlen (end), 0) < 0) error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); - /* Paranoia. */ - memset (password, 0, strlen (password)); + /* Paranoia. */ + memset (password, 0, strlen (password)); } { @@ -3935,20 +3951,28 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) return; rejected: + error (0, 0, + "authorization failed: server %s rejected access to %s for user %s", + CVSroot_hostname, CVSroot_directory, CVSroot_username); + + /* Output a special error message if authentication was attempted + with no password -- the user should be made aware that they may + have missed a step. */ + if (no_passwd) + { + error (0, 0, + "used empty password; try \"cvs login\" with a real password"); + } + if (shutdown (sock, 2) < 0) { - error (0, 0, - "authorization failed: server %s rejected access", - CVSroot_hostname); - error (1, 0, + error (0, 0, "shutdown() failed (server %s): %s", CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); } - error (1, 0, - "authorization failed: server %s rejected access", - CVSroot_hostname); + error_exit(); } #endif /* AUTH_CLIENT_SUPPORT */ @@ -4111,9 +4135,16 @@ connect_to_gserver (sock, hostinfo) if (stat_maj != GSS_S_COMPLETE && stat_maj != GSS_S_CONTINUE_NEEDED) { OM_uint32 message_context; + OM_uint32 new_stat_min; + + message_context = 0; + gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE, + GSS_C_NULL_OID, &message_context, &tok_out); + error (0, 0, "GSSAPI authentication failed: %s", + (char *) tok_out.value); message_context = 0; - gss_display_status (&stat_min, stat_maj, GSS_C_GSS_CODE, + gss_display_status (&new_stat_min, stat_min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &message_context, &tok_out); error (1, 0, "GSSAPI authentication failed: %s", (char *) tok_out.value); @@ -4137,7 +4168,29 @@ connect_to_gserver (sock, hostinfo) recv_bytes (sock, cbuf, 2); need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff); - assert (need <= sizeof buf); + + if (need > sizeof buf) + { + int got; + + /* This usually means that the server sent us an error + message. Read it byte by byte and print it out. + FIXME: This is a terrible error handling strategy. + However, even if we fix the server, we will still + want to do this to work with older servers. */ + buf[0] = cbuf[0]; + buf[1] = cbuf[1]; + got = recv (sock, buf + 2, sizeof buf - 2, 0); + if (got < 0) + error (1, 0, "recv() from server %s: %s", + CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); + buf[got + 2] = '\0'; + if (buf[got + 1] == '\n') + buf[got + 1] = '\0'; + error (1, 0, "error from server %s: %s", CVSroot_hostname, + buf); + } + recv_bytes (sock, buf, need); tok_in.length = need; } @@ -4171,7 +4224,7 @@ send_variable_proc (node, closure) void start_server () { - int tofd, fromfd; + int tofd, fromfd, rootless; char *log = getenv ("CVS_CLIENT_LOG"); @@ -4350,7 +4403,8 @@ the :server: access method is not supported by this port of CVS"); stored_mode = NULL; } - if (strcmp (command_name, "init") != 0) + rootless = (strcmp (command_name, "init") == 0); + if (!rootless) { send_to_server ("Root ", 0); send_to_server (CVSroot_directory, 0); @@ -4474,7 +4528,7 @@ the :server: access method is not supported by this port of CVS"); } } - if (cvsencrypt) + if (cvsencrypt && !rootless) { #ifdef ENCRYPTION /* Turn on encryption before turning on compression. We do @@ -4521,7 +4575,7 @@ the :server: access method is not supported by this port of CVS"); #endif /* ! ENCRYPTION */ } - if (gzip_level) + if (gzip_level && !rootless) { if (supported_request ("Gzip-stream")) { @@ -4563,7 +4617,7 @@ the :server: access method is not supported by this port of CVS"); } } - if (cvsauthenticate && ! cvsencrypt) + if (cvsauthenticate && ! cvsencrypt && !rootless) { /* Turn on authentication after turning on compression, so that we can compress the authentication information. We @@ -4594,7 +4648,7 @@ the :server: access method is not supported by this port of CVS"); } #ifdef FILENAMES_CASE_INSENSITIVE - if (supported_request ("Case")) + if (supported_request ("Case") && !rootless) send_to_server ("Case\012", 0); #endif @@ -4964,6 +5018,7 @@ struct send_data int build_dirs; int force; int no_contents; + int backup_modified; }; static int send_fileproc PROTO ((void *callerdat, struct file_info *finfo)); @@ -5085,6 +5140,18 @@ warning: ignoring -k options due to server limitations"); } else send_modified (filename, finfo->fullname, vers); + + if (args->backup_modified) + { + char *bakname; + bakname = backup_file (filename, vers->vn_user); + /* This behavior is sufficiently unexpected to + justify overinformativeness, I think. */ + if (! really_quiet) + printf ("(Locally modified %s moved to %s)\n", + filename, bakname); + free (bakname); + } } else { @@ -5193,9 +5260,6 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) dir_exists = isdir (cvsadm_name); free (cvsadm_name); - /* initialize the ignore list for this directory */ - ignlist = getlist (); - /* * If there is an empty directory (e.g. we are doing `cvs add' on a * newly-created directory), the server still needs to know about it. @@ -5211,6 +5275,9 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) char *repos = Name_Repository (dir, update_dir); send_a_repository (dir, repos, update_dir); free (repos); + + /* initialize the ignore list for this directory */ + ignlist = getlist (); } else { @@ -5235,6 +5302,29 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) return (dir_exists ? R_PROCESS : R_SKIP_ALL); } +static int send_dirleave_proc PROTO ((void *, char *, int, char *, List *)); + +/* + * send_dirleave_proc () is called back by the recursion code upon leaving + * a directory. All it does is delete the ignore list if it hasn't already + * been done (by send_filesdone_proc). + */ +/* ARGSUSED */ +static int +send_dirleave_proc (callerdat, dir, err, update_dir, entries) + void *callerdat; + char *dir; + int err; + char *update_dir; + List *entries; +{ + + /* Delete the ignore list if it hasn't already been done. */ + if (ignlist) + dellist (&ignlist); + return err; +} + /* * Send each option in a string to the server, one by one. * This assumes that the options are separated by spaces, for example @@ -5426,9 +5516,10 @@ send_files (argc, argv, local, aflag, flags) args.build_dirs = flags & SEND_BUILD_DIRS; args.force = flags & SEND_FORCE; args.no_contents = flags & SEND_NO_CONTENTS; + args.backup_modified = flags & BACKUP_MODIFIED_FILES; err = start_recursion (send_fileproc, send_filesdoneproc, - send_dirent_proc, (DIRLEAVEPROC)NULL, (void *) &args, + send_dirent_proc, send_dirleave_proc, (void *) &args, argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0); if (err) error_exit (); diff --git a/contrib/cvs/src/client.h b/contrib/cvs/src/client.h index c323cf3..b4d404a 100644 --- a/contrib/cvs/src/client.h +++ b/contrib/cvs/src/client.h @@ -109,6 +109,7 @@ send_files PROTO((int argc, char **argv, int local, int aflag, #define SEND_BUILD_DIRS 1 #define SEND_FORCE 2 #define SEND_NO_CONTENTS 4 +#define BACKUP_MODIFIED_FILES 8 /* Send an argument to the remote server. */ void diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c index c4cbd24..1c1f71c 100644 --- a/contrib/cvs/src/commit.c +++ b/contrib/cvs/src/commit.c @@ -263,6 +263,7 @@ find_fileproc (callerdat, finfo) else error (0, 0, "use `%s add' to create an entry for %s", program_name, finfo->fullname); + freevers_ts (&vers); return 1; } else if (vers->ts_user != NULL @@ -284,6 +285,7 @@ find_fileproc (callerdat, finfo) cases. FIXME: we probably should be printing a message and returning 1 for many of those cases (but I'm not sure exactly which ones). */ + freevers_ts (&vers); return 0; } @@ -421,28 +423,12 @@ commit (argc, argv) /* some checks related to the "-F logfile" option */ if (logfile) { - int n, logfd; - struct stat statbuf; + size_t size = 0, len; if (saved_message) error (1, 0, "cannot specify both a message and a log file"); - /* FIXME: Why is this binary? Needs more investigation. */ - if ((logfd = CVS_OPEN (logfile, O_RDONLY | OPEN_BINARY)) < 0) - error (1, errno, "cannot open log file %s", logfile); - - if (fstat(logfd, &statbuf) < 0) - error (1, errno, "cannot find size of log file %s", logfile); - - saved_message = xmalloc (statbuf.st_size + 1); - - /* FIXME: Should keep reading until EOF, rather than assuming the - first read gets the whole thing. */ - if ((n = read (logfd, saved_message, statbuf.st_size + 1)) < 0) - error (1, errno, "cannot read log message from %s", logfile); - - (void) close (logfd); - saved_message[n] = '\0'; + get_file (logfile, logfile, "r", &saved_message, &size, &len); } #ifdef CLIENT_SUPPORT @@ -473,11 +459,14 @@ commit (argc, argv) error (1, 0, "correct above errors first!"); if (find_args.argc == 0) + { /* Nothing to commit. Exit now without contacting the server (note that this means that we won't print "? foo" for files which merit it, because we don't know what is in the CVSROOT/cvsignore file). */ + dellist (&find_args.ulist); return 0; + } /* Now we keep track of which files we actually are going to operate on, and only work with those files in the future. @@ -583,6 +572,8 @@ commit (argc, argv) previous versions of client/server CVS, but it probably is a Good Thing, or at least Not Such A Bad Thing. */ send_file_names (find_args.argc, find_args.argv, 0); + free (find_args.argv); + dellist (&find_args.ulist); send_to_server ("ci\012", 0); err = get_responses_and_close (); @@ -672,16 +663,11 @@ commit (argc, argv) Lock_Cleanup (); dellist (&mulist); + /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - time_t now; - - for (;;) - { - (void) time (&now); - if (now != last_register_time) break; - sleep (1); /* to avoid time-stamp races */ - } + while (time ((time_t *) NULL) == last_register_time) + sleep (1); } return (err); @@ -794,6 +780,12 @@ check_fileproc (callerdat, finfo) size_t cvsroot_len = strlen (CVSroot_directory); + if (!finfo->repository) + { + error (0, 0, "nothing known about `%s'", finfo->fullname); + return (1); + } + if (strncmp (finfo->repository, CVSroot_directory, cvsroot_len) == 0 && ISDIRSEP (finfo->repository[cvsroot_len]) && strncmp (finfo->repository + cvsroot_len + 1, @@ -1290,6 +1282,8 @@ commit_fileproc (callerdat, finfo) { if (finfo->rcs == NULL) error (1, 0, "internal error: no parsed RCS file"); + if (ci->rev) + free (ci->rev); ci->rev = RCS_whatbranch (finfo->rcs, ci->tag); err = Checkin ('A', finfo, finfo->rcs->path, ci->rev, ci->tag, ci->options, saved_message); @@ -1400,6 +1394,8 @@ out: } } } + if (SIG_inCrSect ()) + SIG_endCrSect (); return (err); } @@ -1500,6 +1496,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries) cvs_output (": Executing '", 0); run_print (stdout); cvs_output ("'\n", 0); + cvs_flushout (); (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); free (repos); } @@ -1582,8 +1579,10 @@ commit_dirleaveproc (callerdat, dir, err, update_dir, entries) this being a confusing feature! */ if (err == 0 && write_dirtag != NULL) { + char *repos = Name_Repository (dir, update_dir); WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch, - update_dir, Name_Repository (dir, update_dir)); + update_dir, repos); + free (repos); } return (err); @@ -1751,6 +1750,9 @@ remove_file (finfo, tag, message) "failed to commit dead revision for `%s'", finfo->fullname); return (1); } + /* At this point, the file has been committed as removed. We should + probably tell the history file about it */ + history_write ('R', NULL, finfo->rcs->head, finfo->file, finfo->repository); if (rev != NULL) free (rev); @@ -1962,6 +1964,11 @@ checkaddfile (file, repository, tag, options, rcsnode) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT); + /* Begin a critical section around the code that spans the + first commit on the trunk of a file that's already been + committed on a branch. */ + SIG_beginCrSect (); + if (RCS_setattic (rcsfile, 0)) { retval = 1; @@ -2044,74 +2051,76 @@ checkaddfile (file, repository, tag, options, rcsnode) newfile = 1; if (desc != NULL) free (desc); + if (rcsnode != NULL) + { + assert (*rcsnode == NULL); + *rcsnode = rcsfile; + } } /* when adding a file for the first time, and using a tag, we need to create a dead revision on the trunk. */ - if (adding_on_branch && newfile) + if (adding_on_branch) { - char *tmp; - FILE *fp; - - /* move the new file out of the way. */ - fname = xmalloc (strlen (file) + sizeof (CVSADM) - + sizeof (CVSPREFIX) + 10); - (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file); - rename_file (file, fname); - - /* Create empty FILE. Can't use copy_file with a DEVNULL - argument -- copy_file now ignores device files. */ - fp = fopen (file, "w"); - if (fp == NULL) - error (1, errno, "cannot open %s for writing", file); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", file); - - tmp = xmalloc (strlen (file) + strlen (tag) + 80); - /* commit a dead revision. */ - (void) sprintf (tmp, "file %s was initially added on branch %s.", - file, tag); - retcode = RCS_checkin (rcsfile, NULL, tmp, NULL, - RCS_FLAGS_DEAD | RCS_FLAGS_QUIET); - free (tmp); - if (retcode != 0) + if (newfile) { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not create initial dead revision %s", rcs); - retval = 1; - goto out; - } + char *tmp; + FILE *fp; - /* put the new file back where it was */ - rename_file (fname, file); - free (fname); + /* move the new file out of the way. */ + fname = xmalloc (strlen (file) + sizeof (CVSADM) + + sizeof (CVSPREFIX) + 10); + (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file); + rename_file (file, fname); - /* double-check that the file was written correctly */ - freercsnode (&rcsfile); - rcsfile = RCS_parse (file, repository); - if (rcsfile == NULL) - { - error (0, 0, "could not read %s", rcs); - retval = 1; - goto out; - } - if (rcsnode != NULL) - { - assert (*rcsnode == NULL); - *rcsnode = rcsfile; - } + /* Create empty FILE. Can't use copy_file with a DEVNULL + argument -- copy_file now ignores device files. */ + fp = fopen (file, "w"); + if (fp == NULL) + error (1, errno, "cannot open %s for writing", file); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", file); + + tmp = xmalloc (strlen (file) + strlen (tag) + 80); + /* commit a dead revision. */ + (void) sprintf (tmp, "file %s was initially added on branch %s.", + file, tag); + retcode = RCS_checkin (rcsfile, NULL, tmp, NULL, + RCS_FLAGS_DEAD | RCS_FLAGS_QUIET); + free (tmp); + if (retcode != 0) + { + error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, + "could not create initial dead revision %s", rcs); + retval = 1; + goto out; + } - /* and lock it once again. */ - if (lock_RCS (file, rcsfile, NULL, repository)) - { - error (0, 0, "cannot lock `%s'.", rcs); - retval = 1; - goto out; + /* put the new file back where it was */ + rename_file (fname, file); + free (fname); + + /* double-check that the file was written correctly */ + freercsnode (&rcsfile); + rcsfile = RCS_parse (file, repository); + if (rcsfile == NULL) + { + error (0, 0, "could not read %s", rcs); + retval = 1; + goto out; + } + if (rcsnode != NULL) + *rcsnode = rcsfile; + + /* and lock it once again. */ + if (lock_RCS (file, rcsfile, NULL, repository)) + { + error (0, 0, "cannot lock `%s'.", rcs); + retval = 1; + goto out; + } } - } - if (adding_on_branch) - { /* when adding with a tag, we need to stub a branch, if it doesn't already exist. */ @@ -2194,6 +2203,8 @@ checkaddfile (file, repository, tag, options, rcsnode) retval = 0; out: + if (retval != 0 && SIG_inCrSect ()) + SIG_endCrSect (); free (rcs); return retval; } diff --git a/contrib/cvs/src/create_adm.c b/contrib/cvs/src/create_adm.c index 7f8f581..878b058 100644 --- a/contrib/cvs/src/create_adm.c +++ b/contrib/cvs/src/create_adm.c @@ -22,7 +22,8 @@ don't print warnings; all errors are fatal then. */ int -Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn) +Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn, + dotemplate) char *dir; char *update_dir; char *repository; @@ -30,6 +31,7 @@ Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn) char *date; int nonbranch; int warn; + int dotemplate; { FILE *fout; char *cp; @@ -168,7 +170,7 @@ Create_Admin (dir, update_dir, repository, tag, date, nonbranch, warn) WriteTag (dir, tag, date, nonbranch, update_dir, repository); #ifdef SERVER_SUPPORT - if (server_active) + if (server_active && dotemplate) { server_template (update_dir, repository); } diff --git a/contrib/cvs/src/cvs.h b/contrib/cvs/src/cvs.h index 8a1501c..0277c86 100644 --- a/contrib/cvs/src/cvs.h +++ b/contrib/cvs/src/cvs.h @@ -390,6 +390,7 @@ extern List *root_directories; extern char *current_root; extern char *emptydir_name PROTO ((void)); +extern int safe_location PROTO ((void)); extern int trace; /* Show all commands */ extern int noexec; /* Don't modify disk anywhere */ @@ -499,7 +500,7 @@ void *valloc PROTO((size_t bytes)); time_t get_date PROTO((char *date, struct timeb *now)); extern int Create_Admin PROTO ((char *dir, char *update_dir, char *repository, char *tag, char *date, - int nonbranch, int warn)); + int nonbranch, int warn, int dotemplate)); extern int expand_at_signs PROTO ((char *, off_t, FILE *)); /* Locking subsystem (implemented in lock.c). */ @@ -525,7 +526,7 @@ void cat_module PROTO((int status)); void check_entries PROTO((char *dir)); void close_module PROTO((DBM * db)); void copy_file PROTO((const char *from, const char *to)); -void fperror PROTO((FILE * fp, int status, int errnum, char *message,...)); +void fperrmsg PROTO((FILE * fp, int status, int errnum, char *message,...)); void free_names PROTO((int *pargc, char *argv[])); extern int ign_name PROTO ((char *name)); @@ -546,6 +547,7 @@ void make_directories PROTO((const char *name)); void make_directory PROTO((const char *name)); extern int mkdir_if_needed PROTO ((char *name)); void rename_file PROTO((const char *from, const char *to)); +char *backup_file PROTO((const char *file, const char *suffix)); /* Expand wildcards in each element of (ARGC,ARGV). This is according to the files which exist in the current directory, and accordingly to OS-specific conventions regarding wildcard syntax. It might be desirable to change the @@ -577,7 +579,7 @@ void do_editor PROTO((char *dir, char **messagep, void do_verify PROTO((char *message, char *repository)); -typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where, +typedef int (*CALLBACKPROC) PROTO((int argc, char *argv[], char *where, char *mwhere, char *mfile, int shorten, int local_specified, char *omodule, char *msg)); @@ -636,6 +638,7 @@ int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc, int dosrcs)); void SIG_beginCrSect PROTO((void)); void SIG_endCrSect PROTO((void)); +int SIG_inCrSect PROTO((void)); void read_cvsrc PROTO((int *argc, char ***argv, char *cmdname)); char *make_message_rcslegal PROTO((char *message)); @@ -853,6 +856,7 @@ extern int cvsremove PROTO((int argc, char **argv)); extern int rtag PROTO((int argc, char **argv)); extern int cvsstatus PROTO((int argc, char **argv)); extern int cvstag PROTO((int argc, char **argv)); +extern int version PROTO((int argc, char **argv)); extern unsigned long int lookup_command_attribute PROTO((char *)); @@ -869,6 +873,8 @@ extern void tag_check_valid PROTO ((char *, int, char **, int, int, char *)); extern void tag_check_valid_join PROTO ((char *, int, char **, int, int, char *)); +#include "server.h" + /* From server.c and documented there. */ extern void cvs_output PROTO ((const char *, size_t)); extern void cvs_output_binary PROTO ((char *, size_t)); @@ -876,7 +882,3 @@ extern void cvs_outerr PROTO ((const char *, size_t)); extern void cvs_flusherr PROTO ((void)); extern void cvs_flushout PROTO ((void)); extern void cvs_output_tagged PROTO ((char *, char *)); - -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) -#include "server.h" -#endif diff --git a/contrib/cvs/src/edit.c b/contrib/cvs/src/edit.c index 59d363c..df649b6 100644 --- a/contrib/cvs/src/edit.c +++ b/contrib/cvs/src/edit.c @@ -427,6 +427,15 @@ edit (argc, argv) setting_tcommit = 1; } + if (strpbrk (hostname, "+,>;=\t\n") != NULL) + error (1, 0, + "host name (%s) contains an invalid character (+,>;=\\t\\n)", + hostname); + if (strpbrk (CurDir, "+,>;=\t\n") != NULL) + error (1, 0, +"current directory (%s) contains an invalid character (+,>;=\\t\\n)", + CurDir); + /* No need to readlock since we aren't doing anything to the repository. */ err = start_recursion (edit_fileproc, (FILESDONEPROC) NULL, @@ -553,6 +562,15 @@ unedit_fileproc (callerdat, finfo) return 0; } +static const char *const unedit_usage[] = +{ + "Usage: %s %s [-lR] [files...]\n", + "-l: Local directory only, not recursive\n", + "-R: Process directories recursively\n", + "(Specify the --help global option for a list of other help options)\n", + NULL +}; + int unedit (argc, argv) int argc; @@ -563,7 +581,7 @@ unedit (argc, argv) int err; if (argc == -1) - usage (edit_usage); + usage (unedit_usage); optind = 0; while ((c = getopt (argc, argv, "+lR")) != -1) @@ -578,7 +596,7 @@ unedit (argc, argv) break; case '?': default: - usage (edit_usage); + usage (unedit_usage); break; } } @@ -1060,6 +1078,7 @@ editors_fileproc (callerdat, finfo) cvs_output ("\n", 1); } out:; + free (them); return 0; } diff --git a/contrib/cvs/src/entries.c b/contrib/cvs/src/entries.c index 7e258a9..14163bb 100644 --- a/contrib/cvs/src/entries.c +++ b/contrib/cvs/src/entries.c @@ -807,7 +807,8 @@ Subdirs_Known (entries) if (!noexec) { /* Create Entries.Log so that Entries_Close will do something. */ - fp = CVS_FOPEN (CVSADM_ENTLOG, "a"); + entfilename = CVSADM_ENTLOG; + fp = CVS_FOPEN (entfilename, "a"); if (fp == NULL) { int save_errno = errno; @@ -821,7 +822,7 @@ Subdirs_Known (entries) else { if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", CVSADM_ENTLOG); + error (1, errno, "cannot close %s", entfilename); } } } diff --git a/contrib/cvs/src/error.c b/contrib/cvs/src/error.c index 64b686c..fe5877f 100644 --- a/contrib/cvs/src/error.c +++ b/contrib/cvs/src/error.c @@ -64,7 +64,8 @@ extern char *strerror (); void error_exit PROTO ((void)) { - Lock_Cleanup(); + rcs_cleanup (); + Lock_Cleanup (); #ifdef SERVER_SUPPORT if (server_active) server_cleanup (0); @@ -122,7 +123,7 @@ error (status, errnum, message, va_alist) int num; unsigned int unum; int ch; - unsigned char buf[100]; + char buf[100]; cvs_outerr (program_name, 0); if (command_name && *command_name) @@ -201,9 +202,9 @@ error (status, errnum, message, va_alist) /* VARARGS */ void #if defined (HAVE_VPRINTF) && defined (__STDC__) -fperror (FILE *fp, int status, int errnum, char *message, ...) +fperrmsg (FILE *fp, int status, int errnum, char *message, ...) #else -fperror (fp, status, errnum, message, va_alist) +fperrmsg (fp, status, errnum, message, va_alist) FILE *fp; int status; int errnum; diff --git a/contrib/cvs/src/fileattr.c b/contrib/cvs/src/fileattr.c index 4042d2a..bae03a6 100644 --- a/contrib/cvs/src/fileattr.c +++ b/contrib/cvs/src/fileattr.c @@ -126,7 +126,7 @@ fileattr_read () any line other than the first for that filename. This is the way that CVS has behaved since file attributes were first introduced. */ - free (newnode); + freenode (newnode); } else if (line[0] == 'D') { @@ -513,6 +513,7 @@ fileattr_write () FILE *fp; char *fname; mode_t omask; + struct unrecog *p; if (!attrs_modified) return; @@ -616,17 +617,10 @@ fileattr_write () } /* Then any other attributes. */ - while (unrecog_head != NULL) + for (p = unrecog_head; p != NULL; p = p->next) { - struct unrecog *p; - - p = unrecog_head; fputs (p->line, fp); fputs ("\012", fp); - - unrecog_head = p->next; - free (p->line); - free (p); } if (fclose (fp) < 0) @@ -649,4 +643,11 @@ fileattr_free () if (fileattr_default_attrs != NULL) free (fileattr_default_attrs); fileattr_default_attrs = NULL; + while (unrecog_head) + { + struct unrecog *p = unrecog_head; + unrecog_head = p->next; + free (p->line); + free (p); + } } diff --git a/contrib/cvs/src/filesubr.c b/contrib/cvs/src/filesubr.c index f3da62a..3a800a9 100644 --- a/contrib/cvs/src/filesubr.c +++ b/contrib/cvs/src/filesubr.c @@ -51,9 +51,13 @@ copy_file (from, to) if (isdevice (from)) { +#if defined(HAVE_MKNOD) && defined(HAVE_ST_RDEV) if (stat (from, &sb) < 0) error (1, errno, "cannot stat %s", from); mknod (to, sb.st_mode, sb.st_rdev); +#else + error (1, 0, "cannot copy device files on this system (%s)", from); +#endif } else { @@ -620,10 +624,15 @@ xcmp (file1, file2) numbers match. */ if (S_ISBLK (sb1.st_mode) || S_ISCHR (sb1.st_mode)) { +#ifdef HAVE_ST_RDEV if (sb1.st_rdev == sb2.st_rdev) return 0; else return 1; +#else + error (1, 0, "cannot compare device files on this system (%s and %s)", + file1, file2); +#endif } if ((fd1 = open (file1, O_RDONLY)) < 0) diff --git a/contrib/cvs/src/hardlink.c b/contrib/cvs/src/hardlink.c index 046cf3a..309d27f 100644 --- a/contrib/cvs/src/hardlink.c +++ b/contrib/cvs/src/hardlink.c @@ -63,7 +63,7 @@ lookup_file_by_inode (filepath) /* inodestr contains the hexadecimal representation of an inode, so it requires two bytes of text to represent each byte of the inode number. */ - inodestr = (char *) xmalloc (2*sizeof(ino_t)*sizeof(char) + 1); + inodestr = (char *) xmalloc (2*sizeof(ino_t) + 1); if (stat (file, &sb) < 0) { if (existence_error (errno)) @@ -85,7 +85,7 @@ lookup_file_by_inode (filepath) if (hp == NULL) { hp = getnode (); - hp->type = UNKNOWN; + hp->type = NT_UNKNOWN; hp->key = inodestr; hp->data = (char *) getlist(); hp->delproc = dellist; @@ -100,7 +100,7 @@ lookup_file_by_inode (filepath) if (p == NULL) { p = getnode(); - p->type = UNKNOWN; + p->type = NT_UNKNOWN; p->key = xstrdup (filepath); p->data = NULL; (void) addnode ((List *) hp->data, p); @@ -128,7 +128,7 @@ update_hardlink_info (file) /* file is a relative pathname; assume it's from the current working directory. */ char *dir = xgetwd(); - path = xmalloc (sizeof(char) * (strlen(dir) + strlen(file) + 2)); + path = xmalloc (strlen(dir) + strlen(file) + 2); sprintf (path, "%s/%s", dir, file); free (dir); } @@ -176,8 +176,7 @@ list_linked_files_on_disk (file) else { char *dir = xgetwd(); - path = (char *) xmalloc (sizeof(char) * - (strlen(dir) + strlen(file) + 2)); + path = (char *) xmalloc (strlen(dir) + strlen(file) + 2); sprintf (path, "%s/%s", dir, file); free (dir); } @@ -193,7 +192,7 @@ list_linked_files_on_disk (file) /* inodestr contains the hexadecimal representation of an inode, so it requires two bytes of text to represent each byte of the inode number. */ - inodestr = (char *) xmalloc (2*sizeof(ino_t)*sizeof(char) + 1); + inodestr = (char *) xmalloc (2*sizeof(ino_t) + 1); sprintf (inodestr, "%lx", (unsigned long) sb.st_ino); /* Make sure the files linked to this inode are sorted. */ @@ -280,7 +279,7 @@ find_checkedout_proc (node, data) /* Look at this file in the hardlist and see whether the checked_out field is 1, meaning that it has been checked out during this CVS run. */ path = (char *) - xmalloc (sizeof(char) * (strlen (dir) + strlen (node->key) + 2)); + xmalloc (strlen (dir) + strlen (node->key) + 2); sprintf (path, "%s/%s", dir, node->key); link = lookup_file_by_inode (path); free (path); diff --git a/contrib/cvs/src/hash.c b/contrib/cvs/src/hash.c index af000ac..7e562b8 100644 --- a/contrib/cvs/src/hash.c +++ b/contrib/cvs/src/hash.c @@ -102,7 +102,7 @@ dellist (listp) { /* put the nodes into the cache */ #ifndef NOCACHE - p->type = UNKNOWN; + p->type = NT_UNKNOWN; p->next = nodecache; nodecache = p; #else @@ -147,7 +147,7 @@ getnode () /* always make it clean */ memset ((char *) p, 0, sizeof (Node)); - p->type = UNKNOWN; + p->type = NT_UNKNOWN; return (p); } @@ -211,7 +211,7 @@ freenode (p) /* then put it in the cache */ #ifndef NOCACHE - p->type = UNKNOWN; + p->type = NT_UNKNOWN; p->next = nodecache; nodecache = p; #else @@ -456,7 +456,7 @@ nodetypestring (type) Ntype type; { switch (type) { - case UNKNOWN: return("UNKNOWN"); + case NT_UNKNOWN: return("UNKNOWN"); case HEADER: return("HEADER"); case ENTRIES: return("ENTRIES"); case FILES: return("FILES"); @@ -470,6 +470,7 @@ nodetypestring (type) case FILEATTR: return("FILEATTR"); case VARIABLE: return("VARIABLE"); case RCSFIELD: return("RCSFIELD"); + case RCSCMPFLD: return("RCSCMPFLD"); } return(""); diff --git a/contrib/cvs/src/hash.h b/contrib/cvs/src/hash.h index 06867a7..f98353d 100644 --- a/contrib/cvs/src/hash.h +++ b/contrib/cvs/src/hash.h @@ -16,9 +16,9 @@ */ enum ntype { - UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE, + NT_UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE, RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE, FILEATTR, - VARIABLE, RCSFIELD + VARIABLE, RCSFIELD, RCSCMPFLD }; typedef enum ntype Ntype; diff --git a/contrib/cvs/src/history.c b/contrib/cvs/src/history.c index bc7d1a6..9f66e86 100644 --- a/contrib/cvs/src/history.c +++ b/contrib/cvs/src/history.c @@ -195,7 +195,7 @@ static struct hrec } *hrec_head; -static char *fill_hrec PROTO((char *line, struct hrec * hr)); +static void fill_hrec PROTO((char *line, struct hrec * hr)); static int accept_hrec PROTO((struct hrec * hr, struct hrec * lr)); static int select_hrec PROTO((struct hrec * hr)); static int sort_order PROTO((const PTR l, const PTR r)); @@ -233,6 +233,8 @@ static short tz_local; static time_t tz_seconds_east_of_GMT; static char *tz_name = "+0000"; +char *logHistory = ALL_REC_TYPES; + /* -r, -t, or -b options, malloc'd. These are "" if the option in question is not specified or is overridden by another option. The main reason for using "" rather than NULL is historical. Together @@ -288,9 +290,9 @@ static const char *const history_usg[] = " -o Checked out modules\n", " -m Look for specified module (repeatable)\n", " -x [TOEFWUCGMAR] Extract by record type\n", + " -e Everything (same as -x, but all record types)\n", " Flags:\n", " -a All users (Default is self)\n", - " -e Everything (same as -x, but all record types)\n", " -l Last modified (committed or modified report)\n", " -w Working directory must match\n", " Options:\n", @@ -523,13 +525,17 @@ history (argc, argv) break; } } - c = optind; /* Save the handled option count */ + argc -= optind; + argv += optind; + for (i = 0; i < argc; i++) + save_file ("", argv[i], (char *) NULL); + /* ================ Now analyze the arguments a bit */ if (!report_count) v_checkout++; else if (report_count > 1) - error (1, 0, "Only one report type allowed from: \"-Tcomx\"."); + error (1, 0, "Only one report type allowed from: \"-Tcomxe\"."); #ifdef CLIENT_SUPPORT if (client_active) @@ -613,7 +619,8 @@ history (argc, argv) * If the user has not specified a date oriented flag ("Since"), sort * by Repository/file before date. Default is "just" date. */ - if (!since_date && !*since_rev && !*since_tag && !*backto) + if (last_entry + || (!since_date && !*since_rev && !*since_tag && !*backto)) { repos_sort++; file_sort++; @@ -642,7 +649,8 @@ history (argc, argv) /* See comments in "modified" above */ if (!last_entry && user_list) user_sort++; - if (!since_date && !*since_rev && !*since_tag && !*backto) + if (last_entry + || (!since_date && !*since_rev && !*since_tag && !*backto)) file_sort++; } @@ -657,11 +665,6 @@ history (argc, argv) (void) strcat (rec_types, "T"); } - argc -= c; - argv += c; - for (i = 0; i < argc; i++) - save_file ("", argv[i], (char *) NULL); - if (histfile) fname = xstrdup (histfile); else @@ -673,7 +676,11 @@ history (argc, argv) } read_hrecs (fname); - qsort ((PTR) hrec_head, hrec_count, sizeof (struct hrec), sort_order); + if(hrec_count>0) + { + qsort ((PTR) hrec_head, hrec_count, + sizeof (struct hrec), sort_order); + } report_hrecs (); free (fname); if (since_date != NULL) @@ -706,6 +713,8 @@ history_write (type, update_dir, revs, name, repository) if (logoff) /* History is turned off by cmd line switch */ return; + if ( strchr(logHistory, type) == NULL ) + return; fname = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + sizeof (CVSROOTADM_HISTORY) + 10); (void) sprintf (fname, "%s/%s/%s", CVSroot_directory, @@ -725,7 +734,14 @@ history_write (type, update_dir, revs, name, repository) goto out; fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666); if (fd < 0) - error (1, errno, "cannot open history file: %s", fname); + { + if (! really_quiet) + { + error (0, errno, "warning: cannot write to history file %s", + fname); + } + goto out; + } repos = Short_Repository (repository); @@ -965,27 +981,26 @@ expand_modules () * * Split it into 7 parts and drop the parts into a "struct hrec". * Return a pointer to the character following the newline. + * */ -#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) +#define NEXT_BAR(here) do { while (isspace(*line)) line++; hr->here = line; while ((c = *line++) && c != '|') ; if (!c) return; *(line - 1) = '\0'; } while (0) -static char * +static void fill_hrec (line, hr) char *line; struct hrec *hr; { - char *cp, *rtn; + char *cp; int c; int off; static int idx = 0; unsigned long date; memset ((char *) hr, 0, sizeof (*hr)); + while (isspace ((unsigned char) *line)) line++; - if (!(rtn = strchr (line, '\n'))) - return (""); - *rtn++ = '\0'; hr->type = line++; (void) sscanf (line, "%lx", &date); @@ -993,7 +1008,7 @@ fill_hrec (line, hr) while (*line && strchr ("0123456789abcdefABCDEF", *line)) line++; if (*line == '\0') - return (rtn); + return; line++; NEXT_BAR (user); @@ -1012,27 +1027,38 @@ fill_hrec (line, hr) if (strchr ("FOET", *(hr->type))) hr->mod = line; - NEXT_BAR (file); /* This returns ptr to next line or final '\0' */ - return (rtn); /* If it falls through, go on to next record */ + NEXT_BAR (file); } + +#ifndef STAT_BLOCKSIZE +#if HAVE_ST_BLKSIZE +#define STAT_BLOCKSIZE(s) (s).st_blksize +#else +#define STAT_BLOCKSIZE(s) (4 * 1024) +#endif +#endif + + /* read_hrecs's job is to read the history file and fill in all the "hrec" * (history record) array elements with the ones we need to print. * * Logic: - * - Read the whole history file into a single buffer. - * - Walk through the buffer, parsing lines out of the buffer. - * 1. Split line into pointer and integer fields in the "next" hrec. - * 2. Apply tests to the hrec to see if it is wanted. - * 3. If it *is* wanted, bump the hrec pointer down by one. + * - Read a block from the file. + * - Walk through the block parsing line into hr records. + * - if the hr isn't used, free its strings, if it is, bump the hrec counter + * - at the end of a block, copy the end of the current block to the start + * of space for the next block, then read in the next block. If we get less + * than the whole block, we're done. */ static void read_hrecs (fname) char *fname; { - char *cp, *cp2; - int i, fd; - struct hrec *hr; + unsigned char *cpstart, *cp, *nl; + char *hrline; + int i; + int fd; struct stat st_buf; if ((fd = CVS_OPEN (fname, O_RDONLY | OPEN_BINARY)) < 0) @@ -1041,54 +1067,75 @@ read_hrecs (fname) if (fstat (fd, &st_buf) < 0) error (1, errno, "can't stat history file"); - /* Exactly enough space for lines data */ - if (!(i = st_buf.st_size)) + if (!(st_buf.st_size)) error (1, 0, "history file is empty"); - cp = xmalloc (i + 2); - if (read (fd, cp, i) != i) - error (1, errno, "cannot read log file"); - (void) close (fd); - - if (*(cp + i - 1) != '\n') - { - *(cp + i) = '\n'; /* Make sure last line ends in '\n' */ - i++; - } - *(cp + i) = '\0'; - for (cp2 = cp; cp2 - cp < i; cp2++) - { - if (*cp2 != '\n' && !isprint ((unsigned char) *cp2)) - *cp2 = ' '; - } + cpstart = xmalloc (2 * STAT_BLOCKSIZE(st_buf)); + cpstart[0] = '\0'; + cp = cpstart; hrec_max = HREC_INCREMENT; - hrec_head = (struct hrec *) xmalloc (hrec_max * sizeof (struct hrec)); + hrec_head = xmalloc (hrec_max * sizeof (struct hrec)); - while (*cp) + for (;;) { + for (nl = cp; *nl && *nl != '\n'; nl++) + if (!isprint(*nl)) *nl = ' '; + + if (!*nl) + { + if (nl - cp >= STAT_BLOCKSIZE(st_buf)) + { + error(1, 0, "history line too long (> %lu)", + (unsigned long) STAT_BLOCKSIZE(st_buf)); + } + if (nl > cp) + memmove (cpstart, cp, nl - cp); + nl = cpstart + (nl - cp); + cp = cpstart; + i = read (fd, nl, STAT_BLOCKSIZE(st_buf)); + if (i > 0) + { + nl[i] = '\0'; + continue; + } + if (i < 0) + error (1, errno, "error reading history file"); + if (nl == cp) break; + nl[1] = '\0'; + } + *nl = '\0'; + if (hrec_count == hrec_max) { struct hrec *old_head = hrec_head; hrec_max += HREC_INCREMENT; - hrec_head = (struct hrec *) xrealloc ((char *) hrec_head, - hrec_max * sizeof (struct hrec)); - if (hrec_head != old_head) - { - if (last_since_tag) - last_since_tag = hrec_head + (last_since_tag - old_head); - if (last_backto) - last_backto = hrec_head + (last_backto - old_head); - } + hrec_head = xrealloc ((char *) hrec_head, + hrec_max * sizeof (struct hrec)); + if (last_since_tag) + last_since_tag = hrec_head + (last_since_tag - old_head); + if (last_backto) + last_backto = hrec_head + (last_backto - old_head); } - hr = hrec_head + hrec_count; - cp = fill_hrec (cp, hr); /* cp == next line or '\0' at end of buffer */ + /* fill_hrec dates from when history read the entire + history file in one chunk, and then records were pulled out + by pointing to the various parts of this big chunk. This is + why there are ugly hacks here: I don't want to completely + re-write the whole history stuff right now. */ - if (select_hrec (hr)) + hrline = xstrdup ((char *)cp); + fill_hrec (hrline, &hrec_head[hrec_count]); + if (select_hrec (&hrec_head[hrec_count])) hrec_count++; + else + free(hrline); + + cp = nl + 1; } + free (cpstart); + close (fd); /* Special selection problem: If "since_tag" is set, we have saved every * record from the 1st occurrence of "since_tag", when we want to save @@ -1169,11 +1216,10 @@ select_hrec (hr) if (since_date) { char *ourdate = date_from_time_t (hr->date); - - if (RCS_datecmp (ourdate, since_date) < 0) - return (0); - + count = RCS_datecmp (ourdate, since_date); free (ourdate); + if (count < 0) + return (0); } else if (*since_rev) { @@ -1426,9 +1472,9 @@ report_hrecs () else tm = localtime (&(lr->date)); - (void) printf ("%c %02d/%02d %02d:%02d %s %-*s", ty, tm->tm_mon + 1, - tm->tm_mday, tm->tm_hour, tm->tm_min, tz_name, - user_len, lr->user); + (void) printf ("%c %04d-%02d-%02d %02d:%02d %s %-*s", ty, + tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, + tm->tm_min, tz_name, user_len, lr->user); workdir = xmalloc (strlen (lr->dir) + strlen (lr->end) + 10); (void) sprintf (workdir, "%s%s", lr->dir, lr->end); diff --git a/contrib/cvs/src/ignore.c b/contrib/cvs/src/ignore.c index df08017..4ea61ad 100644 --- a/contrib/cvs/src/ignore.c +++ b/contrib/cvs/src/ignore.c @@ -333,9 +333,7 @@ ign_dir_add (name) (dir_ign_max + 1) * sizeof (char *)); } - dir_ign_list[dir_ign_current] = name; - - dir_ign_current += 1 ; + dir_ign_list[dir_ign_current++] = xstrdup (name); } @@ -414,9 +412,9 @@ ignore_files (ilist, entries, update_dir, proc) { file = dp->d_name; if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0) - continue; + goto continue_loop; if (findnode_fn (ilist, file) != NULL) - continue; + goto continue_loop; if (subdirs) { Node *node; @@ -437,14 +435,14 @@ ignore_files (ilist, entries, update_dir, proc) dir = isdir (p); free (p); if (dir) - continue; + goto continue_loop; } } /* We could be ignoring FIFOs and other files which are neither regular files nor directories here. */ if (ign_name (file)) - continue; + goto continue_loop; if ( #ifdef DT_DIR @@ -455,9 +453,12 @@ ignore_files (ilist, entries, update_dir, proc) if ( #ifdef DT_DIR - dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN && + dp->d_type == DT_DIR + || (dp->d_type == DT_UNKNOWN && S_ISDIR (sb.st_mode)) +#else + S_ISDIR (sb.st_mode) #endif - S_ISDIR(sb.st_mode)) + ) { if (! subdirs) { @@ -468,7 +469,7 @@ ignore_files (ilist, entries, update_dir, proc) if (isdir (temp)) { free (temp); - continue; + goto continue_loop; } free (temp); } @@ -476,16 +477,20 @@ ignore_files (ilist, entries, update_dir, proc) #ifdef S_ISLNK else if ( #ifdef DT_DIR - dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN && + dp->d_type == DT_LNK + || (dp->d_type == DT_UNKNOWN && S_ISLNK(sb.st_mode)) +#else + S_ISLNK (sb.st_mode) #endif - S_ISLNK(sb.st_mode)) + ) { - continue; + goto continue_loop; } #endif } (*proc) (file, xdir); + continue_loop: errno = 0; } if (errno != 0) diff --git a/contrib/cvs/src/import.c b/contrib/cvs/src/import.c index 57ff619..e1fb460 100644 --- a/contrib/cvs/src/import.c +++ b/contrib/cvs/src/import.c @@ -266,12 +266,22 @@ import (argc, argv) client_import_setup (repository); err = import_descend (message, argv[1], argc - 2, argv + 2); client_import_done (); + if (message) + free (message); + free (repository); + free (vbranch); + free (vhead); send_to_server ("import\012", 0); err += get_responses_and_close (); return err; } #endif + if (!safe_location ()) + { + error (1, 0, "attempt to import the repository"); + } + /* * Make all newly created directories writable. Should really use a more * sophisticated security mechanism here. @@ -453,9 +463,12 @@ import_descend (message, vtag, targc, targv) } else if ( #ifdef DT_DIR - dp->d_type == DT_LNK || dp->d_type == DT_UNKNOWN && + dp->d_type == DT_LNK + || (dp->d_type == DT_UNKNOWN && islink (dp->d_name)) +#else + islink (dp->d_name) #endif - islink (dp->d_name)) + ) { add_log ('L', dp->d_name); err++; @@ -725,8 +738,8 @@ add_rev (message, rcs, vfile, vers) { if (!noexec) { - fperror (logfp, 0, status == -1 ? ierrno : 0, - "ERROR: Check-in of %s failed", rcs->path); + fperrmsg (logfp, 0, status == -1 ? ierrno : 0, + "ERROR: Check-in of %s failed", rcs->path); error (0, status == -1 ? ierrno : 0, "ERROR: Check-in of %s failed", rcs->path); } @@ -765,8 +778,8 @@ add_tags (rcs, vfile, vtag, targc, targv) if ((retcode = RCS_settag(rcs, vtag, vbranch)) != 0) { ierrno = errno; - fperror (logfp, 0, retcode == -1 ? ierrno : 0, - "ERROR: Failed to set tag %s in %s", vtag, rcs->path); + fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0, + "ERROR: Failed to set tag %s in %s", vtag, rcs->path); error (0, retcode == -1 ? ierrno : 0, "ERROR: Failed to set tag %s in %s", vtag, rcs->path); return (1); @@ -789,9 +802,9 @@ add_tags (rcs, vfile, vtag, targc, targv) else { ierrno = errno; - fperror (logfp, 0, retcode == -1 ? ierrno : 0, - "WARNING: Couldn't add tag %s to %s", targv[i], - rcs->path); + fperrmsg (logfp, 0, retcode == -1 ? ierrno : 0, + "WARNING: Couldn't add tag %s to %s", targv[i], + rcs->path); error (0, retcode == -1 ? ierrno : 0, "WARNING: Couldn't add tag %s to %s", targv[i], rcs->path); @@ -1054,7 +1067,14 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt, stat the file before opening it. -twp */ if (CVS_LSTAT (userfile, &sb) < 0) - error (1, errno, "cannot lstat %s", user); + { + /* not fatal, continue import */ + if (add_logfp != NULL) + fperrmsg (add_logfp, 0, errno, + "ERROR: cannot lstat file %s", userfile); + error (0, errno, "cannot lstat file %s", userfile); + goto read_error; + } file_type = sb.st_mode & S_IFMT; fpuser = NULL; @@ -1069,8 +1089,8 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt, { /* not fatal, continue import */ if (add_logfp != NULL) - fperror (add_logfp, 0, errno, - "ERROR: cannot read file %s", userfile); + fperrmsg (add_logfp, 0, errno, + "ERROR: cannot read file %s", userfile); error (0, errno, "ERROR: cannot read file %s", userfile); goto read_error; } @@ -1202,12 +1222,18 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt, case S_IFREG: break; case S_IFCHR: case S_IFBLK: +#ifdef HAVE_ST_RDEV if (fprintf (fprcs, "special\t%s %lu;\012", (file_type == S_IFCHR ? "character" : "block"), (unsigned long) sb.st_rdev) < 0) goto write_error; +#else + error (0, 0, +"can't import %s: unable to import device files on this system", +userfile); +#endif break; default: error (0, 0, @@ -1253,12 +1279,18 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt, case S_IFREG: break; case S_IFCHR: case S_IFBLK: +#ifdef HAVE_ST_RDEV if (fprintf (fprcs, "special\t%s %lu;\012", (file_type == S_IFCHR ? "character" : "block"), (unsigned long) sb.st_rdev) < 0) goto write_error; +#else + error (0, 0, +"can't import %s: unable to import device files on this system", +userfile); +#endif break; default: error (0, 0, @@ -1377,8 +1409,8 @@ add_rcs_file (message, rcs, user, add_vhead, key_opt, { ierrno = errno; if (add_logfp != NULL) - fperror (add_logfp, 0, ierrno, - "WARNING: cannot change mode of file %s", rcs); + fperrmsg (add_logfp, 0, ierrno, + "WARNING: cannot change mode of file %s", rcs); error (0, ierrno, "WARNING: cannot change mode of file %s", rcs); err++; } @@ -1397,14 +1429,14 @@ write_error_noclose: if (fclose (fpuser) < 0) error (0, errno, "cannot close %s", user); if (add_logfp != NULL) - fperror (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs); + fperrmsg (add_logfp, 0, ierrno, "ERROR: cannot write file %s", rcs); error (0, ierrno, "ERROR: cannot write file %s", rcs); if (ierrno == ENOSPC) { if (CVS_UNLINK (rcs) < 0) error (0, errno, "cannot remove %s", rcs); if (add_logfp != NULL) - fperror (add_logfp, 0, 0, "ERROR: out of space - aborting"); + fperrmsg (add_logfp, 0, 0, "ERROR: out of space - aborting"); error (1, 0, "ERROR: out of space - aborting"); } read_error: @@ -1513,7 +1545,7 @@ import_descend_dir (message, dir, vtag, targc, targv) return (0); if (save_cwd (&cwd)) { - fperror (logfp, 0, 0, "ERROR: cannot get working directory"); + fperrmsg (logfp, 0, 0, "ERROR: cannot get working directory"); return (1); } @@ -1544,7 +1576,7 @@ import_descend_dir (message, dir, vtag, targc, targv) if ( CVS_CHDIR (dir) < 0) { ierrno = errno; - fperror (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository); + fperrmsg (logfp, 0, ierrno, "ERROR: cannot chdir to %s", repository); error (0, ierrno, "ERROR: cannot chdir to %s", repository); err = 1; goto out; @@ -1559,9 +1591,9 @@ import_descend_dir (message, dir, vtag, targc, targv) (void) sprintf (rcs, "%s%s", repository, RCSEXT); if (isfile (repository) || isfile(rcs)) { - fperror (logfp, 0, 0, - "ERROR: %s is a file, should be a directory!", - repository); + fperrmsg (logfp, 0, 0, + "ERROR: %s is a file, should be a directory!", + repository); error (0, 0, "ERROR: %s is a file, should be a directory!", repository); err = 1; @@ -1570,8 +1602,8 @@ import_descend_dir (message, dir, vtag, targc, targv) if (noexec == 0 && CVS_MKDIR (repository, 0777) < 0) { ierrno = errno; - fperror (logfp, 0, ierrno, - "ERROR: cannot mkdir %s -- not added", repository); + fperrmsg (logfp, 0, ierrno, + "ERROR: cannot mkdir %s -- not added", repository); error (0, ierrno, "ERROR: cannot mkdir %s -- not added", repository); err = 1; diff --git a/contrib/cvs/src/lock.c b/contrib/cvs/src/lock.c index 3776b2c..1b98180 100644 --- a/contrib/cvs/src/lock.c +++ b/contrib/cvs/src/lock.c @@ -175,8 +175,12 @@ lock_name (repository, name) assert (CVSroot_directory != NULL); assert (strncmp (repository, CVSroot_directory, strlen (CVSroot_directory)) == 0); - short_repos = repository + strlen (CVSroot_directory); - assert (*short_repos++ == '/'); + short_repos = repository + strlen (CVSroot_directory) + 1; + + if (strcmp (repository, CVSroot_directory) == 0) + short_repos = "."; + else + assert (short_repos[-1] == '/'); retval = xmalloc (strlen (lock_dir) + strlen (short_repos) @@ -755,8 +759,8 @@ set_lock (lock, will_wait) if (errno != EEXIST) { error (0, errno, - "failed to create lock directory in repository `%s'", - lock->repository); + "failed to create lock directory for `%s' (%s)", + lock->repository, masterlock); return (L_ERROR); } diff --git a/contrib/cvs/src/log.c b/contrib/cvs/src/log.c index 398d650..2e230e3 100644 --- a/contrib/cvs/src/log.c +++ b/contrib/cvs/src/log.c @@ -149,6 +149,47 @@ static const char *const log_usage[] = NULL }; +#ifdef CLIENT_SUPPORT + +/* Helper function for send_arg_list. */ +static int send_one PROTO ((Node *, void *)); + +static int +send_one (node, closure) + Node *node; + void *closure; +{ + char *option = (char *) closure; + + send_to_server ("Argument ", 0); + send_to_server (option, 0); + if (strcmp (node->key, "@@MYSELF") == 0) + /* It is a bare -w option. Note that we must send it as + -w rather than messing with getcaller() or something (which on + the client will return garbage). */ + ; + else + send_to_server (node->key, 0); + send_to_server ("\012", 0); + return 0; +} + +/* For each element in ARG, send an argument consisting of OPTION + concatenated with that element. */ +static void send_arg_list PROTO ((char *, List *)); + +static void +send_arg_list (option, arg) + char *option; + List *arg; +{ + if (arg == NULL) + return; + walklist (arg, send_one, (void *)option); +} + +#endif + int cvslog (argc, argv) int argc; @@ -158,12 +199,13 @@ cvslog (argc, argv) int err = 0; int local = 0; struct log_data log_data; - struct option_revlist *rl, **prl; + struct option_revlist **prl; if (argc == -1) usage (log_usage); memset (&log_data, 0, sizeof log_data); + prl = &log_data.revlist; optind = 0; while ((c = getopt (argc, argv, "+bd:hlNRr::s:tw::")) != -1) @@ -189,12 +231,8 @@ cvslog (argc, argv) log_data.nameonly = 1; break; case 'r': - rl = log_parse_revlist (optarg); - for (prl = &log_data.revlist; - *prl != NULL; - prl = &(*prl)->next) - ; - *prl = rl; + *prl = log_parse_revlist (optarg); + prl = &(*prl)->next; break; case 's': log_parse_list (&log_data.statelist, optarg); @@ -206,7 +244,7 @@ cvslog (argc, argv) if (optarg != NULL) log_parse_list (&log_data.authorlist, optarg); else - log_parse_list (&log_data.authorlist, getcaller ()); + log_parse_list (&log_data.authorlist, "@@MYSELF"); break; case '?': default: @@ -220,18 +258,97 @@ cvslog (argc, argv) #ifdef CLIENT_SUPPORT if (client_active) { - int i; + struct datelist *p; + struct option_revlist *rp; + char datetmp[MAXDATELEN]; /* We're the local client. Fire up the remote server. */ start_server (); ign_setup (); - for (i = 1; i < argc && argv[i][0] == '-'; i++) - send_arg (argv[i]); + if (log_data.default_branch) + send_arg ("-b"); + + while (log_data.datelist != NULL) + { + p = log_data.datelist; + log_data.datelist = p->next; + send_to_server ("Argument -d\012", 0); + send_to_server ("Argument ", 0); + date_to_internet (datetmp, p->start); + send_to_server (datetmp, 0); + if (p->inclusive) + send_to_server ("<=", 0); + else + send_to_server ("<", 0); + date_to_internet (datetmp, p->end); + send_to_server (datetmp, 0); + send_to_server ("\012", 0); + if (p->start) + free (p->start); + if (p->end) + free (p->end); + free (p); + } + while (log_data.singledatelist != NULL) + { + p = log_data.singledatelist; + log_data.singledatelist = p->next; + send_to_server ("Argument -d\012", 0); + send_to_server ("Argument ", 0); + date_to_internet (datetmp, p->end); + send_to_server (datetmp, 0); + send_to_server ("\012", 0); + if (p->end) + free (p->end); + free (p); + } + + if (log_data.header) + send_arg ("-h"); + if (local) + send_arg("-l"); + if (log_data.notags) + send_arg("-N"); + if (log_data.nameonly) + send_arg("-R"); + if (log_data.long_header) + send_arg("-t"); + + while (log_data.revlist != NULL) + { + rp = log_data.revlist; + log_data.revlist = rp->next; + send_to_server ("Argument -r", 0); + if (rp->branchhead) + { + if (rp->first != NULL) + send_to_server (rp->first, 0); + send_to_server (".", 1); + } + else + { + if (rp->first != NULL) + send_to_server (rp->first, 0); + send_to_server (":", 1); + if (rp->last != NULL) + send_to_server (rp->last, 0); + } + send_to_server ("\012", 0); + if (rp->first) + free (rp->first); + if (rp->last) + free (rp->last); + free (rp); + } + send_arg_list ("-s", log_data.statelist); + dellist (&log_data.statelist); + send_arg_list ("-w", log_data.authorlist); + dellist (&log_data.authorlist); - send_files (argc - i, argv + i, local, 0, SEND_NO_CONTENTS); - send_file_names (argc - i, argv + i, SEND_EXPAND_WILD); + send_files (argc - optind, argv + optind, local, 0, SEND_NO_CONTENTS); + send_file_names (argc - optind, argv + optind, SEND_EXPAND_WILD); send_to_server ("log\012", 0); err = get_responses_and_close (); @@ -239,11 +356,50 @@ cvslog (argc, argv) } #endif + /* OK, now that we know we are local/server, we can resolve @@MYSELF + into our user name. */ + if (findnode (log_data.authorlist, "@@MYSELF") != NULL) + log_parse_list (&log_data.authorlist, getcaller ()); + err = start_recursion (log_fileproc, (FILESDONEPROC) NULL, log_dirproc, (DIRLEAVEPROC) NULL, (void *) &log_data, argc - optind, argv + optind, local, W_LOCAL | W_REPOS | W_ATTIC, 0, 1, (char *) NULL, 1); + + while (log_data.revlist) + { + struct option_revlist *rl = log_data.revlist->next; + if (log_data.revlist->first) + free (log_data.revlist->first); + if (log_data.revlist->last) + free (log_data.revlist->last); + free (log_data.revlist); + log_data.revlist = rl; + } + while (log_data.datelist) + { + struct datelist *nd = log_data.datelist->next; + if (log_data.datelist->start) + free (log_data.datelist->start); + if (log_data.datelist->end) + free (log_data.datelist->end); + free (log_data.datelist); + log_data.datelist = nd; + } + while (log_data.singledatelist) + { + struct datelist *nd = log_data.singledatelist->next; + if (log_data.singledatelist->start) + free (log_data.singledatelist->start); + if (log_data.singledatelist->end) + free (log_data.singledatelist->end); + free (log_data.singledatelist); + log_data.singledatelist = nd; + } + dellist (&log_data.statelist); + dellist (&log_data.authorlist); + return (err); } @@ -255,77 +411,65 @@ static struct option_revlist * log_parse_revlist (argstring) const char *argstring; { - char *copy; + char *orig_copy, *copy; struct option_revlist *ret, **pr; /* Unfortunately, rlog accepts -r without an argument to mean that latest revision on the default branch, so we must support that for compatibility. */ if (argstring == NULL) - { - ret = (struct option_revlist *) xmalloc (sizeof *ret); - ret->first = NULL; - ret->last = NULL; - ret->next = NULL; - ret->branchhead = 0; - return ret; - } + argstring = ""; ret = NULL; pr = &ret; /* Copy the argument into memory so that we can change it. We don't want to change the argument because, at least as of this - writing, we will use it if we send the arguments to the server. - We never bother to free up our copy. */ - copy = xstrdup (argstring); + writing, we will use it if we send the arguments to the server. */ + orig_copy = copy = xstrdup (argstring); while (copy != NULL) { char *comma; - char *cp; - char *first, *last; struct option_revlist *r; comma = strchr (copy, ','); if (comma != NULL) *comma++ = '\0'; - first = copy; - cp = strchr (copy, ':'); - if (cp == NULL) - last = copy; - else - { - *cp++ = '\0'; - last = cp; - } - - if (*first == '\0') - first = NULL; - if (*last == '\0') - last = NULL; - r = (struct option_revlist *) xmalloc (sizeof *r); r->next = NULL; - r->first = first; - r->last = last; - if (first != last - || first[strlen (first) - 1] != '.') - { - r->branchhead = 0; - } + r->first = copy; + r->branchhead = 0; + r->last = strchr (copy, ':'); + if (r->last != NULL) + *r->last++ = '\0'; else { - r->branchhead = 1; - first[strlen (first) - 1] = '\0'; + r->last = r->first; + if (r->first[0] != '\0' && r->first[strlen (r->first) - 1] == '.') + { + r->branchhead = 1; + r->first[strlen (r->first) - 1] = '\0'; + } } + if (*r->first == '\0') + r->first = NULL; + if (*r->last == '\0') + r->last = NULL; + + if (r->first != NULL) + r->first = xstrdup (r->first); + if (r->last != NULL) + r->last = xstrdup (r->last); + *pr = r; pr = &r->next; copy = comma; } + free (orig_copy); return ret; } @@ -342,8 +486,7 @@ log_parse_date (log_data, argstring) /* Copy the argument into memory so that we can change it. We don't want to change the argument because, at least as of this writing, we will use it if we send the arguments to the server. */ - copy = xstrdup (argstring); - orig_copy = copy; + orig_copy = copy = xstrdup (argstring); while (copy != NULL) { struct datelist *nd, **pd; diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c index 46707e2..1a774e0 100644 --- a/contrib/cvs/src/login.c +++ b/contrib/cvs/src/login.c @@ -12,6 +12,12 @@ #ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */ +#ifdef HAVE_GETPASSPHRASE +#define GETPASS getpassphrase +#else +#define GETPASS getpass +#endif + /* There seems to be very little agreement on which system header getpass is declared in. With a lot of fancy autoconfiscation, we could perhaps detect this, but for now we'll just rely on @@ -20,7 +26,7 @@ varadic, believe it or not). On Cray, getpass will be declared in either stdlib.h or unistd.h. */ #ifndef _CRAY -extern char *getpass (); +extern char *GETPASS (); #endif #ifndef CVS_PASSWORD_FILE @@ -142,7 +148,7 @@ login (argc, argv) fflush (stdout); passfile = construct_cvspass_filename (); - typed_password = getpass ("CVS password: "); + typed_password = GETPASS ("CVS password: "); typed_password = scramble (typed_password); /* Force get_cvs_password() to use this one (when the client @@ -289,14 +295,15 @@ login (argc, argv) } /* Returns the _scrambled_ password. The server must descramble - before hashing and comparing. */ + before hashing and comparing. If password file not found, or + password not found in the file, just return NULL. */ char * get_cvs_password () { int found_it = 0; int root_len; - char *password; - char *linebuf = (char *) NULL; + char *password = NULL; + char *linebuf = NULL; size_t linebuf_len; FILE *fp; char *passfile; @@ -339,11 +346,10 @@ get_cvs_password () passfile = construct_cvspass_filename (); fp = CVS_FOPEN (passfile, "r"); - if (fp == NULL) + if (fp == NULL) { - error (0, errno, "could not open %s", passfile); free (passfile); - error (1, 0, "use \"cvs login\" to log in first"); + return NULL; } root_len = strlen (CVSroot_original); @@ -369,23 +375,19 @@ get_cvs_password () char *tmp; strtok (linebuf, " "); - password = strtok (NULL, "\n"); + tmp = strtok (NULL, "\n"); + if (tmp == NULL) + error (1, 0, "bad entry in %s for %s", passfile, CVSroot_original); /* Give it permanent storage. */ - tmp = xstrdup (password); - memset (password, 0, strlen (password)); - free (linebuf); - return tmp; - } - else - { - if (linebuf) - free (linebuf); - error (0, 0, "cannot find password"); - error (1, 0, "use \"cvs login\" to log in first"); + password = xstrdup (tmp); + memset (tmp, 0, strlen (password)); } - /* NOTREACHED */ - return NULL; + + if (linebuf) + free (linebuf); + free (passfile); + return password; } static const char *const logout_usage[] = @@ -395,7 +397,7 @@ static const char *const logout_usage[] = NULL }; -/* Remove any entry for the CVSRoot repository found in "CVS/.cvspass". */ +/* Remove any entry for the CVSRoot repository found in .cvspass. */ int logout (argc, argv) int argc; @@ -403,7 +405,7 @@ logout (argc, argv) { char *passfile; FILE *fp; - char *tmp_name; + char *tmp_name = NULL; FILE *tmp_fp; char *linebuf = (char *) NULL; size_t linebuf_len; @@ -498,6 +500,10 @@ logout (argc, argv) error (0, errno, "cannot remove %s", tmp_name); chmod (passfile, 0600); } + + if (tmp_name) + free (tmp_name); + return 0; } diff --git a/contrib/cvs/src/logmsg.c b/contrib/cvs/src/logmsg.c index 6d45ca3..cb08cdf 100644 --- a/contrib/cvs/src/logmsg.c +++ b/contrib/cvs/src/logmsg.c @@ -182,7 +182,6 @@ do_editor (dir, messagep, repository, changes) char *fname; struct stat pre_stbuf, post_stbuf; int retcode = 0; - char *p; if (noexec || reuse_log_message) return; @@ -216,7 +215,6 @@ do_editor (dir, messagep, repository, changes) { FILE *tfp; char buf[1024]; - char *p; size_t n; size_t nwrite; @@ -231,9 +229,9 @@ do_editor (dir, messagep, repository, changes) { while (!feof (tfp)) { + char *p = buf; n = fread (buf, 1, sizeof buf, tfp); nwrite = n; - p = buf; while (nwrite > 0) { n = fwrite (p, 1, nwrite, fp); @@ -315,7 +313,8 @@ do_editor (dir, messagep, repository, changes) if (*messagep) { - p = *messagep; + size_t message_len = post_stbuf.st_size + 1; + size_t offset = 0; while (1) { line_length = getline (&line, &line_chars_allocated, fp); @@ -327,8 +326,11 @@ do_editor (dir, messagep, repository, changes) } if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0) continue; - (void) strcpy (p, line); - p += line_length; + if (offset + line_length >= message_len) + expand_string (messagep, &message_len, + offset + line_length + 1); + (void) strcpy (*messagep + offset, line); + offset += line_length; } } if (fclose (fp) < 0) @@ -759,7 +761,7 @@ logfile_write (repository, filter, message, logfp, changes) } len = fmt_end - fmt_begin; - str_list_format = xmalloc (sizeof (char) * (len + 1)); + str_list_format = xmalloc (len + 1); strncpy (str_list_format, fmt_begin, len); str_list_format[len] = '\0'; diff --git a/contrib/cvs/src/main.c b/contrib/cvs/src/main.c index e211db6..86913e1 100644 --- a/contrib/cvs/src/main.c +++ b/contrib/cvs/src/main.c @@ -111,30 +111,31 @@ static const struct cmd { "history", "hi", "his", history }, { "import", "im", "imp", import }, { "init", NULL, NULL, init }, -#ifdef SERVER_SUPPORT +#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) { "kserver", NULL, NULL, server }, /* placeholder */ #endif { "log", "lo", "rlog", cvslog }, #ifdef AUTH_CLIENT_SUPPORT { "login", "logon", "lgn", login }, { "logout", NULL, NULL, logout }, -#ifdef SERVER_SUPPORT +#endif /* AUTH_CLIENT_SUPPORT */ +#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) { "pserver", NULL, NULL, server }, /* placeholder */ #endif -#endif /* AUTH_CLIENT_SUPPORT */ { "rdiff", "patch", "pa", patch }, { "release", "re", "rel", release }, { "remove", "rm", "delete", cvsremove }, - { "status", "st", "stat", cvsstatus }, { "rtag", "rt", "rfreeze", rtag }, +#ifdef SERVER_SUPPORT + { "server", NULL, NULL, server }, +#endif + { "status", "st", "stat", cvsstatus }, { "tag", "ta", "freeze", cvstag }, { "unedit", NULL, NULL, unedit }, { "update", "up", "upd", update }, + { "version", "ve", "ver", version }, { "watch", NULL, NULL, watch }, { "watchers", NULL, NULL, watchers }, -#ifdef SERVER_SUPPORT - { "server", NULL, NULL, server }, -#endif { NULL, NULL, NULL, NULL }, }; @@ -179,7 +180,7 @@ static const char *const usg[] = version control means. */ "For CVS updates and additional information, see\n", - " Cyclic Software at http://www.cyclic.com/ or\n", + " the CVS home page at http://www.cvshome.org/ or\n", " Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n", NULL, }; @@ -199,15 +200,24 @@ static const char *const cmd_usage[] = " history Show repository access history\n", " import Import sources into CVS, using vendor branches\n", " init Create a CVS repository if it doesn't exist\n", +#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) + " kserver Kerberos server mode\n", +#endif " log Print out history information for files\n", #ifdef AUTH_CLIENT_SUPPORT - " login Prompt for password for authenticating server.\n", - " logout Removes entry in .cvspass for remote repository.\n", + " login Prompt for password for authenticating server\n", + " logout Removes entry in .cvspass for remote repository\n", #endif /* AUTH_CLIENT_SUPPORT */ +#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) + " pserver Password server mode\n", +#endif " rdiff Create 'patch' format diffs between releases\n", " release Indicate that a Module is no longer in use\n", " remove Remove an entry from the repository\n", " rtag Add a symbolic tag to a module\n", +#ifdef SERVER_SUPPORT + " server Server mode\n", +#endif " status Display status information on checked out files\n", " tag Add a symbolic tag to checked out version of files\n", " unedit Undo an edit command\n", @@ -343,6 +353,7 @@ lookup_command_attribute (cmd_name) (strcmp (cmd_name, "log") != 0) && (strcmp (cmd_name, "noop") != 0) && (strcmp (cmd_name, "watchers") != 0) && + (strcmp (cmd_name, "release") != 0) && (strcmp (cmd_name, "status") != 0)) { ret |= CVS_CMD_MODIFIES_REPOSITORY; @@ -362,6 +373,11 @@ main_cleanup (sig) switch (sig) { +#ifdef SIGABRT + case SIGABRT: + name = "abort"; + break; +#endif #ifdef SIGHUP case SIGHUP: name = "hangup"; @@ -405,8 +421,6 @@ main (argc, argv) char **argv; { char *CVSroot = CVSROOT_DFLT; - extern char *version_string; - extern char *config_string; char *cp, *end; const struct cmd *cm; int c, err = 0; @@ -418,6 +432,7 @@ main (argc, argv) int help = 0; /* Has the user asked for help? This lets us support the `cvs -H cmd' convention to give help for cmd. */ + static const char short_options[] = "+Qqrwtnlvb:T:e:d:Hfz:s:xa"; static struct option long_options[] = { {"help", 0, NULL, 'H'}, @@ -492,7 +507,7 @@ main (argc, argv) opterr = 0; while ((c = getopt_long - (argc, argv, "+f", NULL, NULL)) + (argc, argv, short_options, long_options, &option_index)) != EOF) { if (c == 'f') @@ -509,7 +524,7 @@ main (argc, argv) opterr = 1; while ((c = getopt_long - (argc, argv, "+Qqrwtnlvb:T:e:d:Hfz:s:xa", long_options, &option_index)) + (argc, argv, short_options, long_options, &option_index)) != EOF) { switch (c) @@ -551,14 +566,11 @@ main (argc, argv) logoff = 1; break; case 'v': - /* Having the year here is a good idea, so people have - some idea of how long ago their version of CVS was - released. */ - (void) fputs (version_string, stdout); - (void) fputs (config_string, stdout); + (void) fputs ("\n", stdout); + version (0, (char **) NULL); (void) fputs ("\n", stdout); (void) fputs ("\ -Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ +Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ Jeff Polk, and other authors\n", stdout); (void) fputs ("\n", stdout); (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout); @@ -602,9 +614,9 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ case 'z': #ifdef CLIENT_SUPPORT gzip_level = atoi (optarg); - if (gzip_level <= 0 || gzip_level > 9) + if (gzip_level < 0 || gzip_level > 9) error (1, 0, - "gzip compression level must be between 1 and 9"); + "gzip compression level must be between 0 and 9"); #endif /* If no CLIENT_SUPPORT, we just silently ignore the gzip level, so that users can have it in their .cvsrc and not @@ -657,7 +669,10 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ } if (!cm->fullname) - usage (cmd_usage); /* no match */ + { + fprintf (stderr, "Unknown command: `%s'\n\n", command_name); + usage (cmd_usage); + } else command_name = cm->fullname; /* Global pointer for later use */ @@ -765,25 +780,23 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ #ifndef DONT_USE_SIGNALS /* make sure we clean up on error */ +#ifdef SIGABRT + (void) SIG_register (SIGABRT, main_cleanup); +#endif #ifdef SIGHUP (void) SIG_register (SIGHUP, main_cleanup); - (void) SIG_register (SIGHUP, Lock_Cleanup); #endif #ifdef SIGINT (void) SIG_register (SIGINT, main_cleanup); - (void) SIG_register (SIGINT, Lock_Cleanup); #endif #ifdef SIGQUIT (void) SIG_register (SIGQUIT, main_cleanup); - (void) SIG_register (SIGQUIT, Lock_Cleanup); #endif #ifdef SIGPIPE (void) SIG_register (SIGPIPE, main_cleanup); - (void) SIG_register (SIGPIPE, Lock_Cleanup); #endif #ifdef SIGTERM (void) SIG_register (SIGTERM, main_cleanup); - (void) SIG_register (SIGTERM, Lock_Cleanup); #endif #endif /* !DONT_USE_SIGNALS */ @@ -878,7 +891,7 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ { Node *n; n = getnode (); - n->type = UNKNOWN; + n->type = NT_UNKNOWN; n->key = xstrdup (CVSroot); n->data = NULL; @@ -921,11 +934,8 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ current_root); /* - * Check to see if we can write into the history file. If not, - * we assume that we can't work in the repository. - * BUT, only if the history file exists. + * Check to see if the repository exists. */ - if (!client_active) { char *path; @@ -933,8 +943,7 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ path = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) - + 20 - + sizeof (CVSROOTADM_HISTORY)); + + 20); (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM); if (!isaccessible (path, R_OK | X_OK)) { @@ -945,14 +954,6 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ error (1, save_errno, "%s", path); } } - (void) strcat (path, "/"); - (void) strcat (path, CVSROOTADM_HISTORY); - if (isfile (path) && !isaccessible (path, R_OK | W_OK)) - { - save_errno = errno; - error (0, 0, "Sorry, you don't have read/write access to the history file"); - error (1, save_errno, "%s", path); - } free (path); } @@ -961,12 +962,17 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ /* FIXME (njc): should we always set this with the CVSROOT from the command line? */ if (cvs_update_env) { + static char *prev; char *env; env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1); (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot); (void) putenv (env); - /* do not free env, as putenv has control of it */ + /* do not free env yet, as putenv has control of it */ + /* but do free the previous value, if any */ + if (prev != NULL) + free (prev); + prev = env; } #endif } diff --git a/contrib/cvs/src/mkmodules.c b/contrib/cvs/src/mkmodules.c index 4244258..4e4b5d0 100644 --- a/contrib/cvs/src/mkmodules.c +++ b/contrib/cvs/src/mkmodules.c @@ -280,14 +280,23 @@ static const char *const config_contents[] = { "# Set this to \"no\" if pserver shouldn't check system users/passwords\n", "#SystemAuth=no\n", "\n", + "# Put CVS lock files in this directory rather than directly in the repository.\n", + "#LockDir=/var/lock/cvs\n", + "\n", +#ifdef PRESERVE_PERMISSIONS_SUPPORT "# Set `PreservePermissions' to `yes' to save file status information\n", "# in the repository.\n", "#PreservePermissions=no\n", "\n", +#endif "# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top\n", "# level of the new working directory when using the `cvs checkout'\n", "# command.\n", "#TopLevelAdmin=no\n", + "\n", + "# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the\n", + "# history file, or a subset as needed (ie `TMAR' logs all write operations)\n", + "#LogHistory=TOFEWGCMAR\n", NULL }; @@ -372,6 +381,9 @@ mkmodules (dir) size_t line_allocated = 0; const struct admin_file *fileptr; + if (noexec) + return 0; + if (save_cwd (&cwd)) error_exit (); @@ -865,6 +877,9 @@ init (argc, argv) if ( CVS_CHDIR (adm) < 0) error (1, errno, "cannot change to directory %s", adm); + /* Make Emptydir so it's there if we need it */ + mkdir_if_needed (CVSNULLREPOS); + /* 80 is long enough for all the administrative file names, plus "/" and so on. */ info = xmalloc (strlen (adm) + 80); @@ -926,6 +941,29 @@ init (argc, argv) fp = open_file (info, "w"); if (fclose (fp) < 0) error (1, errno, "cannot close %s", info); + + /* Make the new history file world-writeable, since every CVS + user will need to be able to write to it. We use chmod() + because xchmod() is too shy. */ + chmod (info, 0666); + } + + /* Make an empty val-tags file to prevent problems creating it later. */ + strcpy (info, adm); + strcat (info, "/"); + strcat (info, CVSROOTADM_VALTAGS); + if (!isfile (info)) + { + FILE *fp; + + fp = open_file (info, "w"); + if (fclose (fp) < 0) + error (1, errno, "cannot close %s", info); + + /* Make the new val-tags file world-writeable, since every CVS + user will need to be able to write to it. We use chmod() + because xchmod() is too shy. */ + chmod (info, 0666); } free (info); diff --git a/contrib/cvs/src/modules.c b/contrib/cvs/src/modules.c index 9907cc8..0381ec9 100644 --- a/contrib/cvs/src/modules.c +++ b/contrib/cvs/src/modules.c @@ -120,10 +120,9 @@ do_module (db, mname, m_type, msg, callback_proc, where, int modargc; int xmodargc; char **modargv; - char **xmodargv; + char **xmodargv = NULL; /* Found entry from modules file, including options and such. */ char *value = NULL; - char *zvalue = NULL; char *mwhere = NULL; char *mfile = NULL; char *spec_opt = NULL; @@ -186,25 +185,21 @@ do_module (db, mname, m_type, msg, callback_proc, where, val.dptr = NULL; if (val.dptr != NULL) { - /* null terminate the value XXX - is this space ours? */ - val.dptr[val.dsize] = '\0'; + /* copy and null terminate the value */ + value = xmalloc (val.dsize + 1); + memcpy (value, val.dptr, val.dsize); + value[val.dsize] = '\0'; /* If the line ends in a comment, strip it off */ - if ((cp = strchr (val.dptr, '#')) != NULL) - { - do - *cp-- = '\0'; - while (isspace ((unsigned char) *cp)); - } + if ((cp = strchr (value, '#')) != NULL) + *cp = '\0'; else - { - /* Always strip trailing spaces */ - cp = strchr (val.dptr, '\0'); - while (cp > val.dptr && isspace ((unsigned char) *--cp)) - *cp = '\0'; - } + cp = value + val.dsize; + + /* Always strip trailing spaces */ + while (cp > value && isspace ((unsigned char) *--cp)) + *cp = '\0'; - value = val.dptr; mwhere = xstrdup (mname); goto found; } @@ -297,7 +292,7 @@ do_module (db, mname, m_type, msg, callback_proc, where, error_exit (); cwd_saved = 1; - err += callback_proc (&modargc, modargv, where, mwhere, mfile, + err += callback_proc (modargc, modargv, where, mwhere, mfile, shorten, local_specified, mname, msg); @@ -332,17 +327,20 @@ do_module (db, mname, m_type, msg, callback_proc, where, { char *cp2; - /* null terminate the value XXX - is this space ours? */ - val.dptr[val.dsize] = '\0'; + /* copy and null terminate the value */ + value = xmalloc (val.dsize + 1); + memcpy (value, val.dptr, val.dsize); + value[val.dsize] = '\0'; /* If the line ends in a comment, strip it off */ - if ((cp2 = strchr (val.dptr, '#')) != NULL) - { - do - *cp2-- = '\0'; - while (isspace ((unsigned char) *cp2)); - } - value = val.dptr; + if ((cp2 = strchr (value, '#')) != NULL) + *cp2 = '\0'; + else + cp2 = value + val.dsize; + + /* Always strip trailing spaces */ + while (cp2 > value && isspace ((unsigned char) *--cp2)) + *cp2 = '\0'; /* mwhere gets just the module name */ mwhere = xstrdup (mname); @@ -375,11 +373,7 @@ do_module (db, mname, m_type, msg, callback_proc, where, error_exit (); cwd_saved = 1; - /* copy value to our own string since if we go recursive we'll be - really screwed if we do another dbm lookup */ assert (value != NULL); - zvalue = xstrdup (value); - value = zvalue; /* search the value for the special delimiter and save for later */ if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL) @@ -387,62 +381,9 @@ do_module (db, mname, m_type, msg, callback_proc, where, *cp = '\0'; /* null out the special char */ spec_opt = cp + 1; /* save the options for later */ - if (cp != value) /* strip whitespace if necessary */ - while (isspace ((unsigned char) *--cp)) - *cp = '\0'; - - if (cp == value) - { - /* - * we had nothing but special options, so skip arg - * parsing and regular stuff entirely - * - * If there were only special ones though, we must - * make the appropriate directory and cd to it - */ - char *dir; - - /* XXX - XXX - MAJOR HACK - DO NOT SHIP - this needs to - be !pipeout, but we don't know that here yet */ - if (!run_module_prog) - goto out; - - dir = where ? where : mname; - /* XXX - think about making null repositories at each dir here - instead of just at the bottom */ - make_directories (dir); - if ( CVS_CHDIR (dir) < 0) - { - error (0, errno, "cannot chdir to %s", dir); - spec_opt = NULL; - err++; - goto out; - } - if (!isfile (CVSADM)) - { - char *nullrepos; - - nullrepos = emptydir_name (); - - Create_Admin (".", dir, - nullrepos, (char *) NULL, (char *) NULL, 0, 0); - if (!noexec) - { - FILE *fp; - - fp = open_file (CVSADM_ENTSTAT, "w+"); - if (fclose (fp) == EOF) - error (1, errno, "cannot close %s", CVSADM_ENTSTAT); -#ifdef SERVER_SUPPORT - if (server_active) - server_set_entstat (dir, nullrepos); -#endif - } - free (nullrepos); - } - out: - goto do_special; - } + /* strip whitespace if necessary */ + while (cp > value && isspace ((unsigned char) *--cp)) + *cp = '\0'; } /* don't do special options only part of a module was specified */ @@ -460,7 +401,8 @@ do_module (db, mname, m_type, msg, callback_proc, where, /* Put the value on a line with XXX prepended for getopt to eat */ line = xmalloc (strlen (value) + 10); - (void) sprintf (line, "%s %s", "XXX", value); + strcpy(line, "XXX "); + strcpy(line + 4, value); /* turn the line into an argv[] array */ line2argv (&xmodargc, &xmodargv, line, " \t"); @@ -478,56 +420,56 @@ do_module (db, mname, m_type, msg, callback_proc, where, alias = 1; break; case 'd': - nonalias_opt = 1; if (mwhere) free (mwhere); mwhere = xstrdup (optarg); + nonalias_opt = 1; break; case 'i': - nonalias_opt = 1; if (checkin_prog) free (checkin_prog); checkin_prog = xstrdup (optarg); + nonalias_opt = 1; break; case 'l': - nonalias_opt = 1; local_specified = 1; + nonalias_opt = 1; break; case 'o': - nonalias_opt = 1; if (checkout_prog) free (checkout_prog); checkout_prog = xstrdup (optarg); + nonalias_opt = 1; break; case 'e': - nonalias_opt = 1; if (export_prog) free (export_prog); export_prog = xstrdup (optarg); + nonalias_opt = 1; break; case 't': - nonalias_opt = 1; if (tag_prog) free (tag_prog); tag_prog = xstrdup (optarg); + nonalias_opt = 1; break; case 'u': - nonalias_opt = 1; if (update_prog) free (update_prog); update_prog = xstrdup (optarg); + nonalias_opt = 1; break; case '?': error (0, 0, "modules file has invalid option for key %s value %s", - key.dptr, val.dptr); + key.dptr, value); err++; goto do_module_return; } } modargc -= optind; modargv += optind; - if (modargc == 0) + if (modargc == 0 && spec_opt == NULL) { error (0, 0, "modules file missing directory for module %s", mname); ++err; @@ -575,15 +517,66 @@ module `%s' is a request for a file in a module which is not a directory", } /* otherwise, process this module */ - err += callback_proc (&modargc, modargv, where, mwhere, mfile, shorten, - local_specified, mname, msg); + if (modargc > 0) + { + err += callback_proc (modargc, modargv, where, mwhere, mfile, shorten, + local_specified, mname, msg); + } + else + { + /* + * we had nothing but special options, so we must + * make the appropriate directory and cd to it + */ + char *dir; + + /* XXX - XXX - MAJOR HACK - DO NOT SHIP - this needs to + be !pipeout, but we don't know that here yet */ + if (!run_module_prog) + goto do_special; - free_names (&xmodargc, xmodargv); + dir = where ? where : (mwhere ? mwhere : mname); + /* XXX - think about making null repositories at each dir here + instead of just at the bottom */ + make_directories (dir); + if ( CVS_CHDIR (dir) < 0) + { + error (0, errno, "cannot chdir to %s", dir); + spec_opt = NULL; + err++; + goto do_special; + } + if (!isfile (CVSADM)) + { + char *nullrepos; + + nullrepos = emptydir_name (); + + Create_Admin (".", dir, + nullrepos, (char *) NULL, (char *) NULL, 0, 0, 1); + if (!noexec) + { + FILE *fp; + + fp = open_file (CVSADM_ENTSTAT, "w+"); + if (fclose (fp) == EOF) + error (1, errno, "cannot close %s", CVSADM_ENTSTAT); +#ifdef SERVER_SUPPORT + if (server_active) + server_set_entstat (dir, nullrepos); +#endif + } + free (nullrepos); + } + } /* if there were special include args, process them now */ do_special: + free_names (&xmodargc, xmodargv); + xmodargv = NULL; + /* blow off special options if -l was specified */ if (local_specified) spec_opt = NULL; @@ -635,7 +628,7 @@ 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 ((unsigned char) *--cp)); + while (cp > spec_opt && isspace ((unsigned char) *--cp)); } else next_opt = NULL; @@ -745,6 +738,7 @@ module `%s' is a request for a file in a module which is not a directory", cvs_output (": Executing '", 0); run_print (stdout); cvs_output ("'\n", 0); + cvs_flushout (); } err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); free (expanded_path); @@ -755,6 +749,8 @@ module `%s' is a request for a file in a module which is not a directory", do_module_return: /* clean up */ + if (xmodargv != NULL) + free_names (&xmodargc, xmodargv); if (mwhere) free (mwhere); if (checkin_prog) @@ -769,8 +765,8 @@ module `%s' is a request for a file in a module which is not a directory", free (update_prog); if (cwd_saved) free_cwd (&cwd); - if (zvalue != NULL) - free (zvalue); + if (value != NULL) + free (value); if (xvalue != NULL) free (xvalue); diff --git a/contrib/cvs/src/myndbm.c b/contrib/cvs/src/myndbm.c index f674ac1..7795f66 100644 --- a/contrib/cvs/src/myndbm.c +++ b/contrib/cvs/src/myndbm.c @@ -211,7 +211,8 @@ mydbm_load_file (fp, list) value = xmalloc (value_allocated); cont = 0; - while ((line_length = getstr (&line, &line_size, fp, '\012', 0)) >= 0) + while ((line_length = + getstr (&line, &line_size, fp, '\012', 0, GETLINE_NO_LIMIT)) >= 0) { if (line_length > 0 && line[line_length - 1] == '\012') { diff --git a/contrib/cvs/src/parseinfo.c b/contrib/cvs/src/parseinfo.c index 1c1ab70..0bf6d3c 100644 --- a/contrib/cvs/src/parseinfo.c +++ b/contrib/cvs/src/parseinfo.c @@ -10,6 +10,8 @@ #include "getline.h" #include +extern char *logHistory; + /* * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for * the first line in the file that matches the REPOSITORY, or if ALL != 0, any lines @@ -32,7 +34,7 @@ Parse_Info (infofile, repository, callproc, all) char *default_value = NULL; char *expanded_value= NULL; int callback_done, line_number; - char *cp, *exp, *value, *srepos; + char *cp, *exp, *value, *srepos, bad; const char *regex_err; if (CVSroot_original == NULL) @@ -110,10 +112,6 @@ Parse_Info (infofile, repository, callproc, all) if (expanded_value != NULL) free (expanded_value); expanded_value = expand_path (value, infofile, line_number); - if (!expanded_value) - { - continue; - } /* * At this point, exp points to the regular expression, and value @@ -127,9 +125,10 @@ Parse_Info (infofile, repository, callproc, all) { /* Is it OK to silently ignore all but the last DEFAULT expression? */ - if (default_value != NULL) + if (default_value != NULL && default_value != &bad) free (default_value); - default_value = xstrdup (expanded_value); + default_value = (expanded_value != NULL ? + xstrdup (expanded_value) : &bad); continue; } @@ -140,11 +139,13 @@ Parse_Info (infofile, repository, callproc, all) */ if (strcmp (exp, "ALL") == 0) { - if (all) - err += callproc (repository, expanded_value); - else + if (!all) error(0, 0, "Keyword `ALL' is ignored at line %d in %s file", line_number, infofile); + else if (expanded_value != NULL) + err += callproc (repository, expanded_value); + else + err++; continue; } @@ -163,7 +164,10 @@ Parse_Info (infofile, repository, callproc, all) continue; /* no match */ /* it did, so do the callback and note that we did one */ - err += callproc (repository, expanded_value); + if (expanded_value != NULL) + err += callproc (repository, expanded_value); + else + err++; callback_done = 1; } if (ferror (fp_info)) @@ -173,10 +177,15 @@ Parse_Info (infofile, repository, callproc, all) /* if we fell through and didn't callback at all, do the default */ if (callback_done == 0 && default_value != NULL) - err += callproc (repository, default_value); + { + if (default_value != &bad) + err += callproc (repository, default_value); + else + err++; + } /* free up space if necessary */ - if (default_value != NULL) + if (default_value != NULL && default_value != &bad) free (default_value); if (expanded_value != NULL) free (expanded_value); @@ -367,6 +376,14 @@ warning: this CVS does not support PreservePermissions"); opendir it or something, but I don't see any particular reason to do that now rather than waiting until lock.c. */ } + else if (strcmp (line, "LogHistory") == 0) + { + if (strcmp (p, "all") != 0) + { + logHistory=malloc(strlen (p) + 1); + strcpy (logHistory, p); + } + } else { /* We may be dealing with a keyword which was added in a diff --git a/contrib/cvs/src/patch.c b/contrib/cvs/src/patch.c index f16a331..9aa26f3 100644 --- a/contrib/cvs/src/patch.c +++ b/contrib/cvs/src/patch.c @@ -20,7 +20,7 @@ static Dtype patch_dirproc PROTO ((void *callerdat, char *dir, char *repos, char *update_dir, List *entries)); static int patch_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int patch_proc PROTO((int *pargc, char **argv, char *xwhere, +static int patch_proc PROTO((int argc, char **argv, char *xwhere, char *mwhere, char *mfile, int shorten, int local_specified, char *mname, char *msg)); @@ -230,6 +230,9 @@ patch (argc, argv) #endif /* clean up if we get a signal */ +#ifdef SIGABRT + (void) SIG_register (SIGABRT, patch_cleanup); +#endif #ifdef SIGHUP (void) SIG_register (SIGHUP, patch_cleanup); #endif @@ -261,9 +264,9 @@ patch (argc, argv) */ /* ARGSUSED */ static int -patch_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, +patch_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, mname, msg) - int *pargc; + int argc; char **argv; char *xwhere; char *mwhere; @@ -273,6 +276,7 @@ patch_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, char *mname; char *msg; { + char *myargv[2]; int err = 0; int which; char *repository; @@ -314,13 +318,10 @@ patch_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, } else { - int i; - - /* a file means muck argv */ - for (i = 1; i < *pargc; i++) - free (argv[i]); - argv[1] = xstrdup (mfile); - (*pargc) = 2; + myargv[0] = argv[0]; + myargv[1] = mfile; + argc = 2; + argv = myargv; } free (path); } @@ -341,19 +342,19 @@ patch_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, if (rev1 != NULL && !rev1_validated) { - tag_check_valid (rev1, *pargc - 1, argv + 1, local, 0, NULL); + tag_check_valid (rev1, argc - 1, argv + 1, local, 0, NULL); rev1_validated = 1; } if (rev2 != NULL && !rev2_validated) { - tag_check_valid (rev2, *pargc - 1, argv + 1, local, 0, NULL); + tag_check_valid (rev2, argc - 1, argv + 1, local, 0, NULL); rev2_validated = 1; } /* start the recursion processor */ err = start_recursion (patch_fileproc, (FILESDONEPROC) NULL, patch_dirproc, (DIRLEAVEPROC) NULL, NULL, - *pargc - 1, argv + 1, local, + argc - 1, argv + 1, local, which, 0, 1, where, 1); free (where); @@ -735,6 +736,10 @@ failed to read diff file header %s for %s: end of file", tmpfile3, rcs); tmpfile1 = tmpfile2 = tmpfile3 = NULL; out2: + if (vers_tag != NULL) + free (vers_tag); + if (vers_head != NULL) + free (vers_head); if (rcs != NULL) free (rcs); return (ret); diff --git a/contrib/cvs/src/rcs.c b/contrib/cvs/src/rcs.c index 64524b1..b28572c 100644 --- a/contrib/cvs/src/rcs.c +++ b/contrib/cvs/src/rcs.c @@ -60,6 +60,7 @@ static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp, static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp)); static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp, char **valp)); +static int rcsbuf_valcmp PROTO ((struct rcsbuffer *)); static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish, size_t *lenp)); static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish, @@ -154,6 +155,7 @@ static const char spacetab[] = { #define whitespace(c) (spacetab[(unsigned char)c] != 0) static char *rcs_lockfile; +static int rcs_lockfd = -1; /* A few generic thoughts on error handling, in particular the printing of unexpected characters that we find in the RCS file @@ -542,9 +544,10 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp) if (rdata->other == NULL) rdata->other = getlist (); kv = getnode (); - kv->type = RCSFIELD; + kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD; kv->key = xstrdup (key); - kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL); + kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, + (size_t *) NULL); if (addnode (rdata->other, kv) != 0) { error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", @@ -590,9 +593,7 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp) key, rcsfile); free (rdata->desc); } - /* Don't need to rcsbuf_valcopy `value' because - getdelta already did that. */ - rdata->desc = xstrdup (value); + rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL); } rdata->delta_pos = rcsbuf_ftell (&rcsbuf); @@ -748,9 +749,10 @@ RCS_fully_parse (rcs) if (vnode->other == NULL) vnode->other = getlist (); kv = getnode (); - kv->type = RCSFIELD; + kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD; kv->key = xstrdup (key); - kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL); + kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, + (size_t *) NULL); if (addnode (vnode->other, kv) != 0) { error (0, 0, @@ -1028,6 +1030,9 @@ rcsbuf_close (rcsbuf) characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do appropriate massaging. */ +/* Note that the extreme hair in rcsbuf_getkey is because profiling + statistics show that it was worth it. */ + static int rcsbuf_getkey (rcsbuf, keyp, valp) struct rcsbuffer *rcsbuf; @@ -1283,13 +1288,10 @@ rcsbuf_getkey (rcsbuf, keyp, valp) } /* The value extends past the '@' string. We need to undo the - closing of the '@' done in the default case above. This + '@' stripping done in the default case above. This case never happens in a plain RCS file, but it can happen if user defined phrases are used. */ - if (rcsbuf->vlen != 0) - (*valp)[rcsbuf->vlen] = ' '; - else - *valp = ptr; + ((*valp)--)[rcsbuf->vlen++] = '@'; } /* Here we have a value which is not a simple '@' string. We need @@ -1328,459 +1330,47 @@ rcsbuf_getkey (rcsbuf, keyp, valp) { size_t vlen; - /* We're done with the value. Trim any trailing - whitespace. */ - - rcsbuf->ptr = psemi + 1; - - start = *valp; - while (psemi > start && my_whitespace (psemi[-1])) - --psemi; - *psemi = '\0'; - - vlen = psemi - start; - if (vlen == 0) - *valp = NULL; - rcsbuf->vlen = vlen; - - return 1; - } - - /* We found an '@' string in the value. We set - RCSBUF->AT_STRING, which means that we won't be able to - compress whitespace correctly for this type of value. - Since this type of value never arises in a normal RCS file, - this should not be a big deal. It means that if anybody - adds a phrase which can have both an '@' string and regular - text, they will have to handle whitespace compression - themselves. */ - - rcsbuf->at_string = 1; - - *pat = ' '; - - ptr = pat + 1; - - while (1) - { - while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) - { - /* Note that we pass PTREND as the PTR value to - rcsbuff_fill, so that we will wind up setting PTR - to the location corresponding to the old PTREND, so - that we don't search the same bytes again. */ - ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); - if (ptr == NULL) - error (1, 0, - "EOF while looking for end of string in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - /* Handle the special case of an '@' right at the end of - the known bytes. */ - if (pat + 1 >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp); - if (ptr == NULL) - error (1, 0, "EOF in value in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - if (pat[1] != '@') - break; - - /* We found an '@' pair in the string. Keep looking. */ - ++rcsbuf->embedded_at; - ptr = pat + 2; - } - - /* Here PAT points to the final '@' in the string. */ - - *pat = ' '; - - ptr = pat + 1; - } - -#undef my_whitespace -} - -/* TODO: Eliminate redundant code in rcsbuf_getkey, rcsbuf_getid, - rcsbuf_getstring, rcsbuf_getword. These last three functions were - all created by hacking monstrous swaths of code from rcsbuf_getkey, - and some engineering would make the code easier to read and - maintain. - - Note that the extreme hair in rcsbuf_getkey is because profiling - statistics show that it was worth it. - - We probably could be processing "hardlinks" by first calling - rcsbuf_getkey, and breaking up the value afterwards; the code to - break it up would not need to be hacked for speed. This would - remove the need for rcsbuf_getword, rcsbuf_getid, and - rcsbuf_getstring, as the other calls are easy to remove. */ - -/* Read an `id' (in the sense of rcsfile(5)) from RCSBUF, and store in - IDP. */ - -static int -rcsbuf_getid (rcsbuf, idp) - struct rcsbuffer *rcsbuf; - char **idp; -{ - register const char * const my_spacetab = spacetab; - register char *ptr, *ptrend; - char c; - -#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) - - rcsbuf->vlen = 0; - rcsbuf->at_string = 0; - rcsbuf->embedded_at = 0; - - ptr = rcsbuf->ptr; - ptrend = rcsbuf->ptrend; - - /* Sanity check. */ - if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size) - abort (); - - /* If the pointer is more than RCSBUF_BUFSIZE bytes into the - buffer, move back to the start of the buffer. This keeps the - buffer from growing indefinitely. */ - if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE) - { - int len; - - len = ptrend - ptr; - - /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes - at a time, so we can't have more bytes than that past PTR. */ - if (len > RCSBUF_BUFSIZE) - abort (); - - /* Update the POS field, which holds the file offset of the - first byte in the RCSBUF_BUFFER buffer. */ - rcsbuf->pos += ptr - rcsbuf_buffer; - - memcpy (rcsbuf_buffer, ptr, len); - ptr = rcsbuf_buffer; - ptrend = ptr + len; - rcsbuf->ptrend = ptrend; - } - - /* Skip leading whitespace. */ - - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL); - if (ptr == NULL) - return 0; - ptrend = rcsbuf->ptrend; - } - - c = *ptr; - if (! my_whitespace (c)) - break; - - ++ptr; - } - - /* We've found the start of the key. */ - - *idp = ptr; - - if (c != ';') - { - while (1) - { - ++ptr; - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, idp, (char **) NULL); - if (ptr == NULL) - error (1, 0, "EOF in key in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - c = *ptr; - if (c == ';' || my_whitespace (c)) - break; - } - } - - /* Here *IDP points to the id in the buffer, C is the character - we found at the end of the key, and PTR points to the location in - the buffer where we found C. We may not set *PTR to \0, because - it may overwrite a terminating semicolon. The calling function - must copy and terminate the id on its own. */ - - rcsbuf->ptr = ptr; - return 1; - -#undef my_whitespace -} - -/* Read an RCS @-delimited string. Store the result in STRP. */ - -static int -rcsbuf_getstring (rcsbuf, strp) - struct rcsbuffer *rcsbuf; - char **strp; -{ - register const char * const my_spacetab = spacetab; - register char *ptr, *ptrend; - char *pat; - size_t vlen; - char c; - -#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) - - rcsbuf->vlen = 0; - rcsbuf->at_string = 0; - rcsbuf->embedded_at = 0; - - ptr = rcsbuf->ptr; - ptrend = rcsbuf->ptrend; - - /* Sanity check. */ - if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size) - abort (); - - /* If the pointer is more than RCSBUF_BUFSIZE bytes into the - buffer, move back to the start of the buffer. This keeps the - buffer from growing indefinitely. */ - if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE) - { - int len; - - len = ptrend - ptr; - - /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes - at a time, so we can't have more bytes than that past PTR. */ - if (len > RCSBUF_BUFSIZE) - abort (); - - /* Update the POS field, which holds the file offset of the - first byte in the RCSBUF_BUFFER buffer. */ - rcsbuf->pos += ptr - rcsbuf_buffer; - - memcpy (rcsbuf_buffer, ptr, len); - ptr = rcsbuf_buffer; - ptrend = ptr + len; - rcsbuf->ptrend = ptrend; - } - - /* Skip leading whitespace. */ - - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL); - if (ptr == NULL) - error (1, 0, "unexpected end of file reading %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - c = *ptr; - if (! my_whitespace (c)) - break; - - ++ptr; - } - - /* PTR should now point to the start of a string. */ - if (c != '@') - error (1, 0, "expected @-string at '\\x%x' in %s", - c, rcsbuf->filename); - - /* Optimize the common case of a value composed of a single - '@' string. */ - - rcsbuf->at_string = 1; - - ++ptr; - - *strp = ptr; - - while (1) - { - while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) - { - /* Note that we pass PTREND as the PTR value to - rcsbuf_fill, so that we will wind up setting PTR to - the location corresponding to the old PTREND, so - that we don't search the same bytes again. */ - ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, strp); - if (ptr == NULL) - error (1, 0, - "EOF while looking for end of string in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - /* Handle the special case of an '@' right at the end of - the known bytes. */ - if (pat + 1 >= ptrend) - { - /* Note that we pass PAT, not PTR, here. */ - pat = rcsbuf_fill (rcsbuf, pat, NULL, strp); - if (pat == NULL) - { - /* EOF here is OK; it just means that the last - character of the file was an '@' terminating a - value for a key type which does not require a - trailing ';'. */ - pat = rcsbuf->ptrend - 1; - - } - ptrend = rcsbuf->ptrend; - - /* Note that the value of PTR is bogus here. This is - OK, because we don't use it. */ - } - - if (pat + 1 >= ptrend || pat[1] != '@') - break; - - /* We found an '@' pair in the string. Keep looking. */ - ++rcsbuf->embedded_at; - ptr = pat + 2; - } - - /* Here PAT points to the final '@' in the string. */ - - *pat = '\0'; - - vlen = pat - *strp; - if (vlen == 0) - *strp = NULL; - rcsbuf->vlen = vlen; - rcsbuf->ptr = pat + 1; - - return 1; - -#undef my_whitespace -} - -/* Read an RCS `word', in the sense of rcsfile(5) (an id, a num, a - @-delimited string, or `:'). Store the result in WORDP. If a - `;' is reached without reading any text, the result is NULL. */ - -static int -rcsbuf_getword (rcsbuf, wordp) - struct rcsbuffer *rcsbuf; - char **wordp; -{ - register const char * const my_spacetab = spacetab; - register char *ptr, *ptrend; - char c; - -#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) - - rcsbuf->vlen = 0; - rcsbuf->at_string = 0; - rcsbuf->embedded_at = 0; - - ptr = rcsbuf->ptr; - ptrend = rcsbuf->ptrend; - - /* Sanity check. */ - if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size) - abort (); - - /* If the pointer is more than RCSBUF_BUFSIZE bytes into the - buffer, move back to the start of the buffer. This keeps the - buffer from growing indefinitely. */ - if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE) - { - int len; - - len = ptrend - ptr; - - /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes - at a time, so we can't have more bytes than that past PTR. */ - if (len > RCSBUF_BUFSIZE) - abort (); - - /* Update the POS field, which holds the file offset of the - first byte in the RCSBUF_BUFFER buffer. */ - rcsbuf->pos += ptr - rcsbuf_buffer; - - memcpy (rcsbuf_buffer, ptr, len); - ptr = rcsbuf_buffer; - ptrend = ptr + len; - rcsbuf->ptrend = ptrend; - } - - /* Skip leading whitespace. */ - - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL); - if (ptr == NULL) - error (1, 0, "unexpected end of file reading %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - c = *ptr; - if (! my_whitespace (c)) - break; - - ++ptr; - } + /* We're done with the value. Trim any trailing + whitespace. */ - /* If we have reached `;', there is no value. */ - if (c == ';') - { - *wordp = NULL; - *ptr++ = '\0'; - rcsbuf->ptr = ptr; - rcsbuf->vlen = 0; - return 1; - } + rcsbuf->ptr = psemi + 1; - /* PTR now points to the start of a value. Find out whether it is - a num, an id, a string or a colon. */ - if (c == ':') - { - *wordp = ptr++; - rcsbuf->ptr = ptr; - rcsbuf->vlen = 1; - return 1; - } + start = *valp; + while (psemi > start && my_whitespace (psemi[-1])) + --psemi; + *psemi = '\0'; - if (c == '@') - { - char *pat; - size_t vlen; + vlen = psemi - start; + if (vlen == 0) + *valp = NULL; + rcsbuf->vlen = vlen; - /* Optimize the common case of a value composed of a single - '@' string. */ + return 1; + } - rcsbuf->at_string = 1; + /* We found an '@' string in the value. We set RCSBUF->AT_STRING + and RCSBUF->EMBEDDED_AT to indicate that we won't be able to + compress whitespace correctly for this type of value. + Since this type of value never arises in a normal RCS file, + this should not be a big deal. It means that if anybody + adds a phrase which can have both an '@' string and regular + text, they will have to handle whitespace compression + themselves. */ - ++ptr; + rcsbuf->at_string = 1; + rcsbuf->embedded_at = -1; - *wordp = ptr; + ptr = pat + 1; while (1) { while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) { /* Note that we pass PTREND as the PTR value to - rcsbuf_fill, so that we will wind up setting PTR to - the location corresponding to the old PTREND, so + rcsbuff_fill, so that we will wind up setting PTR + to the location corresponding to the old PTREND, so that we don't search the same bytes again. */ - ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, wordp); + ptr = rcsbuf_fill (rcsbuf, ptrend, keyp, valp); if (ptr == NULL) error (1, 0, "EOF while looking for end of string in RCS file %s", @@ -1792,92 +1382,24 @@ rcsbuf_getword (rcsbuf, wordp) the known bytes. */ if (pat + 1 >= ptrend) { - /* Note that we pass PAT, not PTR, here. */ - pat = rcsbuf_fill (rcsbuf, pat, NULL, wordp); - if (pat == NULL) - { - /* EOF here is OK; it just means that the last - character of the file was an '@' terminating a - value for a key type which does not require a - trailing ';'. */ - pat = rcsbuf->ptrend - 1; - - } + ptr = rcsbuf_fill (rcsbuf, ptr, keyp, valp); + if (ptr == NULL) + error (1, 0, "EOF in value in RCS file %s", + rcsbuf->filename); ptrend = rcsbuf->ptrend; - - /* Note that the value of PTR is bogus here. This is - OK, because we don't use it. */ } - if (pat + 1 >= ptrend || pat[1] != '@') + if (pat[1] != '@') break; /* We found an '@' pair in the string. Keep looking. */ - ++rcsbuf->embedded_at; ptr = pat + 2; } /* Here PAT points to the final '@' in the string. */ - - *pat = '\0'; - - vlen = pat - *wordp; - if (vlen == 0) - *wordp = NULL; - rcsbuf->vlen = vlen; - rcsbuf->ptr = pat + 1; - - return 1; - } - - /* C is neither `:', `;' nor `@', so it should be the start of a num - or an id. Make sure it is not another special character. */ - if (c == '$' || c == '.' || c == ',') - { - error (1, 0, "illegal special character in RCS field in %s", - rcsbuf->filename); - } - - *wordp = ptr; - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, wordp); - if (ptr == NULL) - error (1, 0, "unexpected end of file reading %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - /* Legitimate ID characters are digits, dots and any `graphic - printing character that is not a special.' This test ought - to do the trick. */ - c = *ptr; - if (isprint ((unsigned char) c) && - c != ';' && c != '$' && c != ',' && c != '@' && c != ':') - { - ++ptr; - continue; - } - break; - } - - /* PTR points to the last non-id character in this word, and C is - the character in its memory cell. Check to make sure that it - is a legitimate word delimiter -- whitespace or semicolon. */ - if (c == ';' || my_whitespace (c)) - { - rcsbuf->vlen = ptr - *wordp; - rcsbuf->ptr = ptr; - return 1; + ptr = pat + 1; } - error (1, 0, "illegal special character in RCS field in %s", - rcsbuf->filename); - /* Shut up compiler warnings. */ - return 0; - #undef my_whitespace } @@ -1984,6 +1506,8 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp) koff = *keyp - rcsbuf_buffer; if (valp != NULL && *valp != NULL) voff = *valp - rcsbuf_buffer; + koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer; + voff = valp == NULL ? 0 : *valp - rcsbuf_buffer; expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, rcsbuf_buffer_size + RCSBUF_BUFSIZE); @@ -2009,6 +1533,16 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp) return ptr; } +/* Test whether the last value returned by rcsbuf_getkey is a composite + value or not. */ + +static int +rcsbuf_valcmp (rcsbuf) + struct rcsbuffer *rcsbuf; +{ + return rcsbuf->at_string && rcsbuf->embedded_at < 0; +} + /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer, returning the memory buffer. Polish the value like rcsbuf_valpolish, q.v. */ @@ -2032,7 +1566,7 @@ rcsbuf_valcopy (rcsbuf, val, polish, lenp) } vlen = rcsbuf->vlen; - embedded_at = rcsbuf->embedded_at; + embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at; ret = xmalloc (vlen - embedded_at + 1); @@ -2139,6 +1673,7 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp) orig_to = to; embedded_at = rcsbuf->embedded_at; + assert (embedded_at > 0); if (lenp != NULL) *lenp = len - embedded_at; @@ -2187,6 +1722,112 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp) } } +#ifdef PRESERVE_PERMISSIONS_SUPPORT + +/* Copy the next word from the value VALP returned by rcsbuf_getkey into a + memory buffer, updating VALP and returning the memory buffer. Return + NULL when there are no more words. */ + +static char * +rcsbuf_valword (rcsbuf, valp) + struct rcsbuffer *rcsbuf; + char **valp; +{ + register const char * const my_spacetab = spacetab; + register char *ptr, *pat; + char c; + +#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) + + if (*valp == NULL) + return NULL; + + for (ptr = *valp; my_whitespace (*ptr); ++ptr) ; + if (*ptr == '\0') + { + assert (ptr - *valp == rcsbuf->vlen); + *valp = NULL; + rcsbuf->vlen = 0; + return NULL; + } + + /* PTR now points to the start of a value. Find out whether it is + a num, an id, a string or a colon. */ + c = *ptr; + if (c == ':') + { + rcsbuf->vlen -= ++ptr - *valp; + *valp = ptr; + return xstrdup (":"); + } + + if (c == '@') + { + int embedded_at = 0; + size_t vlen; + + pat = ++ptr; + while ((pat = strchr (pat, '@')) != NULL) + { + if (pat[1] != '@') + break; + ++embedded_at; + pat += 2; + } + + /* Here PAT points to the final '@' in the string. */ + *pat++ = '\0'; + assert (rcsbuf->at_string); + vlen = rcsbuf->vlen - (pat - *valp); + rcsbuf->vlen = pat - ptr - 1; + rcsbuf->embedded_at = embedded_at; + ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL); + *valp = pat; + rcsbuf->vlen = vlen; + if (strchr (pat, '@') == NULL) + rcsbuf->at_string = 0; + else + rcsbuf->embedded_at = -1; + return ptr; + } + + /* *PTR is neither `:', `;' nor `@', so it should be the start of a num + or an id. Make sure it is not another special character. */ + if (c == '$' || c == '.' || c == ',') + { + error (1, 0, "illegal special character in RCS field in %s", + rcsbuf->filename); + } + + pat = ptr; + while (1) + { + /* Legitimate ID characters are digits, dots and any `graphic + printing character that is not a special.' This test ought + to do the trick. */ + c = *++pat; + if (!isprint ((unsigned char) c) || + c == ';' || c == '$' || c == ',' || c == '@' || c == ':') + break; + } + + /* PAT points to the last non-id character in this word, and C is + the character in its memory cell. Check to make sure that it + is a legitimate word delimiter -- whitespace or end. */ + if (c != '\0' && !my_whitespace (c)) + error (1, 0, "illegal special character in RCS field in %s", + rcsbuf->filename); + + *pat = '\0'; + rcsbuf->vlen -= pat - *valp; + *valp = pat; + return xstrdup (ptr); + +#undef my_whitespace +} + +#endif + /* Return the current position of an rcsbuf. */ static unsigned long @@ -2864,8 +2505,8 @@ RCS_nodeisbranch (rcs, rev) return (1); } free (magic); - free (version); } + free (version); return (0); } @@ -2914,8 +2555,8 @@ RCS_whatbranch (rcs, rev) return (magic); } free (magic); - free (version); } + free (version); return ((char *) NULL); } @@ -4067,6 +3708,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) uses for ci -k. */ if (kw == KEYWORD_LOG && (sizeof "checked in with -k by " <= loglen + || log == NULL || strncmp (log, "checked in with -k by ", sizeof "checked in with -k by " - 1) != 0)) { @@ -4085,6 +3727,10 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) if (expand != KFLAG_V) ++s; + /* CVS never has empty log messages, but old RCS files might. */ + if (log == NULL) + log = ""; + /* Find the start of the line. */ start = srch; while (start > buf && start[-1] != '\n') @@ -4655,6 +4301,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) #ifdef PRESERVE_PERMISSIONS_SUPPORT else if (special_file) { +#ifdef HAVE_MKNOD char *dest; /* Can send either to WORKFILE or to SOUT, as long as SOUT is @@ -4675,6 +4322,11 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) if (mknod (dest, special_file, devnum) < 0) error (1, errno, "could not create special file %s", dest); +#else + error (1, 0, +"cannot create %s: unable to create special files on this system", +workfile); +#endif } #endif else @@ -5038,8 +4690,10 @@ RCS_addbranch (rcs, branch) if (nodep == NULL) { error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint); + free (branchpoint); return NULL; } + free (branchpoint); branchnode = (RCSVers *) nodep->data; /* If BRANCH was a full branch number, make sure it is higher than MAX. */ @@ -5241,6 +4895,7 @@ RCS_checkin (rcs, workfile, message, rev, flags) if (S_ISLNK (sb.st_mode)) { np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("symlink"); np->data = xreadlink (workfile); addnode (delta->other_delta, np); @@ -5249,18 +4904,21 @@ RCS_checkin (rcs, workfile, message, rev, flags) { (void) sprintf (buf, "%u", sb.st_uid); np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("owner"); np->data = xstrdup (buf); addnode (delta->other_delta, np); (void) sprintf (buf, "%u", sb.st_gid); np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("group"); np->data = xstrdup (buf); addnode (delta->other_delta, np); (void) sprintf (buf, "%o", sb.st_mode & 07777); np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("permissions"); np->data = xstrdup (buf); addnode (delta->other_delta, np); @@ -5271,7 +4929,9 @@ RCS_checkin (rcs, workfile, message, rev, flags) case S_IFREG: break; case S_IFCHR: case S_IFBLK: +#ifdef HAVE_ST_RDEV np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("special"); sprintf (buf, "%s %lu", ((sb.st_mode & S_IFMT) == S_IFCHR @@ -5279,6 +4939,11 @@ RCS_checkin (rcs, workfile, message, rev, flags) (unsigned long) sb.st_rdev); np->data = xstrdup (buf); addnode (delta->other_delta, np); +#else + error (0, 0, +"can't preserve %s: unable to save device files on this system", +workfile); +#endif break; default: @@ -5323,8 +4988,9 @@ RCS_checkin (rcs, workfile, message, rev, flags) delta->version = xstrdup (newrev); nodep = getnode(); nodep->type = RCSVERS; - nodep->key = xstrdup (newrev); + nodep->delproc = rcsvers_delproc; nodep->data = (char *) delta; + nodep->key = delta->version; (void) addnode (rcs->versions, nodep); dtext->version = xstrdup (newrev); @@ -5358,7 +5024,6 @@ RCS_checkin (rcs, workfile, message, rev, flags) error (1, errno, "cannot ftell for %s", rcs->path); putdeltatext (fout, dtext); rcs_internal_unlockfile (fout, rcs->path); - freedeltatext (dtext); if ((flags & RCS_FLAGS_KEEPFILE) == 0) { @@ -5370,7 +5035,8 @@ RCS_checkin (rcs, workfile, message, rev, flags) if (!checkin_quiet) cvs_output ("done\n", 5); - return 0; + status = 0; + goto checkin_done; } /* Derive a new revision number. From the `ci' man page: @@ -5466,6 +5132,13 @@ RCS_checkin (rcs, workfile, message, rev, flags) goto checkin_done; } delta->version = RCS_addbranch (rcs, branch); + if (!delta->version) + { + free (branch); + free (newrev); + status = 1; + goto checkin_done; + } adding_branch = 1; p = strrchr (branch, '.'); *p = '\0'; @@ -5690,8 +5363,9 @@ RCS_checkin (rcs, workfile, message, rev, flags) rcs->versions = getlist(); nodep = getnode(); nodep->type = RCSVERS; - nodep->key = xstrdup (delta->version); + nodep->delproc = rcsvers_delproc; nodep->data = (char *) delta; + nodep->key = delta->version; (void) addnode (rcs->versions, nodep); /* Write the new RCS file, inserting the new delta at COMMITPT. */ @@ -5714,8 +5388,10 @@ RCS_checkin (rcs, workfile, message, rev, flags) } if (unlink_file (tmpfile) < 0) error (0, errno, "cannot remove %s", tmpfile); + free (tmpfile); if (unlink_file (changefile) < 0) error (0, errno, "cannot remove %s", changefile); + free (changefile); if (!checkin_quiet) cvs_output ("done\n", 5); @@ -5798,6 +5474,7 @@ RCS_cmp_file (rcs, rev, options, filename) retcode = xcmp (tmp, filename); if (CVS_UNLINK (tmp) < 0) error (0, errno, "cannot remove %s", tmp); + free (tmp); return retcode; } else @@ -6158,17 +5835,14 @@ RCS_unlock (rcs, rev, unlock_quiet) lock = NULL; for (p = locks->list->next; p != locks->list; p = p->next) { - if (STREQ (p->data, user)) + if (lock != NULL) { - if (lock != NULL) - { - if (!unlock_quiet) - error (0, 0, "\ + if (!unlock_quiet) + error (0, 0, "\ %s: multiple revisions locked by %s; please specify one", rcs->path, user); - return 1; - } - lock = p; + return 1; } + lock = p; } if (lock == NULL) return 0; /* no lock found, ergo nothing to do */ @@ -6248,6 +5922,7 @@ RCS_addaccess (rcs, user) return; } } + free (access); rcs->access = (char *) xrealloc (rcs->access, strlen (rcs->access) + strlen (user) + 2); strcat (rcs->access, " "); @@ -6271,13 +5946,19 @@ RCS_delaccess (rcs, user) if (rcs->access == NULL) return; + if (user == NULL) + { + free (rcs->access); + rcs->access = NULL; + return; + } + p = rcs->access; ulen = strlen (user); while (p != NULL) { - if (p[ulen] == '\0' || p[ulen] == ' ') - if (strncmp (p, user, ulen) == 0) - break; + if (strncmp (p, user, ulen) == 0 && (p[ulen] == '\0' || p[ulen] == ' ')) + break; p = strchr (p, ' '); if (p != NULL) ++p; @@ -7676,7 +7357,7 @@ getdelta (rcsbuf, rcsfile, keyp, valp) char **valp; { RCSVers *vnode; - char *key, *value, *keybuf, *valbuf, *cp; + char *key, *value, *cp; Node *kv; /* Get revision number if it wasn't passed in. This uses @@ -7794,81 +7475,32 @@ unable to parse %s; `state' not in the expected place", rcsfile); */ while (1) { - int len; - size_t valbuflen; - - key = NULL; - - if (! rcsbuf_getid (rcsbuf, &keybuf)) + if (! rcsbuf_getkey (rcsbuf, &key, &value)) error (1, 0, "unexpected end of file reading %s", rcsfile); - /* rcsbuf_getid did not terminate the key, so copy it to new space. */ - len = rcsbuf->ptr - keybuf; - key = (char *) xmalloc (sizeof(char) * (len + 1)); - strncpy (key, keybuf, len); - key[len] = '\0'; - - /* The `desc' keyword has only a single string value, with no - trailing semicolon, so it must be handled specially. */ - if (STREQ (key, RCSDESC)) - { - (void) rcsbuf_getstring (rcsbuf, &valbuf); - value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen); + /* The `desc' keyword is the end of the deltas. */ + if (strcmp (key, RCSDESC) == 0) break; - } #ifdef PRESERVE_PERMISSIONS_SUPPORT + /* The `hardlinks' value is a group of words, which must be parsed separately and added as a list to vnode->hardlinks. */ - if (STREQ (key, "hardlinks")) + if (strcmp (key, "hardlinks") == 0) { - Node *n; + char *word; vnode->hardlinks = getlist(); - while (1) + while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL) { - if (! rcsbuf_getword (rcsbuf, &valbuf)) - error (1, 0, "unexpected end of file reading %s", rcsfile); - if (valbuf == NULL) - break; - n = getnode(); - n->key = rcsbuf_valcopy (rcsbuf, valbuf, 1, NULL); + Node *n = getnode(); + n->key = word; addnode (vnode->hardlinks, n); } continue; } #endif - /* Get the value. */ - value = NULL; - while (1) - { - if (! rcsbuf_getword (rcsbuf, &valbuf)) - error (1, 0, "unexpected end of file reading %s", rcsfile); - if (valbuf == NULL) - break; - - /* Copy valbuf to new space so we can polish it, then - append it to value. */ - - if (value == NULL) - { - value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen); - } - else - { - char *temp_value; - - temp_value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen); - len = strlen (value); - value = (char *) xrealloc - (value, sizeof(char) * (len + valbuflen + 2)); - value[len] = ' '; - strcpy (value + len + 1, temp_value); - free (temp_value); - } - } - /* Enable use of repositories created by certain obsolete versions of CVS. This code should remain indefinately; there is no procedure for converting old repositories, and @@ -7897,9 +7529,10 @@ unable to parse %s; `state' not in the expected place", rcsfile); if (vnode->other_delta == NULL) vnode->other_delta = getlist (); kv = getnode (); - kv->type = RCSFIELD; - kv->key = key; - kv->data = value; + kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; + kv->key = xstrdup (key); + kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, + (size_t *) NULL); if (addnode (vnode->other_delta, kv) != 0) { /* Complaining about duplicate keys in newphrases seems @@ -7984,9 +7617,10 @@ RCS_getdeltatext (rcs, fp, rcsbuf) break; p = getnode(); - p->type = RCSFIELD; + p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; p->key = xstrdup (key); - p->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL); + p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, + (size_t *) NULL); if (addnode (d->other, p) < 0) { error (0, 0, "warning: %s, delta %s: duplicate field `%s'", @@ -8067,8 +7701,8 @@ putrcsfield_proc (node, vfp) A case where we are wrong in a much more clear-cut way is that we let through non-graphic characters such as whitespace and control characters. */ - int n = strcspn (node->data, "$,.:;@"); - if (node->data[n] == 0) + + if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL) fputs (node->data, fp); else { @@ -8229,7 +7863,13 @@ RCS_putdtree (rcs, rev, fp) /* Find the delta node for this revision. */ p = findnode (rcs->versions, rev); - assert (p != NULL); + if (p == NULL) + { + error (1, 0, + "error parsing repository file %s, file may be corrupt.", + rcs->path); + } + versp = (RCSVers *) p->data; /* Print the delta node and recurse on its `next' node. This prints @@ -8350,6 +7990,7 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt) /* If this revision has been outdated, just skip it. */ if (dadmin->outdated) { + freedeltatext (dtext); --actions; continue; } @@ -8469,7 +8110,7 @@ count_delta_actions (np, ignore) /* * Clean up temporary files */ -static RETSIGTYPE +RETSIGTYPE rcs_cleanup () { /* Note that the checks for existence_error are because we are @@ -8483,11 +8124,18 @@ rcs_cleanup () of a just-created file) reentrancy won't be an issue. */ if (rcs_lockfile != NULL) { - if (unlink_file (rcs_lockfile) < 0 + char *tmp = rcs_lockfile; + rcs_lockfile = NULL; + if (rcs_lockfd >= 0) + { + if (close (rcs_lockfd) != 0) + error (0, errno, "error closing lock file %s", tmp); + rcs_lockfd = -1; + } + if (unlink_file (tmp) < 0 && !existence_error (errno)) - error (0, errno, "cannot remove %s", rcs_lockfile); + error (0, errno, "cannot remove %s", tmp); } - rcs_lockfile = NULL; } /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style @@ -8521,7 +8169,6 @@ static FILE * rcs_internal_lockfile (rcsfile) char *rcsfile; { - int fd; struct stat rstat; FILE *fp; static int first_call = 1; @@ -8530,6 +8177,9 @@ rcs_internal_lockfile (rcsfile) { first_call = 0; /* clean up if we get a signal */ +#ifdef SIGABRT + (void) SIG_register (SIGABRT, rcs_cleanup); +#endif #ifdef SIGHUP (void) SIG_register (SIGHUP, rcs_cleanup); #endif @@ -8549,6 +8199,7 @@ rcs_internal_lockfile (rcsfile) /* Get the lock file name: `,file,' for RCS file `file,v'. */ assert (rcs_lockfile == NULL); + assert (rcs_lockfd < 0); rcs_lockfile = rcs_lockfilename (rcsfile); /* Use the existing RCS file mode, or read-only if this is a new @@ -8575,11 +8226,11 @@ rcs_internal_lockfile (rcsfile) rely on O_EXCL these days. This might be true for unix (I don't really know), but I am still pretty skeptical in the case of the non-unix systems. */ - fd = open (rcs_lockfile, - OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, - S_IRUSR | S_IRGRP | S_IROTH); + rcs_lockfd = open (rcs_lockfile, + OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, + S_IRUSR | S_IRGRP | S_IROTH); - if (fd < 0) + if (rcs_lockfd < 0) { error (1, errno, "could not open lock file `%s'", rcs_lockfile); } @@ -8588,10 +8239,10 @@ rcs_internal_lockfile (rcsfile) /* Because we change the modes later, we don't worry about this in the non-HAVE_FCHMOD case. */ #ifdef HAVE_FCHMOD - if (fchmod (fd, rstat.st_mode) < 0) + if (fchmod (rcs_lockfd, rstat.st_mode) < 0) error (1, errno, "cannot change mode for %s", rcs_lockfile); #endif - fp = fdopen (fd, FOPEN_BINARY_WRITE); + fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE); if (fp == NULL) error (1, errno, "cannot fdopen %s", rcs_lockfile); @@ -8604,6 +8255,7 @@ rcs_internal_unlockfile (fp, rcsfile) char *rcsfile; { assert (rcs_lockfile != NULL); + assert (rcs_lockfd >= 0); /* Abort if we could not write everything successfully to LOCKFILE. This is not a great error-handling mechanism, but should prevent @@ -8619,6 +8271,7 @@ rcs_internal_unlockfile (fp, rcsfile) error (1, 0, "error writing to lock file %s", rcs_lockfile); if (fclose (fp) == EOF) error (1, errno, "error closing lock file %s", rcs_lockfile); + rcs_lockfd = -1; rename_file (rcs_lockfile, rcsfile); @@ -8712,6 +8365,22 @@ RCS_rewrite (rcs, newdtext, insertpt) rcs_internal_unlockfile (fout, rcs->path); } +/* Abandon changes to an RCS file. */ + +void +RCS_abandon (rcs) + RCSNode *rcs; +{ + free_rcsnode_contents (rcs); + rcs->symbols_data = NULL; + rcs->expand = NULL; + rcs->access = NULL; + rcs->locks_data = NULL; + rcs->comment = NULL; + rcs->desc = NULL; + rcs->flags |= PARTIAL; +} + /* Annotate command. In rcs.c for historical reasons (from back when what is now RCS_deltas was part of annotate_fileproc). */ diff --git a/contrib/cvs/src/rcs.h b/contrib/cvs/src/rcs.h index 0a28161..3466398 100644 --- a/contrib/cvs/src/rcs.h +++ b/contrib/cvs/src/rcs.h @@ -8,8 +8,10 @@ * RCS source control definitions needed by rcs.c and friends */ -/* String which indicates a conflict if it occurs at the start of a line. */ -#define RCS_MERGE_PAT ">>>>>>> " +/* Strings which indicate a conflict if they occur at the start of a line. */ +#define RCS_MERGE_PAT_1 "<<<<<<< " +#define RCS_MERGE_PAT_2 "=======\n" +#define RCS_MERGE_PAT_3 ">>>>>>> " #define RCSEXT ",v" #define RCSPAT "*,v" @@ -227,7 +229,9 @@ int RCS_delete_revs PROTO ((RCSNode *, char *, char *, int)); void RCS_addaccess PROTO ((RCSNode *, char *)); void RCS_delaccess PROTO ((RCSNode *, char *)); char *RCS_getaccess PROTO ((RCSNode *)); +RETSIGTYPE rcs_cleanup PROTO ((void)); void RCS_rewrite PROTO ((RCSNode *, Deltatext *, char *)); +void RCS_abandon PROTO ((RCSNode *)); int rcs_change_text PROTO ((const char *, char *, size_t, const char *, size_t, char **, size_t *)); char *make_file_label PROTO ((char *, char *, RCSNode *)); diff --git a/contrib/cvs/src/recurse.c b/contrib/cvs/src/recurse.c index e93afbf..1cb2fbb 100644 --- a/contrib/cvs/src/recurse.c +++ b/contrib/cvs/src/recurse.c @@ -173,6 +173,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, seems to be handled somewhere (else) but why should it be a separate case? Needs investigation... */ just_subdirs = 1; + free (root); } #endif @@ -590,7 +591,7 @@ do_recursion (frame) /* Add it to our list. */ Node *n = getnode (); - n->type = UNKNOWN; + n->type = NT_UNKNOWN; n->key = xstrdup (this_root); if (addnode (root_directories, n)) @@ -1015,7 +1016,7 @@ but CVS uses %s for its own purposes; skipping %s directory", /* Add it to our list. */ Node *n = getnode (); - n->type = UNKNOWN; + n->type = NT_UNKNOWN; n->key = xstrdup (this_root); if (addnode (root_directories, n)) @@ -1132,6 +1133,7 @@ addfile (listp, dir, file) char *file; { Node *n; + List *fl; /* add this dir. */ addlist (listp, dir); @@ -1144,7 +1146,9 @@ addfile (listp, dir, file) } n->type = DIRS; - addlist ((List **) &n->data, file); + fl = (List *) n->data; + addlist (&fl, file); + n->data = (char *) fl; return; } @@ -1204,6 +1208,7 @@ unroll_files_proc (p, closure) } dirlist = save_dirlist; - filelist = NULL; + if (filelist) + dellist (&filelist); return(err); } diff --git a/contrib/cvs/src/release.c b/contrib/cvs/src/release.c index ca7945b..06d582f 100644 --- a/contrib/cvs/src/release.c +++ b/contrib/cvs/src/release.c @@ -190,7 +190,7 @@ release (argc, argv) { if (strchr ("MARCZ", *line)) c++; - (void) printf (line); + (void) fputs (line, stdout); } if (line_length < 0 && !feof (fp)) error (0, errno, "cannot read from subprocess"); diff --git a/contrib/cvs/src/remove.c b/contrib/cvs/src/remove.c index 2dacdf1..f0055d9 100644 --- a/contrib/cvs/src/remove.c +++ b/contrib/cvs/src/remove.c @@ -103,6 +103,7 @@ cvsremove (argc, argv) /* FIXME: Can't we set SEND_NO_CONTENTS here? Needs investigation. */ send_files (argc, argv, local, 0, 0); send_file_names (argc, argv, 0); + free_names (&argc, argv); send_to_server ("remove\012", 0); return get_responses_and_close (); } diff --git a/contrib/cvs/src/repos.c b/contrib/cvs/src/repos.c index 2738665..bc2b4be 100644 --- a/contrib/cvs/src/repos.c +++ b/contrib/cvs/src/repos.c @@ -106,12 +106,6 @@ Name_Repository (dir, update_dir) * one by tacking on the CVSROOT environment variable. If the CVSROOT * environment variable is not set, die now. */ - if (strcmp (repos, "..") == 0 || strncmp (repos, "../", 3) == 0) - { - error (0, 0, "in directory %s:", xupdate_dir); - error (0, 0, "`..'-relative repositories are not supported."); - error (1, 0, "illegal source repository"); - } if (! isabsolute(repos)) { char *newrepos; @@ -123,6 +117,12 @@ Name_Repository (dir, update_dir) error (0, 0, "or specify the '-d' option to %s.", program_name); error (1, 0, "illegal repository setting"); } + if (pathname_levels (repos) > 0) + { + error (0, 0, "in directory %s:", xupdate_dir); + error (0, 0, "`..'-relative repositories are not supported."); + error (1, 0, "illegal source repository"); + } newrepos = xmalloc (strlen (CVSroot_directory) + strlen (repos) + 10); (void) sprintf (newrepos, "%s/%s", CVSroot_directory, repos); free (repos); diff --git a/contrib/cvs/src/root.c b/contrib/cvs/src/root.c index d88c6f4..81859c8 100644 --- a/contrib/cvs/src/root.c +++ b/contrib/cvs/src/root.c @@ -174,9 +174,9 @@ Create_Root (dir, rootdir) directories. Then we can check against them when a remote user hands us a CVSROOT directory. */ -static unsigned int root_allow_count; +static int root_allow_count; static char **root_allow_vector; -static unsigned int root_allow_size; +static int root_allow_size; void root_allow_add (arg) @@ -233,8 +233,7 @@ void root_allow_free () { if (root_allow_vector != NULL) - free (root_allow_vector); - root_allow_count = 0; + free_names (&root_allow_count, root_allow_vector); root_allow_size = 0; } @@ -242,7 +241,7 @@ int root_allow_ok (arg) char *arg; { - unsigned int i; + int i; if (root_allow_count == 0) { @@ -295,7 +294,7 @@ parse_cvsroot (CVSroot) char *CVSroot; { static int cvsroot_parsed = 0; - char *cvsroot_copy, *p; + char *cvsroot_copy, *cvsroot_save, *p; int check_hostname; /* Don't go through the trouble twice. */ @@ -305,10 +304,19 @@ parse_cvsroot (CVSroot) return 0; } + if (CVSroot_original != NULL) + free (CVSroot_original); + if (CVSroot_directory != NULL) + free (CVSroot_directory); + if (CVSroot_username != NULL) + free (CVSroot_username); + if (CVSroot_hostname != NULL) + free (CVSroot_hostname); + CVSroot_original = xstrdup (CVSroot); - cvsroot_copy = xstrdup (CVSroot); + cvsroot_save = cvsroot_copy = xstrdup (CVSroot); - if ((*cvsroot_copy == ':')) + if (*cvsroot_copy == ':') { char *method = ++cvsroot_copy; @@ -324,6 +332,7 @@ parse_cvsroot (CVSroot) if (! (p = strchr (method, ':'))) { error (0, 0, "bad CVSroot: %s", CVSroot); + free (cvsroot_save); return 1; } *p = '\0'; @@ -348,6 +357,7 @@ parse_cvsroot (CVSroot) else { error (0, 0, "unknown method in CVSroot: %s", CVSroot); + free (cvsroot_save); return 1; } } @@ -378,19 +388,19 @@ parse_cvsroot (CVSroot) { /* Check to see if there is a username in the string. */ - if ((p = strchr (cvsroot_copy, '@'))) + if ((p = strchr (cvsroot_copy, '@')) != NULL) { - CVSroot_username = cvsroot_copy; *p = '\0'; + CVSroot_username = xstrdup (cvsroot_copy); cvsroot_copy = ++p; if (*CVSroot_username == '\0') CVSroot_username = NULL; } - if ((p = strchr (cvsroot_copy, ':'))) + if ((p = strchr (cvsroot_copy, ':')) != NULL) { - CVSroot_hostname = cvsroot_copy; *p = '\0'; + CVSroot_hostname = xstrdup (cvsroot_copy); cvsroot_copy = ++p; if (*CVSroot_hostname == '\0') @@ -398,7 +408,8 @@ parse_cvsroot (CVSroot) } } - CVSroot_directory = cvsroot_copy; + CVSroot_directory = xstrdup(cvsroot_copy); + free (cvsroot_save); #if ! defined (CLIENT_SUPPORT) && ! defined (DEBUG) if (CVSroot_method != local_method) @@ -422,12 +433,10 @@ 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 %s access method", - CVSroot_method == local_method ? "local" : "fork"); + error (0, 0, "when using local access method"); error (0, 0, "(%s)", CVSroot); return 1; } @@ -440,6 +449,18 @@ parse_cvsroot (CVSroot) error (1, 0, "CVSROOT %s must be an absolute pathname", CVSroot_directory); break; + case fork_method: + /* We want :fork: to behave the same as other remote access + methods. Therefore, don't check to see that the repository + name is absolute -- let the server do it. */ + if (CVSroot_username || CVSroot_hostname) + { + error (0, 0, "can't specify hostname and username in CVSROOT"); + error (0, 0, "when using fork access method"); + error (0, 0, "(%s)", CVSroot); + return 1; + } + break; case kserver_method: #ifndef HAVE_KERBEROS error (0, 0, "Your CVSROOT is set for a kerberos access method"); @@ -488,18 +509,24 @@ parse_cvsroot (CVSroot) /* Set up the global CVSroot* variables as if we're using the local - 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). */ + repository DIR. */ void set_local_cvsroot (dir) char *dir; { - CVSroot_original = dir; + if (CVSroot_original != NULL) + free (CVSroot_original); + CVSroot_original = xstrdup(dir); CVSroot_method = local_method; - CVSroot_directory = CVSroot_original; + if (CVSroot_directory != NULL) + free (CVSroot_directory); + CVSroot_directory = xstrdup(dir); + if (CVSroot_username != NULL) + free (CVSroot_username); CVSroot_username = NULL; + if (CVSroot_hostname != NULL) + free (CVSroot_hostname); CVSroot_hostname = NULL; client_active = 0; } diff --git a/contrib/cvs/src/rtag.c b/contrib/cvs/src/rtag.c index 5fd825f..bc14d88 100644 --- a/contrib/cvs/src/rtag.c +++ b/contrib/cvs/src/rtag.c @@ -29,7 +29,7 @@ static int rtag_fileproc PROTO ((void *callerdat, struct file_info *finfo)); static int rtag_filesdoneproc PROTO ((void *callerdat, int err, char *repos, char *update_dir, List *entries)); -static int rtag_proc PROTO((int *pargc, char **argv, char *xwhere, +static int rtag_proc PROTO((int argc, char **argv, char *xwhere, char *mwhere, char *mfile, int shorten, int local_specified, char *mname, char *msg)); static int rtag_delete PROTO((RCSNode *rcsfile)); @@ -222,9 +222,9 @@ rtag (argc, argv) */ /* ARGSUSED */ static int -rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, +rtag_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, mname, msg) - int *pargc; + int argc; char **argv; char *xwhere; char *mwhere; @@ -236,6 +236,7 @@ rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, { /* Begin section which is identical to patch_proc--should this be abstracted out somehow? */ + char *myargv[2]; int err = 0; int which; char *repository; @@ -277,13 +278,10 @@ rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, } else { - int i; - - /* a file means muck argv */ - for (i = 1; i < *pargc; i++) - free (argv[i]); - argv[1] = xstrdup (mfile); - (*pargc) = 2; + myargv[0] = argv[0]; + myargv[1] = mfile; + argc = 2; + argv = myargv; } free (path); } @@ -305,7 +303,7 @@ rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, if (numtag != NULL && !numtag_validated) { - tag_check_valid (numtag, *pargc - 1, argv + 1, local, 0, NULL); + tag_check_valid (numtag, argc - 1, argv + 1, local, 0, NULL); numtag_validated = 1; } @@ -315,7 +313,7 @@ rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, mtlist = getlist(); err = start_recursion (check_fileproc, check_filesdoneproc, (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - *pargc - 1, argv + 1, local, which, 0, 1, + argc - 1, argv + 1, local, which, 0, 1, where, 1); if (err) @@ -326,7 +324,7 @@ rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified, /* start the recursion processor */ err = start_recursion (rtag_fileproc, rtag_filesdoneproc, rtag_dirproc, (DIRLEAVEPROC) NULL, NULL, - *pargc - 1, argv + 1, local, + argc - 1, argv + 1, local, which, 0, 0, where, 1); free (where); dellist(&mtlist); diff --git a/contrib/cvs/src/run.c b/contrib/cvs/src/run.c index 41f4457..d382cef 100644 --- a/contrib/cvs/src/run.c +++ b/contrib/cvs/src/run.c @@ -207,6 +207,18 @@ run_exec (stin, stout, sterr, flags) (void) close (sherr); } +#ifdef SETXID_SUPPORT + /* + ** This prevents a user from creating a privileged shell + ** from the text editor when the SETXID_SUPPORT option is selected. + */ + if (!strcmp (run_argv[0], Editor) && setegid (getgid ())) + { + error (0, errno, "cannot set egid to gid"); + _exit (127); + } +#endif + /* dup'ing is done. try to run it now */ (void) execvp (run_argv[0], run_argv); error (0, errno, "cannot exec %s", run_argv[0]); diff --git a/contrib/cvs/src/sanity.sh b/contrib/cvs/src/sanity.sh index 6130289..84e67cc 100755 --- a/contrib/cvs/src/sanity.sh +++ b/contrib/cvs/src/sanity.sh @@ -25,21 +25,6 @@ # See TODO list at end of file. -# You can't run CVS as root; print a nice error message here instead -# of somewhere later, after making a mess. -# Commented out because: -# (1) whoami is not portable. If memory serves the POSIX way is "id -un". -# ("logname" or "who am i" are similar but different--they have more to -# do with who logged in on your tty than your uid). -# (2) This definition of "root" doesn't quite match CVS's (which is based -# on uid 0, not username "root"). -#case "`whoami`" in -# "root" ) -# echo "sanity.sh: test suite does not work correctly when run as root" >&2 -# exit 1 -# ;; -#esac - # required to make this script work properly. unset CVSREAD @@ -68,7 +53,8 @@ export LC_ALL # So this would be lost if everything was `pwd`-based. I suppose # if we wanted to get baroque we could start making symlinks # to ensure the two are different. -TESTDIR=${TESTDIR:-/tmp/cvs-sanity} +tmp=`(cd /tmp; /bin/pwd || pwd) 2>/dev/null` +: ${TESTDIR=$tmp/cvs-sanity} # "debugger" #set -x @@ -121,6 +107,7 @@ PROG=`basename ${testcvs}` # should be here. a-zA-Z obviously. People complained when 0-9 were # not allowed in usernames. Other than that I'm not sure. username="[-a-zA-Z0-9][-a-zA-Z0-9]*" +author="[-a-zA-Z0-9][-a-zA-Z0-9]*" # Regexp to match the name of a temporary file (from cvs_temp_name). # This appears in certain diff output. @@ -154,34 +141,87 @@ if test -f check.log; then mv check.log check.plog fi -GEXPRLOCS="`echo $PATH | sed 's/:/ /g'` /usr/local/bin /usr/contrib/bin /usr/gnu/bin /local/bin /local/gnu/bin /gun/bin" +# clean any old remnants (we need the chmod because some tests make +# directories read-only) +if test -d ${TESTDIR}; then + chmod -R a+wx ${TESTDIR} + rm -rf ${TESTDIR} +fi +mkdir ${TESTDIR} +cd ${TESTDIR} -EXPR=expr +# Make sure various tools work the way we expect, or try to find +# versions that do. +: ${AWK=awk} +: ${EXPR=expr} +: ${ID=id} +: ${TR=tr} -# Cause NextStep 3.3 users to lose in a more graceful fashion. -if $EXPR 'abc -def' : 'abc -def' >/dev/null; then - : good, it works -else - for path in $GEXPRLOCS ; do - if test -x $path/gexpr ; then - if test "X`$path/gexpr --version`" != "X--version" ; then - EXPR=$path/gexpr +find_tool () +{ + GLOCS="`echo $PATH | sed 's/:/ /g'` /usr/local/bin /usr/contrib/bin /usr/gnu/bin /local/bin /local/gnu/bin /gun/bin" + TOOL="" + for path in $GLOCS ; do + if test -x $path/g$1 ; then + if test "X`$path/g$1 --version`" != "X--version" ; then + TOOL=$path/g$1 break fi fi - if test -x $path/expr ; then - if test "X`$path/expr --version`" != "X--version" ; then - EXPR=$path/expr + if test -x $path/$1 ; then + if test "X`$path/$1 --version`" != "X--version" ; then + TOOL=$path/$1 break fi fi done + if test -z "$TOOL"; then + : + else + echo "Notice: The default version of $1 is defective, using" >&2 + echo "$TOOL instead." >&2 + fi + echo "$TOOL" +} + +# You can't run CVS as root; print a nice error message here instead +# of somewhere later, after making a mess. +case "`$ID -u`" in + "0") + echo "Test suite does not work correctly when run as root" >&2 + exit 1 + ;; + + "") + ID=`find_tool id` + if test -z "$ID" ; then + echo 'Running these tests requires an "id" program that understands the' >&2 + echo '-u and -n flags. Make sure that such an id (GNU, or many but not' >&2 + echo 'all vendor-supplied versions) is in your path.' >&2 + exit 1 + fi + ;; +esac +username=`$ID -un` +if $EXPR "${username}" : "${username}" >/dev/null; then + : good, it works +else + echo "Test suite does not work correctly when run by a username" >&2 + echo "containing regular expression meta-characters." >&2 + exit 1 +fi + +# Cause NextStep 3.3 users to lose in a more graceful fashion. +if $EXPR 'abc +def' : 'abc +def' >/dev/null; then + : good, it works +else + EXPR=`find_tool expr` if test -z "$EXPR" ; then - echo 'Running these tests requires an "expr" program that can handle' - echo 'multi-line patterns. Make sure that such an expr (GNU, or many but' - echo 'not all vendor-supplied versions) is in your path.' + echo 'Running these tests requires an "expr" program that can handle' >&2 + echo 'multi-line patterns. Make sure that such an expr (GNU, or many but' >&2 + echo 'not all vendor-supplied versions) is in your path.' >&2 exit 1 fi fi @@ -191,20 +231,7 @@ fi if $EXPR 'a b' : 'a c' >/dev/null; then - for path in $GEXPRLOCS ; do - if test -x $path/gexpr ; then - if test "X`$path/gexpr --version`" != "X--version" ; then - EXPR=$path/gexpr - break - fi - fi - if test -x $path/expr ; then - if test "X`$path/expr --version`" != "X--version" ; then - EXPR=$path/expr - break - fi - fi - done + EXPR=`find_tool expr` if test -z "$EXPR" ; then echo 'Warning: you are using a version of expr which does not correctly' echo 'match multi-line patterns. Some tests may spuriously pass.' @@ -215,6 +242,35 @@ else : good, it works fi +# More SunOS lossage... +echo 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' >${TESTDIR}/foo +cat ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo >${TESTDIR}/bar +cat ${TESTDIR}/bar ${TESTDIR}/bar ${TESTDIR}/bar ${TESTDIR}/bar >${TESTDIR}/foo +cat ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo ${TESTDIR}/foo >${TESTDIR}/bar +if $EXPR "`cat ${TESTDIR}/bar`" : "`cat ${TESTDIR}/bar`" >/dev/null; then + : good, it works +else + EXPR=`find_tool expr` + if test -z "$EXPR" ; then + echo 'Warning: you are using a version of expr which does not correctly' + echo 'match large patterns. Some tests may spuriously fail.' + echo 'You may wish to make sure GNU expr is in your path.' + EXPR=expr + fi +fi +if $EXPR "`cat ${TESTDIR}/bar`x" : "`cat ${TESTDIR}/bar`y" >/dev/null; then + EXPR=`find_tool expr` + if test -z "$EXPR" ; then + echo 'Warning: you are using a version of expr which does not correctly' + echo 'match large patterns. Some tests may spuriously pass.' + echo 'You may wish to make sure GNU expr is in your path.' + EXPR=expr + fi +else + : good, it works +fi +rm -f ${TESTDIR}/foo ${TESTDIR}/bar + # That we should have to do this is total bogosity, but GNU expr # version 1.9.4-1.12 uses the emacs definition of "$" instead of the unix # (e.g. SunOS 4.1.3 expr) one. Rumor has it this will be fixed in the @@ -265,6 +321,19 @@ else QUESTION='\?' fi +# now make sure that tr works on NULs +if $EXPR `echo "123" | ${TR} '2' '\0'` : "123" >/dev/null; then + TR=`find_tool tr` + if test -z "$TR" ; then + echo 'Warning: you are using a version of tr which does not correctly' + echo 'handle NUL bytes. Some tests may spuriously pass or fail.' + echo 'You may wish to make sure GNU tr is in your path.' + TR=tr + fi +else + : good, it works +fi + pass () { echo "PASS: $1" >>${LOGFILE} @@ -359,15 +428,15 @@ dotest_all_in_one () dotest_line_by_line () { line=1 - while [ $line -le `wc -l ${TESTDIR}/dotest.tmp` ] ; do - echo "$line matched \c" >>$LOGFILE + while [ $line -le `wc -l <${TESTDIR}/dotest.tmp` ] ; do if $EXPR "`sed -n ${line}p ${TESTDIR}/dotest.tmp`" : \ "`sed -n ${line}p ${TESTDIR}/dotest.exp`" >/dev/null; then : else - echo "**** expected line: " >>${LOGFILE} + echo "Line $line:" >> ${LOGFILE} + echo "**** expected: " >>${LOGFILE} sed -n ${line}p ${TESTDIR}/dotest.exp >>${LOGFILE} - echo "**** got line: " >>${LOGFILE} + echo "**** got: " >>${LOGFILE} sed -n ${line}p ${TESTDIR}/dotest.tmp >>${LOGFILE} unset line return 1 @@ -443,7 +512,7 @@ dotest_internal_debug () dotest () { rm -f ${TESTDIR}/dotest.ex? 2>&1 - if $2 >${TESTDIR}/dotest.tmp 2>&1; then + if eval "$2" >${TESTDIR}/dotest.tmp 2>&1; then : so far so good else status=$? @@ -458,7 +527,7 @@ dotest () dotest_lit () { rm -f ${TESTDIR}/dotest.ex? 2>&1 - if $2 >${TESTDIR}/dotest.tmp 2>&1; then + if eval "$2" >${TESTDIR}/dotest.tmp 2>&1; then : so far so good else status=$? @@ -482,7 +551,7 @@ dotest_lit () dotest_fail () { rm -f ${TESTDIR}/dotest.ex? 2>&1 - if $2 >${TESTDIR}/dotest.tmp 2>&1; then + if eval "$2" >${TESTDIR}/dotest.tmp 2>&1; then status=$? cat ${TESTDIR}/dotest.tmp >>${LOGFILE} echo "exit status was $status" >>${LOGFILE} @@ -497,7 +566,7 @@ dotest_fail () # Like dotest except second argument is the required exitstatus. dotest_status () { - $3 >${TESTDIR}/dotest.tmp 2>&1 + eval "$3" >${TESTDIR}/dotest.tmp 2>&1 status=$? if test "$status" = "$2"; then : so far so good @@ -513,7 +582,7 @@ dotest_status () dotest_sort () { rm -f ${TESTDIR}/dotest.ex? 2>&1 - if $2 >${TESTDIR}/dotest.tmp1 2>&1; then + if eval "$2" >${TESTDIR}/dotest.tmp1 2>&1; then : so far so good else status=$? @@ -521,18 +590,10 @@ dotest_sort () echo "exit status was $status" >>${LOGFILE} fail "$1" fi - sort < ${TESTDIR}/dotest.tmp1 > ${TESTDIR}/dotest.tmp + ${TR} ' ' ' ' < ${TESTDIR}/dotest.tmp1 | sort > ${TESTDIR}/dotest.tmp dotest_internal "$@" } -# clean any old remnants (we need the chmod because some tests make -# directories read-only) -if test -d ${TESTDIR}; then - chmod -R a+wx ${TESTDIR} - rm -rf ${TESTDIR} -fi -mkdir ${TESTDIR} -cd ${TESTDIR} # This will show up in cvs history output where it prints the working # directory. It should *not* appear in any cvs output referring to the # repository; cvs should use the name of the repository as specified. @@ -573,10 +634,11 @@ if test x"$*" = x; then tests="${tests} branches branches2 tagc tagf" tests="${tests} rcslib multibranch import importb importc" tests="${tests} import-after-initial" - tests="${tests} join join2 join3 join-readonly-conflict" + tests="${tests} join join2 join3 join-readonly-conflict join-admin" tests="${tests} new newb conflicts conflicts2 conflicts3" + tests="${tests} clean" # Checking out various places (modules, checkout -d, &c) - tests="${tests} modules modules2 modules3 modules4" + tests="${tests} modules modules2 modules3 modules4 modules5" tests="${tests} mkmodules-temp-file-removal" tests="${tests} cvsadm emptydir abspath toplevel toplevel2" # Log messages, error messages. @@ -587,7 +649,7 @@ if test x"$*" = x; then 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" + tests="${tests} serverpatch log log2 logopt 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 backuprecover" @@ -595,7 +657,7 @@ if test x"$*" = x; then tests="${tests} history" tests="${tests} big modes modes2 modes3 stamps" # PreservePermissions stuff: permissions, symlinks et al. - tests="${tests} perms symlinks symlinks2 hardlinks" + # tests="${tests} perms symlinks symlinks2 hardlinks" # More tag and branch tests, keywords. tests="${tests} sticky keyword keyword2 keywordlog" tests="${tests} head tagdate multibranch2 tag8k" @@ -667,6 +729,7 @@ if test "x$remote" = xyes; then fi dotest 1 "${testcvs} init" '' +dotest 1a "${testcvs} init" '' ### The big loop for what in $tests; do @@ -805,6 +868,21 @@ done" ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile new revision: 3\.1; previous revision: 2\.0 done" + + # Test using -r to create a branch + dotest_fail basica-8a3 "${testcvs} -q ci -m bogus -r 3.0.0" \ +"Checking in ssfile; +${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile +${PROG} [a-z]*: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v: can't find branch point 3\.0 +${PROG} [a-z]*: could not check in ssfile" + dotest basica-8a4 "${testcvs} -q ci -m valid -r 3.1.2" \ +"Checking in ssfile; +${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v <-- ssfile +new revision: 3\.1\.2\.1; previous revision: 3\.1 +done" + # now get rid of the sticky tag and go back to the trunk + dotest basica-8a5 "${testcvs} -q up -A" "[UP] ssfile" + cd ../.. dotest basica-8b "${testcvs} -q diff -r1.2 -r1.3" \ "Index: sdir/ssdir/ssfile @@ -814,6 +892,15 @@ retrieving revision 1\.2 retrieving revision 1\.3 diff -r1\.2 -r1\.3" + dotest_fail basica-8b1 "${testcvs} -q diff -r1.2 -r1.3 -C 3isacrowd" \ +"Index: sdir/ssdir/ssfile +=================================================================== +RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v +retrieving revision 1\.2 +retrieving revision 1\.3 +diff -C3isacrowd -r1\.2 -r1\.3 +${PROG} [a-z]*: invalid context length argument" + # The .* here will normally be "No such file or directory", # but if memory serves some systems (AIX?) have a different message. : dotest_fail basica-9 \ @@ -864,6 +951,10 @@ done" deleting revision 2\.0 deleting revision 1\.3 done" + dotest basica-o6a "${testcvs} admin -o 3.1.2: ssfile" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v +deleting revision 3\.1\.2\.1 +done" dotest basica-o7 "${testcvs} log -N ssfile" " RCS file: ${TESTDIR}/cvsroot/first-dir/sdir/ssdir/ssfile,v Working file: ssfile @@ -1193,7 +1284,7 @@ ${PROG} [a-z]*: Updating second-dir" # For CVS to make a syntactic check for "." wouldn't suffice. # On Linux 2.2 systems, the cwd may be gone, so we recreate it # to allow basicc-11 to actually happen - if ! test -d ../first-dir; then + if test ! -d ../first-dir; then cd .. mkdir ./first-dir cd ./first-dir @@ -2067,44 +2158,50 @@ ${PROG} [a-z]*: Importing ${TESTDIR}/cvsroot/second-dir/dir1/dir2" # which don't exist in the remote output? would seem to be # a CVS bug. dotest basic2-64 "${testcvs} his -x TOFWUCGMAR -a" \ -"O [0-9/]* [0-9:]* ${PLUS}0000 ${username} first-dir =first-dir= ${TMPPWD}/\* -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir == ${TMPPWD} -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir == ${TMPPWD} -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1 == ${TMPPWD} -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1 == ${TMPPWD} -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1/dir2 == ${TMPPWD} -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1/dir2 == ${TMPPWD} -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir == ${TMPPWD} -M [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == ${TMPPWD} -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1 == ${TMPPWD} -M [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1 == ${TMPPWD} -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1/dir2 == ${TMPPWD} -M [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1/dir2 == ${TMPPWD} -F [0-9/]* [0-9:]* ${PLUS}0000 ${username} =first-dir= ${TMPPWD}/\* -T [0-9/]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-head:A\] -T [0-9/]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-tag:rtagged-by-head\] -T [0-9/]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-revision:1\.1\] -O [0-9/]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir =first-dir= ${TMPPWD}/\* -U [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == ${TMPPWD}/first-dir -U [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir == ${TMPPWD}/first-dir" \ -"O [0-9/]* [0-9:]* ${PLUS}0000 ${username} first-dir =first-dir= /\* -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir == -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir == -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1 == -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1 == -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1/dir2 == -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1/dir2 == -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir == -M [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1 == -M [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1 == -A [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1/dir2 == -M [0-9/]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1/dir2 == -F [0-9/]* [0-9:]* ${PLUS}0000 ${username} =first-dir= /\* -T [0-9/]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-head:A\] -T [0-9/]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-tag:rtagged-by-head\] -T [0-9/]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-revision:1\.1\] -O [0-9/]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir =first-dir= /\*" +"O [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir =first-dir= ${TMPPWD}/\* +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir == ${TMPPWD} +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir == ${TMPPWD} +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1 == ${TMPPWD} +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1 == ${TMPPWD} +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1/dir2 == ${TMPPWD} +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1/dir2 == ${TMPPWD} +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir == ${TMPPWD} +M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == ${TMPPWD} +R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir == ${TMPPWD} +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1 == ${TMPPWD} +M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1 == ${TMPPWD} +R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1 == ${TMPPWD} +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1/dir2 == ${TMPPWD} +M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1/dir2 == ${TMPPWD} +R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1/dir2 == ${TMPPWD} +F [0-9-]* [0-9:]* ${PLUS}0000 ${username} =first-dir= ${TMPPWD}/\* +T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-head:A\] +T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-tag:rtagged-by-head\] +T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-revision:1\.1\] +O [0-9-]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir =first-dir= ${TMPPWD}/\* +U [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == ${TMPPWD}/first-dir +U [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir == ${TMPPWD}/first-dir" \ +"O [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir =first-dir= /\* +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir == +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir == +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1 == +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1 == +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file6 first-dir/dir1/dir2 == +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file7 first-dir/dir1/dir2 == +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir == +M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir == +R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir == +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1 == +M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1 == +R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1 == +A [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.1 file14 first-dir/dir1/dir2 == +M [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6 first-dir/dir1/dir2 == +R [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file7 first-dir/dir1/dir2 == +F [0-9-]* [0-9:]* ${PLUS}0000 ${username} =first-dir= /\* +T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-head:A\] +T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-tag:rtagged-by-head\] +T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir \[rtagged-by-revision:1\.1\] +O [0-9-]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir =first-dir= /\*" rm -rf ${CVSROOT_DIRNAME}/first-dir rm -rf ${CVSROOT_DIRNAME}/second-dir @@ -2246,10 +2343,9 @@ done" spacefiles) # More filename tests, in particular spaces in file names. - # If we start using eval in dotest, this test should become - # easier to write (in fact, it may be possible to just - # change a few of the names in basica or some other test, - # always good to keep the testsuite concise). + # (it might be better to just change a few of the names in + # basica or some other test instead, always good to keep the + # testsuite concise). # I wrote this test to worry about problems in do_module; # but then I found that the CVS server has its own problems @@ -2283,24 +2379,16 @@ ${TESTDIR}/cvsroot/top,v <-- top initial revision: 1\.1 done" mkdir 'first dir' - if ${testcvs} add 'first dir' >${TESTDIR}/output.tmp 2>&1; then - dotest spacefiles-4 "cat ${TESTDIR}/output.tmp" \ + dotest spacefiles-4 "${testcvs} add 'first dir'" \ "Directory ${TESTDIR}/cvsroot/first dir added to the repository" - else - fail spacefiles-4 - fi mkdir ./${dashb} dotest spacefiles-5 "${testcvs} add -- ${dashb}" \ "Directory ${TESTDIR}/cvsroot/${dashb} added to the repository" cd 'first dir' touch 'a file' - if ${testcvs} add 'a file' >${TESTDIR}/output.tmp 2>&1; then - dotest spacefiles-6 "cat ${TESTDIR}/output.tmp" \ + dotest spacefiles-6 "${testcvs} add 'a file'" \ "${PROG} [a-z]*: scheduling file .a file. for addition ${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" - else - fail spacefiles-6 - fi dotest spacefiles-7 "${testcvs} -q ci -m add" \ "RCS file: ${TESTDIR}/cvsroot/first dir/a file,v done @@ -2322,22 +2410,13 @@ done" dotest spacefiles-11 "${testcvs} -q co -- ${dashc}" "U \./${dashc}" rm ./${dashc} dotest spacefiles-12 "${testcvs} -q co -- /${dashc}" "U \./${dashc}" - if ${testcvs} -q co 'first dir' >${TESTDIR}/output.tmp 2>&1; then - dotest spacefiles-13 "cat ${TESTDIR}/output.tmp" \ + dotest spacefiles-13 "${testcvs} -q co 'first dir'" \ "U first dir/a file" - else - fail spacefiles-13 - fi cd .. mkdir 3; cd 3 - if ${testcvs} -q co 'first dir/a file' >${TESTDIR}/output.tmp 2>&1 - then - dotest spacefiles-14 "cat ${TESTDIR}/output.tmp" \ + dotest spacefiles-14 "${testcvs} -q co 'first dir/a file'" \ "U first dir/a file" - else - fail spacefiles-14 - fi cd .. rm -r 1 2 3 @@ -3573,15 +3652,9 @@ ${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" \ + echo no | dotest dirs-4 "${testcvs} release -d dir1/sdir" \ "${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\. @@ -3603,7 +3676,6 @@ D/sdir////" cd .. rm -r imp-dir 1 - rm ${TESTDIR}/output.tmp # clean up our repositories rm -rf ${CVSROOT_DIRNAME}/dir1 @@ -3952,7 +4024,7 @@ Merging differences between 1\.1\.2\.1 and 1\.1\.2\.1\.2\.1 into file1 rcsmerge: warning: conflicts during merge" dotest branches-16 "cat file1" '<<<<<<< file1 1:ancest -======= +[=]====== 1:brbr [>]>>>>>> 1\.1\.2\.1\.2\.1' @@ -4514,7 +4586,7 @@ mumble; } EOF # Use dotest_fail because exit status from `cvs diff' must be 1. - dotest_fail rcslib-diffrgx-3 "${testcvs} diff -c -F.*( rgx.c" \ + dotest_fail rcslib-diffrgx-3 "${testcvs} diff -c -F'.*(' rgx.c" \ "Index: rgx\.c =================================================================== RCS file: ${TESTDIR}/cvsroot/first-dir/rgx\.c,v @@ -4904,7 +4976,7 @@ done" " - ${PROG} checkout -jvendor-branch:yesterday -jvendor-branch first-dir + ${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 @@ -4950,7 +5022,7 @@ Use the following command to help the merge:" dotest import-113 \ "${testcvs} -q co -jjunk-1_0 -jjunk-2_0 first-dir" \ -"${PROG} [a-z]*: file first-dir/imported-f1 is present in revision junk-2_0 +"${PROG} [a-z]*: file first-dir/imported-f1 does not exist, but is present in revision junk-2_0 RCS file: ${TESTDIR}/cvsroot/first-dir/imported-f2,v retrieving revision 1\.1\.1\.1 retrieving revision 1\.1\.1\.2 @@ -5014,7 +5086,7 @@ No conflicts created by this import" " - ${PROG} -d ${CVSROOT} 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 @@ -5147,14 +5219,14 @@ ${PROG} [a-z]*: Updating bdir/subdir" "${PROG} [a-z]*: in directory adir/sub1/ssdir: ${PROG} \[[a-z]* aborted\]: there is no version here; do .${PROG} checkout. first" # The workaround is to leave off the "-r wip_test". - dotest importc-8 "${testcvs} -q ci -m modify" \ + dotest importc-7a "${testcvs} -q ci -m modify" \ "Checking in cdir/cfile; ${TESTDIR}/cvsroot/first-dir/cdir/cfile,v <-- cfile new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 done" else # Remote doesn't have the bug in the first place. - dotest importc-7 "${testcvs} -q ci -m modify -r wip_test" \ + dotest importc-7r "${testcvs} -q ci -m modify -r wip_test" \ "Checking in cdir/cfile; ${TESTDIR}/cvsroot/first-dir/cdir/cfile,v <-- cfile new revision: 1\.1\.1\.1\.2\.1; previous revision: 1\.1\.1\.1 @@ -5688,6 +5760,63 @@ M file2 R file3 A file8" + # Checkout the mainline again to try merging from the trunk + # to a branch. + cd .. + rm -r first-dir + dotest join-30 "${testcvs} -q co first-dir" \ +'U first-dir/file2 +U first-dir/file3 +U first-dir/file4 +U first-dir/file7' + cd first-dir + + # Tag the current revisions on the trunk. + dotest join-31 "${testcvs} -q tag T3 ." \ +'T file2 +T file3 +T file4 +T file7' + + # Modify file7. + echo 'second revision of file7' > file7 + dotest join-32 "${testcvs} -q ci -mx ." \ +"Checking in file7; +${TESTDIR}/cvsroot/first-dir/file7,v <-- file7 +new revision: 1\.2; previous revision: 1\.1 +done" + + # And Tag again. + dotest join-33 "${testcvs} -q tag T4 ." \ +'T file2 +T file3 +T file4 +T file7' + + # Now update branch to T3. + cd ../../2/first-dir + dotest join-34 "${testcvs} -q up -jT3" \ +"${PROG} [a-z]*: file file4 does not exist, but is present in revision T3 +U file7" + + # Verify that the right changes have been scheduled. + dotest join-35 "${testcvs} -q update" \ +'A file7' + + # Now update to T4. + # This is probably a bug, although in this particular case it just + # happens to do the right thing; see above join-20. + dotest join-36 "${testcvs} -q up -j T3 -j T4" \ +"A file7 +RCS file: ${TESTDIR}/cvsroot/first-dir/file7,v +retrieving revision 1\.1 +retrieving revision 1\.2 +Merging differences between 1\.1 and 1\.2 into file7" + + # Verify that the right changes have been scheduled. + dotest join-37 "${testcvs} -q update" \ +'A file7' + cd ../.. rm -r 1 2 3 @@ -5975,6 +6104,49 @@ C m" rm -rf ${CVSROOT_DIRNAME}/$module ;; + join-admin) + mkdir 1; cd 1 + dotest join-admin-1 "$testcvs -q co -l ." '' + module=x + mkdir $module + $testcvs -q add $module >>$LOGFILE 2>&1 + cd $module + + # Create a file so applying the first tag works. + echo foo > a + $testcvs -Q add a > /dev/null 2>&1 + $testcvs -Q ci -m. a > /dev/null 2>&1 + + $testcvs -Q tag -b B + $testcvs -Q tag -b M1 + echo '$''Id$' > b + $testcvs -Q add b > /dev/null 2>&1 + $testcvs -Q ci -m. b > /dev/null 2>&1 + $testcvs -Q tag -b M2 + + $testcvs -Q update -r B + $testcvs -Q update -kk -jM1 -jM2 + $testcvs -Q ci -m. b >/dev/null 2>&1 + + $testcvs -Q update -A + + # Verify that the -kk flag from the update did not + # propagate to the repository. + dotest join-admin-1 "$testcvs status b" \ +"=================================================================== +File: b Status: Up-to-date + + Working revision: 1\.1.* + Repository revision: 1\.1 ${TESTDIR}/cvsroot/x/b,v + Sticky Tag: (none) + Sticky Date: (none) + Sticky Options: (none)" + + cd ../.. + rm -rf 1 + rm -rf ${CVSROOT_DIRNAME}/$module + ;; + new) # look for stray "no longer pertinent" messages. mkdir ${CVSROOT_DIRNAME}/first-dir @@ -6262,9 +6434,24 @@ File: a Status: File had conflicts on merge "${PROG} [a-z]*: file .a. had a conflict and has not been modified ${PROG} \[[a-z]* aborted\]: correct above errors first!" - echo lame attempt at resolving it >>a # Try to check in the file with the conflict markers in it. - dotest conflicts-status-2 "${testcvs} status a" \ + # Make sure we detect any one of the three conflict markers + mv a aa + grep '^<<<<<<<' aa >a + dotest conflicts-status-2 "${testcvs} -nq ci -m try a" \ +"${PROG} [a-z]*: warning: file .a. seems to still contain conflict indicators" + + grep '^=======' aa >a + dotest conflicts-status-3 "${testcvs} -nq ci -m try a" \ +"${PROG} [a-z]*: warning: file .a. seems to still contain conflict indicators" + + grep '^>>>>>>>' aa >a + dotest conflicts-status-4 "${testcvs} -qn ci -m try a" \ +"${PROG} [a-z]*: warning: file .a. seems to still contain conflict indicators" + + mv aa a + echo lame attempt at resolving it >>a + dotest conflicts-status-5 "${testcvs} status a" \ "=================================================================== File: a Status: File had conflicts on merge @@ -6283,7 +6470,7 @@ done" # OK, the user saw the warning (good user), and now # resolves it for real. echo resolve conflict >a - dotest conflicts-status-3 "${testcvs} status a" \ + dotest conflicts-status-6 "${testcvs} status a" \ "=================================================================== File: a Status: Locally Modified @@ -6297,7 +6484,7 @@ File: a Status: Locally Modified ${TESTDIR}/cvsroot/first-dir/a,v <-- a new revision: 1\.4; previous revision: 1\.3 done" - dotest conflicts-status-4 "${testcvs} status a" \ + dotest conflicts-status-7 "${testcvs} status a" \ "=================================================================== File: a Status: Up-to-date @@ -6790,6 +6977,62 @@ ${PROG} update: cannot open CVS/Entries for reading: No such file or directory" rm -rf ${CVSROOT_DIRNAME}/first-dir ;; + clean) + # Test update -C (overwrite local mods w/ repository copies) + mkdir 1; cd 1 + dotest clean-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest clean-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + echo "The usual boring test text." > cleanme.txt + dotest clean-3 "${testcvs} add cleanme.txt" \ +"${PROG} [a-z]*: scheduling file .cleanme\.txt. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest clean-4 "${testcvs} -q ci -m clean-3" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/cleanme\.txt,v +done +Checking in cleanme\.txt; +${TESTDIR}/cvsroot/first-dir/cleanme\.txt,v <-- cleanme\.txt +initial revision: 1\.1 +done" + # Okay, preparation is done, now test. + # Check that updating an unmodified copy works. + dotest clean-5 "${testcvs} -q update" '' + # Check that updating -C an unmodified copy works. + dotest clean-6 "${testcvs} -q update -C" '' + # Check that updating a modified copy works. + echo "fish" >> cleanme.txt + dotest clean-7 "${testcvs} -q update" 'M cleanme\.txt' + # Check that updating -C a modified copy works. + dotest clean-8 "${testcvs} -q update -C" \ +"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1) +U cleanme\.txt" + # And check that the backup copy really was made. + dotest clean-9 "cat .#cleanme.txt.1.1" \ +"The usual boring test text\. +fish" + + # Do it all again, this time naming the file explicitly. + rm .#cleanme.txt.1.1 + dotest clean-10 "${testcvs} -q update cleanme.txt" '' + dotest clean-11 "${testcvs} -q update -C cleanme.txt" '' + echo "bluegill" >> cleanme.txt + dotest clean-12 "${testcvs} -q update cleanme.txt" 'M cleanme\.txt' + dotest clean-13 "${testcvs} -q update -C cleanme.txt" \ +"(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1) +U cleanme\.txt" + # And check that the backup copy really was made. + dotest clean-14 "cat .#cleanme.txt.1.1" \ +"The usual boring test text\. +bluegill" + + # Done. Clean up. + cd ../.. + rm -rf 1 + rm -rf ${TESTDIR}/cvsroot/first-dir + ;; + modules) # Tests of various ways to define and use modules. # Roadmap to various modules tests: @@ -6802,6 +7045,7 @@ ${PROG} update: cannot open CVS/Entries for reading: No such file or directory" # ampersand modules: modules2 # -s: modules. # -d: modules, modules3, cvsadm + # -i, -o, -u, -e, -t: modules5 # slashes in module names: modules3 ############################################################ @@ -6893,76 +7137,88 @@ ${PROG} [a-z]*: Rebuilding administrative file database" mkdir 1 cd 1 - if ${testcvs} -q co first-dir; then - pass 143 - else - fail 143 - fi + dotest modules-143 "${testcvs} -q co first-dir" "" cd first-dir mkdir subdir - ${testcvs} add subdir >>${LOGFILE} - cd subdir + dotest modules-143a "${testcvs} add subdir" \ +"Directory ${TESTDIR}/cvsroot/first-dir/subdir added to the repository" + cd subdir mkdir ssdir - ${testcvs} add ssdir >>${LOGFILE} + dotest modules-143b "${testcvs} add ssdir" \ +"Directory ${TESTDIR}/cvsroot/first-dir/subdir/ssdir added to the repository" touch a b - if ${testcvs} add a b 2>>${LOGFILE} ; then - pass 144 - else - fail 144 - fi + dotest modules-144 "${testcvs} add a b" \ +"${PROG} [a-z]*: scheduling file .a. for addition +${PROG} [a-z]*: scheduling file .b. for addition +${PROG} [a-z]*: use .${PROG} commit. to add these files permanently" - if ${testcvs} ci -m added >>${LOGFILE} 2>&1; then - pass 145 - else - fail 145 - fi + dotest modules-145 "${testcvs} ci -m added" \ +"${PROG} [a-z]*: Examining . +${PROG} [a-z]*: Examining ssdir +RCS file: ${TESTDIR}/cvsroot/first-dir/subdir/a,v +done +Checking in a; +${TESTDIR}/cvsroot/first-dir/subdir/a,v <-- a +initial revision: 1\.1 +done +RCS file: ${TESTDIR}/cvsroot/first-dir/subdir/b,v +done +Checking in b; +${TESTDIR}/cvsroot/first-dir/subdir/b,v <-- b +initial revision: 1\.1 +done" cd .. - if ${testcvs} -q co CVSROOT >>${LOGFILE}; then - pass 146 - else - fail 146 - fi + dotest modules-146 "${testcvs} -q co CVSROOT" \ +"U CVSROOT/checkoutlist +U CVSROOT/commitinfo +U CVSROOT/config +U CVSROOT/cvswrappers +U CVSROOT/editinfo +U CVSROOT/loginfo +U CVSROOT/modules +U CVSROOT/notify +U CVSROOT/rcsinfo +U CVSROOT/taginfo +U CVSROOT/verifymsg" # Here we test that CVS can deal with CVSROOT (whose repository # is at top level) in the same directory as subdir (whose repository # is a subdirectory of first-dir). TODO: Might want to check that # files can actually get updated in this state. - if ${testcvs} -q update; then - pass 147 - else - fail 147 - fi + dotest modules-147 "${testcvs} -q update" "" + + cat >CVSROOT/modules <CVSROOT/modules - echo dirmodule first-dir/subdir >>CVSROOT/modules - echo namedmodule -d nameddir first-dir/subdir >>CVSROOT/modules - echo aliasmodule -a first-dir/subdir/a >>CVSROOT/modules - echo aliasnested -a first-dir/subdir/ssdir >>CVSROOT/modules - echo topfiles -a first-dir/file1 first-dir/file2 >>CVSROOT/modules - echo world -a . >>CVSROOT/modules - echo statusmod -s Mungeable >>CVSROOT/modules - - # Options must come before arguments. It is possible this should - # be relaxed at some point (though the result would be bizarre for - # -a); for now test the current behavior. - echo bogusalias first-dir/subdir/a -a >>CVSROOT/modules - if ${testcvs} ci -m 'add modules' CVSROOT/modules \ - >>${LOGFILE} 2>&1; then - pass 148 - else - fail 148 - fi cd .. # The "statusmod" module contains an error; trying to use it # will produce "modules file missing directory" I think. # However, that shouldn't affect the ability of "cvs co -c" or # "cvs co -s" to do something reasonable with it. - dotest 148a0 "${testcvs} co -c" 'aliasmodule -a first-dir/subdir/a + dotest modules-148a0 "${testcvs} co -c" 'aliasmodule -a first-dir/subdir/a aliasnested -a first-dir/subdir/ssdir bogusalias first-dir/subdir/a -a dirmodule first-dir/subdir @@ -6974,7 +7230,7 @@ world -a \.' # There is code in modules.c:save_d which explicitly skips # modules defined with -a, which is why aliasmodule is not # listed. - dotest 148a1 "${testcvs} co -s" \ + dotest modules-148a1 "${testcvs} co -s" \ 'statusmod Mungeable bogusalias NONE first-dir/subdir/a -a dirmodule NONE first-dir/subdir @@ -6982,123 +7238,60 @@ namedmodule NONE first-dir/subdir realmodule NONE first-dir/subdir a' # Test that real modules check out to realmodule/a, not subdir/a. - if ${testcvs} co realmodule >>${LOGFILE}; then - pass 149a1 - else - fail 149a1 - fi - if test -d realmodule && test -f realmodule/a; then - pass 149a2 - else - fail 149a2 - fi - if test -f realmodule/b; then - fail 149a3 - else - pass 149a3 - fi - if ${testcvs} -q co realmodule; then - pass 149a4 - else - fail 149a4 - fi - if echo "yes" | ${testcvs} release -d realmodule >>${LOGFILE} ; then - pass 149a5 - else - fail 149a5 - fi - - dotest_fail 149b1 "${testcvs} co realmodule/a" \ + dotest modules-149a1 "${testcvs} co realmodule" "U realmodule/a" + dotest modules-149a2 "test -d realmodule && test -f realmodule/a" "" + dotest_fail modules-149a3 "test -f realmodule/b" "" + dotest modules-149a4 "${testcvs} -q co realmodule" "" + dotest modules-149a5 "echo yes | ${testcvs} release -d realmodule" \ +"You have \[0\] altered files in this repository\. +Are you sure you want to release (and delete) directory .realmodule.: " + + dotest_fail modules-149b1 "${testcvs} co realmodule/a" \ "${PROG}"' [a-z]*: module `realmodule/a'\'' is a request for a file in a module which is not a directory' \ "${PROG}"' [a-z]*: module `realmodule/a'\'' is a request for a file in a module which is not a directory '"${PROG}"' \[[a-z]* aborted\]: cannot expand modules' # Now test the ability to check out a single file from a directory - if ${testcvs} co dirmodule/a >>${LOGFILE}; then - pass 150c - else - fail 150c - fi - if test -d dirmodule && test -f dirmodule/a; then - pass 150d - else - fail 150d - fi - if test -f dirmodule/b; then - fail 150e - else - pass 150e - fi - if echo "yes" | ${testcvs} release -d dirmodule >>${LOGFILE} ; then - pass 150f - else - fail 150f - fi + dotest modules-150c "${testcvs} co dirmodule/a" "U dirmodule/a" + dotest modules-150d "test -d dirmodule && test -f dirmodule/a" "" + dotest_fail modules-150e "test -f dirmodule/b" "" + dotest modules-150f "echo yes | ${testcvs} release -d dirmodule" \ +"You have \[0\] altered files in this repository\. +Are you sure you want to release (and delete) directory .dirmodule.: " # Now test the ability to correctly reject a non-existent filename. # For maximum studliness we would check that an error message is # being output. - if ${testcvs} co dirmodule/nonexist >>${LOGFILE} 2>&1; then - # We accept a zero exit status because it is what CVS does - # (Dec 95). Probably the exit status should be nonzero, - # however. - pass 150g1 - else - pass 150g1 - fi + # We accept a zero exit status because it is what CVS does + # (Dec 95). Probably the exit status should be nonzero, + # however. + dotest modules-150g1 "${testcvs} co dirmodule/nonexist" \ +"${PROG} [a-z]*: warning: new-born dirmodule/nonexist has disappeared" # We tolerate the creation of the dirmodule directory, since that # is what CVS does, not because we view that as preferable to not # creating it. - if test -f dirmodule/a || test -f dirmodule/b; then - fail 150g2 - else - pass 150g2 - fi + dotest_fail modules-150g2 "test -f dirmodule/a || test -f dirmodule/b" "" rm -r dirmodule # Now test that a module using -d checks out to the specified # directory. - dotest 150h1 "${testcvs} -q co namedmodule" 'U nameddir/a + dotest modules-150h1 "${testcvs} -q co namedmodule" \ +'U nameddir/a U nameddir/b' - if test -f nameddir/a && test -f nameddir/b; then - pass 150h2 - else - fail 150h2 - fi + dotest modules-150h2 "test -f nameddir/a && test -f nameddir/b" "" echo add line >>nameddir/a - dotest 150h3 "${testcvs} -q co namedmodule" 'M nameddir/a' + dotest modules-150h3 "${testcvs} -q co namedmodule" 'M nameddir/a' rm nameddir/a - dotest 150h4 "${testcvs} -q co namedmodule" 'U nameddir/a' - if echo "yes" | ${testcvs} release -d nameddir >>${LOGFILE} ; then - pass 150h99 - else - fail 150h99 - fi + dotest modules-150h4 "${testcvs} -q co namedmodule" 'U nameddir/a' + dotest modules-150h99 "echo yes | ${testcvs} release -d nameddir" \ +"You have \[0\] altered files in this repository\. +Are you sure you want to release (and delete) directory .nameddir.: " # Now test that alias modules check out to subdir/a, not # aliasmodule/a. - if ${testcvs} co aliasmodule >>${LOGFILE}; then - pass 151 - else - fail 151 - fi - if test -d aliasmodule; then - fail 152 - else - pass 152 - fi + dotest modules-151 "${testcvs} co aliasmodule" "" + dotest_fail modules-152 "test -d aliasmodule" "" echo abc >>first-dir/subdir/a - if (${testcvs} -q co aliasmodule | tee test153.tmp) \ - >>${LOGFILE}; then - pass 153 - else - fail 153 - fi - echo 'M first-dir/subdir/a' >ans153.tmp - if cmp test153.tmp ans153.tmp; then - pass 154 - else - fail 154 - fi + dotest modules-153 "${testcvs} -q co aliasmodule" "M first-dir/subdir/a" cd .. rm -r 1 @@ -7218,6 +7411,8 @@ done" cd CVSROOT echo 'ampermodule &first-dir &second-dir' > modules echo 'combmodule third-dir file3 &first-dir' >> modules + echo 'ampdirmod -d newdir &first-dir &second-dir' >> modules + echo 'badmod -d newdir' >> modules # Depending on whether the user also ran the modules test # we will be checking in revision 1.2 or 1.3. dotest modules2-2 "${testcvs} -q ci -m add-modules" \ @@ -7294,11 +7489,11 @@ initial revision: 1\.1 done" cd .. fi + cd .. + rm -r 1 # Now test the "combmodule" module (combining regular modules # and ampersand modules in the same module definition). - cd .. - rm -r 1 mkdir 1; cd 1 dotest modules2-14 "${testcvs} co combmodule" \ "U combmodule/file3 @@ -7325,6 +7520,22 @@ U first-dir/amper1" cd .. rm -r 1 + # Now test the "ampdirmod" and "badmod" modules to be sure that + # options work with ampersand modules but don't prevent the + # "missing directory" error message. + mkdir 1; cd 1 + dotest modules2-20 "${testcvs} co ampdirmod" \ +"${PROG} [a-z]*: Updating first-dir +U first-dir/amper1 +${PROG} [a-z]*: Updating second-dir" + dotest modules2-21 "test -f newdir/first-dir/amper1" "" + dotest_fail modules2-22 "${testcvs} co badmod" \ +"${PROG} [a-z]*: modules file missing directory for module badmod" \ +"${PROG} [a-z]*: modules file missing directory for module badmod +${PROG} \[[a-z]* aborted\]: cannot expand modules" + cd .. + rm -r 1 + # Test that CVS gives an error if one combines -a with # other options. # Probably would be better to break this out into a separate @@ -7646,6 +7857,226 @@ add-it rm -rf ${CVSROOT_DIRNAME}/first-dir ;; + modules5) + # Test module programs + + mkdir ${CVSROOT_DIRNAME}/first-dir + mkdir 1 + cd 1 + dotest modules5-1 "${testcvs} -q co first-dir" "" + cd first-dir + mkdir subdir + dotest modules5-2 "${testcvs} add subdir" \ +"Directory ${TESTDIR}/cvsroot/first-dir/subdir added to the repository" + cd subdir + mkdir ssdir + dotest modules5-3 "${testcvs} add ssdir" \ +"Directory ${TESTDIR}/cvsroot/first-dir/subdir/ssdir added to the repository" + touch a b + dotest modules5-4 "${testcvs} add a b" \ +"${PROG} [a-z]*: scheduling file .a. for addition +${PROG} [a-z]*: scheduling file .b. for addition +${PROG} [a-z]*: use .${PROG} commit. to add these files permanently" + + dotest modules5-5 "${testcvs} ci -m added" \ +"${PROG} [a-z]*: Examining . +${PROG} [a-z]*: Examining ssdir +RCS file: ${TESTDIR}/cvsroot/first-dir/subdir/a,v +done +Checking in a; +${TESTDIR}/cvsroot/first-dir/subdir/a,v <-- a +initial revision: 1\.1 +done +RCS file: ${TESTDIR}/cvsroot/first-dir/subdir/b,v +done +Checking in b; +${TESTDIR}/cvsroot/first-dir/subdir/b,v <-- b +initial revision: 1\.1 +done" + + cd .. + dotest modules5-6 "${testcvs} -q co CVSROOT" \ +"U CVSROOT/checkoutlist +U CVSROOT/commitinfo +U CVSROOT/config +U CVSROOT/cvswrappers +U CVSROOT/editinfo +U CVSROOT/loginfo +U CVSROOT/modules +U CVSROOT/notify +U CVSROOT/rcsinfo +U CVSROOT/taginfo +U CVSROOT/verifymsg" + + for i in checkin checkout update export tag; do + cat >> ${CVSROOT_DIRNAME}/$i.sh <CVSROOT/modules <>realmodule/a + dotest modules5-13 "${testcvs} -q ci -m." \ +"Checking in realmodule/a; +${CVSROOT_DIRNAME}/first-dir/subdir/a,v <-- a +new revision: 1\.2; previous revision: 1\.1 +done +${PROG} [a-z]*: Executing ..${CVSROOT_DIRNAME}/checkin\.sh. .${CVSROOT_DIRNAME}/first-dir/subdir.. +checkin script invoked in /.*/realmodule +args: ${CVSROOT_DIRNAME}/first-dir/subdir" + else + dotest modules5-11 "${testcvs} -q co realmodule" \ +"checkout script invoked in ${TESTDIR}/1 +args: realmodule" + dotest modules5-12 "${testcvs} -q update" \ +"${PROG} [a-z]*: Executing ..${CVSROOT_DIRNAME}/update\.sh. .${CVSROOT_DIRNAME}/first-dir/subdir.. +update script invoked in ${TESTDIR}/1/realmodule +args: ${CVSROOT_DIRNAME}/first-dir/subdir" + echo "change" >>realmodule/a + dotest modules5-13 "${testcvs} -q ci -m." \ +"Checking in realmodule/a; +${CVSROOT_DIRNAME}/first-dir/subdir/a,v <-- a +new revision: 1\.2; previous revision: 1\.1 +done +${PROG} [a-z]*: Executing ..${CVSROOT_DIRNAME}/checkin\.sh. .${CVSROOT_DIRNAME}/first-dir/subdir.. +checkin script invoked in ${TESTDIR}/1/realmodule +args: ${CVSROOT_DIRNAME}/first-dir/subdir" + fi + dotest modules5-14 "echo yes | ${testcvs} release -d realmodule" \ +"You have \[0\] altered files in this repository\. +Are you sure you want to release (and delete) directory .realmodule.: " + dotest modules5-15 "${testcvs} -q rtag -Dnow MYTAG realmodule" \ +"tag script invoked in ${TESTDIR}/1 +args: realmodule MYTAG" + if test "$remote" = "yes"; then + dotest modules5-16 "${testcvs} -q export -r MYTAG realmodule" \ +"U realmodule/a +export script invoked in .* +args: realmodule" + else + dotest modules5-16 "${testcvs} -q export -r MYTAG realmodule" \ +"U realmodule/a +export script invoked in ${TESTDIR}/1 +args: realmodule" + fi + + dotest_fail modules5-17 "${testcvs} co realmodule/a" \ +"${PROG}"' [a-z]*: module `realmodule/a'\'' is a request for a file in a module which is not a directory' \ +"${PROG}"' [a-z]*: module `realmodule/a'\'' is a request for a file in a module which is not a directory +'"${PROG}"' \[[a-z]* aborted\]: cannot expand modules' + + # FIXCVS: The client gets confused in these cases and tries to + # store the scripts in the wrong places. + if test "$remote" != "yes"; then + # Now test the ability to check out a single file from a directory + dotest modules5-18 "${testcvs} co dirmodule/a" \ +"U dirmodule/a +${PROG} [a-z]*: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule.. +checkout script invoked in ${TESTDIR}/1 +args: dirmodule" + dotest modules5-19 "test -d dirmodule && test -f dirmodule/a" "" + dotest_fail modules5-20 "test -f dirmodule/b" "" + dotest modules5-21 "echo yes | ${testcvs} release -d dirmodule" \ +"You have \[0\] altered files in this repository\. +Are you sure you want to release (and delete) directory .dirmodule.: " + + # Now test the ability to correctly reject a non-existent filename. + # For maximum studliness we would check that an error message is + # being output. + # We accept a zero exit status because it is what CVS does + # (Dec 95). Probably the exit status should be nonzero, + # however. + dotest modules5-22 "${testcvs} co dirmodule/nonexist" \ +"${PROG} [a-z]*: warning: new-born dirmodule/nonexist has disappeared +${PROG} [a-z]*: Executing ..${CVSROOT_DIRNAME}/checkout\.sh. .dirmodule.. +checkout script invoked in ${TESTDIR}/1 +args: dirmodule" + + # We tolerate the creation of the dirmodule directory, since that + # is what CVS does, not because we view that as preferable to not + # creating it. + dotest_fail modules5-23 "test -f dirmodule/a || test -f dirmodule/b" "" + rm -r dirmodule + + # Now test that a module using -d checks out to the specified + # directory. + dotest modules5-24 "${testcvs} -q co namedmodule" \ +"U nameddir/a +U nameddir/b +checkout script invoked in ${TESTDIR}/1 +args: nameddir" + dotest modules5-25 "test -f nameddir/a && test -f nameddir/b" "" + echo add line >>nameddir/a + # This seems suspicious: when we checkout an existing directory, + # the checkout script gets executed in addition to the update + # script. Is that by design or accident? + dotest modules5-26 "${testcvs} -q co namedmodule" \ +"M nameddir/a +${PROG} [a-z]*: Executing ..${CVSROOT_DIRNAME}/update\.sh. .${CVSROOT_DIRNAME}/first-dir/subdir.. +update script invoked in ${TESTDIR}/1/nameddir +args: ${CVSROOT_DIRNAME}/first-dir/subdir +checkout script invoked in ${TESTDIR}/1 +args: nameddir" + rm nameddir/a + dotest modules5-27 "${testcvs} -q co namedmodule" \ +"U nameddir/a +${PROG} [a-z]*: Executing ..${CVSROOT_DIRNAME}/update\.sh. .${CVSROOT_DIRNAME}/first-dir/subdir.. +update script invoked in ${TESTDIR}/1/nameddir +args: ${CVSROOT_DIRNAME}/first-dir/subdir +checkout script invoked in ${TESTDIR}/1 +args: nameddir" + dotest modules5-28 "echo yes | ${testcvs} release -d nameddir" \ +"You have \[0\] altered files in this repository\. +Are you sure you want to release (and delete) directory .nameddir.: " + fi + + cd .. + rm -rf 1 ${CVSROOT_DIRNAME}/first-dir ${CVSROOT_DIRNAME}/*.sh + ;; + 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 @@ -7777,7 +8208,9 @@ Checking in CVSROOT/modules; ${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* done -${PROG} [a-z]*: Rebuilding administrative file database" +${PROG} [a-z]*: Rebuilding administrative file database" \ +"${PROG} [a-z]*: Examining . +${PROG} [a-z]*: Examining CVSROOT" rm -rf CVS CVSROOT; # Create the various modules @@ -9115,6 +9548,8 @@ ${PROG} [a-z]*: Rebuilding administrative file database" "U CVSROOT/modules" echo "# Module defs for emptydir tests" > CVSROOT/modules echo "2d1mod -d dir2d1/sub2d1 mod1" >> CVSROOT/modules + echo "2d1moda -d dir2d1/suba moda/modasub" >> CVSROOT/modules + echo "comb -a 2d1mod 2d1moda" >> CVSROOT/modules dotest emptydir-2 "${testcvs} ci -m add-modules" \ "${PROG} [a-z]*: Examining CVSROOT @@ -9122,27 +9557,39 @@ Checking in CVSROOT/modules; ${CVSROOT_DIRNAME}/CVSROOT/modules,v <-- modules new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* done -${PROG} [a-z]*: Rebuilding administrative file database" +${PROG} [a-z]*: Rebuilding administrative file database" \ +"${PROG} [a-z]*: Examining CVSROOT" rm -rf CVS CVSROOT - mkdir ${CVSROOT_DIRNAME}/mod1 + mkdir ${CVSROOT_DIRNAME}/mod1 ${CVSROOT_DIRNAME}/moda # Populate. Not sure we really need to do this. - dotest emptydir-3 "${testcvs} co mod1" \ -"${PROG} [a-z]*: Updating mod1" + dotest emptydir-3 "${testcvs} -q co -l ." "" + dotest emptydir-3a "${testcvs} co mod1 moda" \ +"${PROG} [a-z]*: Updating mod1 +${PROG} [a-z]*: Updating moda" echo "file1" > mod1/file1 - cd mod1 - dotest emptydir-4 "${testcvs} add file1" \ -"${PROG} [a-z]*: scheduling file .file1. for addition -${PROG} [a-z]*: use '${PROG} commit' to add this file permanently" - cd .. - dotest emptydir-5 "${testcvs} -q ci -m yup mod1" \ + mkdir moda/modasub + dotest emptydir-3b "${testcvs} add moda/modasub" \ +"Directory ${TESTDIR}/cvsroot/moda/modasub added to the repository" + echo "filea" > moda/modasub/filea + dotest emptydir-4 "${testcvs} add mod1/file1 moda/modasub/filea" \ +"${PROG} [a-z]*: scheduling file .mod1/file1. for addition +${PROG} [a-z]*: scheduling file .moda/modasub/filea. for addition +${PROG} [a-z]*: use '${PROG} commit' to add these files permanently" + dotest emptydir-5 "${testcvs} -q ci -m yup" \ "RCS file: ${CVSROOT_DIRNAME}/mod1/file1,v done Checking in mod1/file1; ${CVSROOT_DIRNAME}/mod1/file1,v <-- file1 initial revision: 1\.1 +done +RCS file: ${CVSROOT_DIRNAME}/moda/modasub/filea,v +done +Checking in moda/modasub/filea; +${CVSROOT_DIRNAME}/moda/modasub/filea,v <-- filea +initial revision: 1\.1 done" - rm -rf mod1 CVS + rm -rf mod1 moda CVS # End Populate. dotest emptydir-6 "${testcvs} co 2d1mod" \ @@ -9154,11 +9601,11 @@ U dir2d1/sub2d1/file1" # 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_fail emptydir-8 "${testcvs} -q ci -m add" \ -"${PROG} \[[a-z]* aborted\]: cannot check in to ${TESTDIR}/cvsroot/CVSROOT/Emptydir" + dotest_fail emptydir-7 "${testcvs} add emptyfile" \ +"${PROG} \[[a-z]* aborted\]: cannot add to ${TESTDIR}/cvsroot/CVSROOT/Emptydir" + mkdir emptydir + dotest_fail emptydir-8 "${testcvs} add emptydir" \ +"${PROG} \[[a-z]* aborted\]: cannot add to ${TESTDIR}/cvsroot/CVSROOT/Emptydir" cd .. rm -rf CVS dir2d1 @@ -9173,11 +9620,25 @@ ${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" dotest emptydir-11 "${testcvs} -q -n update -d -P" '' cd ../.. rm -r edir + cd .. + # Now start playing with moda. + mkdir 2; cd 2 + dotest emptydir-12 "${testcvs} -q co 2d1moda" \ +"U dir2d1/suba/filea" + # OK, this is the crux of the matter. Some people think + # it would be more logical if this showed "moda". But why + # "moda" (from module 2d1moda) and not "." (from module 2d1mod)? + dotest emptydir-13 "cat dir2d1/CVS/Repository" "CVSROOT/Emptydir" + dotest emptydir-14 "${testcvs} co comb" \ +"${PROG} [a-z]*: Updating dir2d1/sub2d1 +U dir2d1/sub2d1/file1 +${PROG} [a-z]*: Updating dir2d1/suba" + dotest emptydir-15 "cat dir2d1/CVS/Repository" "CVSROOT/Emptydir" cd .. - rm -r 1 - rm -rf ${CVSROOT_DIRNAME}/mod1 + rm -r 1 2 + rm -rf ${CVSROOT_DIRNAME}/mod1 ${CVSROOT_DIRNAME}/moda # I guess for the moment the convention is going to be # that we don't need to remove ${CVSROOT_DIRNAME}/CVSROOT/Emptydir ;; @@ -10002,6 +10463,14 @@ done" cd .. dotest errmsg2-8 "${testcvs} add first-dir/sdir" \ "Directory ${TESTDIR}/cvsroot/first-dir/sdir added to the repository" + # while we're here... check commit with no CVS directory + dotest_fail errmsg2-8a "${testcvs} -q ci first-dir nonexistant" \ +"${PROG} [a-z]*: nothing known about .nonexistant' +${PROG} \[[a-z]* aborted\]: correct above errors first!" + dotest_fail errmsg2-8b "${testcvs} -q ci nonexistant first-dir" \ +"${PROG} [a-z]*: nothing known about .nonexistant' +${PROG} \[[a-z]* aborted\]: correct above errors first!" + dotest errmsg2-8c "${testcvs} -q ci first-dir" "" cd first-dir @@ -10075,6 +10544,16 @@ done" dotest_fail errmsg2-19 "${testcvs} annotate -rtest -Dyesterday" \ "${PROG} \[[a-z]* aborted\]: rcsbuf_open: internal error" + # trying to import the repository + + if test "$remote" = "no"; then + cd ${CVSROOT_DIRNAME} + dotest_fail errmsg2-20 "${testcvs} import -mtest . A B" \ +"${PROG} \[[a-z]* aborted\]: attempt to import the repository" + dotest_fail errmsg2-21 "${testcvs} import -mtest first-dir A B" \ +"${PROG} \[[a-z]* aborted\]: attempt to import the repository" + fi + cd .. rm -r 1 rm -rf ${TESTDIR}/cvsroot/first-dir @@ -10366,7 +10845,25 @@ Fnw1 _watched= D _watched=" cd .. - cd .. + # Do a little error testing + dotest devcom2-18 "${testcvs} -q co -d first+dir first-dir" \ +"U first${PLUS}dir/nw1 +U first${PLUS}dir/w1 +U first${PLUS}dir/w2 +U first${PLUS}dir/w3" + cd first+dir + dotest_fail devcom2-19 "${testcvs} edit" \ +"${PROG} \[[a-z]* aborted\]: current directory (${TESTDIR}/2/first${PLUS}dir) contains an invalid character (${PLUS},>;=\\\\t\\\\n)" + + # Make sure there are no droppings lying around + dotest devcom2-20 "cat ${CVSROOT_DIRNAME}/first-dir/CVS/fileattr" \ +"Fw1 _watched= +Fw2 _watched= +Fw3 _watched= +Fnw1 _watched= +D _watched=" + + cd ../.. # Use -f because of the readonly files. rm -rf 1 2 @@ -10639,14 +11136,9 @@ done" rm -f CVS/Baserev # This will fail on most systems. - if echo "yes" | ${testcvs} -Q unedit $file \ - >${TESTDIR}/test.tmp 2>&1 ; then - dotest unedit-without-baserev-4 "cat ${TESTDIR}/test.tmp" \ + echo "yes" | dotest unedit-without-baserev-4 "${testcvs} -Q unedit $file" \ "m has been modified; revert changes${QUESTION} ${PROG} unedit: m not mentioned in CVS/Baserev ${PROG} unedit: run update to complete the unedit" - else - fail unedit-without-baserev-4 - fi # SunOS4.1.4 systems make it this far, but with a corrupted # CVS/Entries file. Demonstrate the corruption! @@ -10694,13 +11186,9 @@ rcsmerge: warning: conflicts during merge ${PROG} [a-z]*: conflicts found in m C m" rm CVS/Baserev - if (echo yes | ${testcvs} unedit m) >${TESTDIR}/test.tmp 2>&1; then - dotest unedit-without-baserev-14 "cat ${TESTDIR}/test.tmp" \ + echo yes | dotest unedit-without-baserev-14 "${testcvs} unedit m" \ "m has been modified; revert changes${QUESTION} ${PROG} unedit: m not mentioned in CVS/Baserev ${PROG} unedit: run update to complete the unedit" - else - fail unedit-without-baserev-14 - fi if test "$remote" = yes; then dotest unedit-without-baserev-15 "${testcvs} -q update" "U m" else @@ -10844,26 +11332,14 @@ ${QUESTION} first-dir/rootig.c ${QUESTION} second-dir/.cvsignore ${QUESTION} second-dir/notig.c" - if echo yes | ${testcvs} release -d first-dir \ - >${TESTDIR}/ignore.tmp; then - pass ignore-192 - else - fail ignore-192 - fi - dotest ignore-193 "cat ${TESTDIR}/ignore.tmp" \ + echo yes | dotest ignore-192 "${testcvs} release -d first-dir" \ "${QUESTION} \.cvsignore You have \[0\] altered files in this repository. Are you sure you want to release (and delete) directory .first-dir': " echo add a line >>second-dir/foobar.c rm second-dir/notig.c second-dir/.cvsignore - if echo yes | ${testcvs} release -d second-dir \ - >${TESTDIR}/ignore.tmp; then - pass ignore-194 - else - fail ignore-194 - fi - dotest ignore-195 "cat ${TESTDIR}/ignore.tmp" \ + echo yes | dotest ignore-194 "${testcvs} release -d second-dir" \ "M foobar.c You have \[1\] altered files in this repository. Are you sure you want to release (and delete) directory .second-dir': " @@ -10871,7 +11347,6 @@ Are you sure you want to release (and delete) directory .second-dir': " rm -r 1 cd .. rm -r wnt - rm ${TESTDIR}/ignore.tmp rm -rf ${CVSROOT_DIRNAME}/first-dir ${CVSROOT_DIRNAME}/second-dir ;; @@ -10887,8 +11362,8 @@ Are you sure you want to release (and delete) directory .second-dir': " 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", 2, 10, 137, 13, 10 }' \ - binfile.dat + ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ + binfile.dat cat binfile.dat binfile.dat >binfile2.dat cd first-dir cp ../binfile.dat binfile @@ -11159,8 +11634,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", 2, 10, 137, 13, 10 }' \ - ../binfile + ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ + ../binfile cat ../binfile ../binfile >../binfile2 cat ../binfile2 ../binfile >../binfile3 @@ -11321,8 +11796,8 @@ checkin 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 }' \ - binfile.dat + ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ + binfile.dat cd first-dir echo hello >file1 dotest binfiles3-2 "${testcvs} add file1" \ @@ -11377,9 +11852,9 @@ 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 + 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 + echo 'aawwee%$$##@@!!jjil' | ${TR} w '\000' >>${TESTDIR}/1/binfile5.dat cp ../binfile4.dat file1 dotest binfiles3-9 "${testcvs} -q ci -m change" \ @@ -12011,6 +12486,7 @@ ${PROG} [a-z]*: Rebuilding administrative file database" dotest info-1 "${testcvs} -q co CVSROOT" "[UP] CVSROOT${DOTSTAR}" cd CVSROOT + rm -f $TESTDIR/testlog $TESTDIR/testlog2 echo "ALL sh -c \"echo x\${=MYENV}\${=OTHER}y\${=ZEE}=\$USER=\$CVSROOT= >>$TESTDIR/testlog; cat >/dev/null\"" > loginfo # The following cases test the format string substitution echo "ALL echo %{sVv} >>$TESTDIR/testlog2; cat >/dev/null" >> loginfo @@ -12051,11 +12527,18 @@ ${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 initial revision: 1\.1 done ${PROG} [a-z]*: loginfo:1: no such user variable \${=ZEE}" + echo line0 >>file1 + dotest info-6b "${testcvs} -q -sOTHER=foo ci -m mod-it" \ +"Checking in file1; +${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 +new revision: 1\.2; previous revision: 1\.1 +done +${PROG} [a-z]*: loginfo:1: no such user variable \${=ZEE}" echo line1 >>file1 dotest info-7 "${testcvs} -q -s OTHER=value -s ZEE=z ci -m mod-it" \ "Checking in file1; ${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 -new revision: 1\.2; previous revision: 1\.1 +new revision: 1\.3; previous revision: 1\.2 done" cd .. dotest info-9 "cat $TESTDIR/testlog" "xenv-valueyz=${username}=${TESTDIR}/cvsroot=" @@ -12068,6 +12551,11 @@ first-dir file1,1.1,1.2 first-dir 1.2 first-dir file1 first-dir 1.1AX +first-dir file1ux +first-dir file1,1.2,1.3 +first-dir 1.3 +first-dir file1 +first-dir 1.2AX first-dir file1ux' cd CVSROOT @@ -12075,7 +12563,7 @@ first-dir file1ux' dotest info-11 "${testcvs} -q -s ZEE=garbage ci -m nuke-loginfo" \ "Checking in loginfo; ${TESTDIR}/cvsroot/CVSROOT/loginfo,v <-- loginfo -new revision: 1\.[0-9]; previous revision: 1\.[0-9] +new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* done ${PROG} [a-z]*: Rebuilding administrative file database" @@ -12086,6 +12574,7 @@ if head -1 < \$1 | grep '^BugId:[ ]*[0-9][0-9]*$' > /dev/null; then exit 0 else echo "No BugId found." + sleep 1 exit 1 fi EOF @@ -12094,7 +12583,7 @@ EOF dotest info-v1 "${testcvs} -q ci -m add-verification" \ "Checking in verifymsg; ${TESTDIR}/cvsroot/CVSROOT/verifymsg,v <-- verifymsg -new revision: 1\.2; previous revision: 1\.1 +new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* done ${PROG} [a-z]*: Rebuilding administrative file database" @@ -12111,7 +12600,7 @@ EOF dotest info-v3 "${testcvs} -q ci -F ${TESTDIR}/comment.tmp" \ "Checking in file1; ${TESTDIR}/cvsroot/first-dir/file1,v <-- file1 -new revision: 1\.3; previous revision: 1\.2 +new revision: 1\.4; previous revision: 1\.3 done" cd .. mkdir another-dir @@ -12130,7 +12619,7 @@ ${PROG} \[[a-z]* aborted\]: Message verification failed" dotest info-cleanup-verifymsg "${testcvs} -q ci -m nuke-verifymsg" \ "Checking in verifymsg; ${TESTDIR}/cvsroot/CVSROOT/verifymsg,v <-- verifymsg -new revision: 1\.[0-9]; previous revision: 1\.[0-9] +new revision: 1\.[0-9]*; previous revision: 1\.[0-9]* done ${PROG} [a-z]*: Rebuilding administrative file database" cd .. @@ -12392,8 +12881,10 @@ U file1' # -h: admin-19a-log # -N: log, log2, admin-19a-log # -b, -r: log - # -d: rcs - # -s, -R: rcs3 + # -d: logopt, rcs + # -s: logopt, rcs3 + # -R: logopt, rcs3 + # -w, -t: not tested yet (TODO) # Check in a file with a few revisions and branches. mkdir ${CVSROOT_DIRNAME}/first-dir @@ -12529,7 +13020,40 @@ ${log_rev2} ${log_rev1} ${log_trailer}" - dotest log-14 "${testcvs} log -r file1" \ + dotest log-14 "${testcvs} log -r file1" \ +"${log_header} +${log_tags} +${log_header2} +total revisions: 5; selected revisions: 1 +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}" + +# Check that unusual syntax works correctly. + + dotest log-14c "${testcvs} log -r: file1" \ "${log_header} ${log_tags} ${log_header2} @@ -12537,8 +13061,7 @@ total revisions: 5; selected revisions: 1 description: ${log_rev3} ${log_trailer}" - - dotest log-14a "${testcvs} log -rHEAD file1" \ + dotest log-14d "${testcvs} log -r, file1" \ "${log_header} ${log_tags} ${log_header2} @@ -12546,13 +13069,8 @@ 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} + dotest log-14e "${testcvs} log -r. file1" \ +"${log_header} ${log_tags} ${log_header2} total revisions: 5; selected revisions: 1 @@ -12600,6 +13118,18 @@ description: ${log_rev2b} ${log_trailer}" + # Multiple -r options are undocumented; see comments in + # cvs.texinfo about whether they should be deprecated. + dotest log-18a "${testcvs} log -r1.2.2.2 -r1.3:1.3 file1" \ +"${log_header} +${log_tags} +${log_header2} +total revisions: 5; selected revisions: 2 +description: +${log_rev3} +${log_rev2b} +${log_trailer}" + # This test would fail with the old invocation of rlog, but it # works with the builtin log support. dotest log-19 "${testcvs} log -rbranch. file1" \ @@ -12730,18 +13260,13 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; 1 =============================================================================" - # I believe that in Real Life (TM), this is broken for remote. - # That is, the filename in question must be the filename of a - # file on the server. It only happens to work here because the - # client machine and the server machine are one and the same. echo 'longer description' >${TESTDIR}/descrip echo 'with two lines' >>${TESTDIR}/descrip 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" +"${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 @@ -12760,22 +13285,13 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; 1 =============================================================================" - # Reading the description from stdin is broken for remote. - # 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. + # 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 - else - fail log2-9 - fi - dotest log2-10 "${testcvs} log -N file1" " + dotest log2-9 "echo change from stdin | ${testcvs} admin -t -q file1" "" + dotest log2-10 "${testcvs} log -N file1" " RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v Working file: file1 head: 1\.1 @@ -12792,8 +13308,6 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; 1 =============================================================================" - fi # end of tests skipped for remote - cd .. rm ${TESTDIR}/descrip rm -r first-dir @@ -12801,6 +13315,49 @@ date: [0-9/]* [0-9:]*; author: ${username}; state: Exp; ;; + logopt) + # Some tests of log.c's option parsing and such things. + mkdir 1; cd 1 + dotest logopt-1 "${testcvs} -q co -l ." '' + mkdir first-dir + dotest logopt-2 "${testcvs} add first-dir" \ +"Directory ${TESTDIR}/cvsroot/first-dir added to the repository" + cd first-dir + echo hi >file1 + dotest logopt-3 "${testcvs} add file1" \ +"${PROG} [a-z]*: scheduling file .file1. for addition +${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" + dotest logopt-4 "${testcvs} -q ci -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 +done" + cd .. + + dotest logopt-5 "${testcvs} log -R -d 2038-01-01" \ +"${PROG} [a-z]*: Logging \. +${PROG} [a-z]*: Logging first-dir +${TESTDIR}/cvsroot/first-dir/file1,v" + dotest logopt-6 "${testcvs} log -d 2038-01-01 -R" \ +"${PROG} [a-z]*: Logging \. +${PROG} [a-z]*: Logging first-dir +${TESTDIR}/cvsroot/first-dir/file1,v" + dotest logopt-6a "${testcvs} log -Rd 2038-01-01" \ +"${PROG} [a-z]*: Logging \. +${PROG} [a-z]*: Logging first-dir +${TESTDIR}/cvsroot/first-dir/file1,v" + dotest logopt-7 "${testcvs} log -s Exp -R" \ +"${PROG} [a-z]*: Logging \. +${PROG} [a-z]*: Logging first-dir +${TESTDIR}/cvsroot/first-dir/file1,v" + + cd .. + rm -r 1 + rm -rf ${CVSROOT_DIRNAME}/first-dir + ;; + ann) # Tests of "cvs annotate". See also: # basica-10 A simple annotate test @@ -13296,7 +13853,7 @@ add file1 # ISO8601 format. There are many, many, other variations # specified by ISO8601 which we should be testing too. - dotest rcs-3 "${testcvs} -q log -d 1996-12-11<" " + dotest rcs-3 "${testcvs} -q log -d '1996-12-11<'" " RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v Working file: file1 head: 1\.3 @@ -13315,9 +13872,8 @@ delete second line; modify twelfth line =============================================================================" # RFC822 format (as amended by RFC1123). - if ${testcvs} -q log -d '<3 Apr 2000 00:00' >${TESTDIR}/rcs4.tmp - then - dotest rcs-4 "cat ${TESTDIR}/rcs4.tmp" " + dotest rcs-4 "${testcvs} -q log -d '<3 Apr 2000 00:00'" \ +" RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v Working file: file1 head: 1\.3 @@ -13338,9 +13894,6 @@ revision 1\.1 date: 1996/11/24 15:56:05; author: kingdon; state: Exp; add file1 =============================================================================" - else - fail rcs-4 - fi # Intended behavior for "cvs annotate" is that it displays the # last two digits of the year. Make sure it does that rather @@ -13545,47 +14098,22 @@ a1 1 next branch revision @" - if ${testcvs} -q update -p -D '1970-12-31 11:30 UT' file2 \ - >${TESTDIR}/rcs4.tmp - then - dotest rcs-9 "cat ${TESTDIR}/rcs4.tmp" "start revision" - else - fail rcs-9 - fi + dotest rcs-9 "${testcvs} -q update -p -D '1970-12-31 11:30 UT' file2" \ +"start revision" - if ${testcvs} -q update -p -D '1970-12-31 12:30 UT' file2 \ - >${TESTDIR}/rcs4.tmp - then - dotest rcs-10 "cat ${TESTDIR}/rcs4.tmp" "mid revision" - else - fail rcs-10 - fi + dotest rcs-10 "${testcvs} -q update -p -D '1970-12-31 12:30 UT' file2" \ +"mid revision" - if ${testcvs} -q update -p -D '1971-01-01 00:30 UT' file2 \ - >${TESTDIR}/rcs4.tmp - then - dotest rcs-11 "cat ${TESTDIR}/rcs4.tmp" "new year revision" - else - fail rcs-11 - fi + dotest rcs-11 "${testcvs} -q update -p -D '1971-01-01 00:30 UT' file2" \ +"new year revision" # Same test as rcs-10, but with am/pm. - if ${testcvs} -q update -p -D 'December 31, 1970 12:30pm UT' file2 \ - >${TESTDIR}/rcs4.tmp - then - dotest rcs-12 "cat ${TESTDIR}/rcs4.tmp" "mid revision" - else - fail rcs-12 - fi + dotest rcs-12 "${testcvs} -q update -p -D 'December 31, 1970 12:30pm UT' file2" \ +"mid revision" # Same test as rcs-11, but with am/pm. - if ${testcvs} -q update -p -D 'January 1, 1971 12:30am UT' file2 \ - >${TESTDIR}/rcs4.tmp - then - dotest rcs-13 "cat ${TESTDIR}/rcs4.tmp" "new year revision" - else - fail rcs-13 - fi + dotest rcs-13 "${testcvs} -q update -p -D 'January 1, 1971 12:30am UT' file2" \ +"new year revision" # OK, now make sure cvs log doesn't have any trouble with the # newphrases and such. @@ -13631,9 +14159,49 @@ revision 1\.2\.6\.1 date: 1971/01/01 08:00:05; author: joe; state: Exp; lines: ${PLUS}1 -1 \*\*\* empty log message \*\*\* =============================================================================" + # Now test each date format for "cvs log -d". + # Earlier than 1971-01-01 + dotest rcs-15 "${testcvs} -q log -d '<1971-01-01 00:00 GMT' file2 \ + | grep revision" \ +"total revisions: 7; selected revisions: 3 +revision 1\.3 +revision 1\.2 +revision 1\.1" + # Later than 1971-01-01 + dotest rcs-16 "${testcvs} -q log -d '1971-01-01 00:00 GMT<' file2 \ + | grep revision" \ +"total revisions: 7; selected revisions: 4 +revision 1\.5 +revision 1\.4 +revision 1\.2\.6\.2 +revision 1\.2\.6\.1" + # Alternate syntaxes for later and earlier; multiple -d options + dotest rcs-17 "${testcvs} -q log -d '>1971-01-01 00:00 GMT' \ + -d '1970-12-31 12:15 GMT>' file2 | grep revision" \ +"total revisions: 7; selected revisions: 5 +revision 1\.5 +revision 1\.4 +revision 1\.1 +revision 1\.2\.6\.2 +revision 1\.2\.6\.1" + # Range, and single date + dotest rcs-18 "${testcvs} -q log -d '1970-12-31 11:30 GMT' \ + -d '1971-01-01 00:00:05 GMT<1971-01-01 01:00:01 GMT' \ + file2 | grep revision" \ +"total revisions: 7; selected revisions: 2 +revision 1\.5 +revision 1\.1" + # Alternate range syntax; equality + dotest rcs-19 "${testcvs} -q log \ + -d '1971-01-01 01:00:01 GMT>=1971-01-01 00:00:05 GMT' \ + file2 | grep revision" \ +"total revisions: 7; selected revisions: 2 +revision 1\.5 +revision 1\.4" + cd .. - rm -r first-dir ${TESTDIR}/rcs4.tmp + rm -r first-dir rm -rf ${CVSROOT_DIRNAME}/first-dir ;; @@ -13684,41 +14252,17 @@ EOF cd first-dir # 9 Sep 1999 - if ${testcvs} -q update -p -D '1999-09-09 11:30 UT' file1 \ - >${TESTDIR}/rcs4.tmp - then - dotest rcs2-2 "cat ${TESTDIR}/rcs4.tmp" \ + dotest rcs2-2 "${testcvs} -q update -p -D '1999-09-09 11:30 UT' file1" \ "Tonight we're going to party like it's a certain year" - else - fail rcs2-2 - fi # 1 Jan 2001. - if ${testcvs} -q update -p -D '2001-01-01 11:30 UT' file1 \ - >${TESTDIR}/rcs4.tmp - then - dotest rcs2-3 "cat ${TESTDIR}/rcs4.tmp" \ + dotest rcs2-3 "${testcvs} -q update -p -D '2001-01-01 11:30 UT' file1" \ "two year hiatus" - else - fail rcs2-3 - fi # 29 Feb 2000 - if ${testcvs} -q update -p -D '2000-02-29 11:30 UT' file1 \ - >${TESTDIR}/rcs4.tmp - then - dotest rcs2-4 "cat ${TESTDIR}/rcs4.tmp" \ + dotest rcs2-4 "${testcvs} -q update -p -D '2000-02-29 11:30 UT' file1" \ "2000 is also a good year for leaping" - else - fail rcs2-4 - fi # 29 Feb 2003 is invalid - if ${testcvs} -q update -p -D '2003-02-29 11:30 UT' file1 \ - >${TESTDIR}/rcs4.tmp 2>&1 - then - fail rcs2-5 - else - dotest rcs2-5 "cat ${TESTDIR}/rcs4.tmp" \ + dotest_fail rcs2-5 "${testcvs} -q update -p -D '2003-02-29 11:30 UT' file1" \ "${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" @@ -13736,22 +14280,10 @@ EOF # 31 May 1999), it seems to fail. # # Sigh. - 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 + dotest rcs2-7 "${testcvs} -q update -p -D '100 months' file1" \ +"head revision" + dotest rcs2-8 "${testcvs} -q update -p -D '8 years' file1" \ +"head revision" cd .. rm -r first-dir @@ -13772,7 +14304,7 @@ EOF # 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" +"${PROG} \[[a-z]* aborted\]: EOF while looking for value in RCS file ${TESTDIR}/cvsroot/first-dir/file1,v" cat <${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@ @@ -13793,25 +14325,15 @@ 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" \ + + # 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" \ "${DOTSTAR}ssertion.*failed${DOTSTAR}" "${DOTSTAR}failed assertion${DOTSTAR}" - cd .. - fi # remote + cd first-dir + dotest_fail rcs3-5a "${testcvs} log -s nostate file1" \ +"${DOTSTAR}ssertion.*failed${DOTSTAR}" "${DOTSTAR}failed assertion${DOTSTAR}" + cd .. # See remote code above for rationale for cd. cd first-dir @@ -13819,7 +14341,7 @@ ${PROG} \[log aborted\]: no repository" "${TESTDIR}/cvsroot/first-dir/file1,v" # OK, now put an extraneous '\0' at the end. - awk >${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" @@ -13882,6 +14404,7 @@ ${PROG} \[[a-z]* aborted\]: cannot stat ${TESTDIR}/locks: No such file or direct cd ../../.. dotest lockfiles-8 "${testcvs} -q update" "" + dotest lockfiles-9 "${testcvs} -q co -l ." "" cd CVSROOT echo "# nobody here but us comments" >config @@ -14099,9 +14622,9 @@ ${PROG} \[[a-z]* aborted\]: could not find desired version 1\.6 in ${TESTDIR}/cv # database dirs in a workspace with later revisions than those in the # recovered repository cd repos-first-dir -DATADIRS=\`find . -name CVS\` +DATADIRS=\`find . -name CVS -print\` cd ../first-dir -find . -name CVS |xargs rm -rf +find . -name CVS -print | xargs rm -rf for file in \${DATADIRS}; do cp -r ../repos-first-dir/\${file} \${file} done" >fixit @@ -14204,42 +14727,79 @@ done" # slowly and carefully. cat >${CVSROOT_DIRNAME}/CVSROOT/history </*0|ccvs||ccvs +O3396c677|anonymous|/src|ccvs||src +O3397c677|kingdon|/*0|ccvs||ccvs M339cafae|nk||ccvs/src|1.229|sanity.sh +M339cafff|anonymous||ccvs/src|1.23|Makefile M339dc339|kingdon|~/work/*0|ccvs/src|1.231|sanity.sh W33a6eada|anonymous|*4|ccvs/emx||Makefile.in C3b235f50|kingdon||ccvs/emx|1.3|README M3b23af50|kingdon|~/work/*0|ccvs/doc|1.281|cvs.texinfo EOF dotest history-1 "${testcvs} history -e -a" \ -"O 06/04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= /\* -W 06/17 19:51 ${PLUS}0000 anonymous Makefile\.in ccvs/emx == /emx -M 06/10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src -C 06/10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == -M 06/10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc -M 06/10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == " - if ${testcvs} history -e -a -D '10 Jun 1997 13:00 UT' \ - >${TESTDIR}/output.tmp - then - dotest history-2 "cat ${TESTDIR}/output.tmp" \ -"W 06/17 19:51 ${PLUS}0000 anonymous Makefile\.in ccvs/emx == /emx -M 06/10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src -C 06/10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == -M 06/10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc" - else - fail history-2 - fi - if ${testcvs} history -e -a -D '10 Jun 2001 13:00 UT' \ - >${TESTDIR}/output.tmp - then - # For reasons that are completely unclear to me, the number - # of spaces betwen "kingdon" and "1.281" is different than - # for the other tests. - dotest history-3 "cat ${TESTDIR}/output.tmp" \ -"M 06/10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc" - else - fail history-3 - fi - rm ${TESTDIR}/output.tmp +"O 1997-06-04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= /\* +O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= /\* +M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == +W 1997-06-17 19:51 ${PLUS}0000 anonymous Makefile\.in ccvs/emx == /emx +O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= /\* +M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src +C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == +M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc +M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == " + + dotest history-2 "${testcvs} history -e -a -D '10 Jun 1997 13:00 UT'" \ +"W 1997-06-17 19:51 ${PLUS}0000 anonymous Makefile\.in ccvs/emx == /emx +M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src +C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == +M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc" + + dotest history-3 "${testcvs} history -e -a -D '10 Jun 2001 13:00 UT'" \ +"M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs\.texinfo ccvs/doc == ~/work/ccvs/doc" + + dotest history-4 "${testcvs} history -ac sanity.sh" \ +"M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src +M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == " + + dotest history-5 "${testcvs} history -a -xCGUWAMR README sanity.sh" \ +"M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src +C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == +M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == " + + dotest history-6 "${testcvs} history -xCGUWAMR -a -f README -f sanity.sh" \ +"M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src +C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == +M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == " + + dotest history-7 "${testcvs} history -xCGUWAMR -a -f sanity.sh README" \ +"M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity\.sh ccvs/src == ~/work/ccvs/src +C 2001-06-10 11:51 ${PLUS}0000 kingdon 1\.3 README ccvs/emx == +M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity\.sh ccvs/src == " + + dotest history-8 "${testcvs} history -ca -D '1970-01-01 00:00 UT'" \ +"M 1997-06-10 01:36 ${PLUS}0000 nk 1\.229 sanity.sh ccvs/src == +M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == +M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity.sh ccvs/src == ~/work/ccvs/src +M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs.texinfo ccvs/doc == ~/work/ccvs/doc" + + dotest history-9 "${testcvs} history -acl" \ +"M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs.texinfo ccvs/doc == ~/work/ccvs/doc +M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == +M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity.sh ccvs/src == ~/work/ccvs/src" + + dotest history-10 "${testcvs} history -lca -D '1970-01-01 00:00 UT'" \ +"M 2001-06-10 17:33 ${PLUS}0000 kingdon 1\.281 cvs.texinfo ccvs/doc == ~/work/ccvs/doc +M 1997-06-10 01:38 ${PLUS}0000 anonymous 1\.23 Makefile ccvs/src == +M 1997-06-10 21:12 ${PLUS}0000 kingdon 1\.231 sanity.sh ccvs/src == ~/work/ccvs/src" + + dotest history-11 "${testcvs} history -aw" \ +"O 1997-06-04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= /\* +O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= /\* +O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= /\*" + + dotest history-12 "${testcvs} history -aw -D'1970-01-01 00:00 UT'" \ +"O 1997-06-04 19:48 ${PLUS}0000 anonymous ccvs =ccvs= /\* +O 1997-06-05 14:00 ${PLUS}0000 anonymous ccvs =src= /\* +O 1997-06-06 08:12 ${PLUS}0000 kingdon ccvs =ccvs= /\*" ;; big) @@ -14481,17 +15041,17 @@ done" # 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 ." '' + dotest modes3-1 "${testcvs} -q co -l ." '' mkdir first-dir second-dir - dotest modes-2 "${testcvs} add first-dir second-dir" \ + dotest modes3-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" \ + dotest modes3-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" \ + dotest modes3-4 "${testcvs} -q ci -m add" \ "RCS file: ${TESTDIR}/cvsroot/first-dir/aa,v done Checking in first-dir/aa; @@ -14505,7 +15065,7 @@ ${TESTDIR}/cvsroot/second-dir/ab,v <-- ab initial revision: 1\.1 done" chmod a= ${TESTDIR}/cvsroot/first-dir - dotest modes-5 "${testcvs} update" \ + dotest modes3-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 @@ -14517,7 +15077,7 @@ ${PROG} [a-z]*: Updating second-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" \ + dotest modes3-6 "${testcvs} update -dP" \ "${PROG} [a-z]*: Updating . ${PROG} [a-z]*: Updating CVSROOT U ${DOTSTAR} @@ -15470,9 +16030,9 @@ xx" "${PROG} [a-z]*: scheduling file .file1. for addition ${PROG} [a-z]*: use .${PROG} commit. to add this file permanently" - awk 'BEGIN { printf "%c%c%c%sRevision: 1.1 $@%c%c", \ + ${AWK} 'BEGIN { printf "%c%c%c%sRevision: 1.1 $@%c%c", \ 2, 10, 137, "$", 13, 10 }' \ - ../binfile.dat + ../binfile.dat cp ../binfile.dat . dotest keyword2-5 "${testcvs} add -kb binfile.dat" \ "${PROG} [a-z]*: scheduling file .binfile\.dat. for addition @@ -15577,8 +16137,8 @@ done" T file1" dotest keyword2-18 "${testcvs} -q update -r branch2" '' - awk 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ - >binfile.dat + ${AWK} 'BEGIN { printf "%c%c%c@%c%c", 2, 10, 137, 13, 10 }' \ + >binfile.dat dotest keyword2-19 "${testcvs} -q ci -m badbadbad" \ "Checking in binfile\.dat; ${TESTDIR}/cvsroot/first-dir/binfile\.dat,v <-- binfile\.dat @@ -15851,51 +16411,16 @@ new revision: 1\.1\.4\.2; previous revision: 1\.1\.4\.1 done" cd ../.. mkdir 2; cd - if ${testcvs} -q export -r br2 -D'1 minute ago' first-dir \ - >${TESTDIR}/tagdate.tmp 2>&1; then - if ${EXPR} "`cat ${TESTDIR}/tagdate.tmp`" : \ -"[UP] first-dir/file1" >/dev/null; then - pass tagdate-14 - else - echo "** expected: " >>${LOGFILE} - echo "[UP] first-dir/file1" >>${LOGFILE} - echo "** got: " >>${LOGFILE} - cat ${TESTDIR}/tagdate.tmp >>${LOGFILE} - fail tagdate-14 - fi - else - echo "Bad exit status" >>${LOGFILE} - fail tagdate-14 - fi - - if ${EXPR} "`cat first-dir/file1`" : "br2-1" >/dev/null; then - pass tagdate-15 - else - fail tagdate-15 - fi + dotest tagdate-14 "${testcvs} -q export -r br2 -D'1 minute ago' first-dir" \ +"[UP] first-dir/file1" + dotest tagdate-15 "cat first-dir/file1" "br2-1" # Now for annotate cd ../1/first-dir - if ${testcvs} annotate -rbr2 -D'1 minute ago' \ - >${TESTDIR}/tagdate.tmp 2>&1; then - if ${EXPR} "`cat ${TESTDIR}/tagdate.tmp`" : \ + dotest tagdate-16 "${testcvs} annotate -rbr2 -D'1 minute ago'" \ "Annotations for file1 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1\.4\.1 (${username} *[0-9a-zA-Z-]*): br2-1" >/dev/null; then - pass tagdate-16 - else - echo "** expected: " >>${LOGFILE} - echo "Annotations for file1 -\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* -1\.1\.4\.1 (${username} *[0-9a-zA-Z-]*): br2-1" >>${LOGFILE} - echo "** got: " >>${LOGFILE} - cat ${TESTDIR}/tagdate.tmp >>${LOGFILE} - fail tagdate-16 - fi - else - echo "Bad exit status" >>${LOGFILE} - fail tagdate-16 - fi +1\.1\.4\.1 (${username} *[0-9a-zA-Z-]*): br2-1" dotest tagdate-17 "${testcvs} annotate -rbr2 -Dnow" \ "Annotations for file1 @@ -15908,7 +16433,6 @@ done" fi cd ../.. - rm ${TESTDIR}/tagdate.tmp rm -r 1 2 rm -rf ${CVSROOT_DIRNAME}/first-dir ;; @@ -16452,16 +16976,27 @@ access list: keyword substitution: kv total revisions: 2 =============================================================================" - # Put the access list back, to avoid special cases later. - dotest admin-19a-fix "${testcvs} -q admin -eauth3 file1" \ + fi # end of tests skipped for remote + + # Now test that plain -e works right. + dotest admin-19a-2 "${testcvs} -q admin -e file1" \ "RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v done" - fi # end of tests skipped for remote + dotest admin-19a-3 "${testcvs} -q log -h -N file1" " +RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +Working file: file1 +head: 1\.1 +branch: +locks: strict +access list: +keyword substitution: kv +total revisions: 2 +=============================================================================" - # Now test that plain -e is at least parsed right. CVS 1.10 - # would wrongly treat "-e file1" as "-efile1". - dotest_fail admin-19a-2 "${testcvs} -q admin -e file1" \ -"${PROG} \[[a-z]* aborted\]: removing entire access list not yet implemented" + # Put the access list back, to avoid special cases later. + dotest admin-19a-4 "${testcvs} -q admin -afoo,auth2 file1" \ +"RCS file: ${TESTDIR}/cvsroot/first-dir/file1,v +done" # Add another revision to file2, so we can delete one. echo 'add a line' >> file2 @@ -17020,13 +17555,13 @@ add cat >${TESTDIR}/lockme <${CVSROOT_DIRNAME}/CVSROOT/passwd - ${testcvs} pserver >${TESTDIR}/pserver.tmp 2>&1 <${CVSROOT_DIRNAME}/CVSROOT/passwd <${TESTDIR}/pserver.tmp 2>&1 <${TESTDIR}/pserver.tmp 2>&1 <${TESTDIR}/pserver.tmp 2>&1 <${TESTDIR}/pserver.tmp 2>&1 <${TESTDIR}/pserver.tmp 2>&1 <config @@ -19835,38 +20450,28 @@ ${PROG} [a-z]*: Rebuilding administrative file database" server) # Some tests of the server (independent of the client). if test "$remote" = yes; then - if ${testcvs} server >${TESTDIR}/server.tmp <>${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 <>${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 { \ + ${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}' \ - gzipped.dat + gzipped.dat # Note that the CVS client sends "-b 1.1.1", and this # test doesn't. But the server also defaults to that. cat <session.dat @@ -19887,21 +20492,20 @@ z25 EOF cat gzipped.dat >>session.dat echo import >>session.dat - if ${testcvs} server >${TESTDIR}/server.tmp >${LOGFILE} - fail server-4 - fi +ok" ${TESTDIR}/server.tmp <>${LOGFILE} - fail server-6 - fi # Sending the second "noop" before waiting for the output # from the first is bogus but hopefully we can get away # with it. - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-7 - fi # OK, now test a few error conditions. - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-8 - fi - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-9 - fi # First demonstrate an interesting quirk in the protocol. # The "watchers" request selects the files to operate based # on files which exist in the working directory. So if we # don't send "Entry" or the like, it won't do anything. # Wants to be documented in cvsclient.texi... - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-10 - fi - # See if "watchers" and "editors" display the right thing. - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-11 - fi - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-12 - fi # Now do an unedit. - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-13 - fi # Now try "watchers" and "editors" again. - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-14 - fi - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server-15 - fi if test "$keep" = yes; then echo Keeping ${TESTDIR} and exiting due to --keep @@ -20078,7 +20625,6 @@ EOF rm -rf ${TESTDIR}/crerepos rm gzipped.dat session.dat - rm ${TESTDIR}/server.tmp fi # skip the whole thing for local ;; @@ -20086,66 +20632,46 @@ EOF # More server tests, in particular testing that various # possible security holes are plugged. if test "$remote" = yes; then - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server2-1 - fi - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server2-2 - fi - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server2-3 - fi # OK, now a few tests for the rule that one cannot pass a # filename containing a slash to Modified, Is-modified, # Notify, Questionable, or Unchanged. For completeness # we'd try them all. For lazyness/conciseness we don't. - if ${testcvs} server >${TESTDIR}/server.tmp <>${LOGFILE} - fail server2-4 - fi fi ;; @@ -20175,7 +20701,7 @@ EOF 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\." +"${PROG} \[checkout aborted\]: This server does not support the global -q option${DOTSTAR}" dotest client-2 "${testcvs} co first-dir" "special message" cat >${TESTDIR}/serveme </dev/null EOF cd first-dir mkdir ${TESTDIR}/bogus + # The ${DOTSTAR} is to match a potential "broken pipe" if the + # client exits before the server script sends everything dotest_fail client-3 "${testcvs} update" "merge-it -${PROG} \[update aborted\]: protocol error: Copy-file tried to specify directory" +${PROG} \[update aborted\]: protocol error: Copy-file tried to specify director${DOTSTAR}" cat >${TESTDIR}/serveme < 0) @@ -1338,10 +1355,10 @@ receive_file (size, file, gzipped) fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) + int save_errno = errno; + if (alloc_pending (40 + strlen (arg))) sprintf (pending_error_text, "E cannot open %s", arg); - pending_error = errno; + pending_error = save_errno; return; } @@ -1407,7 +1424,7 @@ receive_file (size, file, gzipped) goto out; } - if (gunzip_and_write (fd, file, filebuf, size)) + if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size)) { if (alloc_pending (80)) sprintf (pending_error_text, @@ -1433,10 +1450,10 @@ receive_file (size, file, gzipped) out: if (close (fd) < 0 && !error_pending ()) { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) + int save_errno = errno; + if (alloc_pending (40 + strlen (arg))) sprintf (pending_error_text, "E cannot close %s", arg); - pending_error = errno; + pending_error = save_errno; return; } } @@ -1515,10 +1532,11 @@ serve_modified (arg) { sprintf (pending_error_text, "E error reading size for %s", arg); - pending_error = errno; + pending_error = status; } } } + free (mode_text); return; } if (size_text[0] == 'z') @@ -1543,16 +1561,24 @@ serve_modified (arg) return; size -= nread; } + free (mode_text); return; } if (outside_dir (arg)) + { + free (mode_text); return; + } if (size >= 0) { receive_file (size, arg, gzipped); - if (error_pending ()) return; + if (error_pending ()) + { + free (mode_text); + return; + } } if (checkin_time_valid) @@ -1563,9 +1589,11 @@ serve_modified (arg) t.modtime = t.actime = checkin_time; if (utime (arg, &t) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (arg))) sprintf (pending_error_text, "E cannot utime %s", arg); + pending_error = save_errno; + free (mode_text); return; } checkin_time_valid = 0; @@ -1576,8 +1604,7 @@ serve_modified (arg) free (mode_text); if (status) { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) + if (alloc_pending (40 + strlen (arg))) sprintf (pending_error_text, "E cannot change mode for %s", arg); pending_error = status; @@ -1852,9 +1879,10 @@ server_write_entries () f = CVS_FOPEN (CVSADM_ENT, "a"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_ENT))) sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT); + pending_error = save_errno; } } for (p = entries; p != NULL;) @@ -1863,10 +1891,11 @@ server_write_entries () { if (fprintf (f, "%s\n", p->entry) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen(CVSADM_ENT))) sprintf (pending_error_text, "E cannot write to %s", CVSADM_ENT); + pending_error = save_errno; } } free (p->entry); @@ -1877,9 +1906,10 @@ server_write_entries () entries = NULL; if (f != NULL && fclose (f) == EOF && !error_pending ()) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_ENT))) sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT); + pending_error = save_errno; } } @@ -1911,8 +1941,8 @@ static void serve_notify (arg) char *arg; { - struct notify_note *new; - char *data; + struct notify_note *new = NULL; + char *data = NULL; int status; if (error_pending ()) return; @@ -1920,27 +1950,26 @@ serve_notify (arg) if (outside_dir (arg)) return; + if (dir_name == NULL) + goto error; + new = (struct notify_note *) malloc (sizeof (struct notify_note)); if (new == NULL) { pending_error = ENOMEM; return; } - if (dir_name == NULL) - goto error; new->dir = malloc (strlen (dir_name) + 1); - if (new->dir == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (new->dir, dir_name); new->filename = malloc (strlen (arg) + 1); - if (new->filename == NULL) + if (new->dir == NULL || new->filename == NULL) { pending_error = ENOMEM; + if (new->dir != NULL) + free (new->dir); + free (new); return; } + strcpy (new->dir, dir_name); strcpy (new->filename, arg); status = buf_read_line (buf_from_net, &data, (int *) NULL); @@ -1966,6 +1995,9 @@ serve_notify (arg) } } } + free (new->filename); + free (new->dir); + free (new); } else { @@ -2013,11 +2045,18 @@ serve_notify (arg) } return; error: - pending_error_text = malloc (80); - if (pending_error_text) + pending_error = 0; + if (alloc_pending (80)) strcpy (pending_error_text, "E Protocol error; misformed Notify request"); - pending_error = 0; + if (data != NULL) + free (data); + if (new != NULL) + { + free (new->filename); + free (new->dir); + free (new); + } return; } @@ -2060,6 +2099,7 @@ server_notify () buf_append_char (buf_to_net, '/'); buf_output0 (buf_to_net, notify_list->filename); buf_append_char (buf_to_net, '\n'); + free (repos); p = notify_list->next; free (notify_list->filename); @@ -2647,22 +2687,26 @@ error \n"); if (pipe (stdout_pipe) < 0) { + buf_output0 (buf_to_net, "E pipe failed\n"); print_error (errno); goto error_exit; } if (pipe (stderr_pipe) < 0) { + buf_output0 (buf_to_net, "E pipe failed\n"); print_error (errno); goto error_exit; } if (pipe (protocol_pipe) < 0) { + buf_output0 (buf_to_net, "E pipe failed\n"); print_error (errno); goto error_exit; } #ifdef SERVER_FLOWCONTROL if (pipe (flowcontrol_pipe) < 0) { + buf_output0 (buf_to_net, "E pipe failed\n"); print_error (errno); goto error_exit; } @@ -2673,6 +2717,7 @@ error \n"); dev_null_fd = CVS_OPEN (DEVNULL, O_RDONLY); if (dev_null_fd < 0) { + buf_output0 (buf_to_net, "E open /dev/null failed\n"); print_error (errno); goto error_exit; } @@ -2700,6 +2745,7 @@ error \n"); command_pid = fork (); if (command_pid < 0) { + buf_output0 (buf_to_net, "E fork failed\n"); print_error (errno); goto error_exit; } @@ -2733,8 +2779,11 @@ error \n"); error (1, errno, "can't set up pipes"); if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0) error (1, errno, "can't set up pipes"); + close (dev_null_fd); close (stdout_pipe[0]); + close (stdout_pipe[1]); close (stderr_pipe[0]); + close (stderr_pipe[1]); close (protocol_pipe[0]); #ifdef SERVER_FLOWCONTROL close (flowcontrol_pipe[1]); @@ -2769,6 +2818,7 @@ error \n"); * When we exit, that will close the pipes, giving an EOF to * the parent. */ + buf_free (protocol); exit (exitstatus); } @@ -2825,6 +2875,7 @@ error \n"); if (close (stdout_pipe[1]) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2832,6 +2883,7 @@ error \n"); if (close (stderr_pipe[1]) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2839,6 +2891,7 @@ error \n"); if (close (protocol_pipe[1]) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2847,6 +2900,7 @@ error \n"); #ifdef SERVER_FLOWCONTROL if (close (flowcontrol_pipe[0]) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2855,6 +2909,7 @@ error \n"); if (close (dev_null_fd) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2922,6 +2977,7 @@ error \n"); if (numfds < 0 && errno != EINTR) { + buf_output0 (buf_to_net, "E select failed\n"); print_error (errno); goto error_exit; } @@ -2933,48 +2989,6 @@ error \n"); buf_send_output (buf_to_net); } - if (stdout_pipe[0] >= 0 - && (FD_ISSET (stdout_pipe[0], &readfds))) - { - int status; - - status = buf_input_data (stdoutbuf, (int *) NULL); - - buf_copy_lines (buf_to_net, stdoutbuf, 'M'); - - if (status == -1) - stdout_pipe[0] = -1; - else if (status > 0) - { - print_error (status); - goto error_exit; - } - - /* What should we do with errors? syslog() them? */ - buf_send_output (buf_to_net); - } - - if (stderr_pipe[0] >= 0 - && (FD_ISSET (stderr_pipe[0], &readfds))) - { - int status; - - status = buf_input_data (stderrbuf, (int *) NULL); - - buf_copy_lines (buf_to_net, stderrbuf, 'E'); - - if (status == -1) - stderr_pipe[0] = -1; - else if (status > 0) - { - print_error (status); - goto error_exit; - } - - /* What should we do with errors? syslog() them? */ - buf_send_output (buf_to_net); - } - if (protocol_pipe[0] >= 0 && (FD_ISSET (protocol_pipe[0], &readfds))) { @@ -2985,9 +2999,13 @@ error \n"); status = buf_input_data (protocol_inbuf, &count_read); if (status == -1) + { + close (protocol_pipe[0]); protocol_pipe[0] = -1; + } else if (status > 0) { + buf_output0 (buf_to_net, "E buf_input_data failed\n"); print_error (status); goto error_exit; } @@ -3024,6 +3042,56 @@ error \n"); } } } + + if (stdout_pipe[0] >= 0 + && (FD_ISSET (stdout_pipe[0], &readfds))) + { + int status; + + status = buf_input_data (stdoutbuf, (int *) NULL); + + buf_copy_lines (buf_to_net, stdoutbuf, 'M'); + + if (status == -1) + { + close (stdout_pipe[0]); + stdout_pipe[0] = -1; + } + else if (status > 0) + { + buf_output0 (buf_to_net, "E buf_input_data failed\n"); + print_error (status); + goto error_exit; + } + + /* What should we do with errors? syslog() them? */ + buf_send_output (buf_to_net); + } + + if (stderr_pipe[0] >= 0 + && (FD_ISSET (stderr_pipe[0], &readfds))) + { + int status; + + status = buf_input_data (stderrbuf, (int *) NULL); + + buf_copy_lines (buf_to_net, stderrbuf, 'E'); + + if (status == -1) + { + close (stderr_pipe[0]); + stderr_pipe[0] = -1; + } + else if (status > 0) + { + buf_output0 (buf_to_net, "E buf_input_data failed\n"); + print_error (status); + goto error_exit; + } + + /* What should we do with errors? syslog() them? */ + buf_send_output (buf_to_net); + } } /* @@ -3045,6 +3113,11 @@ error \n"); buf_output0 (buf_to_net, "E Protocol error: uncounted data discarded\n"); +#ifdef SERVER_FLOWCONTROL + close (flowcontrol_pipe[1]); + flowcontrol_pipe[1] = -1; +#endif /* SERVER_FLOWCONTROL */ + errs = 0; while (command_pid > 0) @@ -3099,6 +3172,12 @@ E CVS locks may need cleaning up.\n"); */ set_block (buf_to_net); buf_flush (buf_to_net, 1); + buf_shutdown (protocol_inbuf); + buf_free (protocol_inbuf); + buf_shutdown (stderrbuf); + buf_free (stderrbuf); + buf_shutdown (stdoutbuf); + buf_free (stdoutbuf); } if (errs) @@ -3129,6 +3208,10 @@ E CVS locks may need cleaning up.\n"); close (stderr_pipe[1]); close (stdout_pipe[0]); close (stdout_pipe[1]); +#ifdef SERVER_FLOWCONTROL + close (flowcontrol_pipe[0]); + close (flowcontrol_pipe[1]); +#endif /* SERVER_FLOWCONTROL */ free_args_and_return: /* Now free the arguments. */ @@ -3184,6 +3267,7 @@ server_pause_check() if (numfds < 0 && errno != EINTR) { + buf_output0 (buf_to_net, "E select failed\n"); print_error (errno); return; } @@ -3624,23 +3708,29 @@ serve_editors (arg) do_cvs_command ("editors", editors); } -static int noop PROTO ((int, char **)); +static void serve_noop PROTO ((char *)); -static int -noop (argc, argv) - int argc; - char **argv; +static void +serve_noop (arg) + char *arg; { - return 0; + + server_write_entries (); + if (!print_pending_error ()) + { + (void) server_notify (); + buf_output0 (buf_to_net, "ok\n"); + } + buf_flush (buf_to_net, 1); } -static void serve_noop PROTO ((char *)); +static void serve_version PROTO ((char *)); static void -serve_noop (arg) +serve_version (arg) char *arg; { - do_cvs_command ("noop", noop); + do_cvs_command ("version", version); } static void serve_init PROTO ((char *)); @@ -4017,7 +4107,7 @@ CVS server internal error: unhandled case in server_updated"); if (file != NULL) { - buf_output (protocol, file, file_used); + buf_output (protocol, (char *) file, file_used); free (file); file = NULL; } @@ -4314,9 +4404,9 @@ serve_ignore (arg) } static int -expand_proc (pargc, argv, where, mwhere, mfile, shorten, +expand_proc (argc, argv, where, mwhere, mfile, shorten, local_specified, omodule, msg) - int *pargc; + int argc; char **argv; char *where; char *mwhere; @@ -4355,7 +4445,7 @@ expand_proc (pargc, argv, where, mwhere, mfile, shorten, { /* We may not need to do this anymore -- check the definition of aliases before removing */ - if (*pargc == 1) + if (argc == 1) { buf_output0 (buf_to_net, "Module-expansion "); if (server_dir != NULL) @@ -4368,7 +4458,7 @@ expand_proc (pargc, argv, where, mwhere, mfile, shorten, } else { - for (i = 1; i < *pargc; ++i) + for (i = 1; i < argc; ++i) { buf_output0 (buf_to_net, "Module-expansion "); if (server_dir != NULL) @@ -4460,24 +4550,27 @@ serve_checkin_prog (arg) f = CVS_FOPEN (CVSADM_CIPROG, "w+"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_CIPROG))) sprintf (pending_error_text, "E cannot open %s", CVSADM_CIPROG); + pending_error = save_errno; return; } if (fprintf (f, "%s\n", arg) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_CIPROG))) sprintf (pending_error_text, "E cannot write to %s", CVSADM_CIPROG); + pending_error = save_errno; return; } if (fclose (f) == EOF) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_CIPROG))) sprintf (pending_error_text, "E cannot close %s", CVSADM_CIPROG); + pending_error = save_errno; return; } } @@ -4503,23 +4596,26 @@ E Flag -u in modules not allowed in readonly mode"); f = CVS_FOPEN (CVSADM_UPROG, "w+"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_UPROG))) sprintf (pending_error_text, "E cannot open %s", CVSADM_UPROG); + pending_error = save_errno; return; } if (fprintf (f, "%s\n", arg) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_UPROG))) sprintf (pending_error_text, "E cannot write to %s", CVSADM_UPROG); + pending_error = save_errno; return; } if (fclose (f) == EOF) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_UPROG))) sprintf (pending_error_text, "E cannot close %s", CVSADM_UPROG); + pending_error = save_errno; return; } } @@ -4572,7 +4668,7 @@ struct request requests[] = REQ_LINE("Case", serve_case, 0), REQ_LINE("Argument", serve_argument, RQ_ESSENTIAL), REQ_LINE("Argumentx", serve_argumentx, RQ_ESSENTIAL), - REQ_LINE("Global_option", serve_global_option, 0), + REQ_LINE("Global_option", serve_global_option, RQ_ROOTLESS), REQ_LINE("Gzip-stream", serve_gzip_stream, 0), REQ_LINE("wrapper-sendme-rcsOptions", serve_wrapper_sendme_rcs_options, @@ -4616,7 +4712,8 @@ struct request requests[] = REQ_LINE("editors", serve_editors, 0), REQ_LINE("init", serve_init, RQ_ROOTLESS), REQ_LINE("annotate", serve_annotate, 0), - REQ_LINE("noop", serve_noop, 0), + REQ_LINE("noop", serve_noop, RQ_ROOTLESS), + REQ_LINE("version", serve_version, RQ_ROOTLESS), REQ_LINE(NULL, NULL, 0) #undef REQ_LINE @@ -4840,16 +4937,10 @@ server (argc, argv) for that case. */ if (!isabsolute (Tmpdir)) { - pending_error_text = malloc (80 + strlen (Tmpdir)); - if (pending_error_text == NULL) - { - pending_error = ENOMEM; - } - else - { + if (alloc_pending (80 + strlen (Tmpdir))) sprintf (pending_error_text, "E Value of %s for TMPDIR is not absolute", Tmpdir); - } + /* FIXME: we would like this error to be persistent, that is, not cleared by print_pending_error. The current client will exit as soon as it gets an error, but the protocol spec @@ -4858,6 +4949,7 @@ server (argc, argv) else { int status; + int i = 0; server_temp_dir = malloc (strlen (Tmpdir) + 80); if (server_temp_dir == NULL) @@ -4904,12 +4996,21 @@ error ENOMEM Virtual memory exhausted.\n"); /* Create the temporary directory, and set the mode to 700, to discourage random people from tampering with it. */ - status = mkdir_p (server_temp_dir); - if (status != 0 && status != EEXIST) + while ((status = mkdir_p (server_temp_dir)) == EEXIST) { - if (alloc_pending (80)) - strcpy (pending_error_text, - "E can't create temporary directory"); + static const char suffix[] = "abcdefghijklmnopqrstuvwxyz"; + + if (i >= sizeof suffix - 1) break; + if (i == 0) p = server_temp_dir + strlen (server_temp_dir); + p[0] = suffix[i++]; + p[1] = '\0'; + } + if (status != 0) + { + if (alloc_pending (80 + strlen (server_temp_dir))) + sprintf (pending_error_text, + "E can't create temporary directory %s", + server_temp_dir); pending_error = status; } #ifndef CHMOD_BROKEN @@ -4918,9 +5019,10 @@ error ENOMEM Virtual memory exhausted.\n"); if (chmod (server_temp_dir, S_IRWXU) < 0) { int save_errno = errno; - if (alloc_pending (80)) - strcpy (pending_error_text, "\ -E cannot change permissions on temporary directory"); + if (alloc_pending (80 + strlen (server_temp_dir))) + sprintf (pending_error_text, +"E cannot change permissions on temporary directory %s", + server_temp_dir); pending_error = save_errno; } } @@ -4928,6 +5030,9 @@ E cannot change permissions on temporary directory"); } } +#ifdef SIGABRT + (void) SIG_register (SIGABRT, server_cleanup); +#endif #ifdef SIGHUP (void) SIG_register (SIGHUP, server_cleanup); #endif @@ -5107,7 +5212,7 @@ error 0 %s: no such user\n", username); if (setgid (getegid ()) < 0) { /* See comments at setuid call below for more discussion. */ - printf ("error 0 setuid failed: %s\n", strerror (errno)); + printf ("error 0 setgid failed: %s\n", strerror (errno)); /* Don't worry about server_cleanup; server_active isn't set yet. */ error_exit (); @@ -5119,7 +5224,7 @@ error 0 %s: no such user\n", username); if (setgid (pw->pw_gid) < 0) { /* See comments at setuid call below for more discussion. */ - printf ("error 0 setuid failed: %s\n", strerror (errno)); + printf ("error 0 setgid failed: %s\n", strerror (errno)); /* Don't worry about server_cleanup; server_active isn't set yet. */ error_exit (); @@ -5144,6 +5249,12 @@ error 0 %s: no such user\n", username); the client. */ umask (0); +#ifdef AUTH_SERVER_SUPPORT + /* Make sure our CVS_Username has been set. */ + if (CVS_Username == NULL) + CVS_Username = xstrdup (username); +#endif + #if HAVE_PUTENV /* Set LOGNAME and USER in the environment, in case they are already set to something else. */ @@ -5169,14 +5280,15 @@ extern char *crypt PROTO((const char *, const char *)); /* * 0 means no entry found for this user. - * 1 means entry found and password matches. + * 1 means entry found and password matches (or found password is empty) * 2 means entry found, but password does not match. * - * If success, host_user_ptr will be set to point at the system + * If 1, host_user_ptr will be set to point at the system * username (i.e., the "real" identity, which may or may not be the * CVS username) of this user; caller may free this. Global * CVS_Username will point at an allocated copy of cvs username (i.e., * the username argument below). + * kff todo: FIXME: last sentence is not true, it applies to caller. */ static int check_repository_password (username, password, repository, host_user_ptr) @@ -5229,18 +5341,72 @@ check_repository_password (username, password, repository, host_user_ptr) if (fclose (fp) < 0) error (0, errno, "cannot close %s", filename); - /* If found_it != 0, then linebuf contains the information we need. */ + /* If found_it, then linebuf contains the information we need. */ if (found_it) { char *found_password, *host_user_tmp; + char *non_cvsuser_portion; + + /* We need to make sure lines such as + * + * "username::sysuser\n" + * "username:\n" + * "username: \n" + * + * all result in a found_password of NULL, but we also need to + * make sure that + * + * "username: :sysuser\n" + * "username: :sysuser\n" + * + * continues to result in an impossible password. That way, + * an admin would be on safe ground by going in and tacking a + * space onto the front of a password to disable the account + * (a technique some people use to close accounts + * temporarily). + */ + + /* Make `non_cvsuser_portion' contain everything after the CVS + username, but null out any final newline. */ + non_cvsuser_portion = linebuf + namelen; + strtok (non_cvsuser_portion, "\n"); + + /* If there's a colon now, we just want to inch past it. */ + if (strchr (non_cvsuser_portion, ':') == non_cvsuser_portion) + non_cvsuser_portion++; + + /* Okay, after this conditional chain, found_password and + host_user_tmp will have useful values: */ + + if ((non_cvsuser_portion == NULL) + || (strlen (non_cvsuser_portion) == 0) + || ((strspn (non_cvsuser_portion, " \t")) + == strlen (non_cvsuser_portion))) + { + found_password = NULL; + host_user_tmp = NULL; + } + else if (strncmp (non_cvsuser_portion, ":", 1) == 0) + { + found_password = NULL; + host_user_tmp = non_cvsuser_portion + 1; + if (strlen (host_user_tmp) == 0) + host_user_tmp = NULL; + } + else + { + found_password = strtok (non_cvsuser_portion, ":"); + host_user_tmp = strtok (NULL, ":"); + } - strtok (linebuf, ":"); - found_password = strtok (NULL, ": \n"); - host_user_tmp = strtok (NULL, ": \n"); + /* Of course, maybe there was no system user portion... */ if (host_user_tmp == NULL) host_user_tmp = username; - if (strcmp (found_password, crypt (password, found_password)) == 0) + /* Verify blank passwords directly, otherwise use crypt(). */ + if ((found_password == NULL) + || ((strcmp (found_password, crypt (password, found_password)) + == 0))) { /* Give host_user_ptr permanent storage. */ *host_user_ptr = xstrdup (host_user_tmp); @@ -5252,7 +5418,7 @@ check_repository_password (username, password, repository, host_user_ptr) retval = 2; } } - else + else /* Didn't find this user, so deny access. */ { *host_user_ptr = NULL; retval = 0; @@ -5335,14 +5501,14 @@ error 0 %s: no such user\n", username); /* user exists and has a password */ host_user = ((! strcmp (found_passwd, crypt (password, found_passwd))) - ? username : NULL); + ? xstrdup (username) : NULL); goto handle_return; } else if (password && *password) { /* user exists and has no system password, but we got one as parameter */ - host_user = username; + host_user = xstrdup (username); goto handle_return; } else @@ -5472,7 +5638,7 @@ pserver_authenticate_connection () #endif /* Make sure the protocol starts off on the right foot... */ - if (getline (&tmp, &tmp_allocated, stdin) < 0) + if (getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX) < 0) /* FIXME: what? We could try writing error/eof, but chances are the network connection is dead bidirectionally. log it somewhere? */ @@ -5503,9 +5669,9 @@ pserver_authenticate_connection () /* Get the three important pieces of information in order. */ /* See above comment about error handling. */ - getline (&repository, &repository_allocated, stdin); - getline (&username, &username_allocated, stdin); - getline (&password, &password_allocated, stdin); + getline_safe (&repository, &repository_allocated, stdin, PATH_MAX); + getline_safe (&username, &username_allocated, stdin, PATH_MAX); + getline_safe (&password, &password_allocated, stdin, PATH_MAX); /* Make them pure. */ strip_trailing_newlines (repository); @@ -5514,7 +5680,7 @@ pserver_authenticate_connection () /* ... and make sure the protocol ends on the right foot. */ /* See above comment about error handling. */ - getline (&tmp, &tmp_allocated, stdin); + getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX); if (strcmp (tmp, verify_and_exit ? "END VERIFICATION REQUEST\n" : "END AUTH REQUEST\n") @@ -5576,6 +5742,7 @@ pserver_authenticate_connection () /* Switch to run as this user. */ switch_to_user (host_user); + free (host_user); free (tmp); free (repository); free (username); diff --git a/contrib/cvs/src/subr.c b/contrib/cvs/src/subr.c index 6a97f28..c9f3747 100644 --- a/contrib/cvs/src/subr.c +++ b/contrib/cvs/src/subr.c @@ -171,7 +171,8 @@ pathname_levels (path) if (-level > max_level) max_level = -level; } - else if (p[0] == '.' && (p[1] == '\0' || p[1] == '/')) + else if (p[0] == '\0' || p[0] == '/' || + (p[0] == '.' && (p[1] == '\0' || p[1] == '/'))) ; else ++level; @@ -218,9 +219,7 @@ line2argv (pargc, argv, line, sepchars) int argv_allocated; /* Small for testing. */ - /* argv_allocated must be at least 3 because at some places - (e.g. checkout_proc) cvs alters argv[2]. */ - argv_allocated = 4; + argv_allocated = 1; *argv = (char **) xmalloc (argv_allocated * sizeof (**argv)); *pargc = 0; @@ -586,7 +585,9 @@ file_has_markers (finfo) error (1, errno, "cannot open %s", finfo->fullname); while (getline (&line, &line_allocated, fp) > 0) { - if (strncmp (line, RCS_MERGE_PAT, sizeof RCS_MERGE_PAT - 1) == 0) + if (strncmp (line, RCS_MERGE_PAT_1, sizeof RCS_MERGE_PAT_1 - 1) == 0 || + strncmp (line, RCS_MERGE_PAT_2, sizeof RCS_MERGE_PAT_2 - 1) == 0 || + strncmp (line, RCS_MERGE_PAT_3, sizeof RCS_MERGE_PAT_3 - 1) == 0) { result = 1; goto out; @@ -647,9 +648,9 @@ get_file (name, fullname, mode, buf, bufsize, len) e = open_file (name, mode); } - if (*bufsize < filesize) + if (*buf == NULL || *bufsize <= filesize) { - *bufsize = filesize; + *bufsize = filesize + 1; *buf = xrealloc (*buf, *bufsize); } @@ -691,12 +692,9 @@ get_file (name, fullname, mode, buf, bufsize, len) *len = nread; /* Force *BUF to be large enough to hold a null terminator. */ - if (*buf != NULL) - { - if (nread == *bufsize) - expand_string (buf, bufsize, *bufsize + 1); - (*buf)[nread] = '\0'; - } + if (nread == *bufsize) + expand_string (buf, bufsize, *bufsize + 1); + (*buf)[nread] = '\0'; } @@ -744,3 +742,37 @@ resolve_symlink (filename) } } } + +/* + * Rename a file to an appropriate backup name based on BAKPREFIX. + * If suffix non-null, then "." is appended to the new name. + * + * Returns the new name, which caller may free() if desired. + */ +char * +backup_file (filename, suffix) + const char *filename; + const char *suffix; +{ + char *backup_name; + + if (suffix == NULL) + { + backup_name = xmalloc (sizeof (BAKPREFIX) + strlen (filename) + 1); + sprintf (backup_name, "%s%s", BAKPREFIX, filename); + } + else + { + backup_name = xmalloc (sizeof (BAKPREFIX) + + strlen (filename) + + strlen (suffix) + + 2); /* one for dot, one for trailing '\0' */ + sprintf (backup_name, "%s%s.%s", BAKPREFIX, filename, suffix); + } + + if (isfile (filename)) + copy_file (filename, backup_name); + + return backup_name; +} + diff --git a/contrib/cvs/src/tag.c b/contrib/cvs/src/tag.c index fb19cba..a9d8534 100644 --- a/contrib/cvs/src/tag.c +++ b/contrib/cvs/src/tag.c @@ -234,9 +234,12 @@ check_fileproc (callerdat, finfo) if ((status != T_UPTODATE) && (status != T_CHECKOUT)) { error (0, 0, "%s is locally modified", finfo->fullname); + freevers_ts (&vers); return (1); } } + else + vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); if (finfo->update_dir[0] == '\0') xdir = "."; @@ -266,11 +269,12 @@ check_fileproc (callerdat, finfo) p->key = xstrdup (finfo->file); p->type = UPDATE; p->delproc = tag_delproc; - vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); if (vers->srcfile == NULL) { if (!really_quiet) error (0, 0, "nothing known about %s", finfo->file); + freevers_ts (&vers); + freenode (p); return (1); } @@ -579,6 +583,8 @@ tag_fileproc (callerdat, finfo) if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch) { free (oversion); + if (branch_mode) + free (rev); freevers_ts (&vers); return (0); } @@ -600,6 +606,8 @@ tag_fileproc (callerdat, finfo) cvs_output (rev, 0); cvs_output ("\n", 1); free (oversion); + if (branch_mode) + free (rev); freevers_ts (&vers); return (0); } @@ -611,9 +619,13 @@ tag_fileproc (callerdat, finfo) error (1, retcode == -1 ? errno : 0, "failed to set tag %s to revision %s in %s", symtag, rev, vers->srcfile->path); + if (branch_mode) + free (rev); freevers_ts (&vers); return (1); } + if (branch_mode) + free (rev); RCS_rewrite (vers->srcfile, NULL, NULL); /* more warm fuzzies */ @@ -718,7 +730,7 @@ val_direntproc (callerdat, dir, repository, update_dir, entries) files in a directory which does not exist yet, but which is about to be created. */ if (isdir (dir)) - return 0; + return R_PROCESS; return R_SKIP_ALL; } diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c index 4a24d15..81d4fea 100644 --- a/contrib/cvs/src/update.c +++ b/contrib/cvs/src/update.c @@ -94,6 +94,7 @@ static char *tag_update_dir; static char *join_rev1, *date_rev1; static char *join_rev2, *date_rev2; static int aflag = 0; +static int toss_local_changes = 0; static int force_tag_match = 1; static int update_build_dirs = 0; static int update_prune_dirs = 0; @@ -110,6 +111,7 @@ static const char *const update_usage[] = " [-I ign] [-W spec] [files...]\n", "\t-A\tReset any sticky tags/date/kopts.\n", "\t-P\tPrune empty directories.\n", + "\t-C\tOverwrite locally modified files with clean repository copies.\n", "\t-d\tBuild directories, like checkout does.\n", "\t-f\tForce a head revision match if tag/date not found.\n", "\t-l\tLocal directory only, no recursion.\n", @@ -145,13 +147,16 @@ update (argc, argv) /* parse the args */ optind = 0; - while ((c = getopt (argc, argv, "+ApPflRQqduk:r:D:j:I:W:")) != -1) + while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:D:j:I:W:")) != -1) { switch (c) { case 'A': aflag = 1; break; + case 'C': + toss_local_changes = 1; + break; case 'I': ign_add (optarg, 0); break; @@ -252,6 +257,8 @@ update (argc, argv) send_arg("-f"); if (aflag) send_arg("-A"); + if (toss_local_changes) + send_arg("-C"); if (update_prune_dirs) send_arg("-P"); client_prune_dirs = update_prune_dirs; @@ -266,28 +273,35 @@ update (argc, argv) option_with_arg ("-j", join_rev2); wrap_send (); - /* If the server supports the command "update-patches", that means - that it knows how to handle the -u argument to update, which - means to send patches instead of complete files. - - We don't send -u if failed_patches != NULL, so that the - server doesn't try to send patches which will just fail - again. At least currently, the client also clobbers the - file and tells the server it is lost, which also will get - a full file instead of a patch, but it seems clean to omit - -u. */ - if (failed_patches == NULL) + if (failed_patches_count == 0) { + unsigned int flags = 0; + + /* If the server supports the command "update-patches", that + means that it knows how to handle the -u argument to update, + which means to send patches instead of complete files. + + We don't send -u if failed_patches != NULL, so that the + server doesn't try to send patches which will just fail + again. At least currently, the client also clobbers the + file and tells the server it is lost, which also will get + a full file instead of a patch, but it seems clean to omit + -u. */ if (supported_request ("update-patches")) send_arg ("-u"); - } - if (failed_patches == NULL) - { + if (update_build_dirs) + flags |= SEND_BUILD_DIRS; + + if (toss_local_changes) { + flags |= SEND_NO_CONTENTS; + flags |= BACKUP_MODIFIED_FILES; + } + /* If noexec, probably could be setting SEND_NO_CONTENTS. Same caveats as for "cvs status" apply. */ - send_files (argc, argv, local, aflag, - update_build_dirs ? SEND_BUILD_DIRS : 0); + + send_files (argc, argv, local, aflag, flags); send_file_names (argc, argv, SEND_EXPAND_WILD); } else @@ -311,11 +325,9 @@ update (argc, argv) send_files (failed_patches_count, failed_patches, local, aflag, update_build_dirs ? SEND_BUILD_DIRS : 0); send_file_names (failed_patches_count, failed_patches, 0); + free_names (&failed_patches_count, failed_patches); } - failed_patches = NULL; - failed_patches_count = 0; - send_to_server ("update\012", 0); status = get_responses_and_close (); @@ -334,13 +346,15 @@ update (argc, argv) conflict-and-patch-failed case. */ if (status != 0 - && (failed_patches == NULL || pass > 1)) + && (failed_patches_count == 0 || pass > 1)) { + if (failed_patches_count > 0) + free_names (&failed_patches_count, failed_patches); return status; } ++pass; - } while (failed_patches != NULL); + } while (failed_patches_count > 0); return 0; } @@ -366,15 +380,20 @@ update (argc, argv) error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); #ifdef SERVER_SUPPORT if (server_active) - server_clear_entstat (".", Name_Repository (NULL, NULL)); + { + char *repos = Name_Repository (NULL, NULL); + server_clear_entstat (".", repos); + free (repos); + } #endif } /* keep the CVS/Tag file current with the specified arguments */ if (aflag || tag || date) { - WriteTag ((char *) NULL, tag, date, 0, - ".", Name_Repository (NULL, NULL)); + char *repos = Name_Repository (NULL, NULL); + WriteTag ((char *) NULL, tag, date, 0, ".", repos); + free (repos); rewrite_tag = 1; nonbranch = 0; } @@ -484,17 +503,11 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, argc, argv, local, which, aflag, 1, preload_update_dir, 1); - /* see if we need to sleep before returning */ + /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - time_t now; - - for (;;) - { - (void) time (&now); - if (now != last_register_time) break; - sleep (1); /* to avoid time-stamp races */ - } + while (time ((time_t *) NULL) == last_register_time) + sleep (1); } return (err); @@ -641,54 +654,82 @@ update_fileproc (callerdat, finfo) break; case T_MODIFIED: /* locally modified */ retval = 0; - if (vers->ts_conflict) - { - char *filestamp; - int retcode; + if (toss_local_changes) + { + char *bakname; + bakname = backup_file (finfo->file, vers->vn_user); + /* This behavior is sufficiently unexpected to + justify overinformativeness, I think. */ +#ifdef SERVER_SUPPORT + if ((! really_quiet) && (! server_active)) +#else /* ! SERVER_SUPPORT */ + if (! really_quiet) +#endif /* SERVER_SUPPORT */ + (void) printf ("(Locally modified %s moved to %s)\n", + finfo->file, bakname); + free (bakname); + + /* The locally modified file is still present, but + it will be overwritten by the repository copy + after this. */ + status = T_CHECKOUT; + retval = checkout_file (finfo, vers, 0, 0, 1); + } + else + { + if (vers->ts_conflict) + { + char *filestamp; + int retcode; + + /* + * If the timestamp has changed and no + * conflict indicators are found, it isn't a + * 'C' any more. + */ - /* - * If the timestamp has changed and no conflict indicators - * are found, it isn't a 'C' any more. - */ #ifdef SERVER_SUPPORT - if (server_active) - retcode = vers->ts_conflict[0] != '='; - else { - filestamp = time_stamp (finfo->file); - retcode = strcmp (vers->ts_conflict, filestamp); - free (filestamp); - } + if (server_active) + retcode = vers->ts_conflict[0] != '='; + else + { + filestamp = time_stamp (finfo->file); + retcode = strcmp (vers->ts_conflict, filestamp); + free (filestamp); + } #else - filestamp = time_stamp (finfo->file); - retcode = strcmp (vers->ts_conflict, filestamp); - free (filestamp); + filestamp = time_stamp (finfo->file); + retcode = strcmp (vers->ts_conflict, filestamp); + free (filestamp); #endif - if (retcode) - { - /* The timestamps differ. But if there are conflict - markers print 'C' anyway. */ - retcode = !file_has_markers (finfo); - } - - if (!retcode) - { - write_letter (finfo, 'C'); - retval = 1; - } - else - { - /* Reregister to clear conflict flag. */ - Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs, - vers->options, vers->tag, - vers->date, (char *)0); - } - } - if (!retval) - { - write_letter (finfo, 'M'); - retval = 0; - } + if (retcode) + { + /* The timestamps differ. But if there + are conflict markers print 'C' anyway. */ + retcode = !file_has_markers (finfo); + } + + if (!retcode) + { + write_letter (finfo, 'C'); + retval = 1; + } + else + { + /* Reregister to clear conflict flag. */ + Register (finfo->entries, finfo->file, + vers->vn_rcs, vers->ts_rcs, + vers->options, vers->tag, + vers->date, (char *)0); + } + } + if (!retval) + { + write_letter (finfo, 'M'); + retval = 0; + } + } break; #ifdef SERVER_SUPPORT case T_PATCH: /* needs patch */ @@ -928,7 +969,8 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries) /* This is a guess. We will rewrite it later via WriteTag. */ 0, - 0); + 0, + 1); rewrite_tag = 1; nonbranch = 0; Subdir_Register (entries, (char *) NULL, dir); @@ -1014,6 +1056,10 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries) { FILE *fp; + /* Delete the ignore list if it hasn't already been done. */ + if (ignlist) + dellist (&ignlist); + /* If we set the tag or date for a new subdirectory in update_dirent_proc, and we're now done with that subdirectory, undo the tag/date setting. Note that we know that the tag and @@ -1059,6 +1105,7 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries) cvs_output (": Executing '", 0); run_print (stdout); cvs_output ("'\n", 0); + cvs_flushout (); (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); } else if (ferror (fp)) @@ -2049,7 +2096,7 @@ join_file (finfo, vers) Vers_TS *vers; { char *backup; - char *options; + char *t_options; int status; char *rev1; @@ -2284,6 +2331,13 @@ join_file (finfo, vers) xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0); + /* Reset any keyword expansion option. Otherwise, when a + command like `cvs update -kk -jT1 -jT2' creates a new file + (because a file had the T2 tag, but not T1), the subsequent + commit of that just-added file effectively would set the + admin `-kk' option for that file in the repository. */ + options = NULL; + /* FIXME: If checkout_file fails, we should arrange to return a non-zero exit status. */ status = checkout_file (finfo, xvers, 1, 0, 1); @@ -2326,11 +2380,11 @@ join_file (finfo, vers) if (jdate2 != NULL) error (0, 0, - "file %s is present in revision %s as of %s", + "file %s does not exist, but is present in revision %s as of %s", finfo->fullname, jrev2, jdate2); else error (0, 0, - "file %s is present in revision %s", + "file %s does not exist, but is present in revision %s", finfo->fullname, jrev2); /* FIXME: Should we arrange to return a non-zero exit status? */ @@ -2372,10 +2426,10 @@ join_file (finfo, vers) copy_file (finfo->file, backup); xchmod (finfo->file, 1); - options = vers->options; + t_options = vers->options; #if 0 - if (*options == '\0') - options = "-kk"; /* to ignore keyword expansions */ + if (*t_options == '\0') + t_options = "-kk"; /* to ignore keyword expansions */ #endif /* If the source of the merge is the same as the working file @@ -2393,12 +2447,12 @@ join_file (finfo, vers) /* This is because of the worry below about $Name. If that isn't a problem, I suspect this code probably works for text files too. */ - && (strcmp (options, "-kb") == 0 + && (strcmp (t_options, "-kb") == 0 || wrap_merge_is_copy (finfo->file))) { /* FIXME: what about nametag? What does RCS_merge do with $Name? */ - if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options, + if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0) status = 2; else @@ -2422,7 +2476,7 @@ join_file (finfo, vers) print. */ write_letter (finfo, 'U'); } - else if (strcmp (options, "-kb") == 0 + else if (strcmp (t_options, "-kb") == 0 || wrap_merge_is_copy (finfo->file) || special_file_mismatch (finfo, rev1, rev2)) { @@ -2432,7 +2486,7 @@ join_file (finfo, vers) the two files, and let them resolve it. It is possible that we should require a "touch foo" or similar step before we allow a checkin. */ - if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options, + if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0) status = 2; else @@ -2463,7 +2517,7 @@ join_file (finfo, vers) } else status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file, - options, rev1, rev2); + t_options, rev1, rev2); if (status != 0 && status != 1) { @@ -2494,9 +2548,9 @@ join_file (finfo, vers) (void) time (&last_register_time); cp = time_stamp (finfo->file); } - Register (finfo->entries, finfo->file, vers->vn_rcs, - "Result of merge", vers->options, vers->tag, - vers->date, cp); + Register (finfo->entries, finfo->file, + vers->vn_rcs ? vers->vn_rcs : "0", "Result of merge", + vers->options, vers->tag, vers->date, cp); if (cp) free(cp); } @@ -2544,8 +2598,8 @@ special_file_mismatch (finfo, rev1, rev2) dev_t rev1_dev, rev2_dev; char *rev1_symlink = NULL; char *rev2_symlink = NULL; - List *rev1_hardlinks; - List *rev2_hardlinks; + List *rev1_hardlinks = NULL; + List *rev2_hardlinks = NULL; int check_uids, check_gids, check_modes; int result; @@ -2574,6 +2628,7 @@ special_file_mismatch (finfo, rev1, rev2) rev1_symlink = xreadlink (finfo->file); else { +#ifdef HAVE_ST_RDEV if (CVS_LSTAT (finfo->file, &sb) < 0) error (1, errno, "could not get file information for %s", finfo->file); @@ -2582,6 +2637,10 @@ special_file_mismatch (finfo, rev1, rev2) rev1_mode = sb.st_mode; if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode)) rev1_dev = sb.st_rdev; +#else + error (1, 0, "cannot handle device files on this system (%s)", + finfo->file); +#endif } rev1_hardlinks = list_linked_files_on_disk (finfo->file); } @@ -2647,6 +2706,7 @@ special_file_mismatch (finfo, rev1, rev2) rev2_symlink = xreadlink (finfo->file); else { +#ifdef HAVE_ST_RDEV if (CVS_LSTAT (finfo->file, &sb) < 0) error (1, errno, "could not get file information for %s", finfo->file); @@ -2655,6 +2715,10 @@ special_file_mismatch (finfo, rev1, rev2) rev2_mode = sb.st_mode; if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode)) rev2_dev = sb.st_rdev; +#else + error (1, 0, "cannot handle device files on this system (%s)", + finfo->file); +#endif } rev2_hardlinks = list_linked_files_on_disk (finfo->file); } diff --git a/contrib/cvs/src/vers_ts.c b/contrib/cvs/src/vers_ts.c index e1ba32d..8d55284 100644 --- a/contrib/cvs/src/vers_ts.c +++ b/contrib/cvs/src/vers_ts.c @@ -87,22 +87,17 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) vers_ts->vn_user = xstrdup (entdata->version); vers_ts->ts_rcs = xstrdup (entdata->timestamp); vers_ts->ts_conflict = xstrdup (entdata->conflict); - if (!tag) + if (!(tag || date) && !(sdtp && sdtp->aflag)) { - if (!(sdtp && sdtp->aflag)) - vers_ts->tag = xstrdup (entdata->tag); - } - if (!date) - { - if (!(sdtp && sdtp->aflag)) - vers_ts->date = xstrdup (entdata->date); + vers_ts->tag = xstrdup (entdata->tag); + vers_ts->date = xstrdup (entdata->date); } vers_ts->entdata = entdata; } /* Even if we don't have an "entries line" as such (vers_ts->entdata), we want to pick up options which could have been from a Kopt protocol request. */ - if (!options || (options && *options == '\0')) + if (!options || *options == '\0') { if (!(sdtp && sdtp->aflag)) vers_ts->options = xstrdup (entdata->options); @@ -126,6 +121,8 @@ Version_TS (finfo, options, tag, date, force_tag_match, set_time) char *rcsexpand = RCS_getexpand (finfo->rcs); if (rcsexpand != NULL) { + if (vers_ts->options != NULL) + free (vers_ts->options); vers_ts->options = xmalloc (strlen (rcsexpand) + 3); strcpy (vers_ts->options, "-k"); strcat (vers_ts->options, rcsexpand); diff --git a/contrib/cvs/src/version.c b/contrib/cvs/src/version.c index 97622ff..c8273fb 100644 --- a/contrib/cvs/src/version.c +++ b/contrib/cvs/src/version.c @@ -12,7 +12,7 @@ #include "cvs.h" -char *version_string = "\nConcurrent Versions System (CVS) 1.10.7"; +char *version_string = "Concurrent Versions System (CVS) 1.11"; #ifdef CLIENT_SUPPORT #ifdef SERVER_SUPPORT @@ -27,3 +27,49 @@ char *config_string = " (server)\n"; char *config_string = "\n"; #endif #endif + +static const char *const version_usage[] = +{ + "Usage: %s %s\n", + NULL +}; + +int +version (argc, argv) + int argc; + char **argv; +{ + int err = 0; + + if (argc == -1) + usage (version_usage); + +#ifdef CLIENT_SUPPORT + if (client_active) + (void) fputs ("Client: ", stdout); +#endif + + /* Having the year here is a good idea, so people have + some idea of how long ago their version of CVS was + released. */ + (void) fputs (version_string, stdout); + (void) fputs (config_string, stdout); + +#ifdef CLIENT_SUPPORT + if (client_active) + { + (void) fputs ("Server: ", stdout); + start_server (); + if (supported_request ("version")) + send_to_server ("version\012", 0); + else + { + send_to_server ("noop\012", 0); + fputs ("(unknown)\n", stdout); + } + err = get_responses_and_close (); + } +#endif + return err; +} + diff --git a/contrib/cvs/src/watch.c b/contrib/cvs/src/watch.c index b2935ac..1a0ecfe 100644 --- a/contrib/cvs/src/watch.c +++ b/contrib/cvs/src/watch.c @@ -473,6 +473,7 @@ watchers_fileproc (callerdat, finfo) cvs_output ("\n", 1); } out:; + free (them); return 0; } diff --git a/contrib/cvs/src/zlib.c b/contrib/cvs/src/zlib.c index fa0c2ad..3bfc542 100644 --- a/contrib/cvs/src/zlib.c +++ b/contrib/cvs/src/zlib.c @@ -467,9 +467,9 @@ gunzip_and_write (fd, fullname, buf, size) if (buf[3] & 4) pos += buf[pos] + (buf[pos + 1] << 8) + 2; if (buf[3] & 8) - pos += strlen (buf + pos) + 1; + pos += strlen ((char *) buf + pos) + 1; if (buf[3] & 16) - pos += strlen (buf + pos) + 1; + pos += strlen ((char *) buf + pos) + 1; if (buf[3] & 2) pos += 2; -- cgit v1.1